面向对象的三大特性:封装,继承,多态,其中封装和继承是多态的基础
概述:某一个事物,在不同时刻表现出来的不同状态,父类的声明指向子类的实现,父类可以调用子类重写后的方法。
转型操作:
向上转型:父类的声明指向子类的实现
向下转型: 假如子类声明指向父类实现,这是非法的。如果将父类型声明数据赋值给子类型,不管父类真实类型是什么,都是非法的。那么应该怎么办呢?可以使用强转语法。子类类型声明 对象名 = (子类类型)父类型变量
Pet p = new Cat();
Cat cat = (Cat)p;
但是强转语法有安全隐患,因为你不能把Pet(宠物)中的Cat(猫)赋值给Dog(狗)吧,所以应该加上判断条件。
Pet p = new Cat();
if(p instanceof Dog){
Dog dog = (Dog)p;
}
多态的三个前提
继承或者实现
子类重写父类中的方法
父类的引用指向子类的对象
注意面试:
静态字段操作 —— 调用的父类的
静态方法操作 —— 调用的父类的
成员字段操作 —— 调用的父类的
package Test02;
public class Fu {
static int age=50;
int salary=30000;
public void show(){
System.out.println("fulei!");
}
public static void eat()
{
System.out.println("fulei");
}
}
package Test02;
public class Zi extends Fu {
static int age=20;
int salary=15000;
public void show(){
System.out.println("子类");
}
public static void eat(){
System.out.println("子类");
}
}
package Test02;
public class Demo01 {
public static void main(String[] args) {
// TODO Auto-generated method stub
Fu a=new Zi();
a.show();//非静态成员方法,子类
a.eat();//静态成员方法,父类
System.out.println(a.age);//静态字段,父类
System.out.println(a.salary);//成员字段,父类
}
}
结果:
子类
fulei
50
30000
记住:
多 态:编译看左(父类),运行看右(子类)
非多态:编译看左,运行看左。非多态特指父类声明指向子类实现,调用成员字段或静态字段或静态方法
比如对于a.show(),假如Fu类中没有show方法,则编译不能通过,若Fu类中有show方法,则调用的是Zi的方法。
下面是一个面试题,请问输出什么?
package Test03;
public class Base {
private String baseName="base";
public Base(){
callName();
}
public void callName(){
System.out.println(baseName);
}
static class Sub extends Base{
private String baseName="sub";
public void callName(){
System.out.println(baseName);
}
}
public static void main(String[] args) {
Base b=new Sub();
}
}
结果为null,因为在new Sub()时,会调用父类中的构造方法Base(),从而会调用callName()方法,由于子类中有callName(),所以此时调用的是子类中的clllName()方法,而此时子类还没有构造,所以baseName的值为null;
package Test03;
public class Base {
private String baseName = "base";
public Base() {
callName();
}
public void callName() {
System.out.println(baseName);
}
static class Sub extends Base {
private String baseName = "sub";
// public void callName() {
// System.out.println(baseName);
// }
}
public static void main(String[] args) {
Base b = new Sub();
}
}
这时结果为base,因为此时子类中没有callName()方法,所以调用的是父类中的callName()方法。