2011-09-28 80 views
30

Quiero cambiar la forma en que se ejecuta un método de una clase sin anular el método, y solo se anula (o se extiende idealmente) la clase interna. Supongamos que no puedo cambiar el hecho de que tengo que hacer esto (estoy modificando una base de código fuente abierto existente y habría fricción al sacar clases o lo que sea).¿Cómo sobrescribir/extender una clase interna desde una subclase?

public class A { 
    static class Thing { 
    public int value() { return 10+value2(); } 
    public int value2() { return 10; } 
    } 

    public String toString() { 
    Thing t = new Thing(); 
    return Integer.toString(t.value()); 
    } 
} 

public class B extends A { 
    static class Thing { 
    public int value2() { return 20; } 
    } 
} 

Mi objetivo es, cambiando lo único, consiguiendo toString de B() para volver "30", en donde actualmente se volverá "20". Lo ideal sería cambiar solo el método value2 (dejando así cualquier otro método sin modificar), pero no sé si esto es posible.

Gracias

Respuesta

35

Creo que necesita un método de fábrica para esto. Considere el ejemplo siguiente (derivado de su fragmento de):

static class A { 
    static class Thing { 
     public int value() { 
      return 10 + value2(); 
     } 
     public int value2() { 
      return 10; 
     } 
    } 
    protected Thing createThing() { 
     return new Thing(); 
    } 
    public String toString() { 
     return Integer.toString(createThing().value()); 
    } 
} 

static class B extends A { 
    static class Thing extends A.Thing { 
     public int value2() { 
      return 20; 
     } 
    } 
    @Override 
    protected Thing createThing() { 
     return new Thing(); // creates B.Thing 
    } 
} 

public static void main(String[] args) { 
    System.out.println(new B()); 
} 

Salida:

30 
+1

Tiene toda la onza de elegancia que esperaba. ¡Gracias! –

+3

Como no lo vi al principio, quiero resaltar que esto requirió la creación de valores superiores en la clase externa. Creo que no hay manera de anular los métodos en la clase interna "Cosa" de una subclase de A. (Me gustaría saber lo contrario). En su lugar, estás reemplazando a A.Thing con un nuevo B.Thing que sombrea en el espacio de nombres de B pero no es visible para los métodos en A. Para usar esto, debe actualizar cada referencia de la clase externa. –

2

No es posible solo cambiando el valor2. El problema es que las llamadas 'nuevas' no se distribuyen dinámicamente: la 'nueva' en toString siempre creará A :: Thing. Se podría solucionar este problema creando una fábrica: algo como esto:

public class A { 
    static class Thing { 
    public int value() { return 10+value2(); } 
    public int value2() { return 10; } 
    } 

    private Thing makeThing() { return new Thing(); } 


    public String toString() { 
    Thing t = new Thing(); 
    return Integer.toString(t.value()); 
    } 
} 

public class B extends A { 
    static class Thing extends A.Thing { 
    public int value2() { return 20; } 
    } 

    private Thing makeThing() { return new Thing(); } 

} 
+0

Usted parece estar utilizando la sintaxis de C++ objeto, no Java. – Thor84no

3

Usted debe ser capaz de extender simplemente la clase interna con la cosa se extiende A.Thing. Mientras sea visible en su alcance, no debería ser un problema.

Cuestiones relacionadas