多态基本特性 覆写 ,重载 ,隐藏

重载

一个类中,我们可以定义多个方法。如果有一系列方法,它们的功能都是类似的,只有参数有所不同,那么,可以把这一组方法名做成同名方法。例如,在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,不能把父类变为子类,因为子类功能比父类多,多的功能无法凭空变出来。

先向上,再向下!!才可以成功