Java初识:抽象类的方法调用机制


Java抽象类方法调用机制


什么是抽象类?
使用abstract关键字修饰的类称为抽象类。
举个例子,你的老板说让你好好工作,等公司发了财人人有份,或者你的朋友说改天请示吃饭啊,这都可以看作是抽象类。所以,抽象类就是指光说不做的类,在实际中不能直接拿来用。
抽象类的作用
我们知道所有的对象都是通过类来描绘的,但并不是所有的类都是用来描绘对象的。抽象类用来定义不想被实例化的类,即不能使用new关键字创建抽象类的对象。

抽象类的定义:

abstract class A{
 ....   
 }  
在这里我们要注意,有抽象方法的类必定是抽象类,反之,抽象类必有抽象方法(同时可以存在非抽象方法,这在编译时不会报错,虽然一般不这么用)。 


下面我们来看一个例子:

abstract class grandFather{         
    abstract void grandFather_mehtod1();
    abstract void grandFather_mehtod2();
    grandFather(){
        System.out.println("调用了grandFather的无参");
    }
}
abstract class Father extends grandFather{      
    abstract void Father_method();
    void father_function(){
        System.out.println("hunt something!");
    }
    Father(){
        System.out.println("调用了Father的无参");
    }
}
class Son_1 extends grandFather{
    void grandFather_mehtod1(){
        System.out.println("Son_1覆写了grandFather_mehtod1");
    }
    void grandFather_mehtod2(){
        System.out.println("Son_1覆写了grandFather_mehtod2");
    }
    void Son1_function(){
        System.out.println("使用了Son_1自己的方法");
    }
    Son_1(){
        System.out.println("调用了Son_1的无参");
    }
}
class Son_2 extends Father{
    void grandFather_mehtod1(){
        System.out.println("Son_2覆写了grandFather_mehtod1");
    }
    void grandFather_mehtod2(){
        System.out.println("Son_2覆写了grandFather_mehtod2");
    }
    void Father_method(){
        System.out.println("Son_2覆写了Father_mehtod");
    }
    void Son2_function(){
        System.out.println("使用了Son2_function");
    }
    Son_2(){
        System.out.println("调用了Son_2的无参");
    }
}

在这里我们定义了四个类,其中:
grandFatherFather是抽象类,他们的关系是Father继承grandFather
Son_1Son_2是两个普通类,其中Son_1继承grandFather,Son_2继承Father

下面我们来实例化上述的类:

            Son_1 s1 = new Son_1();     
            s1.grandFather_mehtod1();
            s1.grandFather_mehtod2();
            s1.Son1_function();
            System.out.println("-----------------------------");

            Son_2 s2 = new Son_2(); 
            s2.grandFather_mehtod1();
            s2.grandFather_mehtod2();
            s2.Father_method();
            s2.father_function();
            s2.Son2_function();
            System.out.println("-----------------------------");

            grandFather gs1 = new Son_1();      
            gs1.grandFather_mehtod1();
            gs1.grandFather_mehtod2();
            ((Son_1) gs1).Son1_function();  
            System.out.println("-----------------------------");
            /* 直接使用gs1.Son1_function()会报错*/

            grandFather gs2 = new Son_2();      
            gs2.grandFather_mehtod1();
            gs2.grandFather_mehtod2();
            ((Son_2) gs2).Son2_function();
            ((Father) gs2).Father_method();
            ((Father) gs2).father_function();
            System.out.println("-----------------------------");
            /* 直接使用
                gs2.Son2_function()
                gs2.Father_method()
                gs2.Father_function()
                    这三个方法会报错*/

            Father fs2 = new Son_2();       
            fs2.grandFather_mehtod1();
            fs2.grandFather_mehtod2();
            fs2.Father_method();
            fs2.father_function();
            ((Son_2) fs2).Son2_function();
            System.out.println("-----------------------------");
            /* 直接使用fs2.Son2_function()会报错*/ 

在这里我们创建了5个对象,分别是
**
Son_1创建的Son_1对象s1
Son_2创建的Son_2对象s2
grandFather创建的Son_1对象gs1
grandFather创建的Son_1对象gs2
Father创建的Son_2对象 fs2
**
接下来我们再来调用各个对象的方法,s1s2就不用多说了,我们从gs1开始看。
这是我们惊奇的发现gs1这个对象并不能直接调用Son_1这个类独有中的方法,但是却可以用由Son_1这个类完成了的抽象类grandFather中的两个方法。
由于我们都知道,grandFather gs1 = new Son_1() 这种写法是通过父类来创建子类对象,本质上还是一个子类的对象,只是创建了一个父类的引用指向这个对象。相当于申请了一个Son_1的空间,所以按理来说应该可以使用Son_1这个类本身的方法。
但实际上会产生报错,解决方案是将gs1强制类型转换为Son_1,这时就相当于利用Son_1创建一个Son_1的对象。

控制台结果查看(myEclipse 10):
gs1方法调用的结果测试

但这是为什么呢?
《Java编程思想》一书给出了答案
由于使用grandFather创建了一个Son_1类的对象,所以虽然是Son_1的对象,但是却把这个对象赋给了grandFather,所以在调用方法时,会按照grandFather的接口约束来调用,由于按照grandFather的寻址方式,所以看不到Son_1的方法。

如果这样说难以理解,我们可以换个方式来理解。
举个例子,现在有一匹狼想要混入羊群,它需要披上羊皮,把自己伪装成羊,才能成功的进入羊群。这时,它不能作出它实际上身为狼特有的动作,只能用羊拥有的动作。如果碰到狼和羊都有的动作,比如说嚎叫,这时狼也要按照羊的叫声来发声,才不会被发现,达到它混入羊群的目的。

本例中,可以把grandFather看作羊,把Son_1看作狼,就更容易理解了。


同理,对于gs2和fs2的方法调用也是如此,都是由于按照父类的接口约束而导致不能直接调用子类独有的方法。

  • 5
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 4
    评论
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值