Java 多态 续

new 子类()的执行过程

        首先上溯子类的所有祖先类,然后再从上向下逐步执行各个层次父类的构造器Object—爷爷的构造 器—父亲的构造器;最后才执行子类自己的构造器

        因为每个类的构造方法中默认第一句话为super()表示调用父类的无参构造器,除非编程super。

特殊情况:

问题:父类已经定义了带参构造器后是否还有无参构造器?

        没有,因为只有当不定义构造器时,系统才提供一个无参构造器。当自定义构造器时,系统不再提供无参构造器

         因为子类的构造器中没有显式调用父类构造器,所以子类构造器方法中第一句是super()表示调用父类中 的无参构造器,但是父类中没有无参构造器,所以报错

面向对象设计思想的要点

        认为客观世界由各种对象组成,任何事物都是对象,复杂的对象可以由比较简单的对象以某种方式 组合而成

        把所有对象都划分成各种对象类,每个对象类都定义了一组数据和一组方法

        按照子类与父类的关系,把若干个对象类组成一个层次结构的系统

        对象彼此之间仅能通过传递消息互相联系

类间多态和类内多态

        多态是同一个行为具有多个不同表现形式或形态的能力。多态就是同一个接口,使用不同的实例而执行 不同操作

类间多态性

父子类之间的一种多态型,例如:动物x=new 猫()

public class Test1 {
    public static void main(String[] args) {
        Animal a1=new Cat();
        A a=new A();
        a.eee(a1);
    }
}
class A{
    public void eee(Animal animal){
        animal.eat();
    }
}
class Animal{
    public void eat(){
        System.out.println("Animal.eat()");
    }
}
class Cat extends Animal{
    @Override
    public void eat() {
        System.out.println("就是爱老鼠");
    }
}
class Dog extends Animal{
    @Override
    public void eat() {
        System.out.println("就是爱肉骨头");
    }
}

        方法调用中的限制:

        针对一个类对象有两种类型,一种称之为编译期类型,编译时系统识别对象的类型,”动物 x = new 猫()”在编译时,系统识别x是动物类别的,所以只能调用动物类定义的方法,而不能调用猫中特殊 的方法。另外一种称之为运行时类型,也就是当程序运行系统识别的类型,new谁就是谁

        覆盖的方法一定不能是private的

类内多态性、

        在一个类对象上调用相同名称的方法,但是当参数不同时执行不同的动作。

public class Test2 {
    public static void main(String[] args) {
        A2 a=new A2();
        // a.pp();
        // a.pp(12);
        a.pp("shitou");
    }
}
class A2 {
    public void pp() {
        System.out.println("A2.pp()");
    }
    public void pp(Integer k) {
        System.out.println("A2.pp(int)");
    }
    public void pp(Object kk) {
        System.out.println("A2.pp(String)");
    
    }
    public void pp(int k1,String k2){}
    public void pp(String k1,int k2){}
}

方法名称相同,参数不同,和返回值类型无关

        参数个数不同

        参数类型不同

        参数顺序不同。注意不同参数名称顺序不同

public class Test1 {
    public static void main(String[] args) {
        Fa ff=new Fa();
        ff.pp(new Integer(123)); //原则:最佳匹配原则
        ff.pp(1.234);
    }
}
class Fa {
    public void pp() {
        System.out.println("Fa.pp()");
    }
    public void pp(Number kk){
        System.out.println("Fa.pp(Number)");
    }
    public void pp(Integer kk){
        System.err.println("Fa.pp(Integer)");
    }
}

不确定个数的参数

public class Test1 {
    public static void main(String[] args) {
        Fa ff = new Fa();
        ff.pp(); //最佳匹配原则
    }
}
class Fa {
    public void pp() {
        System.out.println("Fa.pp()");
    }
    public void pp(int... pages) {// 不确定个数的参数
        System.out.println("Fa.pp(int...)");
    }
}

方法的重写和重载

要求:方法的名称一致。

方法的重写(覆盖)

要求:方法的名称一致。

方法的重写(覆盖)一定发生在父子类之间

public class Test4 {
    public static void main(String[] args) {
        F4 f=new F4(); f.pp(10);
        S4 s=new S4(); s.pp(10);
        F4 fs=new S4(); fs.pp(10);
    }
}
class F4 {
    public void pp(int k) {
        System.out.println("F4.pp(int)");
    }
}
class S4 extends F4 {
    public void pp(int k) { //子类中定义的同名同参数的方法覆盖了父类中的方法定义,如
果需要调用父类中的方法则需要使用super.pp(k)进行调用
        System.out.println("S4.pp(int)");
    }
}

执行规则:new谁运行谁的方法,和声明的类型无关

方法的覆盖定义要求方法名称一致

@Override注解可以使IDE工具在编译源代码时进行检查,如果有手写错误则IDE工具报错

方法的参数一致(个数、类型、顺序),和参数名称无关

类型一致的问题
class Fa {
    public void eat(Integer kk) {
        System.out.println("Animal.eat()");
    }
}
class Son extends Fa {
    @Override
    public void eat(Number kk) { //类型必须一致,即使父类类型都不可以,int和
Integer简单类型和包装类型也不可以。这里去除@override注解则不会有语法错误,这里不是
方法的重写,是方法的重载
        System.out.println("就是爱老鼠");
    }
}

        顺序一致的问题,系统识别方法依靠是方法名称和参数类型列表,和方法参数的名称无关。例如这里 系统识别的方法为eat(String,String)。要识别顺序还得依靠类型的区别,例如eat(int,double)和 eat(double,int)

class Fa {
    public void eat(String s1,String s2) {
    System.out.println("Animal.eat()");
    }
}
    class Son extends Fa {
    @Override
    public void eat(String s2,String s1) {//系统不能识别变量名称
        System.out.println("就是爱老鼠");
    }
}

        返回数据类型一致【面试】(因为如果返回类型不一致,则无法进行语法检查,例如父类返回 Double,而子类返回Integer,调用处语法检查是按照Double进行检查还是按Integer检查?允许父 类中返回的是父类型,而子类中返回子类型,例如父类中返回的是Number类型,而子类中返回的 是Integer)

class Fa {
    public Number eat(double s1,int s2) {
        System.out.println("Animal.eat()");
        return 10.;
    }
}

class Son extends Fa {
    @Override
    public Integer eat(double s2,int s1) { //允许子类中返回值类型是父类返回值
类型的子类型
        System.out.println("就是爱老鼠");
        return 99;
    }
}

抛出异常一致,注意实际上允许子类抛出比父类更少的异常

class Fa {
    public Integer eat(double s1, int s2) throws Exception {
        System.out.println("Animal.eat()");
        return 10;
    }
}
class Son extends Fa {
    @Override
    public Integer eat(double s2, int s1) throws IOException {
        System.out.println("就是爱老鼠");
        return 99;
    }
}

要求子类中的方法范围 >= 父类中方法范围

静态方法覆盖和调用,用谁声明则调用谁的静态方法

只有静态方法覆盖定义父类中的静态,实际上系统不建议这种做法
//The method pp() of type Son must override or implement a supertype
method
public class Test1 {
    public static void main(String[] args) {
        // 直接使用具体类调用静态方法没有任何问题,使用哪个类就调用的是哪个类中定义
的静态方法
        // Fa.pp();Fa...pp
        // Son.pp();Son...pp
        // 事实上静态方法也可以通过创建对象后,使用对象进行调用。声明变量的类型和具
体构建的类型一致,也不会有问题
        // Fa ff=new Fa();
        // ff.pp();
        //如果调用静态方法,则用谁声明调用谁的方法
        Fa ff = new Son();
        ff.pp();//执行结果是Fa...pp
    }
}
class Fa {
    public static void pp() {
        System.out.println("Fa...pp");
    }
}
class Son extends Fa {
    public static void pp() {
        System.out.println("Son...pp");
    }
}

方法的重载

        方法的名称相同,参数不同,和返回值类型无关。可以在一个类内或者父子类之间 调用规则:类型最佳匹配原则

public class Test1 {
    public static void main(String[] args) {
        Fa ff = new Son();
        ff.pp(10);//因为在父类中声明的方法为Integer类型,所以在执行前会自动执行装箱操
作,所以调用的是从父类中继承到的pp(Integer),而不是最佳匹配的pp(int)
    }
}
class Fa {
    protected void pp() {
        System.out.println("Fa.pp()");
    }
    public void pp(Integer kk){
        System.out.println("Fa.pp(Integer)");
    }
}
class Son extends Fa {
    public int pp(int k) {
        System.out.println("Son.pp(int)");
        return 10;
    }
}
public class Test1 {
    public static void main(String[] args) {
        Fa ff = new Son();
        ff.pp(10);
    }
}
class Fa {
    protected void pp() {
        System.out.println("Fa.pp()");
    }
    public void pp(Integer kk){
        System.out.println("Fa.pp(Integer)");
    }
}
class Son extends Fa {
    public void pp(Integer kk){
        System.out.println("Son.pp(Integer)");
    }
    public int pp(int k) {
        System.out.println("Son.pp(int)");
        return 10;
    }
}

评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值