2016-04-18 17 views
1

Wenn ich eine konkrete Klasse habe Foo, und ich möchte einen "Alias" namens Bar hinzufügen, der Foo erweitert aber keine Methoden überschreibt - wird Java mich das tun lassen?Unterklasse ohne Überschreibungen (Alias-Klasse)

Edit: Kontext - das Ziel ist es, schließlich Foo zu Bar umzubenennen, weil Foo schlecht benannt wurde; Allerdings hängt Foo von einem anderen Projekt ab und ich kann sowohl Foo als auch FooCaller nicht im selben Commit ändern. Um zu vermeiden, FooCaller zu brechen, mache ich drei Änderungen: (1) addiere Bar, (2) ändere FooCaller zu BarCaller (gleiches Verhalten), (3) entferne Foo zusammen (wenn es keine FooCaller s mehr gibt).

Gibt es hier irgendwelche Fehler, oder verhält sich Bar genauso wie Foo?

+2

Ich glaube, Sie müssen auf Konstruktoren achten, aber es gibt keine Verpflichtung, Methoden einer Elternklasse außer Kraft zu setzen, es sei denn, die Eltern sind abstrakt. – KevinO

+2

Würden Sie "Foo" oder "Bar" als generischen Typparameter verwenden, z. 'Liste '? – rgettman

+0

@rettman nein nur ein Alias ​​für einen graduellen Refactor – mfrankli

Antwort

1

Ja, Java werden Sie nur für die Zwecke der Aliasing der ursprünglichen Klasse eine nicht final konkrete Klasse lassen Unterklasse.

public class Foo { /* implementation */ } 

public class Bar extends Foo {} 

, dass die minimale Umsetzung wäre, vorausgesetzt, dass es nur ein Standard-Konstruktor in Foo ist. Wenn es Konstrukteuren, die Argumente in Foo nehmen, dann müssen Sie jedem Konstruktor einen Konstruktor in Bar für bieten Sie planen, rufen Sie Ihren Bar Instanzen zu erstellen, zB:

public class Foo { 
    public Foo(String baz) { /* constructor implementation */ } 
} 

public class Bar extends Foo { 
    public Bar(String baz) { super(baz); } 
} 

Alle nicht private Methoden in Foo wird vererbt werden von Bar.

Der einzige Ort, an dem es möglicherweise nicht funktioniert, ist, wenn Sie Bar anstelle von Foo als generischen Typparameter verwenden möchten.

Zum Beispiel, wenn Sie ersetzen ein List<Foo> mit einem List<Bar>, dann List nicht mehr halten alle Foo Instanzen oder Instanzen einer anderen Klasse, die Foo verlängern könnte.

Darüber hinaus, da Java-Generika-invariant sind, ist ein List<Bar>nicht ein Subtyp von List<Foo>, auch wenn ein Bar ein Foo ist. Details dazu, warum das der Fall ist, finden Sie unter Is List a subclass of List? Why aren't Java's generics implicitly polymorphic?. Vielleicht können Sie auch umgehen, wenn Sie List<? extends Foo> verwenden, so dass Sie eine oder eine List<Bar> verwenden können, aber dann können Sie nicht add alles andere als null.

Sie geben an, dass Sie es nicht in Generika verwenden werden, aber es sollte berücksichtigt werden, wenn Ihre Anforderungen erweitert werden.

Zusammenfassend, ja, der Java-Compiler wird Sie tun, aber mit einer begrenzten Oberseite - mit Bar anstelle von Foo als Alias ​​- und ein potenzieller Nachteil sehe ich keinen Grund, diesen Alias-Prozess zu verwenden.

+0

Außerdem kann sich Code, der sich auf getClass() verlässt, anders verhalten. – user140547

+0

Das Generika-Problem ist ein guter Punkt. In meinem speziellen Fall ist es das Ziel, Foo schließlich in Bar umzubenennen, weil Foo schlecht benannt war; Allerdings hängt Foo von einem anderen Projekt ab und ich kann sowohl Foo als auch FooCaller nicht im selben Commit ändern. Um FooCaller nicht zu zerstören, mache ich drei Änderungen: (1) füge Bar hinzu, (2) ändere FooCaller zu BarCaller (gleiches Verhalten), (3) entferne Foo ganz. – mfrankli

+0

@mfrankli das ist ein guter Kontext in Ihre Frage aufzunehmen. Ich schlage vor, Foo in Bar umzubenennen und dann einen neuen Foo zu erstellen, der Bar für Rückwärtskompatibilität erweitert. – dsh

1

Bar verhält sich wie Foo, solange Sie die richtige Sichtbarkeit verwenden. Private Methoden und Eigenschaften in Foo werden für Bar nicht zugänglich sein, und geschützte werden in Bar als privat betrachtet.

Das folgende Beispiel gibt "Foo" an Ihre Konsole aus.

class Example 
{ 
    public static void main (String[] args) 
    { 
     Bar b = new Bar(); 
     System.out.println(b.getName()); 
    } 
} 

class Foo { 
    protected String name; // Will be private in Bar 

    public Foo() { 
     this.name = "Foo"; 
    } 

    public String getName() { 
     return this.name; 
    } 
} 

class Bar extends Foo { 

} 
Verwandte Themen