封装 | 继承 | 多态 |
对象代表什么,就得封装对应的数据,并提供数据对应的行为 | 当类与类之间,存在相同(共性)内容,并满足子类是父类中的一种,就可以考虑使用继承,来优化代码 | 同类型的对象,表现出不同的形态 |
多态的表现形式 | 父类类型 对象名称 = 子类对象; |
多态的前提 | 有继承/实现关系 有父类引用指向子类对象 eg: Fu f = new Zi(); 有方法重写 |
多态的好处 | 使用父类类型作为形参可以接收其所有的子类对象 体现多态的扩展性与便利 |
//多态的最基本引用
public class Test {
public static void main(String[] args) {
Student s = new Student();
s.setName("彭于晏");
s.setAge(18);
Teacher t = new Teacher();
t.setName("刘亦菲");
t.setAge(20);
register(s);//打印结果: 学生的信息为: 彭于晏 18
register(t);//打印结果: 老师的信息为: 刘亦菲 20
}
//这个方法既能接收学生,又能接收老师
//只能把参数写成这两个类型的父类
public static void register(Person p) {
p.show();
}
}
//父类
class Person {
String name;
int age;
public Person() {
}
public Person(String name, int age) {
this.name = name;
this.age = age;
}
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 void show() {
System.out.println(name + " " + age);
}
}
//子类1
class Student extends Person {
@Override
public void show() {
System.out.println("学生的信息为: " + super.getName() + " " + super.getAge());
}
}
//子类2
class Teacher extends Person {
@Override
public void show() {
System.out.println("老师的信息为: " + super.getName() + " " + super.getAge());
}
}
调用成员变量的特点 | 编译看左边,运行也看左边 |
调用成员方法的特点 | 编译看左边,运行看右边 |
//多态中调用成员的特点
public class Test {
public static void main(String[] args) {
//多态方式创建对象
Animal a = new Dog();
//调用成员变量: 编译看左边,运行也看左边
System.out.println(a.name);//打印结果: 动物
//调用成员方法: 编译看左边,运行看右边
a.show();//打印结果: Dog----------show方法
}
}
//父类
class Animal {
String name = "动物";
public void show() {
System.out.println("Animal----------show方法");
}
}
//子类1
class Dog extends Animal {
String name = "狗";
@Override
public void show() {
System.out.println("Dog----------show方法");
}
}
//子类2
class Cat extends Animal {
String name = "猫";
@Override
public void show() {
System.out.println("Cat----------show方法");
}
}
1.在多态形势下,右边对象可以实现解耦合,便于扩展和维护 |
Person p = new Student(); p.work(); //业务逻辑发生改变时,后续待码无需修改,直接改"="右边的子类就行 |
2.定义方法的时候,使用父类类型作为形参,可以接收其所有子类对象,体现多态的扩展性与便利性 |
public static void register(Person p) {......} |
弊端 | 解决方案 |
不能调用子类的特有功能 | 强制类型转换 |
//多态的弊端
//不能调用子类的特有功能
public class Test {
public static void main(String[] args) {
//多态方式创建对象
Animal a1 = new Dog();
a1.eat();//打印结果: 狗在吃骨头!
//但很显然 a.lookHome(); 根本就调用不了
//那怎么解决呢?
//解决方案: 强制类型转换
Dog d = (Dog) a1;
d.lookHome();//打印结果: 狗在看家!
//补充: 强转不能瞎转,之前创建的对象是Dog类型的,那我们就不能转成Cat类型的
//那怎么避免强转类型与真实对象类型不一致会报错呢?
//加一个判断的方法(用instanceof关键字来判断)
Animal a2 = new Cat();
if(a2 instanceof Cat){
Cat c = (Cat) a2;
c.catchMouse();//打印结果: 猫在抓老鼠!
}
else if(a2 instanceof Dog){
Dog c = (Dog) a2;
c.lookHome();
}else{
System.out.println("没有这个类型,无法转换");
}
//代码好麻烦
//jdk14后有新特性
Animal a3 = new Cat();
//先判断a3是否为Cat类型,如果是,则强转成Cat类型,转换之后变量名为cc
//如果不是,则不强转,结果直接是false
if(a3 instanceof Cat cc){
cc.catchMouse();//打印结果: 猫在抓老鼠!
}
}
}
//父类
class Animal {
public void eat() {
System.out.println("动物在吃东西!");
}
}
//子类1
class Dog extends Animal {
@Override
public void eat() {
System.out.println("狗在吃骨头!");
}
public void lookHome() {
System.out.println("狗在看家!");
}
}
//子类2
class Cat extends Animal {
@Override
public void eat() {
System.out.println("猫在吃鱼!");
}
public void catchMouse() {
System.out.println("猫在抓老鼠!");
}
}