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

4
我有以下(第三方)类结构。我们称第三方项目为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。由于这些方法是公共的,所以我觉得应该是可行的。


6
为什么在Java中不允许使用"super.super.method()"语法? - Nathan Hughes
这篇文章建议你做不可能的任务... - J Richard Snape
如果你真的、真的需要这样做,可以查看一下使用反射的这个答案,看看是否适用于你的情况。 - Patricia Shanahan
4个回答

3
您可以使用javassist在任何使用类之前修改它。
但这是一个非常丑陋的hack,请尝试重构 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

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.

0

是的,在“标准”Java方式下,这并不是真正可能的,而且这是一个糟糕的设计决策,但OP可能无法访问原始类。我以前遇到过几次不同jar包的这个问题。

如果您想跳过其中一个超类中的私有方法调用,但仍需要构造函数代码的其他部分或超类的功能,则唯一“简单”的方法是将该代码部分复制粘贴到自己的类中。例如,如果您有这些类:

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

}

0

这将以可怕的方式破坏封装(实际上是禁用了类 B 的某些逻辑部分),在Java中不应该出现。我非常确定这不可能。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接