java学习(十)继承extends、方法覆盖、多态
继承语法
class 类名 extends 父类名{
类体;
}
-
java中规定,子类继承父类,除构造方法不能继承之外,剩下的都可以继承。但是private修饰的私有属性无法在子类中直接访问。
方法覆盖:重写父类方法
-
中国人和美国人都继承人类,中国人调用打招呼希望输出“你好”,但是美国人调用打招呼希望输出“hi,hello”,这时候人类的到招呼方法就不满足需要了,需要方法覆盖。其实就是重写了父类方法。
代码:
public class People{ private String name; public String getName(){ return name; } public void setName(String name){ this.name = name; } //定义一个方法 public void speakHi(){ System.out.println(this.name + "打个招呼"); } }
public class ChinesePeople extends People{ public void speakHi(){ System.out.println("你好,我是 " + this.getName() + ",认识你很高兴"); } }
public class AmericaPeople extends People{ public void speakHi(){ System.out.println("Hi,My name is:" + this.getName() + ",nice to meet you"); } }
public class PeopleTest { public static void main(String[] args) { ChinesePeople cp = new ChinesePeople(); cp.setName("法外狂徒张三"); cp.speakHi(); AmericaPeople ap = new AmericaPeople(); ap.setName("tony"); ap.speakHi(); } }
多态:其实就是同一个行为发生在不同的对象上会有不同的效果。
看Test01和Test02代码
public class Animal{ public void move(){ System.out.println("动物会移动"); } }
public class Cat extends Animal{ //方法覆盖 public void move(){ System.out.println("猫会跑的!"); } //猫特有方法 public void catchMouse(){ System.out.println("猫可抓老鼠!"); } }
public class Bird extends Animal{ //方法覆盖 public void move(){ System.out.println("鸟会动的!"); } //鸟特有的方法 public void fly(){ System.out.println("鸟飞了飞了!"); } }
Test01.java:
public class Test01 { public static void main(String[] args) { //创建 Animal 对象 Animal a = new Animal(); a.move(); //创建 Cat 对象 Cat c = new Cat(); c.move(); c.catchMouse(); //创建鸟儿对象 Bird b = new Bird(); b.move(); b.fly(); } }
Test02.java:
public class Test02{ public static void main(String[] args) { //向上转型 Animal a1 = new Cat(); a1.move(); //向上转型 Animal a2 = new Bird(); a2.move(); } }
解释:在编译阶段编译 器只知道 a1 变量的数据类型是 Animal,那么此时编译器会去 Animal.class字节码中查找 move() 方法,发现 Animal.class 字节码中存在 move()方法,然后将该 move()方法绑定到 a1 引用上, 编译通过了,这个过程我们可以理解为“静态绑定”阶段完成了。紧接着程序开始运行,进入 运行阶段,在运行的时候实际上在堆内存中 new的对象是 Cat 类型,也就是说真正在 move 移 动的时候,是 Cat 猫对象在移动,所以运行的时候就会自动执行 Cat 类当中的 move()方法,这 个过程可以称为“动态绑定”。但无论是什么时候,必须先“静态绑定”成功之后才能进入“动 态绑定”阶段。
向上转型:自动类型转换
-
java 中之所以有多态机制,是因为 java 允许一个父类型的引用指向一个子类型的对象。 这种父类型引用指向了子类对象属于向上转型,或者叫自动类型转换
向下转型:强制类型转换
-
如果想调用子类特有方法,就需要向下转型
public class Test04 { public static void main(String[] args) { //向上转型 Animal a = new Cat(); //a.catchMouse(); //编译报错 //向下转型:为了调用子类对象特有的方法 //强制类型转换将 Animal 类型的 a 引用转换成 Cat 类型的引用c Cat c = (Cat)a; c.catchMouse(); } }
上面代码a.catchMouse();为什么报错呢?
那是因为“Animal a = new Cat();”在编译的时候,编译器只知道 a 变量的数据类型是 Animal,也就是说它只会去 Animal.class 字节码中查找 catchMouse()方法,结果没找到,自然“静态绑定”就失败了,编 译没有通过。就像以上描述的错误信息一样:在类型为 Animal 的变量 a 中找不到方法 catchMouse()。
类型转换异常
public class Test05 { public static void main(String[] args) { Animal a = new Bird(); Cat c = (Cat)a; } }
上述代码可以编译通过,原因是编译器只知道 a 变量是 Animal 类型,Animal 类和 Cat 类之间存在继承关系 ,所以可以进行向下转型 ,语法没问题,问题是运行的时候a引用指向实际是鸟啊,你强制转猫,就报错了。
运算符 instanceof:结果是布尔值,如果是true就可以转型,false就不可以转型。
instanceof 运算符 语法格式:
(引用 instanceof 类型)
代码:
public class Test05 { public static void main(String[] args) { Animal a = new Bird(); if (a instanceof Cat){ //判断引用a是不是Cat类型 Cat c = (Cat)a; c.catchMouse(); }else if(a instanceof Bird){ //判断引用a是不是Bird类型 Bird b = (Bird)a; b.fly(); } } }
其实多态存在的三个必要条件分别是:
① 继承
② 方法覆盖
③ 父类型引用指向子类型对象 ,子类将方法重写之后调用到子类对象上的 方法产生不同效果时,多态就形成了。