2015-04-28 2 views
4

У меня есть следующая (сторонняя) структура класса. Мы будем называть сторонний проект ProjectSeriously, и обратите внимание, что я использую System.out.println вместо других сложных функций (100 строк строк кода).Позвоните super.super.method, пропуская super.method

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 В какой-то другой части этого замечательного проекта, ProjectSeriously. Увидев, что это общественные методы, я чувствую, что это должно быть возможно.

+6

см. [Почему super.super.method(); не разрешено в Java?] (http://stackoverflow.com/q/586363/217324) –

+0

http://stackoverflow.com/questions/586363/why-is-super-super-method-not-allowed-in- java предложит вам выполнить миссию невозможно ... –

+0

Если вам действительно нужно это сделать, посмотрите, сможет ли [этот ответ использовать отражение] (http://stackoverflow.com/a/2692379/1798593) работать в вашем случае , –

ответ

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

Run с:

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

Это разрушит инкапсуляцию ужасным способом (вы по существу отключите часть класса B), и это не должно быть возможным на Java. Я уверен, что это невозможно.

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 
0

Да его не представляется возможным в «стандартной» Java путь, а также его плохое дизайнерское решение, но ОП могут не иметь доступа к исходному классу. Я столкнулся с этой проблемой несколько раз раньше с разными банками.

Если вы хотите пропустить, например, вызов частного метода в одном из суперклассов, но все же нужны другие части кода конструктора или функциональные возможности суперклассов, единственный «простой» способ сделать это в основном копировать-вставить эту часть кода в свой собственный класс. Например, если у вас есть эти классы:

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

} 
Смежные вопросы