向上转型
对象的向上转型一定是安全的,就是:父类对象指向子类对象。但是也有弊端,一旦向上转型为父类,就无法调用子类原本特有的内容。
public class Father{
int num = 10;
public void method(){
System.out.println("父子都有的方法。父亲");
}
public void methodFu(){
System.out.println("父类特有的方法。");
}
public void show(){
System.out.println("父类的num:"+num);
}
}
public class Zi extends Father{
int num = 20;
int member = 10;
public void method(){
System.out.println("父子都有的方法。孩子");
}
public void methodZi(){
System.out.println("子类特有的方法");
}
public void show(){
System.out.println("子类的num:"+num);
}
}
代码当中体现多态:父类引用指向子类对象:
格式:
父类名称 对象名 = new 子类名称();
接口名称 对象名 = new 子类名称();
public class Test{
public static void main(String[] args){
Father fu = new Zi();
fu.method();//父子都有的方法。孩子
fu.methodFu();//父类特有的方法
System.out.println(fu.num);//10
fu.show();//子类的num20
//System.out.println(fu.member);//fu对象中不存在member,编译报错
}
}
上面代码中体现了访问成员变量的两种方式:
1:直接通过对象名成访问成员变量,看等号左边是谁,优先用谁,没有则向上找。
2:直接通过成员方法访问成员变量,看该方法属于谁,优先用谁,没有则向上找。
而在多态的代码中,成员方法的访问规则是:
创建对象时,new 后面跟的是哪个类,就优先用谁,没有则向上找。
口诀:编译看左边,运行看右边。
上面代码通过对象名访问成员变量,等号左边是父类,则找父类的num。
new的是Zi类对象,show()方法运行Zi类中的show。
对比:
成员变量:编译看左边,运行还看左边。
成员方法:编译看左边,运行看右边
编译看左边指的是,在编译阶段优先看等号左边,如果左边这个类中没有该方法/变量,则编译不通过,运行看左/右,指运行是,左/右类中是否含该方法/变量,有就运行,没有则向上找。
向下转型
public abstract class Animal {
public abstract void eat();
}
public class Cat extends Animal {
public void eat(){
System.out.println("猫吃");
}
public void catchMouse(){
System.out.println("猫子类特有方法");
}
}
public class Dog extends Animal {
public void eat(){
System.out.println("狗吃");
}
public void watchHouse(){
System.out.println("狗看家");
}
}
向上转型一定是安全的,但也有弊端(一旦向上转型为父类,就无法调用子类原本特有的内容)
解决方法:用对象的向下转型
对象的向下转型,其实是一个【还原】的动作
格式:子类名称 对象名 = (子类名称) 父类对象。
必须保证对象本来创建的时候,就是猫,才能向下转型猫。
如果对象创建的时候本来就不是猫,现在非要向下转型成为猫,就会报错。
public class DemoMain {
public static void main(String[] args) {
Animal animal = new Cat();
animal.eat();
//animal.catchMose();一旦向上转型为父类,就无法调用子类原本特有的内容。
Cat cat = (Cat)animal;
cat.catchMouse();//子类特有的方法
/*Animal animal1 = new Animal() {
@Override
public void eat() {
System.out.println("吃");
}
};
Cat cat1 = (Cat)animal1;
cat1.catchMouse();//报错,本来是动物,不是猫*/
//下面是错误的乡下转型
Dog dog = (Dog) animal;//本来new的时候是一只猫,现在被变成了狗,错误ClassCastException
}
}
如何才能知到一个父类引用的对象,本来是什么子类
格式: 对象 instanceof 类型, 这将会得到一个boolean值结果。
public class Instanceof {
public static void main(String[] args) {
Animal animal = new Cat();
animal.eat();
//如果调用子类特有方法,需要向下转型。
if (animal instanceof Dog){
Dog dog = (Dog) animal;
dog.watchHouse();
}
if(animal instanceof Cat){
Cat cat = (Cat) animal;
cat.catchMouse();
}
giveMeAPet(new Dog());
}
public static void giveMeAPet(Animal animal){
if (animal instanceof Dog){
Dog dog = (Dog) animal;
dog.watchHouse();
}
if(animal instanceof Cat){
Cat cat = (Cat) animal;
cat.catchMouse();
}
}
}