[英]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.