簡體   English   中英

調用super.super.method,跳過super.method

[英]Call super.super.method, skipping super.method

我有以下(第三方)類結構。 我們將調用第三方項目ProjectSeriously ,並注意我使用System.out.println代替其他復雜功能(100行代碼)。

class A {
    public void hi() {
        // Do an important thing
        System.out.println("Important thing A");
    }
}

class B extends A { 
    public void hi() {
        // Do some terrible, terrible things
        System.out.println("TERRIBLE THING B");

        // Do that important thing
        super.hi();
    }
}

現在我想寫這個(這不是有效的java):

class C extends B { 
    public void hi() {
        // Do some not-so-terrible things
        System.out.println("Ok thing C");

        // Do that important thing
        super.super.hi();
    }
}

我必須將一個B的instanceof傳遞給這個奇妙項目的另一部分, ProjectSeriously 看到這些是公共方法,我覺得這應該是可能的。

使用它之前,您可以使用javassist修改類。

但這是一個非常丑陋的黑客攻擊 ,請嘗試重構A和/或B中的代碼以暴露重要部分。

package test;

import javassist.ClassPool;
import javassist.CtClass;
import javassist.CtMethod;
import javassist.CtNewMethod;

class A {
    public void hi() {
        // Do an important thing
        System.out.println("Important thing A");
    }
}

class B extends A { 
    public void hi() {
        // Do some terrible, terrible things
        System.out.println("TERRIBLE THING B");

        // Do that important thing
        super.hi();
    }
}

class C extends B { 
    public void hi() {
        // Do some not-so-terrible things
        System.out.println("Ok thing C");

        // Do that important thing
        super.hi();
    }
}

public class Main {

    public static void main(String[] args) throws Exception {
        CtClass cc = ClassPool.getDefault().get("test.B"); // don't use test.B.class.getName() as this force the class loader to load the class
        CtMethod m1 = cc.getDeclaredMethod("hi");
        cc.removeMethod(m1);
        CtMethod m2 = CtNewMethod.copy(m1, cc, null);
        m2.setBody("{ /* override method B.hi() body */ return super.hi();}", "this", m1.getName());
        cc.addMethod(m2);
        cc.toClass();
        C obj = new C();
        obj.hi();
    }
}

結果:

Ok thing C
Important thing A

除非您明確公開方法,哪種方法與設計模式相悖,否則沒有太多其他選項:

public class GrandParent {
    public void hi() {
        hiGrandParent();
    }

    protected final void hiGrandParent() {
        System.out.println("Hi from grandparent.");
    }

    public static class Parent extends GrandParent {
        @Override
        public void hi() {
            hiParent();
        }

        protected final void hiParent() {
            System.out.println("Hi from parent.");
        }
    }

    public static class Child extends Parent {
        @Override
        public void hi() {
            hiChild();
            super.hi();
            hiParent();
            hiGrandParent();
        }

        protected final void hiChild() {
            System.out.println("Hi from child.");
        }
    }
}

運行:

public final class RunIt {

    public static void main(final String[] args) {
        new GrandParent.Child().hi();
    }
}

預期產量:

Hi from child.
Hi from parent.
Hi from parent.
Hi from grandparent.

這會以一種可怕的方式打破封裝(你實際上是禁用了B類邏輯的某些部分),而且在Java中它是不可能的。 我很確定這是不可能的。

是的,它不是真正可能的“標准”java方式,也是一個糟糕的設計決定,但OP可能無法訪問原始類。 我幾次用不同的罐子面對這個問題。

如果你想跳過一個超類中的私有方法調用,但仍然需要構造函數代碼的其他部分或超類的功能,唯一“簡單”的方法是基本上復制粘貼那部分代碼進入你自己的類。 例如,如果您有這些類:

public class Foo {

    public Foo() {
        importantFunctionality();
    }

    private void importantFunctionality() {
        System.out.println("DOING IMPORTANT STUFF");
    }

}

public class Bar extends Foo {

    public Bar() {
        super(); //constructor gets called
        killAllBabies(); //I dont want this to get called, but its a private method meaning no overriding
        solveWorldHunger(); //I want to call this, but this is a private method, so no calling this from child classes
    }

    private void killAllBabies() {
        System.out.println("KILLING ALL BABIES");
    }

    private void solveWorldHunger() {
        System.out.println("SOLVING WORLD HUNGER");
    }

}

public class MyClass extends Bar {

    public MyClass() {
        super(); //Not good, because stuff I dont want gets called here
    }

}

解決這個問題的唯一方法是“跳過”前一個類並擴展原始類並實現跳過的類的功能。 不幸的是,由於可擴展性差,這對我們來說是一個問題:

public class MyClass extends Foo {

    public MyClass() {
        super();
        solveWorldHunger();
    }

    private void solveWorldHunger() {
        System.out.println("SOLVING WORLD HUNGER");
    }

}

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM