调用super.super.method,跳过super.method

时间:2015-04-28 19:51:08

标签: java inheritance super

我有以下(第三方)类结构。我们将调用第三方项目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();
    }
}

我必须将instanceof B传递给这个精彩项目的其他部分,ProjectSeriously。看到这些是公共方法,我觉得这应该是可能的。

4 个答案:

答案 0 :(得分:3)

您可以使用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

答案 1 :(得分:0)

除非您明确公开方法,哪种方式违背设计模式,否则还有很多其他方法:

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.

答案 2 :(得分:0)

这将以一种可怕的方式打破封装(你实际上是禁用了类B逻辑的某些部分),而且它在Java中是不可能的。我很确定这是不可能的。

答案 3 :(得分:0)

是的,它并不是真的可以用于标准" java方式,也是一个糟糕的设计决定,但OP可能无法访问原始类。我曾多次用不同的罐子面对这个问题。

如果你想在其中一个超类中跳过例如一个私有方法调用,但仍然需要构造函数代码的其他部分或超类的功能,那么唯一的" easy"这样做的方法是基本上将代码的那部分复制粘贴到你自己的类中。例如,如果您有这些类:

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");
    }

}