Java继承和多态

继承

继承(inherit)也是面向对象三大特性之一。

生活中的继承:某某继承了父亲百亿资产;某某继承了家族产业等等。

简单来看,继承就是获得了原本不属于自己的东西。在Java中亦是如此。

教师、辅导员、学生

某公司正在开发一款高校教学、教务管理系统。其中涉及到教师(Teacher)、辅导员(Assistant)、学生(Student)的信息管理。抛开教师、辅导员、学生的增删改查,如何用Java类表示教师、辅导员、学生?

通过分析:我们需要3个类Teacher、Assistant、Student

Teacher类有姓名、性别、年龄、职称、能授课、能管理学生。

Assistant类有姓名、性别、年龄,能管理学生。

Student类有姓名、性别、年龄,能学习。

Teacher类:

public class Teacher {
    //属性
    private String name;//姓名
    private String sex;//性别
    private int age;//年龄
    private String title;   //职称

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public String getSex() {
        return sex;
    }

    public void setSex(String sex) {
        this.sex = sex;
    }

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }

    public String getTitle() {
        return title;
    }

    public void setTitle(String title) {
        this.title = title;
    }

    //构造方法
    public Teacher() {
    }

    public Teacher(String name, String sex, int age, String title) {
        this.name = name;
        this.sex = sex;
        this.age = age;
        this.title = title;
    }

    //方法
    public void teach() {
        System.out.println(name + "老师正在认真的讲课");
    }

    public void manageStudents() {
        System.out.println("管理学生");
    }

    public void showInfo() {
        System.out.println(name + "," + sex + "," + age + "," + title);
    }
}

Assistant类:

public class Assistant {
    //属性
    private String name;//姓名
    private String sex;//性别
    private int age;//年龄

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public String getSex() {
        return sex;
    }

    public void setSex(String sex) {
        this.sex = sex;
    }

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }

    //构造方法

    public Assistant() {
    }

    public Assistant(String name, String sex, int age) {
        this.name = name;
        this.sex = sex;
        this.age = age;
    }

    //方法
    public void manageStudents() {
        System.out.println("管理学生");
    }

    public void showInfo() {
        System.out.println(name + "," + sex + "," + age);
    }
}

Student类:

public class Student {
    //属性
    private String name;//姓名
    private String sex;//性别
    private int age;//年龄

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public String getSex() {
        return sex;
    }

    public void setSex(String sex) {
        this.sex = sex;
    }

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }

    //构造方法

    public Student() {
    }

    public Student(String name, String sex, int age) {
        this.name = name;
        this.sex = sex;
        this.age = age;
    }

    //方法
    public void study() {
        System.out.println("Good good study,day day up");
    }

    public void showInfo() {
        System.out.println(name + "," + sex + "," + age);
    }
}

测试代码:

public static void main(String[] args) {
    Teacher t = new Teacher("张三", "男", 32, "教授");
    t.showInfo();
    t.teach();
    t.manageStudents();
    Assistant a = new Assistant("李思思", "女", 27);
    a.showInfo();
    a.manageStudents();
    Student stu1 = new Student("张磊", "男", 21);
    stu1.showInfo();
    stu1.study();
    Student stu2 = new Student("李静", "女", 20);
    stu2.showInfo();
    stu2.study();
}

通过观察,你会发现这3个类有部分特征和行为是相同的。都有姓名、性别、年龄属性,都有对应的setter、getter方法。如果要完整的表示这3个类,会更多的属性,更多的setter、getter方法。

如果一个项目比较大,有几百个类,要写多少代码?能不能优化?

教师、辅导员、学生使用继承

Java提供了继承(inherit)功能。继承可以解决我们上述的问题,Java中通过extends关键字来实现继承。

父类:在继承关系里,被继承的类叫做父类,也叫基类或超类。

子类:在继承关系里,继承别的类的类叫子类,也叫派生类。

父类和子类是相对而言的。

继承的语法

public class 类名 extends 父类名{
    //属性
    //方法
}

我们可以将上述案例中相同的特征和行为进行抽取,放到一个单独的类中,把这个类作为父类,再让现有的类继承于这个单独的类,这样就可以继承父类中的特征和行为。

公共父类Person

public class Person {
    //属性
    private String name;    //姓名
    private String sex;     //性别
    private int age;        //年龄
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    public String getSex() {
        return sex;
    }
    public void setSex(String sex) {
        this.sex = sex;
    }
    public int getAge() {
        return age;
    }
    public void setAge(int age) {
        this.age = age;
    }
}

Teacher类

public class Teacher extends Person{
    //属性
    private String title;   //职称

    public String getTitle() {
        return title;
    }
    public void setTitle(String title) {
        this.title = title;
    }

    //构造方法
    public Teacher() {
    }

    public Teacher(String name, String sex, int age, String title) {
        this.setName(name);
        this.setSex(sex);
        this.setAge(age);
        this.title = title;
    }
    //方法
    public void teach() {
        System.out.println(this.getName() + "老师正在认真的讲课");
    }

    public void manageStudents() {
        System.out.println("管理学生");
    }

    public void showInfo() {
        System.out.println(this.getName() + "," + this.getSex() + "," + this.getAge() + "," + title);
    }
}

Assistant类:

public class Assistant extends Person{
    //属性

    //构造方法
    public Assistant() {

    }

    public Assistant(String name, String sex, int age) {
        this.setName(name);
        this.setSex(sex);
        this.setAge(age);
    }

    //方法
    public void manageStudents() {
        System.out.println("管理学生");
    }

    public void showInfo() {
        System.out.println(this.getName() + "," + this.getSex() + "," + this.getAge());
    }
}

Student类:

public class Student extends Person {
    //属性

    //构造方法
    public Student() {

    }

    public Student(String name, String sex, int age) {
        this.setName(name);
        this.setSex(sex);
        this.setAge(age);
    }

    //方法
    public void study() {
        System.out.println("Good good study, day day up");
    }

    public void showInfo() {
        System.out.println(this.getName() + "," + this.getSex() + "," + this.getAge());
    }
}

测试代码:

public static void main(String[] args) {
    Teacher t = new Teacher("张三", "男", 32, "教授");
    t.showInfo();
    t.teach();
    t.manageStudents();

    Assistant a = new Assistant("李思思", "女", 27);
    a.showInfo();
    a.manageStudents();

    Student stu1 = new Student("张磊", "男", 21);
    stu1.showInfo();
    stu1.study();

    Student stu2 = new Student("李静", "女", 20);
    stu2.showInfo();
    stu2.study();
}

通过继承,代码明显少了很多,而且能实现继承前全部的功能。但美中不足的地方是,构造方法赋值比较麻烦,能不能优化?

父类、子类构造方法

子类可以从父类中继承属性和方法,无法继承构造方法,但可以调用父类中的构造方法为我们继承过来的属性赋值

Person类中添加构造方法:

public class Person {
    //属性
    private String name;    //姓名
    private String sex;     //性别
    private int age;        //年龄

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public String getSex() {
        return sex;
    }

    public void setSex(String sex) {
        this.sex = sex;
    }

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }

    //父类构造方法
    public Person() {

    }

    public Person(String name, String sex, int age) {
        this.name = name;
        this.sex = sex;
        this.age = age;
    }
}

Teacher类修改构造方法:

public class Teacher extends Person {
    //属性
    private String title;   //职称

    public String getTitle() {
        return title;
    }

    public void setTitle(String title) {
        this.title = title;
    }

    //构造方法
    public Teacher() {
    }

    public Teacher(String name, String sex, int age, String title) {
        super(name, sex, age);
        this.title = title;
    }

    //方法
    public void teach() {
        System.out.println(this.getName() + "老师正在认真的讲课");
    }

    public void manageStudents() {
        System.out.println("管理学生");
    }

    public void showInfo() {
        System.out.println(this.getName() + "," + this.getSex() + "," + this.getAge() + "," + title);
    }
}

Assistant类修改构造方法:

public class Assistant extends Person {
    //属性

    //构造方法
    public Assistant() {

    }

    public Assistant(String name, String sex, int age) {
        super(name, sex, age);
    }

    //方法
    public void manageStudents() {
        System.out.println("管理学生");
    }

    public void showInfo() {
        System.out.println(this.getName() + "," + this.getSex() + "," + this.getAge());
    }
}

Student类修改构造方法:

public class Student extends Person {
    //属性

    //构造方法
    public Student() {

    }

    public Student(String name, String sex, int age) {
        super(name, sex, age);
    }

    //方法
    public void study() {
        System.out.println("Good good study, day day up");
    }

    public void showInfo() {
        System.out.println(this.getName() + "," + this.getSex() + "," + this.getAge());
    }
}

修改之后,代码仍然能正确的运行。

super关键字

super是一个特殊的关键字,这个关键字用于访问父类中的方法和属性(super相当于父类类名)。

注:private修饰的属性和方法无法直接访问(super.属性名或者super.方法名())。因为private修饰的属性和方法只能在本类中访问。

虽然不能访问,但肯定是继承了。

通过下面的案例学习一下super关键字的用法。

定义2个类,Son类和Father类,Son继承于Father。

Father类代码:

public class Father {
    //属性
    int a;
    private int b;

    //getter、setter
    public int getB() {
        return b;
    }

    public void setB(int b) {
        this.b = b;
    }

    //构造方法
    public Father() {
    }

    public Father(int a, int b) {
        this.a = a;
        this.b = b;
    }

    //打印对象信息
    public void showInfo() {
        System.out.println("a = " + a + ",b = " + b);
    }

    //私有方法--私有方法只能在类内部供类中别的方法调用,例如在publicMethod方法中访问
    private void privateMethod() {
        System.out.println("这是私有方法");
    }

    //公开方法,在这个方法中调用私有方法。
    public void publicMethod() {
        privateMethod();//等价于this.privateMethod();
    }
}

Son类代码:

public class Son extends Father {
    //属性
    private int a;
    private int c;

    //setter、getter
    public int getA() {
        return a;
    }
    public void setA(int a) {
        this.a = a;
    }
    public int getC() {
        return c;
    }
    public void setC(int c) {
        this.c = c;
    }
    //构造方法
    public Son() {
        super();
    }
    public Son(int a, int b) {
        super(a, b);
    }
    public Son(int a, int b, int c) {
        super(a, b);
        this.c = c;
    }

    //打印自身信息
    public void showInfo() {
        System.out.println("a = " + a + ",b = " + this.getB() + ",c = " + c);
    }

    //测试super调用父类方法
    public void testSuperMethod() {
        super.showInfo();
    }

    //测试super调用父类属性
    public void testSuperProperty() {
        System.out.println(a);
        System.out.println(this.a);
        System.out.println(super.a);
        //私有属性不能直接访问,因为private修饰的属性,只能在本类中直接访问。我们可以通过方法间接访问。
//System.out.println(super.b);//报错
        System.out.println(super.getB());
    }
    //测试调用父类中的 私有方法
    public void testSuperPrivateMthod() {
        //私有方法不能直接访问,因为private修饰的方法,只能在本类中直接方法。我们可以通过方法间接访问。
//super.privateMethod();//报错
        super.publicMethod();
    }
}
public static void main(String[] args) {
    Son son = new Son(10,20,30);
    son.showInfo();//如果子类和父类有同名方法,调用的是自身的方法,不是父类继承过来的方法。
    son.testSuperMethod();//测试super调用父类方法
    son.testSuperPrivateMthod();//测试super调用父类私有方法
    son.testSuperProperty();//测试super调用父类属性
    son.publicMethod();//调用继承过来的方法
    son.setB(100);//调用继承过来的setter方法
    son.showInfo();
}

1. 通过super访问父类构造方法。语法:super(参数列表); 主要作用:给继承过来的属性赋初始值。

通过super调用父类构造方法时,代码必须写在第一行。

2. 通过super访问父类中的其他方法(非私有)。语法:super.方法名(参数列表);

3. 通过super访问父类中的属性(非私有)。语法:super.属性名;

this关键字

前面的课程,我们讲了this关键是一个特殊的对象,代指当前对象,即随调用方法,this就是谁。this可以用于区分实例变量和局部变量。

this除了用于区分实例变量和局部变量之外,还有以下2个功能:

1. this调用本类的其他构造方法。语法:this(参数列表); 通过this调用本类构造方法时,代码必须写在第一行

2. this调用本类中其他的方法。(this可省略)

this和super的区别

this.实例变量 访问本类中的实例变量;super.实例变量 访问父类中的实例变量(非私有)。

this.实例方法(…) 访问本类中的实例方法;super.实例方法(...) 访问父类中的实例方法(非私有)。

this(…) 调用本类中的构造方法,写在构造方法的第一行;super(...) 调用父类中的构造方法,写在构造方法的第一行。

this是对象,代表当前对象;super不是对象,只是关键字。

继承中构造方法的访问特点:如果子类构造方法中没有明确写出调用哪个父类构造方法,会默认调用父类的无参构造方法,即super(); -----即使你没有写super(),系统也会默认在第一行代码中调用super()。如果父类不提供无参构造方法,提供有参数的构造方法,子类会报错。

继承中实例方法的访问特点:1.首先在子类中查找要调用的方法,如果有直接调用;2.如果没有,在父类中查找要调用的方法,如果有就执行;3.如果没有,继续向上找父类,如果更上一级父类中有要调用的方法,就执行,如果没有继续向上找,直到根类Object,如果Object中也没有,就报错。

在继承中,子类对象的堆区内存里,既会有子类自身实例变量,也会有父类继承来的实例变量。如果子类和父类有同名的变量,堆内存会有2个变量。

方法重写

方法重写:在继承关系里,如果子类中的某个方法和父类中的方法相同(方法名和参数也要相同),称为子类重写了父类的方法。子类重写父类方法往往是因为父类的方法满足不了子类的需求,所以子类才需要自己实现这个方法。

方法重写、方法重载的区别:

方法重载:在同一个类中,如果多个方法具有相同的方法名,但是参数个数或者参数类型不同(或都不同),这称为方法的重载。

方法重写:在继承关系里,父类的实现满足不了子类的需求,子类可以重新实现父类中定义的方法,这是方法重写。

如果子类重写了父类的方法,我们习惯上在重写的方法上面添加@Override注解。---注解是我们后面要学习的内容。@Override注解的作用是检测方法是否和父类中的方法相同。

继承

继承是Java提供一种语法,这种语法允许子类得到父类的属性和方法。

继承能在保证程序功能不变的情况下,大大简化代码量,因此继承能帮我们更好的去设计类。

在Java中使用extends关键字实现继承。被继承的类叫做父类,或超类,或基类。

Java中继承的特点

1. 一个类只能有一个父类。----不允许多继承

2. 子类会继承父类全部的属性和方法(私有的也能继承,只是不能直接访问),无法继承构造方法。

3. 如果要访问父类中的属性、方法、构造方法使用super关键字。

4. 子类可以重写父类的方法。调用时默认调用子类的方法。

5. 可以多层继承。A extends B,B extends C,这样A将拥有B和C中的内容

6. 所有类的根类是Object。如果一个类没有继承任何类,默认继承Object类。

7. 通常在子类的构造方法中调用父类的构造方法。

根类:没有父类的类。已经是最顶层的类了。

继承的好处和弊端

继承的好处:

1. 提高了代码的复用性(多个类相同的内容可以放到同一个类中)。

2. 提高了代码的维护性(如果方法的代码需要修改,修改一处即可)。

继承弊端:

1. 继承让类与类之间产生了关联,类的耦合性增强了,当父类发生变化时,子类也不得不跟着变化,削弱了子类的独立性。

什么时候使用继承?

1. 继承体现的关系是: is a (是一个)

2. 如果两个类A和B,如果他们在逻辑上满足A是B的一种,或者B是A的一种,就说明他们是继承关系,这个时候可以使用继承来体现,否则就是滥用继承。

3. 例如:苹果和水果,苹果属于水果,可以让苹果类继承于水果类。再例如:苹果手机和手机,苹果手机是手机的一种,可以让苹果手机类继承于手机类。再例如:猫和狗,不能让猫继承于狗,也不能让狗继承于猫,而是定义一个动物类,他们都继承于动物。

继承示例

1. 需求:通过继承设计猫(Cat)和狗(Dog)类,并编写代码测试。猫有姓名和年龄属性,有抓老鼠的方法(catchMouse)。狗有姓名和年龄,有看门的方法(lookDoor)。

2. 代码:

父类Animal:

public class Animal {
    //实例变量
    private String name;//姓名
    private int age;//年龄

    //setter、getter
    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }

    //构造方法
    public Animal() {
        super();
    }

    public Animal(String name, int age) {
        super();
        this.name = name;
        this.age = age;
    }
}

Cat类:

public class Cat extends Animal {
    public Cat() {
        super();
    }
    public Cat(String name, int age) {
        super(name, age);
    }

    public void catchMouse() {
        System.out.println("抓老鼠");
    }
}

Dog类:

public class Dog extends Animal {
    public Dog() {
        super();
    }
    public Dog(String name, int age) {
        super(name, age);
    }

    public void lookDoor() {
        System.out.println("看门");
    }
}

测试代码:

public static void main(String[] args) {
    Cat c1 = new Cat("花花", 2);
    c1.catchMouse();
    System.out.println(c1.getName() + "," + c1.getAge());
    Dog d1 = new Dog("旺财", 5);
    d1.lookDoor();
    System.out.println(d1.getName() + "," + d1.getAge());
}

多态

多态(Polymorphism)是面向对象三大特征的最后一个特征。

什么是多态

多态:指的是对象的多态性,同一对象在不同时刻表现出来的不同形态。

例如:猫

我们可以说猫是猫:猫 cat = new 猫();

也可以说猫是动物:动物 animal = new 猫();

这里猫在不同的时刻表现出来了不同的形态,就是多态。

程序中的多态

多态的前提:

1. 有继承或者实现关系

2. 有方法重写

3. 父类引用指向子类对象(或子类的对象赋值给父类的引用)

实现关系:后面会学习接口(interface),类和接口就是实现关系,类实现接口。

实现关系也可以看成是继承关系

多态示例

父类Animal:

public class Animal {
    public void eat() {
        System.out.println("吃东西");
    }
}

子类Cat:

public class Cat extends Animal {
    @Override
    public void eat() {//子类重写父类方法
        System.out.println("猫吃鱼");
    }

    public void catchMouse() {
        System.out.println("猫抓老鼠");
    }
}

测试类ClassTest:

public class ClassTest {
    public static void main(String[] args) {
        //正常使用:
        Animal animal = new Animal();
        animal.eat();
        Cat cat1 = new Cat();
        cat1.eat();
        cat1.catchMouse();
        System.out.println("----------");
        //多态:
        Animal animal2 = new Cat();//父类引用指向子类对象(或子类的对象赋值给父类的引用)
        animal2.eat();//执行Animal类的eat方法,还是执行Cat类的eat方法
        animal2.catchMouse();//此处会报错
    }
}

上面的Animal animal2 = new Cat();就是多态的体现,猫可以被当做动物来看待。

animal2.eat();这就是多态的使用。虽然猫可以当做动物来看待,但真正执行方法的时候,还是执行子类的方法。

animal2.catchMouse();会报错,当把猫当动物看的时候,编译器会查看动物类是否有catchMouse方法,发现没有,就会报错。

多态中成员访问的特点

父类Animal:

public class Animal {
    int a = 20;
    public void eat() {
        System.out.println("吃东西");
    }
}

子类Cat:

public class Cat extends Animal {
    int a = 100;
    int b = 200;

    @Override
    public void eat() {//重写父类的方法
        System.out.println("猫吃鱼");
    }

    public void catchMouse() {//子类独有的方法
        System.out.println("猫抓老鼠");
    }
}

测试类ClassTest:

public class ClassTest {
    public static void main(String[] args) {
        //正常使用:
        Animal animal = new Animal();
        animal.eat();
        Cat cat1 = new Cat();
        System.out.println(cat1.a);
        System.out.println(cat1.b);
        cat1.eat();
        cat1.catchMouse();
        System.out.println("--------------");
        //多态:
        Animal animal2 = new Cat();//父类引用指向子类对象(或子类的对象赋值给父类的引用)
        System.out.println(animal2.a);
        //System.out.println(animal2.b);//会报错
        animal2.eat();//执行Cat类的eat
        //animal2.catchMouse();//此处会报错。
    }
}

回顾:Java代码运行的流程

编译期:Java源代码(.java)编译成字节码文件(.class)的时期。

运行期:运行字节码的时期。

为什么实例变量和实例方法的访问不一样呢?

因为实例方法有重写,实例变量没有。

多态的应用-参数多态

1. 需求:定义一个Person类,完成饲养猫,饲养狗的功能。设计猫和狗类的时候,使用继承完成。

2. 代码:

父类Animal:

public class Animal {
    public void eat() {
        System.out.println("动物进食");
    }
}

猫类Cat:

public class Cat extends Animal{
    @Override
    public void eat() {
        System.out.println("猫吃鱼");
    }
    //抓老鼠
    public void catchMouse() {
        System.out.println("猫抓老鼠");
    }
}

狗类Dog:

public class Dog extends Animal {
    @Override
    public void eat() {
        System.out.println("狗吃骨头");
    }

    //看门
    public void lookDoor() {
        System.out.println("狗看门");
    }
}

人类Person:

public class Person {
    //养猫
    public void raiseCat(Cat cat) {
        cat.eat();
    }

    //养狗
    public void raiseDog(Dog dog) {
        dog.eat();
    }

    //养任何动物------方法的参数多态
    public void raiseAnimal(Animal animal) {
        animal.eat();
    }
}

测试类ClassTest:

public class ClassTest {
    public static void main(String[] args) {
        //创建猫和狗
        Cat c = new Cat();
        Dog d = new Dog();

        //创建人
        Person p = new Person();

        //饲养猫,饲养狗----不用多态
        p.raiseCat(c);
        p.raiseDog(d);
        System.out.println("---------");
        //饲养猫,饲养狗----使用多态
        p.raiseAnimal(c);//猫可以看做动物。raiseAnimal要求的参数是Animal(即父类型),我们把子类型赋值给了父类型,这就是多态。
        p.raiseAnimal(d);//狗可以看做动物。raiseAnimal要求的参数是Animal(即父类型),我们把子类型赋值给了父类型,这就是多态。
    }
}

多态的应用-数组元素多态

1. 需求:创建一个数组,存放猫和狗。注意数组只能存放相同数据类型的数据。

2. 代码: 猫类、狗类、动物类使用之前定义好的Cat、Dog以及Animal。

测试代码:

public class ClassTest {
    public static void main(String[] args) {
        //创建猫和狗
        Cat c1 = new Cat();
        Cat c2 = new Cat();
        Cat c3 = new Cat();
        Dog d1 = new Dog();
        Dog d2 = new Dog();
        Dog d3 = new Dog();
        Cat[] arr = new Cat[6];
        arr[0] = c1;
        arr[1] = c2;
        arr[2] = c3;
        //      arr[3] = d1;//报错 Cat数组只能存放Cat对象,不能存放Dog对象
        //      arr[4] = d2;//报错 Cat数组只能存放Cat对象,不能存放Dog对象
        //      arr[5] = d3;//报错 Cat数组只能存放Cat对象,不能存放Dog对象

        Dog[] arr2 = new Dog[6];
        //      arr2[0] = c1;//报错 Dog数组只能存放Dog对象,不能存放Cat对象
        //      arr2[1] = c2;//报错 Dog数组只能存放Dog对象,不能存放Cat对象
        //      arr2[2] = c3;//报错 Dog数组只能存放Dog对象,不能存放Cat对象
        arr2[3] = d1;
        arr2[4] = d2;
        arr2[5] = d3;

        //创建Animal数组存放猫和狗。---多态
        Animal[] animals = new Animal[6];
        animals[0] = c1;//把Cat看成Animal存入数组
        animals[1] = c2;//把Cat看成Animal存入数组
        animals[2] = c3;//把Cat看成Animal存入数组
        animals[3] = d1;//把Dog看成Animal存入数组
        animals[4] = d2;//把Dog看成Animal存入数组
        animals[5] = d3;//把Dog看成Animal存入数组
        for (int i = 0; i < animals.length; i++) {
            Animal a = animals[i];
            a.eat();//多态的对象在运行期,执行子类的方法。
        }
    }
}

多态的应用-数组元素或方法返回值多态

1. 需求:用Animal数组存放Cat和Dog。遍历数组,如果元素是猫,执行抓老鼠的方法,如果是狗执行看门方法。

2. 代码: 猫类、狗类、动物类使用之前定义好的Cat、Dog以及Animal。

测试代码ClassTest:

public class ClassTest {
    public static void main(String[] args) {
        //创建猫和狗
        Cat c1 = new Cat();
        Cat c2 = new Cat();
        Cat c3 = new Cat();
        Dog d1 = new Dog();
        Dog d2 = new Dog();
        Dog d3 = new Dog();

        //创建Animal数组存放猫和狗。---多态
        Animal[] animals = new Animal[6];
        animals[0] = c1;//把Cat看成Animal存入数组
        animals[1] = c2;//把Cat看成Animal存入数组
        animals[2] = c3;//把Cat看成Animal存入数组
        animals[3] = d1;//把Dog看成Animal存入数组
        animals[4] = d2;//把Dog看成Animal存入数组
        animals[5] = d3;//把Dog看成Animal存入数组
        for (int i = 0; i < animals.length; i++) {
            Animal a = animals[i];
            if (a instanceof Cat) {
                Cat c = (Cat) a;//强制类型转换
                c.catchMouse();
            } else if (a instanceof Dog) {
                Dog d = (Dog) a;
                d.lookDoor();
            }
        }
    }
}

返回值多态:

动物管理员AnimalManager:

public class AnimalManager {
    public Animal getAnimalByIndex(int index) {
        Cat c1 = new Cat();
        Cat c2 = new Cat();
        Cat c3 = new Cat();
        Dog d1 = new Dog();
        Dog d2 = new Dog();
        Dog d3 = new Dog();
        Animal[] animals = new Animal[6];
        animals[0] = c1;
        animals[1] = c2;
        animals[2] = c3;
        animals[3] = d1;
        animals[4] = d2;
        animals[5] = d3;

        return animals[index];
    }
}

测试代码:

public class ClassTest {
    public static void main(String[] args) {
        AnimalManager am = new AnimalManager();
        Cat a = (Cat)am.getAnimalByIndex(0);
        a.eat();
        a.catchMouse();
        Dog b = (Dog)am.getAnimalByIndex(3);
        b.eat();
        b.lookDoor;
    }
}

intanceof关键字的作用是:判断对象是不是某个类的实例。

例如:a instanceof Cat是判断对象a是否是Cat类的实例,如果是就返回true,否则就是false

如果a是Cat子类的实例,Cat继承于Animal,那么a instanceof Animal也是true。

向上转型:子类类型转换为父类类型。即把子类对象赋值给父类引用。系统自动完成。

向下转型:父类类型转换为子类类型。需要强制类型转换。

方法的返回值类型也可以使用多态(即父类型),实际返回的是子类对象。

例如:在Java桌面编程里,可以把控件添加到页面上,也可以从页面上获取组件。添加组件和获取组件用的就是多态。添加组件的方法可以把父类组件作为方法的参数,调用的时候,添加子类(按钮、输入框、复选框等),获取组件的方法返回值可以设置为组件类型,方法返回的是实际的组件(按钮,输入框,复选框等),通过强制类型转换,转成自己需要的类型。

多态的好处和弊端

好处:提高了程序的扩展性,容易设计出通用的代码。

弊端:屏蔽了子类独有的功能。(不过,可以强转类型)

常用

Java中继承使用extends关键字来完成。

子类能从父类继承所有属性和方法(不能继承构造方法,构造方法的方法名必须和类名相同)。

不能盲目继承,两个类满足is a关系时才使用继承。 例如:狗可以继承动物,香蕉可以继承水果等。

子类继承父类后,发现父类继承来的方法不满足自己的需要,子类可以重写父类中继承过来的方法。

子类想访问父类中的内容可以借助super关键字。

多态指的是把子类当做父类来使用,但执行方法时执行的还是子类重写后的方法。例如:把猫当做动物 使用,调用eat()方法时,执行的是猫的eat()方法,不是父类的eat()方法。

多态能写出通用代码。

封装、继承、多态的学习是指导我们如何更好的设计类。

  • 18
    点赞
  • 29
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Java继承多态Java面向对象编程的重要概念。继承是指子可以继承的属性和方法。在Java,通过使用关键字"extends"来实现继承。例如,可以定义一个父和一个子,子通过extends关键字继承的属性和方法。 多态Java的另一个重要概念,它是指同一个方法可以根据调用对象的不同而表现出不同的行为。方法的重写和重载是多态性的不同表现。重写是指子实现了和父相同名称、相同参数列表和相同返回型的方法,但是具体的实现可能不同。重载是指在同一个可以定义多个同名方法,但是参数列表不同。 通过继承多态Java可以实现代码的重用、灵活性和扩展性。子可以继承的属性和方法,并且可以根据需要进行方法的重写和重载,从而实现不同的行为。这样可以提高代码的可维护性和可扩展性。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* [java学习资料-Java继承多态](https://download.csdn.net/download/weixin_43516258/87905486)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 50%"] - *2* *3* [十三、 封装、继承多态](https://blog.csdn.net/CaesarQu/article/details/117373505)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 50%"] [ .reference_list ]
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值