多态基本特性 覆写 ,重载 ,隐藏
重载
一个类中,我们可以定义多个方法。如果有一系列方法,它们的功能都是类似的,只有参数有所不同,那么,可以把这一组方法名做成同名方法。例如,在Hello
类中,定义多个hello()
方法:
也就是说,方法名字一样,参数不同
class Hello {
public void hello() {
System.out.println("Hello, world!");
}
public void hello(String name) {
System.out.println("Hello, " + name + "!");
}
public void hello(String name, int age) {
if (age < 18) {
System.out.println("Hi, " + name + "!");
} else {
System.out.println("Hello, " + name + "!");
}
}
}
覆写
子类重写父类的方法,要求方法名和参数类型完全一样(参数不能是子类),返回值和异常比父类小或者相同(即为父类的子类),访问修饰符比父类大或者相同。
也就是方法类型参数觉返回值,方法名一样,但是方法内部的代码不一样
class Person {
public void run() {
System.out.println("Person.run");
}
}
在子类Student中,覆写这个run()方法:
class Student extends Person {
@Override
public void run() {
System.out.println("Student.run");
}
}
隐藏
首先达成隐藏的条件父类中的方法和属性是静态的
产生方法的隐藏时,父类和子类的方法同时被static修饰,并且方法签名和返回值类型一致。产生方法的隐藏时,并且使用向上造型时(即用父类声明子类创建对象),方法的执行看的是声明类。效果如下:
public class StaticDemo {
@SuppressWarnings("static-access") public static void main(String[] args) {
// 当构成静态方法的隐藏的时候,方法的执行看的是声明类
A a = new B();
a.m();
}
}
class A {
public static void m() {
System.out.println("A ~~~");
}
}
class B extends A {
public static void m() {
System.out.println("B ~~~");
}
}
结果为
A~~~~~~~~~~~~
多态
多态中最重要的应用,向上转型
如果一个引用变量的类型是Student
,那么它可以指向一个Student
类型的实例:
Student s = new Student();
如果一个引用类型的变量是Person
,那么它可以指向一个Person
类型的实例:
Person p = new Person();
现在问题来了:如果Student
是从Person
继承下来的,那么,一个引用类型为Person
的变量,能否指向Student
类型的实例?
Person p = new Student(); // ???
测试一下就可以发现,这种指向是允许的!
这是因为Student
继承自Person
,因此,它拥有Person
的全部功能。Person
类型的变量,如果指向Student
类型的实例,对它进行操作,是没有问题的!
这种把一个子类类型安全地变为父类类型的赋值,被称为向上转型(upcasting)。
向上转型实际上是把一个子类型安全地变为更加抽象的父类型:
Student s = new Student();
Person p = s; // upcasting, ok
Object o1 = p; // upcasting, ok
Object o2 = s; // upcasting, ok
注意到继承树是Student > Person > Object
,所以,可以把Student
类型转型为Person
,或者更高层次的Object
。
注意: 在向上转型后,若子类有覆写过的方法,调用父类的覆写方法执行的依然是覆写过后的代码。
向下转型
向下转型
和向上转型相反,如果把一个父类类型强制转型为子类类型,就是向下转型(downcasting)。例如:
Person p1 = new Student(); // upcasting, ok
Person p2 = new Person();
Student s1 = (Student) p1; // ok
Student s2 = (Student) p2; // runtime error! ClassCastException!
如果测试上面的代码,可以发现:
Person
类型p1
实际指向Student
实例,Person
类型变量p2
实际指向Person
实例。在向下转型的时候,把p1
转型为Student
会成功,因为p1
确实指向Student
实例,把p2
转型为Student
会失败,因为p2
的实际类型是Person
,不能把父类变为子类,因为子类功能比父类多,多的功能无法凭空变出来。
先向上,再向下!!才可以成功