继承
继承(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()方法。
多态能写出通用代码。
封装、继承、多态的学习是指导我们如何更好的设计类。