文章目录
Java多态知识总结
同一个行为具有多个不同的表现能力或形态的能力即为多态。根据何时确定执行多态方法中的哪一个,可以将多态分为编译时多态和运行时多态。
一、运行时多态
Java的引用变量有两种类型:编译时类型和运行时类型。编译时类型由声明该变量时使用的类型决定,运行时类型由实际赋值给该变量的对象决定。当编译时类型与运行时类型不一致的时候,就可能出现运行时多态。实例变量不具备多态性。
运行时多态出现的三个必要条件
- 继承
- 重写
- 父类引用指向子类对象(即向上转型,由系统自动完成)
重写的条件(两同两小一大)
- 方法名相同
- 形参列表相同
- 子类方法返回值类型应比父类方法返回值类型更小或相等
- 子类方法声明抛出的异常类应比父类方法声明抛出的异常类更小或相等
- 子类方法的访问权限应比父类方法的访问权限更大或相等
运行时多态实例
//父类,动物类
class Animal {
public int tag = 1;
public void name(){
System.out.println("我是动物");
}
public void shout(){
System.out.println("动物叫");
}
}
//子类,狗类
class Dog extends Animal {
public String tag = "dog";
public void shout(){
System.out.println("狗叫");
}
public void run(){
System.out.println("狗跑");
}
}
//子类,猫类
class Cat extends Animal {
public String tag = "cat";
public void shout(){
System.out.println("猫叫");
}
public void run(){
System.out.println("猫跑");
}
}
public class Test {
public static void main(String[] args){
//编译时类型与运行时类型一致,不发生运行时多态
Animal animal = new Animal();
Dog dog = new Dog();
animal.name(); //输出“我是动物”
animal.shout(); //输出“动物叫”
dog.name(); //继承父类的方法,输出“我是动物”
dog.shout(); //调用狗类中的方法,输出“狗叫”
dog.run(); //调用狗类中的方法,输出“狗跑”
//编译时类型与运行时类型不一致,发生运行时多态
Animal ploymophicDog = new Dog();
Animal ploymophicCat = new Cat();
System.out.println(ploymophicDog.tag); //实例变量不具备多态性,输出“1”
System.out.println(ploymophicCat.tag); //实例变量不具备多态性,输出“1”
//ploymophicDog.run(); Animal类中没有run方法,编译出错
//ploymophicCat.run(); Animal类中没有run方法,编译出错
ploymophicDog.shout(); //输出“狗叫”
ploymophicCat.shout(); //输出“猫叫”
}
}
二、编译时多态
编译时多态主要通过函数重载和泛型实现,不需要有派生关系。
① 通过函数重载实现多态
编译器在编译期间通过传入的参数列表的不同来确定具体调用哪个方法
重载的条件(“两同一不同”)
- 同一个类中
- 方法名相同
- 参数列表不同
- 方法的返回值类型、修饰符等与方法的重载无关
函数重载实现多态的实例
public calss Overload{
public void test(){
System.out.println("无参数");
}
public void test(String msg){
System.out.println("重载的方法 " + msg);
}
public static void main(String[] args){
Overload ol= new Overload();
ol.test(); //调用无参数的test方法,输出“无参数”
ol.test("overload"); //调用有参数的test方法,输出“重载的方法 overload”
}
}
② 通过泛型实现多态
与重载的原理类似,编译器在编译期间确定泛型的具体类型。
泛型实现多态的实例
public class Apple<T>{
private T info;
public Apple(T info){
this.info = info;
};
public T getInfo(){
return this.info;
}
public static void main(String[] args){
//传给T形参的为String类型,输出“苹果”
Apple<String> apple1 = new Apple<>("苹果");
System.out.println(apple1.getInfo());
//传给T形参的为Double,输出:“7.78”
Apple<Double> apple2 = new Apple<>(7.78);
System.out.println(apple2.getInfo());
}
}
运行时多态与编译时多态的区别
- 运行时多态是面向对象编程的重要特性之一,符合对客观世界的认知
- 运行时多态发生在运行期间,所以编译器无法进行优化处理。
- 编译时多态在编译器完成,提升运行期效率。