面向对象继承

介绍

面向对象的三大特征:封装性、继承性、多态性。
继承是多态的前提,如果没有继承,就没有多态。
继承主要解决的问题就是:共性抽取。在继承的关系中,子类就是一个父类”。也就是说,子类可以被当做父类看待。例如父类是员工,子类是讲师,那么“讲师就是一个员工”。 关系: is-a。

格式

  1. 定义父类的格式: (一个普通的类定义)
  2. public class 父类名称{
  3. }
  4. 定义子类的格式:
  5. public class子类名称extends父类名称{
  6. // ...
  7. }

举例

  1. //定义一个父类:员工
  2. public c1ass Employee{
  3. public void method () {
  4. System.out.println("方法执行! ");
  5. }
  6. }
  1. //定义了一个员工的子类:讲师
  2. public class Teacher extends Employee {
  3. }
  1. //定义一个父类:员工
  2. public class Employee {
  3. public void method() {
  4. System.out.println("方法执行! ");
  5. }
  6. }
  1. //定义一个父类:员工
  2. public class Assistant {
  3. public void method() {
  4. }
  5. }
  1. //执行程序
  2. public class Demo01Extends {
  3. public static void main(String[] args) {
  4. //创建了一个子类对象
  5. Teacher teacher = new Teacher() ;
  6. // Teacher类当 中虽然什么都没写,但是会继承来自父类的method方法。
  7. teacher.method();//System. out. println(“方法执行! ");
  8. //创建另一个子类助教的对象
  9. Assistant assistant = new Assistant();
  10. assistant.method( );
  11. }
  12. }

证明 父类子类的各类使用

  1. //父类
  2. public class Fu {
  3. int numFu = 10;
  4. int num = 100;
  5. public void methodFu() {
  6. //使用的是本类当中的,不会向下找子类的
  7. System.out.println(num);
  8. }
  9. }
  1. //子类 继承父类
  2. public class Zi extends Fu {
  3. int numZi = 20;
  4. int num = 200;
  5. public void methodZi() {
  6. //因为本类当中有num,所以这里用的是本类的num
  7. System.out.println(num);
  8. }
  9. }
  10. }
  1. /*
  2. 在父子类的继承关系当中,如果成员变量重名,则创建子类对象时,访问有两种方式:
  3. 直接通过子类对象访问成员变量,
  4. 等号左边是谁, 就优先用谁,没有则向.上找。
  5. 间接通过成员方法访问成员变量:
  6. 该方法属于谁, 就优先用谁,没有则向上找。
  7. */
  8. public class Demo01ExtendsField {
  9. public static void main(String[] args) {
  10. Fu fu = new Fu(); //创建父类对象
  11. System.out.println(fu.numFu); //只能使用父类的东西,没有任何子类内容
  12. Zi zi = new Zi();
  13. System.out.println(zi.numFu); // 10
  14. System.out.println(zi.numZi); // 20
  15. //等号左边是谁,就优先用谁
  16. System.out.println(zi.num); //优先子类,200
  17. //这个方法是子类的,优先用子类的,没有再向.上找
  18. zi.methodZi(); // 200
  19. //这个方法是在父类当中定义的,
  20. zi.methodFu(); // 100
  21. }

变量重名访问问题

  1. /*局部变量,
  2. 本类的成员交量,直接写成员变量名
  3. 父类的成员变量,this.成员交量名
  4. super.成员变量名
  5. */
  6. public class Demo01ExtendsField {
  7. Zi zi = new Zi();
  8. zi . method();
  9. }
  1. pub1ic class Fu {
  2. int num = 10;
  3. }
  1. public class Zi extends Fu {
  2. int num = 20;
  3. public void method() {
  4. int num = 30;
  5. System.out.println(num); // 30, 局部变量
  6. System.out.println(this.num); // 20, 本类的成员变量
  7. System.out.println(super.num); // l0, 父类的成员变量
  8. }
  9. }

方法重名访问问题

  1. public class Fu {
  2. public void methodFu() {
  3. System.out.println("父类方法执行! ");
  4. }
  5. public void method() {
  6. System.out.println("父类重名方法执行!" );
  7. }
  8. }
  1. public class Zi extends Fu {
  2. public void methodZi() {
  3. System.out.println("子类方法执行! ");
  4. public void method () {
  5. System.out.println("子类重名方法执行! ");
  6. }
  7. }
  8. }
  1. /*创建的对象是谁,就优先用谁,如果没有则向上找。
  2. 注意事项:
  3. 无论是成员方法还是成员变量,如果没有都是向上找父类,绝对不会向下找子类的。
  4. 重写(Override) :方法的名称-一样, 参数列表[也一样]。覆盖、覆写。
  5. 重载(Overload) ,方法的名称-样,参数列表[不一样]
  6. 方法的覆盖重写特点:创建的是子类对象,则优先用子类方法。
  7. */
  8. public class Demo01ExtendsMethod {
  9. public static void main(String[] args) {
  10. Zi zi=new Zi();
  11. zi . methodFu();
  12. zi . methodZi();
  13. //创建的是new了子类对象,所以优先用子类方法
  14. zi . method();
  15. }
  16. }
  17. 父类方法执行!
  18. 子类方法执行!
  19. 子类重名方法执行!

方法的覆盖重写

重写(Override) :方法的名称-一样, 参数列表[也一样]。覆盖、覆写。
重载(Overload) ,方法的名称-样,参数列表[不一样]
方法的覆盖重写特点:创建的是子类对象,则优先用子类方法。

注意事项

  1. /*
  2. 方法覆盖重写的注意事项:
  3. 1.必须保证父子类之间方法的名称相同,参数列表也相同。
  4. @Override:写在方法前面,用来检测是不是有效的正确覆盖重写。
  5. 这个注解就算不写,只要满足要求,也是正确的方法覆盖重写。
  6. 2.子类方法的返回值必须小于等于父类方法的返回值范围。
  7. 3.子类方法的权限必须[大于等于]父类方法的权限修饰符。
  8. 小扩展提示: public > protected > (default) > private
  9. 备注: (default)不是关键字default,而是什么都不写,留空。
  10. */
  11. public class Demo010verride {
  12. }
  1. public class Fu {
  2. public void method() {
  3. }
  4. }
  1. public class Zi extends Fu {
  2. @Override
  3. public void method() {
  4. }
  5. }

实例:手机功能的重写

设计原则:
对于已经投入使用的类,尽量不要进行修改。
推荐定义一个新的类,来重复利用其中共性内
容,并且添加改动新内容。

  1. //本来的老款手机
  2. public class Phone {
  3. public void call() {
  4. System.out.println("打电话");
  5. }
  6. public void send() {
  7. System.out.println("发短信");
  8. }
  9. public void show() {
  10. System.out.println("显示号码");
  11. }
  12. }
  1. //定义一个新手机,使用老手机作为父类
  2. public class NewPhone extends Phone {
  3. @Override
  4. public void show() {
  5. super.show();
  6. //把父类的show方法拿过来重复
  7. //自己子类再来添加更多内容
  8. System.out.println("显示姓名");
  9. System.out.println("显示头像");
  10. }
  11. }
  12. }
  1. public class Demo01Phone {
  2. public static void main(String[] args) {
  3. Phone phone = new Phone();
  4. phone.call();
  5. phone.send();
  6. phone.show();
  7. System.out.printnn("=======");
  8. NewPhone newPhone = new NewPhone();
  9. newPhone.call();
  10. newPhon.send();
  11. newPhone.show();
  12. }
  13. }

构造方法

  1. public class Demo01Constructor {
  2. /*
  3. 继承关系中,父子类构造方法的访问特点:
  4. 1.子类构造方法当中有一个默认隐含的“super()“周用,所以一-定是先调用的父类构造,后执行的子类构造。
  5. 2.子类构造可以通过super关键字来调用父类重载构造。
  6. 3. super的父类构造调用, 必须是子类构造方法的第一 个语句。不能一 个子类构造调用多次super构造。
  7. 总结:
  8. 子类必须调用父类构造方法,不写则赠送super();写了则用写的指定的super调用。super只能有一个,还必须是第一个。
  9. */
  10. public static void main(String[] args) {
  11. Zi zi = new Zi();
  12. //父类构造方法!
  13. //子类构造方法
  14. }
  15. }
  1. public class Fu {
  2. public Fu() {
  3. System.out.println("父类无参构造");
  4. }
  5. public Fu(int num) {
  6. System.out.println("父类有参构造! ");
  7. }
  8. }
  1. public class Zi extends Fu {
  2. public Zi() {
  3. //隐藏代码 super(); //在调用父类无参构造方法
  4. super(20); //在调用父类重载的构造方法,重载了父类的构造方法 上面无参失效
  5. System.out.println("子类构造方法 !");
  6. }
  7. public void method() {
  8. //super(); //错误写法!只有子类构造方法,才能调用父类构造方法。
  9. }
  10. }

super

super关键字的用法有三种:
1.在子类的成员方法中,访问父类的成员变量。
2.在子类的成员方法中,访问父类的成员方法。
3.在子类的构造方法中,访问父类的构造方法。

  1. public class Zi extends Fu {
  2. int num = 20;
  3. public Zi() {
  4. super();
  5. }
  6. public void methodZi() {
  7. System.out.println(super.num); //父类中的num
  8. public void method () {
  9. super.method();
  10. ii访问父类中的method
  11. System.out.println("子类方法");
  12. }
  13. }
  14. }
  1. public class Fu {
  2. int num = 10;
  3. public void method() {
  4. System.out.println("父类方法");
  5. }
  6. }

this

1.在本类的成员方法中,访问本类的成员变量。
2.在本类的成员方法中,访问本类的另一个成员方法。
3.在本类的构造方法中,访问本类的另-一个构造方法。
在第三种用法当中要注意:
A. this(… )调用也必须是构造方法的第一个语句, 唯一一个。
B. super和this两种构造调用,不能同时使用。(用了this,super不为隐藏代码)

  1. public class zi {
  2. int num = 20;
  3. public Zi() {
  4. }
  5. this(123); //本类的无参构造,调用本类的有参构造
  6. //
  7. this(1,2); //错误写法!
  8. public Zi(int n) {
  9. }
  10. public Zi(int n, int m) {
  11. }
  12. public void showNum() {
  13. int num = 10;
  14. System.out.println(num); //局部变量
  15. System.out.println(this.num); //本类中的成员变量
  16. }
  17. public void methodA() {
  18. System.out.println("AAA");
  19. public void methodB () {
  20. this.methodA();
  21. System.out.println("BBB");
  22. }