精华内容
下载资源
问答
  • 现在画UML图遇到一些继承的类,如果子类调用父类方法直接自己的生命线上, 还是再画一个父类对象,画父类的生命线上。 如果直接自己的生命线上,区分不出来是子类实现的方法还是父类的方法。 如果画...
  • 上回说到,简单工厂不属于GoF的二十三种设计模式,这回可就来真家伙了,大名...createProduct()这个方法在父类中也变成一个抽象方法。然后所有的子类去实现这个方法,不再需要用switch去判断,子类直接返回一个实...

    上回说到,简单工厂不属于GoF的二十三种设计模式,这回可就来真家伙了,大名顶顶的工厂方法模式前来报道!

    GoF类图解释

    工厂方法模式对比简单工厂来说,最核心的一点,其实就是将实现推迟到子类。怎么理解呢?我们可以将上回的简单工厂当做父类,然后有一堆子类去继承它。createProduct()这个方法在父类中也变成一个抽象方法。然后所有的子类去实现这个方法,不再需要用switch去判断,子类直接返回一个实例化的对象即可。

    GoF定义:定义一个用于创建对象的接口,让子类决定实例化哪一个类。Factory Method使一个类的实例化推迟到其子类。

    GoF类图

    6130ecafc3a13a159e01e2141b03f3fa.png

    工厂方法结构类图

    • 类图中的Product为产品
    • 类图中的Creator为创建者
    • 创建者父类有一个抽象的FactoryMethod()工厂方法
    • 所有创建者子类需要实现这个工厂方法,返回对应的具体产品
    • 创建者父类可以有一个AnOperation()操作方法,直接返回product,可以使用FactoryMethod()去返回,这样外部只需要统一调用AnOperation()

    代码实现

    首先是商品相关的接口和实现类,和简单工厂的类似:

    // 商品接口interface Product{    function show() : void;}// 商品实现类Aclass ConcreteProductA implements Product{    public function show() : void{        echo "I'm A.";    }}

    接下来是创建者的抽象和实现类:

    // 创建者抽象类abstract class Creator{    // 抽象工厂方法    abstract protected function FactoryMethod() : Product;    // 操作方法    public function AnOperation() : Product{        return $this->FactoryMethod();    }}// 创建者实现类Aclass ConcreteCreatorA extends Creator{    // 实现操作方法    protected function FactoryMethod() : Product{        return new ConcreteProductA();    }}

    这里和简单工厂就有了本质的区别,我们去掉了恶心的switch,让每个具体的实现类来进行商品对象的创建。没错,单一和封闭,每个单独的创建者子类只在工厂方法中和一个商品有耦合,有没有其他商品和其他的工厂来跟客户合作过这个子类完全不知道。

    同样还是拿手机来比喻:我是一个卖手机的批发商(客户Client,业务方),我需要一批手机(产品ProductA),于是我去让富X康(工厂Creator)来帮我生产。我跟富士康说明了需求,富士康说好的,让我的衡阳工厂(ConcreteCreatorA)来搞定,不需要总厂上,你这小单子,洒洒水啦。然后过了一阵我又需要另一种型号的手机(产品ProductB),富士康看了看后又让郑州富士康(ConcreteCreatorB)来帮我生产。反正不管怎么样,他们总是给了我对应的手机。而且郑州工厂并不知道衡阳工厂生产过什么或者有没有跟我合作过,这一切只有我和总工厂知道。

    完整代码:工厂方法模式

    实例

    场景:光说不练假把式,把上回的短信发送改造改造,我们依然还是使用上回的那几个短信发送商。毕竟大家已经很熟悉了嘛,不过以后要更换也说不定,商场如战场,大家还是利益为先。这样的话,我们通过工厂方法模式来进行解耦,就可以方便的添加修改短信提供商咯。

    短信发送类图

    7598242061b9042266a433aa3671d86e.png

    短信发送工厂方法

    代码实现

    <?phpinterface  Message {    public function send(string $msg);}class AliYunMessage implements Message{    public function send(string $msg){        // 调用接口,发送短信        // xxxxx        return '阿里云短信(原阿里大鱼)发送成功!短信内容:' . $msg;    }}class BaiduYunMessage implements Message{    public function send(string $msg){        // 调用接口,发送短信        // xxxxx        return '百度SMS短信发送成功!短信内容:' . $msg;    }}class JiguangMessage implements Message{    public function send(string $msg){        // 调用接口,发送短信        // xxxxx        return '极光短信发送成功!短信内容:' . $msg;    }}abstract class MessageFactory{    abstract protected function factoryMethod();    public function getMessage(){        return $this->factoryMethod();    }}class AliYunFactory extends MessageFactory{    protected function factoryMethod(){        return new AliYunMessage();    }}class BaiduYunFactory extends MessageFactory{    protected function factoryMethod(){        return new BaiduYunMessage();    }}class JiguangFactory extends MessageFactory{    protected function factoryMethod(){        return new JiguangMessage();    }}// 当前业务需要使用百度云$factory = new BaiduYunFactory();$message = $factory->getMessage();echo $message->send('您有新的短消息,请查收');

    完整源码:短信发送工厂方法

    说明

    • 和类图完全一致,基本不需要什么说明了吧,注意工厂方法模式的特点,实现推迟到了子类!!
    • 业务调用的时候需要耦合一个Factory子类。确实是这样,如果你想一个统一的出口来调用,请在外面加一层简单工厂就好啦,这就当成一道思考题吧
    • 不拘泥于目前的形式,可以不用抽象类,直接用一个接口来定义工厂方法,摒弃掉getMessage()方法,外部直接调用公开的模板方法(factoryMethod)即可

    下期看点

    抽象工厂模式,老大哥即将登场。压轴的总是最强悍的,让我们看看老大哥的本事!

    展开全文
  • 我们知道通过一个指向之类的父类指针可以调用子类的虚方法,因为子类的...直接调用就行,多继承的时候,一个类可能有多个方法表,也就有多个指向这些方法表的指针,一个类有多个父类怎么通过其中一个父类的指...

    我们知道通过一个指向之类的父类指针可以调用子类的虚方法,因为子类的方法会覆盖父类同样的方法,通过这个指针可以找到对象实例的地址,通过实例的地址可以找到指向对应方法表的指针,而通过这个方法的名字就可以确定这个方法在方法表中的位置,直接调用就行,在多继承的时候,一个类可能有多个方法表,也就有多个指向这些方法表的指针,一个类有多个父类,怎么通过其中一个父类的指针调用之类的虚方法?

    其实前面几句话并没有真正说清楚,在单继承中,父类是怎么调用子类的虚方法的,还有多继承又是怎么实现这点的,想知道这些,请认真往下看。

    我们先看单继承是怎么实现的。先上两个简单的类:

    复制代码
    #include <iostream> 
    using namespace std; 
    
    class A
    {
    public:
        A():a(0){}
    
        virtual ~A(){}
        
        virtual void GetA()
        {
            cout<<"A::GetA"<<endl; 
        }
    
        void SetA(int _a)
        {
            a=_a; 
        } 
        int a;
    };
    
    class B:public A
    {
    public:
        B():A(),b(0){}
    
        virtual ~B(){}
         
        virtual void GetA()
        { 
            cout<<"B::GetA"<<endl; 
        }
    
        virtual void GetB()
        { 
            cout<<"B::GetB"<<endl; 
        }
    private:
        int b;
    };
    
    typedef int (*Fun)(void);
    
    void TestA()
    {
        Fun pFun;
        A a; 
        cout<<"类A的虚方法(第0个是A的析构函数):"<<endl;
        int** pVtab0 = (int**)&a;
        for (int i=1; (Fun)pVtab0[0][i]!=NULL; i++){ 
            pFun = (Fun)pVtab0[0][i]; 
            cout << "    ["<<i<<"] "; 
            pFun(); 
        }
        cout<<endl;
        B b ;
        A* b1=&b;
    
        cout<<"类B的虚方法(第0个是B的析构函数)通过类B的实例:"<<endl;
        int** pVtab1 = (int**)&b;
        for (int i=1; (Fun)pVtab1[0][i]!=NULL; i++){ 
            pFun = (Fun)pVtab1[0][i]; 
            cout << "    ["<<i<<"] "; 
            pFun(); 
        }
        cout<<endl;
        cout<<"类B的虚方法(第0个是B的析构函数)通过类A的指针:"<<endl;
        int** pVtab2 = (int**)&*b1;
        for (int i=1; (Fun)pVtab2[0][i]!=NULL; i++){ 
            pFun = (Fun)pVtab2[0][i]; 
            cout << "    ["<<i<<"] "; 
            pFun(); 
        }
        cout<<endl;
        cout<<"     b的地址:"<<&b<<endl;
        cout<<"b1指向的地址:"<<b1<<endl<<endl;
    }
    复制代码

    运行结果如下:

    通过运行结果我们知道:通过父类指向子类的指针调用的是子类的虚方法。在单一继承中,虽然父类有父类的虚方法表,子类有子类的虚方法表,但是子类并没有指向父类虚方法的指针,在子类的实例中,子类和父类是公用一个虚方法表,当然只有一个指向方法表的指针,为什么可以公用一个虚方法表呢,虚方法表的第一个方法是析构函数,子类的方法会覆盖父类的同样的方法,子类新增的虚方法放在虚方法表的后面,也就是说子类的虚方法表完全覆盖父类的虚方法表,即子类的每个虚方法与父类对应的虚方法,在各种的方法表中的索引是一样的。

    但是在多继承中就不是这样了,第一个被继承的类使用起来跟单继承是完全一样的,但是后面被继承的类就不是这样了,且仔细往下看。

    还是先上3个简单的类

    复制代码
    #include <iostream> 
    using namespace std; 
    
    class A
    {
    public:
        A():a(0){}
    
        virtual ~A(){}
        
        virtual void GetA()
        {
            cout<<"A::GetA"<<endl; 
        }
         
        int a;
    };
    
    class B 
    {
    public:
        B():b(0){}
    
        virtual ~B(){}
         
        virtual void SB()
        { 
            cout<<"B::SB"<<endl; 
        } 
    
        virtual void GetB()
        {  
            cout<<"B::GetB"<<endl; 
        }
    
    private:
        int b;
    };
    
    class C:public A,public B 
    {
    public:
        C():c(0){}
    
        virtual ~C(){}
    
        virtual void GetB()//覆盖类B的同名方法
        { 
            cout<<"C::GetB"<<endl; 
        }
    
        virtual void GetC()
        { 
            cout<<"C::GetC"<<endl; 
        }
    
        virtual void JustC()
        {
            cout<<"C::JustC"<<endl; 
        }
    private:
        int c;
    };
    
    typedef int (*Fun)(void);
    
    void testC()
    {
        C* c=new C();
        A* a=c;
        B* b=c;
        Fun pFun;
        cout<<"sizeof(C)="<<sizeof(C)<<endl<<endl;
        cout<<"c的地址:"<<c<<endl;
        cout<<"a的地址:"<<a<<endl;
        cout<<"b的地址:"<<b<<endl<<endl<<endl;
         
        cout<<"类C的虚方法(第0个是C的析构函数)(通过C类型的指针):"<<endl;
        int** pVtab1 = (int**)&*c;
        for (int i=1; (Fun)pVtab1[0][i]!=NULL; i++){ 
            pFun = (Fun)pVtab1[0][i]; 
            cout << "    ["<<i<<"] "<<&*pFun<<"    "; 
            pFun(); 
        }
        cout<<endl<<endl;
        cout<<"类C的虚方法(第0个是C的析构函数)(通过B类型的指针):"<<endl;
        pVtab1 = (int**)&*b;
        for (int i=1; (Fun)pVtab1[0][i]!=NULL; i++){ 
            pFun = (Fun)pVtab1[0][i]; 
            cout << "    ["<<i<<"] "<<&*pFun<<"    "; 
            pFun(); 
        }
    }
    复制代码

    运行结果如下:

    从结果说话:

    Sizeof(C)=20,我们并不意外,在单继承的时候,父类和子类是公用一个指向虚方法表的指针,在多继承中,同样第一个父类和子类公用这个指针,而从第二个父类开始就有自己单独的指针,其实就是父类的实例在子类的内存中保持完整的结构,也就是说在多重继承中,之类的实例就是每一个父类的实例拼接而成的,当然可能因为继承的复杂性,会加一些辅助的指针。

    指针a与指针c指向同一个地址,即c的首地址,而b所指的地址与a所指的地址相差8字节刚好就是类A实例的大小,也就是说在C的内存布局中,先存放了A的实例,在存放B的实例,sizeof(B)=8(字段int b和指向B虚方法表的指针),在家上C自己的字段int c刚好是20字节。

    让我有点意外的是:方法B::SB,C::GetB并没有出现在类C的方法表中,而且C::GetB是C覆写B中的GetB方法,怎么没有出现在C的方法表中呢?在《深入探索C++对象模型》一书中讲到,这两个方法同时应该出现在C的方法表中,同样也会覆盖B的虚方法表。可能是不通的编译器有不同的实现,我用的是VS2010,那本书上讲的是编译器cfront

    OK,我们不用管不同的编译器实现上的区别,这点小区别无伤大雅,虚方法的调用机制还是一样的。

    先来分析几个小例子,看看虚方法的实现机制。

           C* c=new C();

           A* a=c;

           a->GetA();

           c->GetA();

           c->GetC();

    上面已经说了,a与c指向的是同一个地址,且公用同一个虚方法表,而方法GetA,GetC的地址就在这个方法表中,那么调用起来就简单多了,大致就是下面这个样子:

    a->GetA()   ->   (a->vptr1[1])(a);   // GetA在方法表中的索引是1

    c->GetA()  ->  (c->vptr1[1])(c);   // GetA在方法表中的索引是1

    c->GetC()   ->   (a->vptr1[2])(c);   // GetC在方法表中的索引是2

    vptr1表示指向类C第一个方法表的指针,这个指针实际的名字会复杂一些,暂且将指向类C的第一个方法表的指针命名为vptr2,下面会用到这个指针。

    再来分析几行代码:

         B* b=c;

           c->GetB();

           b->GetB();

    指针b和指针c指向的不是同一个地址,那么B* b=c;到底是做了啥呢?大致是会转换成下面这个样子:

    B* b=c+sizeof(A);

    c所指的地址加上A的大小,刚好是b所指的地址。

    c->GetB();同样需要转换,因为方法GetB根本不在c所指的那个方法表中,可能转换成这个样子(实际转换成啥样子我真不知道):

    this=c+sizeof(A);

    (this->vptr2[2])(c);

    如果像编译器cfront所说的那样,方法GetB在vptr1所指的方法表中,那么就不用产生调整this指针了,如果在vptr1所指的方法表中,就让方法表变大了,且跟别的方法表是重复的。

    b->GetB();就不需要做过多的转换了,因为b正好指向vptr2,可能转换成下面这个样子:

    b->GetB()   ->   (b->vptr2[2])(b);   // GetB在方法表中的索引是2

    总之指针所指的方法表如果没有要调用的方法,就要做调整,虚方法需要通过方法表调用,相对于非虚方法,性能就慢那么一点点,这也是别人常说的C++性能不如C的其中一点。

    虚多继承就更麻烦了,不熟悉可能就会被坑。《深入探索C++对象模型》这本书是这样建议的:不要在一个virtual base class中声明nonstatic data members,如果这样做,你会距复杂的深渊越来越近,终不可拔。

    virtual base class还是当做接口来用吧。



    本文转自啊汉博客园博客,原文链接:http://www.cnblogs.com/hlxs/p/3214062.html

    展开全文
  • java,可以通过“super”关键字,很方便的调用父类中方法,但是要调用祖父类的方法怎么样实现呢,本文记录一下《深入理解java虚拟机》一书的介绍。 拥有invokedynamic和java.lang.invoke包之前,...

      在java中,可以通过“super”关键字,很方便的调用到父类中的方法,但是要调用祖父类的方法该怎么样实现呢,本文记录一下《深入理解java虚拟机》一书中的介绍。

      在拥有invokedynamic和java.lang.invoke包之前,使用存粹的java语言很难处理这个问题,原因是子类的方法中根本没有办法获取一个实际类型是祖父类的对象引用,但是有了这两个包,java程序员可以直接解决,在jdk7 update9之前,可以使用以下方法解决:

    package com.example.demo.test;
    
    import java.lang.invoke.MethodHandle;
    import java.lang.invoke.MethodHandles;
    import java.lang.invoke.MethodType;
    import java.lang.reflect.Field;
    
    public class TestExtends {
        public static void main(String[] args){
            Son son = new Son();
            son.thinking();
        }
    }
    
    class GrandFather {
        public void thinking(){
            System.out.println("GrandFather thinking");
        }
    }
    
    class Father extends GrandFather {
        public void thinking(){
            System.out.println("Father thinking");
        }
    }
    
    class Son extends Father {
        public void thinking(){
            try{
                MethodType mt = MethodType.methodType(void.class);
                MethodHandle mh = MethodHandles.lookup().findSpecial(GrandFather.class,"thinking",mt,getClass());
                mh.invoke(this);
            }catch (Exception e){
                e.printStackTrace();
            } catch (Throwable throwable) {
                throwable.printStackTrace();
            }
        }
    }

    但是在jdk7 update9之后的版本运行却只得到

    原因是这个逻辑在jdk7 update9之后的版本被视作一个潜在的安全性缺陷修正了,因为必须保证在findSpecial()查找方法版本的时候受到访问约束(比如对访问控制的限制,对参数类型的限制)。。

    那么在新版本的JDK中应该如何实现这个问题呢,我们看一下新版本的JDK中findSpecial()里面的源码:

    再看一下this.in(specialCaller)里面的源码:

    我们可以看到哪些是需要进行访问保护的,该API在实现的时候是预留了后门的,访问保护是通过一个allowedModes参数来控制的,当这个参数被设置成“TRUSTED“的时候,可以绕开所有的保护措施,这个参数没有开放给外部设置,但是我们可以通过反射来打破这种限制,因此把代码改成以下可以解决这个问题:

    package com.example.demo.test;
    
    import java.lang.invoke.MethodHandle;
    import java.lang.invoke.MethodHandles;
    import java.lang.invoke.MethodType;
    import java.lang.reflect.Field;
    
    public class TestExtends {
        public static void main(String[] args){
            Son son = new Son();
            son.thinking();
        }
    }
    
    class GrandFather {
        public void thinking(){
            System.out.println("GrandFather thinking");
        }
    }
    
    class Father extends GrandFather {
        public void thinking(){
            System.out.println("Father thinking");
        }
    }
    
    class Son extends Father {
        public void thinking() {
            try{
                MethodType mt = MethodType.methodType(void.class);
                Field lookupImpl = MethodHandles.Lookup.class.getDeclaredField("IMPL_LOOKUP");
                lookupImpl.setAccessible(true);
                MethodHandles.Lookup lookup = (MethodHandles.Lookup) lookupImpl.get(null);
                MethodHandle mh = lookup.findSpecial(GrandFather.class,"thinking",mt,GrandFather.class);
                mh.invoke(this);
            }catch (Throwable a){
                a.printStackTrace();
            }
        }
    }
    
    展开全文
  • 且听下面分解子类对象实例化的过程:1 从结果上来看:(继承性)子类继承了父类以后 就获取了父类中声明的属性和方法创建子类对象 堆空间 就会加载所有父类中声明的属性2 从过程来上看 :当我们通过子类的构造器创建...

    大家往往听说  子类继承了父类就有了父类中的所有的非私有的属性,但是怎么就有了父类的属性了呢 ?且听下面分解

    子类对象实例化的过程:

    1 从结果上来看:(继承性)

    子类继承了父类以后 就获取了父类中声明的属性和方法

    创建子类对象 在堆空间中 就会加载所有父类中声明的属性

    2 从过程来上看 :

    当我们通过子类的构造器创建子类的对象是 一定会直接或间接的调用其父类的构造器 进而调用父类的父类的构造器.直到调用了java.langObject类中空参的构造器为止,正因为加载过所有的父类结构 所以才可以看到内存中有父类的结构 子类对象才可以考虑进行调用

    明确:虽然创建子类对象时,调用了父类的构造器 但是自始至终就创建了一个对象 即为new的子类对象

    习题:

    实验 类的继承,super

    1、写一个名为 Account 的类模拟账户。该类的属性和方法如下图所示。该类包括的属性: 账号 id,余额 balance,年利率 annualInterestRate;包含的方法:

    访问器方法(getter 和 setter 方法),返回月利率的方法 getMonthlyInterest(),取款方法 withdraw(),存款方法 deposit()。

    Account private int id private double balance private double annualInterestRate

    public Account (int id, double balance, double annualInterestRate )

    public int getId() public double getBalance() public double getAnnualInterestRate()

    public void setId( int id) public void setBalance(double balance)

    public void setAnnualInterestRate(double annualInterestRate)

    public double getMonthlyInterest()

    public void withdraw (double amount)

    public void deposit (doubleamount)

    写一个用户程序测试 Account 类。在用户程序中,创建一个账号为1122、余额为 20000、

    年利率 4.5%的 Account 对象。使用 withdraw 方法提款 30000 元,并打印余额。 再使用 withdraw 方法提款 2500 元,使用 deposit 方法存款 3000元,然后打印余额和月利 率。

    提示:在提款方法 withdraw 中,需要判断用户余额是否能够满足提款数额的要求,如果不 能,应给出提示。 运行结果如图所示:

    2、创建 Account 类的一个子类 CheckAccount 代表可透支的账户,该账户中定义一个属性 overdraft 代表可透支限额。在 CheckAccount 类中重写 withdraw 方法,其算法如下: 如果(取款金额账户余额), 计算需要透支的额度 判断可透支额 overdraft 是否足够支付本次透支需要,如果可以 将账户余额修改为 0,冲减可透支金额 如果不可以 提示用户超过可透支额的限额

    要求:写一个用户程序测试 CheckAccount 类。在用户程序中,创建一个账号为 1122、余 额为 20000、年利率 4.5%,可透支限额为 5000 元的 CheckAccount 对象。 使用 withdraw 方法提款 5000 元,并打印账户余额和可透支额。 再使用 withdraw 方法提款 18000 元,并打印账户余额和可透支额。 再使用 withdraw 方法提款 3000 元,并打印账户余额和可透支额。

    提示: (1) 子类 CheckAccount 的构造方法需要将从父类继承的 3 个属性和子类自己的属性全 部初始化。 (2) 父类Account的属性balance被设置为private,但在子类CheckAccount的withdraw 方法中需要修改它的值,因此应修改父类的 balance 属性,定义其为 protected。

    68f724bad5a33d9a9f6bd2ca7369ecb7.png

    4a2195c8b79807d0b245afcdfb8022b4.png

    8f900a89c6347c561fdf2122f13be562.png

    961ddebeb323a10fe0623af514929fc1.png

    importjava.util.Scanner;public classAprilFaceToAccount {public static voidmain(String[] args) {

    AprilFiveAccount account= new AprilFiveAccount(1122,20000,0.0045);

    Scanner scanner= newScanner(System.in);int money =scanner.nextInt();

    account.withdraw(money);

    }

    }classAprilFiveAccount{private intid;private double balance; //余额

    private double annualInterestRate; //年利率

    public AprilFiveAccount (int id, double balance, doubleannualInterestRate ){this.id =id;this.balance =balance;this.annualInterestRate =annualInterestRate;

    }public doublegetMonthlyInterest(){//返回月利率

    return getAnnualInterestRate()/12;

    }public void withdraw (double amount){ //取款

    if(amount >balance){

    System.out.println("余额不足");

    System.out.println("余额为:"+balance);

    }else{

    balance-=amount;

    System.out.println("余额为:"+balance);

    System.out.println("月利率为:"+getMonthlyInterest());

    }

    }public void deposit (double amount){ //存款

    if(amount <=0){

    System.out.println("输入的不合法");

    }

    balance+=amount;

    System.out.println("余额为:"+balance);

    }public intgetId() {returnid;

    }public void setId(intid) {this.id =id;

    }public doublegetBalance() {returnbalance;

    }public void setBalance(doublebalance) {this.balance =balance;

    }public doublegetAnnualInterestRate() {returnannualInterestRate;

    }public void setAnnualInterestRate(doubleannualInterestRate) {this.annualInterestRate =annualInterestRate;

    }

    }

    习题1

    8f900a89c6347c561fdf2122f13be562.png

    961ddebeb323a10fe0623af514929fc1.png

    class AprilSixAfternoonCheckAccount extendsAprilFiveAccount{public AprilSixAfternoonCheckAccount(int id, double balance, double annualInterestRate,doubleoverdraft) {super(id, balance, annualInterestRate);this.overdraft =overdraft;

    }private double overdraft; //可透支额度

    public void withdraw(double amount){ //重写取款方法

    double residueue =getBalance();if(amount

    setBalance(getBalance()-amount);

    System.out.println("成功取出: "+amount+"余额为: "+getBalance()+"可透支金额:"+overdraft);

    }else if (amount >getBalance()){if(amount-getBalance() >overdraft){

    System.out.println("用户超过可透支金额");

    System.out.println("withDraw is success 余额为 : "+amount+"额度剩余: "+overdraft);

    }else{

    overdraft= amount-getBalance()-overdraft ; //透支额度校对

    setBalance(0);

    System.out.println("withDraw is success 余额为 : "+amount+"额度剩余: "+overdraft);

    }

    }

    }

    }

    习题2

    展开全文
  • 如果子类中没有这个方法调用 父类的 然后(只要一个接口有此方法)才是接口中的 ,两个同级别的就会冲突 如果不是成员方法 在父类 接口中 有同名的常量 直接就会报错 不会像方法那样优先选择直接父类方法...
  • 1. 如果父类的print有private访问权限,我可以这么理解,new Student().fun()在子类中没找到fun(),然后到父类中找到了,这时候this指向父类,所以this.print()调用的是父类的print()从而输出了“Person"。...
  • 因为在子类不能 直接使用 _属性名的父类的属性默认生成的实例便量,但是在子类方法使用@synthesize 可以对继承过来的属性进行声明一个_属性名 名字的变量(这个变量到底是父类继承过来的还是在子类新生成的 父类...
  • 私有属性和私有方法是类独自私有的,不能外面直接调用,但是可以使用类的实例方法(普通方法)间接调用。 但是继承又会怎么样呢? 继承,如果调用的是继承父类的公有方法,可以公有方法中访问父类中...
  • day 18总结 一、继承 定义 怎么继承 注意 继承的东西 ...在子类中__init__方法中通过super()去调用父类中的__init__ 子类:继承者 同一个子类可以同时继承多个父类:class 子类(父类1, 父类2,
  • super关键字的使用

    2020-11-01 19:49:25
    super关键字出现在子类中,我们new子类的实例对象的时候,子类对象里面会有一个父类对象。怎么去引用里面的父类对象呢?使用super来引用,所以可以得出结论:super主要的功能是完成子类调用父类中的内容,也就是调用...
  • day18 继承

    2021-02-25 22:43:31
    day18 继承 1.继承 什么继承 ...在子类中可以通过super().方法的形式来调用父类方法,不能在静态方法中调用 怎么继承 # class 字类(父类): # pass 2.重写 早字类中添加属性和方法
  •  多态性可以简单地概括为“一个接口,多种方法”,程序运行时才决定调用的函数,它是面向对象编程领域的核心概念。多态(polymorphism),字面意思多种形状。  C++多态性是通过虚函数来实现的,虚函数允许子类重新...
  • 在子类的__init__方法中通过supper()去调用父类的__init__的方法,实现继承。 类方法的调用过程 通过类或则对象在调用方法的时候,回先看当前类有没有这个方法,如果有就直接调用自己类;没有就看父类有...
  • 但是现在我们是将增删改查等操作抽象到了父类中,在子类中直接调用这些方法完成相应操作。那么父类在执行具体的方法怎么才能知道应该调用哪个子类的service或者哪个子类的repository呢?这么问这个问题有点不...
  • 这几天看接口的这一章,Comparable接口看到了一个不知道怎么解释的问题:Object类是所有类的父类,为什么实现Comparable接口的子类一定要重写Object类用protected修饰的的clone方法而不能直接使用?...
  • X++的多态

    2006-10-21 12:36:00
    多态语言的表现上就是用父类类型调用子类方法的实现,C++和C#是通过虚函数表来实现的,具体实例化的时候把重载的函数地址写到虚函数表的地址列表,我想X++应该也是这样实现的.问题在于如果想访问子类特有的函数,...
  • 回头再试试把父类的 <code>LKDBProperty</code> copy 一份添加给子类怎么样。 总结 出现这样的矛盾,本质上是因为最终整合的 <code>+ getTableMapping</code> 的信息跟获取 property 列表</strong> 没有&...
  • 设计模式之简单工厂模式 看书学习设计模式,书本来源《大话设计模式》...1、通过继承,造成多态属性,然后在子类中实现父类的接口,在不同的子类中进行不同的接口实现。直接调用实现的接口方法得到最后的值,这一种思维
  • 如果在抽象类中存在有参构造方法,则必须在子类中明确的使用super([参数列表])指明要调用父类中的哪个构造方法. 这里举例如下: view plaincopy to clipboardprint? abstract class Person { // 应该有姓名和...
  • C++ 多态详解

    2021-01-07 19:29:38
    但我搞不懂为什么要那么做,我们直接在子类中写一个同名的成员函数,从而隐藏父类的函数不就行了么? 忽然感觉学了很长时间的C++只是知道有多态这样一个重要的概念,编程时怎么用,却真的没有仔细想一下它的机制,也...
  • 一小时内学会 C#(txt版本)

    热门讨论 2009-08-19 18:09:37
    正如其名字说的,一旦它们已经进行了写操作、直接初始化或构造函数对其进行了赋值,readonly 数据成员就只能对其进行读取。readonly 和 const 数据成员不同之处在于 const 要求你声明时进行直接初始化。看下面...
  • 比如我希望基类写一个...因为每个service子类都有这样的方法,唯一不同的不过是传入的bean和用到的dao,如何能抽取出这个方法父类中呢?是不是service的基类只能做bean的直接增删查改而没法做更多的业务逻辑?
  • java 面试题 总结

    2009-09-16 08:45:34
    如果在子类中定义某方法与其父类有相同的名称和参数,我们说该方法被重写 (Overriding)。子类的对象使用这个方法时,将调用子类中的定义,对它而言,父类中的定义如同被"屏蔽"了。如果在一个类中定义了多个同名的...

空空如也

空空如也

1 2
收藏数 39
精华内容 15
关键字:

在子类中怎么直接调用父类方法