Frage

Ich dachte, ich Soft bieten würde, wem wie es aus dem Park treffen würde. Was sind Generika, was sind die Vorteile von Generika, warum, wo, wie soll ich sie verwenden? Bitte halten Sie es recht einfach. Danke.

War es hilfreich?

Lösung

  • Sie Erlaubt Code / use Bibliothek Methoden zu schreiben, die typsicher sind, das heißt eine Liste ist garantiert eine Liste von Strings sein.
  • Als Folge der Generika kann der Compiler verwendet werden Kompilierung-Kontrollen Code für Art Sicherheit durchführen, das heißt versuchen Sie einen int in diese Liste von Strings zu setzen? eine Arraylist mit Hilfe würde das dazu führen, eine weniger transparent Laufzeitfehler zu sein.
  • Schneller als Objekte wie es entweder vermeidet Boxen / Unboxing mit (wo .net Werttypen Typen oder vice versa ) oder Gießen von Gegenständen auf den gewünschten Referenztyp verweisen.
  • Sie Code schreiben können, die auf viele Arten mit der gleichen zugrunde liegenden Verhalten, das heißt eine Dictionary verwendet den gleichen zugrunde liegenden Code als Dictionary anwendbar ist; Verwendung von Generika, hatte das Framework-Team nur ein Stück Code zu schreiben, zu beiden Ergebnisse mit den oben genannten Vorteilen zu erreichen.

Andere Tipps

Ich hasse wirklich mich zu wiederholen. Ich hasse die Eingabe die gleiche Sache öfter als ich muss. Ich mag es nicht, Dinge mehrmals mit geringen Unterschieden Neuformulierung.

Statt zu erstellen:

class MyObjectList  {
   MyObject get(int index) {...}
}
class MyOtherObjectList  {
   MyOtherObject get(int index) {...}
}
class AnotherObjectList  {
   AnotherObject get(int index) {...}
}

Ich kann eine wiederverwendbare Klasse bauen ... (in dem Fall, dass Sie die rohe Sammlung aus irgendwelchen Gründen nicht verwenden möchten)

class MyList<T> {
   T get(int index) { ... }
}

Ich bin 3x jetzt effizienter und ich habe nur eine Kopie zu erhalten. Warum würden Sie nicht wollen Sie weniger Code erhalten?

Dies gilt auch für nicht-Collection-Klassen wie zum Beispiel eines Callable<T> oder Reference<T>, die mit anderen Klassen zu interagieren hat. Wollen Sie wirklich Callable<T> und Future<T> und jede andere zugehörige Klasse erweitern typsichere Versionen erstellen?

ich nicht.

, um nicht einer der größten Vorteile von Java Generika ist zu typisieren , wie es Art Überprüfung zum Zeitpunkt der Kompilierung durchführen wird. Dadurch wird die Möglichkeit der ClassCastExceptions reduzieren, die zur Laufzeit geworfen werden kann, und kann robusten Code führen.

Aber ich vermute, dass Sie voll und ganz bewusst, dass sind.

  

Jedes Mal, wenn ich bei Generics aussehen es gibt   ich Kopfschmerzen. Ich finde den besten Teil   Java zu sein, es ist einfach und minimal   Syntax und Generika sind nicht einfach und   eine erhebliche Menge an neuen hinzufügen   Syntax.

Zuerst sah ich den Nutzen von Generika nicht. Ich begann Java aus der 1.4-Syntax lernen (obwohl Java 5 war aus zu der Zeit) und als ich Generika begegnet, fühlte ich, dass es mehr Code zu schreiben war, und ich habe nicht wirklich verstehen, die Vorteile.

Moderne IDEs machen das Schreiben von Code mit Generika zu erleichtern.

Die meisten modernen, anständig IDEs sind intelligent genug, um mit Generika mit dem Schreiben von Code zu unterstützen, vor allem mit Code-Vervollständigung.

Hier ist ein Beispiel für eine Map<String, Integer> mit einem HashMap machen. Der Code, den ich hätte einzutippen ist:

Map<String, Integer> m = new HashMap<String, Integer>();

Und in der Tat, das ist eine Menge geben Sie einfach einen neuen HashMap zu machen. Doch in Wirklichkeit hatte ich nur so viel zu geben, bevor Eklipse wußte, was ich brauchte:

Map<String, Integer> m = new Ha Strg + Space

Es stimmt, ich brauchte HashMap aus einer Liste von Kandidaten zu wählen, aber im Grunde wussten, dass die IDE, was die generischen Typen hinzuzufügen, einschließlich. Mit den richtigen Tools, die Verwendung von Generika ist nicht allzu schlecht.

Darüber hinaus, da die Arten bekannt sind, wenn Elemente aus der generischen Sammlung abrufen, wird das IDE als handeln, wenn das Objekt ist bereits ein Objekt seines deklarierten Typs - es gibt keine Notwendigkeit, um mich für Castings für die IDE zu wissen, was der Objekttyp ist.

Ein wesentlicher Vorteil von Generika aus dem Weg geht es gut mit neuen Java-5-Funktionen spielt Hier ist ein Beispiel von ganzen Zahlen in einem Set werfen und die Berechnung seines Gesamt:.

Set<Integer> set = new HashSet<Integer>();
set.add(10);
set.add(42);

int total = 0;
for (int i : set) {
  total += i;
}

In diesem Stück Code, gibt es drei neue Java-5-Funktionen vorhanden:

Als erstes Generika und Autoboxing von Primitive erlauben den folgenden Zeilen:

set.add(10);
set.add(42);

Die ganze Zahl 10 wird in einen Integer mit dem Wert von 10 autoboxed. (Und gleich für 42). Dann wird das Integer in die Set geworfen, die bekannt ist Integers zu halten. Der Versuch, in einem String werfen würde einen Compiler-Fehler verursachen.

Als nächstes wird für foreach-Schleife nimmt alle drei davon:

for (int i : set) {
  total += i;
}

Zuerst wird die Set enthaltende Integers werden in einer für-jede Schleife verwendet. Jedes Element wird erklärt einen int zu sein und das erlaubt ist, als der Integer an den primitiven int unboxed zurück. Und die Tatsache, dass dieser Unboxing auftritt, ist bekannt, weil Generika wurde verwendet, um festzulegen, dass es Integers im Set gehalten war.

Generics kann der Klebstoff sein, der die neuen Funktionen in Java 5 vereint, und es macht Codierung einfacher und sicherer. Und die meisten der Zeit IDEs sind intelligent genug, um Sie mit guten Vorschlägen, so im Allgemeinen, wird es nicht eine ganze Menge mehr Typisierung.

Und ehrlich gesagt, wie aus dem Set Beispiel zu sehen ist, habe ich das Gefühl, dass Java-5-Funktionen unter Verwendung der Code machen kann prägnanter und robust.

Bearbeiten - Ein Beispiel ohne Generika

Hier finden Sie eine Darstellung der oben Set Beispiel ohne die Verwendung von Generika. Es ist möglich, aber es ist nicht gerade angenehm:

Set set = new HashSet();
set.add(10);
set.add(42);

int total = 0;
for (Object o : set) {
  total += (Integer)o;
}

(Hinweis: Der obige Code nicht markiert Umwandlung Warnung zur Compile-Zeit generieren.)

Wenn Nicht-Generika Sammlungen verwenden, die Typen, die in die Sammlung eingetragen werden, sind Objekte vom Typ Object. Daher wird in diesem Beispiel ein Object ist, was added in den Satz wird.

set.add(10);
set.add(42);

In den obigen Zeilen ist im Spiel Autoboxing - die primitive int Wert 10 und 42 werden autoboxed in Integer Objekte, die den Set hinzugefügt werden. Aber denken Sie daran, werden die Integer Objekte als Objects behandelt werden, da es keine Typinformationen sind weiß der Compiler zu helfen, was die Set geben sollte erwarten.

for (Object o : set) {

Dies ist der Teil, der von entscheidender Bedeutung ist. Der Grund für die for-each-Schleife funktioniert, weil die Set die Iterable -Schnittstelle, die eine Iterator mit Typinformationen zurückgibt, falls vorhanden. (Iterator<T>, das ist.)

Da es jedoch keine Typinformation ist, wird die Set ein Iterator zurück, die die Werte in den Set als Objects zurückkehren wird, und deshalb ist das Element in der foreach-Schleife abgerufen werden muss vom Typ Object sein.

Nun, da die Object vom Set abgerufen wird, muss sie manuell auf einen Integer gegossen werden, um die Addition auszuführen:

  total += (Integer)o;

Hier wird eine Typumwandlung von einem Object zu einem Integer ausgeführt. In diesem Fall wissen wir, dies wird immer funktionieren, aber manuelle Schublade gesteckt macht mir immer das Gefühl, es zerbrechlich Code ist, wenn eine geringfügige Änderung sonst wo hergestellt wird, beschädigt werden könnte. (Ich glaube, dass jede Typumwandlung ein ClassCastException ist geschehen warten, aber ich schweife ab ...)

Die Integer ist jetzt unboxed in ein int und erlaubt die Zugabe in die int Variable total auszuführen.

Ich hoffe ich konnte zeigen, dass die neuen Features von Java 5 sind möglich, mit nicht-generischem Code zu verwenden, aber es ist einfach nicht so sauber und geradlinig wie das Schreiben von Code mit Generika. Und meiner Meinung nach, zu, um alle Vorteile der neuen Funktionen in Java 5, sollte man in Generika zu suchen, wenn zumindest, für die Kontrolle der Kompilierung Zeit erlaubt ungültige Typumwandlungen zu verhindern Ausnahmen zur Laufzeit werfen.

Wenn Sie die Java-Bug-Datenbank suchen sind vor nur 1.5 veröffentlicht wurde, werden Sie siebenmal mehr Fehler finden mit NullPointerException als ClassCastException. Also es scheint nicht, dass es ein großartiges Feature ist, um Fehler zu finden oder zumindest Fehler, die nach ein kleinen Rauchtests bestehen.

Für mich ist der große Vorteil von Generika ist, dass sie dokumentieren im Code wichtige Typinformationen. Wenn ich nicht diese Art Informationen wollte in Code dokumentiert, dann würde ich eine dynamisch typisierte Sprache verwenden, oder zumindest eine Sprache mit mehr impliziten Typinferenz.

Geben Sie eine auf sich selbst Objekt Keeping Sammlungen ist kein schlechter Stil (aber dann der gemeinsame Stil ist effektiv Verkapselung zu ignorieren). Es hängt vielmehr auf das, was Sie tun. Passing Sammlungen „Algorithmen“ ist etwas leichter zu überprüfen (bei oder vor der Kompilierung-Zeit) mit Generika.

Generics in Java erleichtern parametrischer Polymorphismus . Mittels Typparametern können Sie Argumente Arten passieren. So wie ein Verfahren wie String foo(String s) Modelle einige Verhalten, nicht nur für eine bestimmte Zeichenfolge, sondern für jede Saite s, so ein Typ wie List<T> Modelle einige Verhalten, nicht nur für einen bestimmten Typ, aber für jede Art . List<T> sagt, dass für jede Art T, gibt es eine Art von List, deren Elemente Ts . So ist List ein eigentlich ein Typkonstruktor . Es dauert eine Art als Argument und baut einen anderen Typ als Ergebnis.

Hier sind ein paar Beispiele für generische Typen ich jeden Tag benutzen. Zunächst wird eine sehr nützliche generische Schnittstelle:

public interface F<A, B> {
  public B f(A a);
}

Diese Schnittstelle sagt, dass für einige zwei Typen, A und B, gibt es eine Funktion (genannt f), der einen A nimmt und gibt ein B. Wenn Sie diese Schnittstelle, A implementieren und B sein kann alle Typen, die Sie wollen, solange Sie eine Funktion f bereitzustellen, die die früheren und gibt das letzteres nimmt. Hier ist ein Beispiel Implementierung der Schnittstelle:

F<Integer, String> intToString = new F<Integer, String>() {
  public String f(int i) {
    return String.valueOf(i);
  }
}

Vor Generika wurde Polymorphismus von erreicht Subklassifizieren das extends Schlüsselwort. Mit Generika können wir tun, weg tatsächlich mit Subclassing und parametrischen Polymorphismus stattdessen verwenden. Betrachten wir zum Beispiel eine parametrisierte (Generika) Klasse verwendet, um Hash-Codes für jede Art zu berechnen. Statt der überwiegenden Object.hashCode (), würden wir eine generische Klasse wie folgt verwendet werden:

public final class Hash<A> {
  private final F<A, Integer> hashFunction;

  public Hash(final F<A, Integer> f) {
    this.hashFunction = f;
  }

  public int hash(A a) {
    return hashFunction.f(a);
  }
}

Das ist viel flexibler als Vererbung, weil wir mit dem Thema der Verwendung von Zusammensetzung und parametrischen Polymorphismus ohne Sperren spröde Hierarchien bleiben können.

Java Generika sind aber nicht perfekt. Sie können abstrakt über Typen, aber Sie können nicht abstrakt über Typkonstruktoren, zum Beispiel. Das heißt, können Sie „für jede Art T“ sagen, aber man kann nicht „für jede Art T, die einen Parameter vom Typ A nimmt“ sagen.

Generics vermeiden, dass die Leistungseinbußen von Boxen und Unboxing. Grundsätzlich sieht Arraylist vs List . Beide tun die gleichen Kern Dinge, aber List wird viel schneller sein, weil Sie müssen zum / vom Objekt nicht boxen.

Ich mag sie, nur weil sie Ihnen einen schnellen Weg gibt einen benutzerdefinierten Typen zu definieren (wie ich sie sowieso).

So zum Beispiel, anstatt eine Struktur zu definieren, die aus einem String und einer ganzen Zahl, und dann eine ganze Reihe von Objekten und Methoden implementieren zu müssen, wie ein Array dieser Strukturen zuzugreifen und so weiter, können Sie einfach ein Wörterbuch machen

Dictionary<int, string> dictionary = new Dictionary<int, string>();

Und die Compiler / IDE erledigt den Rest der schweren Heben. Ein Wörterbuch insbesondere können Sie den ersten Typ als Schlüssel verwenden (keine wiederholten Werte).

Der beste Nutzen für Generics ist die Wiederverwendung von Code. Lassen Sie uns sagen, dass Sie eine Menge von Business-Objekten haben, und Sie werden sehr ähnlichen Code für jede Einheit schreiben, um die gleichen Aktionen ausführen. (Das heißt Linq to SQL-Operationen).

Mit Generika, können Sie eine Klasse erstellen, die in der Lage sein wird zu einem der Typen zu arbeiten gegeben, die von einer bestimmten Basisklasse erben oder eine bestimmte Schnittstelle implementieren wie folgt:

public interface IEntity
{

}

public class Employee : IEntity
{
    public string FirstName { get; set; }
    public string LastName { get; set; }
    public int EmployeeID { get; set; }
}

public class Company : IEntity
{
    public string Name { get; set; }
    public string TaxID { get; set }
}

public class DataService<ENTITY, DATACONTEXT>
    where ENTITY : class, IEntity, new()
    where DATACONTEXT : DataContext, new()
{

    public void Create(List<ENTITY> entities)
    {
        using (DATACONTEXT db = new DATACONTEXT())
        {
            Table<ENTITY> table = db.GetTable<ENTITY>();

            foreach (ENTITY entity in entities)
                table.InsertOnSubmit (entity);

            db.SubmitChanges();
        }
    }
}

public class MyTest
{
    public void DoSomething()
    {
        var dataService = new DataService<Employee, MyDataContext>();
        dataService.Create(new Employee { FirstName = "Bob", LastName = "Smith", EmployeeID = 5 });
        var otherDataService = new DataService<Company, MyDataContext>();
            otherDataService.Create(new Company { Name = "ACME", TaxID = "123-111-2233" });

    }
}

Beachten Sie die Wiederverwendung des gleichen Service, die verschiedenen Typen in der DoSomething oben angegebenen Methode. Wirklich elegant!

Es gibt viele andere gute Gründe, Generika zu verwenden für Ihre Arbeit, das ist mein Favorit.

  • typisierte Sammlungen - auch wenn man sie nicht verwenden möchten, sind Sie wahrscheinlich mit ihnen aus anderen Bibliotheken, andere Quellen zu tun haben.

  • Allg Typisierung in Klassenerstellung:

    public class Foo { public T get () ...

  • Vermeidung von Casting - ich habe nicht mochte immer Dinge wie

    neue Vergleicher {    public int compareTo (Object o) {      if (o Instanceof classIcareAbout) ...

Wenn Sie im Wesentlichen für eine Bedingung überprüft, die nur existieren sollten, da die Schnittstelle in Bezug auf Objekte ausgedrückt wird.

Meine erste Reaktion auf Generika war ähnlich wie bei Ihnen - „zu unübersichtlich, zu kompliziert“. Meine Erfahrung ist, dass sie für ein bisschen nach der Verwendung Sie sie gewöhnt haben, und Code, ohne sie fühlt sich weniger klar definiert, und nur weniger komfortabel. Abgesehen davon, verwendet der Rest der Java-Welt, um sie, so dass Sie schließlich mit dem Programm bekommen haben werden, nicht wahr?

ein gutes Beispiel zu geben. Stellen Sie sich vor Sie haben eine Klasse namens Foo

public class Foo
{
   public string Bar() { return "Bar"; }
}

Beispiel 1 Jetzt wollen Sie eine Sammlung von Foo Objekte haben. Sie haben zwei Möglichkeiten, Listen- oder Arraylist, die beide in ähnlicher Weise arbeiten.

Arraylist al = new ArrayList();
List<Foo> fl = new List<Foo>();

//code to add Foos
al.Add(new Foo());
f1.Add(new Foo());

In dem obigen Code, wenn ich versuche, eine Klasse von Firetruck statt Foo hinzuzufügen, die Arraylist wird es fügen, aber die generische Liste von Foo verursacht eine Ausnahme ausgelöst werden.

Beispiel zwei.

Jetzt haben Sie Ihre zwei Array-Listen und Sie möchten auf jede der Bar () Funktion aufzurufen. Da hte Arraylist mit Objekten gefüllt ist, müssen Sie sie werfen, bevor Sie Leiste aufrufen können. Aber da die generische Liste von Foo kann nur Foos enthalten, können Sie rufen Bar () direkt auf diese.

foreach(object o in al)
{
    Foo f = (Foo)o;
    f.Bar();
}

foreach(Foo f in fl)
{
   f.Bar();
}

Haben Sie noch nie ein Verfahren (oder eine Klasse) geschrieben, in dem das Schlüsselkonzept der Methode / Klasse war fest nicht auf einen bestimmten Datentyp des Parameter / Instanzvariablen gebunden (man denkt verknüpfte Liste, max / min Funktionen , binäre Suche usw.).

Haben Sie noch nie wünschte, Sie könnten die algorthm / Code wiederverwenden, ohne auf Cut-n-Paste Wiederverwendung oder zu beeinträchtigen starke Typisierung (zB möchte ich eine List von Strings, kein List der Dinge I Hoffnung Strings!)?

Aus diesem Grund sollten Sie wollen verwenden Generika (oder etwas besser).

Vergessen Sie nicht, dass Generika sind nicht nur von Klassen verwendet werden, können sie auch durch Verfahren verwendet werden. Nehmen wir zum Beispiel den folgenden Ausschnitt:

private <T extends Throwable> T logAndReturn(T t) {
    logThrowable(t); // some logging method that takes a Throwable
    return t;
}

Es ist einfach, aber sehr elegant eingesetzt werden. Das Schöne daran ist, dass die Methode gibt, was auch immer es war, dass es gegeben wurde. Dies hilft, wenn Sie Ausnahmen sind die Handhabung erneut geworfen werden müssen, um zurück an den Anrufer:

    ...
} catch (MyException e) {
    throw logAndReturn(e);
}

Der Punkt ist, dass Sie den Typen nicht verlieren, indem es durch eine Methode übergeben. Sie können die richtige Art der Ausnahme statt nur einem Throwable werfen, die alle sein würden Sie ohne Generika tun könnte.

Dies ist nur ein einfaches Beispiel für eine Verwendung für generische Methoden. Es gibt durchaus ein paar andere nette Dinge, die Sie mit generischen Methoden zu tun. Die coolsten, meiner Meinung nach, ist mit Generika Folgern eingeben. Nehmen Sie das folgende Beispiel (aus Josh Blochs Effective Java 2nd Edition):

...
Map<String, Integer> myMap = createHashMap();
...
public <K, V> Map<K, V> createHashMap() {
    return new HashMap<K, V>();
}

Das ist nicht viel tun, aber es funktioniert auf einiger Unordnung abgeholzt, wenn die generischen Typen sind lang (oder verschachtelte, das heißt Map<String, List<String>>).

Der primäre Vorteil, als Mitchel weist darauf hin, ist stark Typisierung ohne mehrere Klassen definieren zu müssen.

Auf diese Weise können Sachen tun können, wie:

List<SomeCustomClass> blah = new List<SomeCustomClass>();
blah[0].SomeCustomFunction();

Ohne Generika, müßten Sie blah werfen [0] auf den richtigen Typ Funktionen zugreifen zu können.

die Jvm wirft trotzdem ... es schafft implizit Code, der den generischen Typ als „Objekt“ behandelt und schafft Abgüsse auf die gewünschte Instanziierung. Java-Generika sind nur syntaktischer Zucker.

Ich weiß, dass dies eine C # Frage, aber Generika auch in anderen Sprachen verwendet werden, und deren Verwendung / Ziele sind recht ähnlich.

Java Collections verwenden Generika seit Java 1.5. Also, ein guter Ort, um sie zu verwenden ist, wenn Sie Ihr eigenes Sammlung artige Objekt zu schaffen.

Ein Beispiel, das ich fast überall zu sehen ist eine Pair-Klasse, die zwei Objekte hält, muss aber mit diesen Objekten in allgemeiner Weise behandeln.

class Pair<F, S> {
    public final F first;
    public final S second;

    public Pair(F f, S s)
    { 
        first = f;
        second = s;   
    }
}  

Wenn Sie diese Pair-Klasse verwenden, können Sie festlegen, welche Art von Objekten Sie es mit und alle Typumwandlung Probleme bei der Kompilierung zeigt beschäftigen wollen, anstatt der Laufzeit.

Generics können auch mit den Schlüsselwörtern ‚super‘ ihre Grenzen definiert haben und ‚‘ erstreckt. Zum Beispiel, wenn Sie mit einer generischen Art beschäftigen wollen, aber Sie wollen sicherstellen, dass es eine Klasse erweitert namens Foo (die eine setTitle Methode hat):

public class FooManager <F extends Foo>{
    public void setTitle(F foo, String title) {
        foo.setTitle(title);
    }
}

Obwohl es nicht sehr interessant, auf seinem eigenen, ist es nützlich zu wissen, dass, wenn Sie mit einem FooManager beschäftigen, wissen Sie, dass es MyClass Typen behandelt, und das MyClass erstreckt Foo.

Von der Sun Java-Dokumentation, als Reaktion auf "warum ich Generika verwenden sollte?":

"Generics bietet eine Möglichkeit für Sie den Typ einer Sammlung an den Compiler zu kommunizieren, so dass geprüft werden kann. Wenn der Compiler den Elementtyp der Sammlung kennt, kann der Compiler überprüfen, dass Sie die Kollektion verwendet haben, konsequent und kann die richtigen Abgüsse auf Werten einfügen aus der Sammlung genommen werden ... der Code der Verwendung von Generika ist klarer und sicherer .... die Compiler bei der Kompilierung überprüfen kann, dass die Art Einschränkungen werden zur Laufzeit nicht verletzt [Hervorhebung von mir]. Da das Programm ohne Warnungen kompiliert, können wir mit Sicherheit sagen, dass es nicht einen Classcast zur Laufzeit. der Nettoeffekt der Verwendung von Generika, vor allem in großen Programmen werfen, ist verbesserte Lesbarkeit und Robustheit . [Hervorhebung von mir] "

Generics können Sie Objekte erstellen, die stark typisiert sind, aber Sie haben nicht die spezifische Art zu definieren. Ich denke, das beste nützliche Beispiel die Liste und ähnliche Klassen ist.

, um die generische Liste können Sie eine List List List haben, was Sie wollen, und Sie können immer die starke Typisierung verweisen, Sie müssen nicht konvertieren oder so etwas würden Sie mit einem Array oder Standard-Liste.

Generics können Sie starke Typisierung für Objekte und Datenstrukturen verwenden, die in der Lage sein sollten, jedes Objekt zu halten. Es entfällt auch langwierig und teuer Umwandlungen, wenn Objekte von generischen Strukturen (Boxen / Unboxing) abgerufen werden.

Ein Beispiel, das verwendet sowohl eine verknüpfte Liste. Was würde sein, eine verkettete Liste Klasse, wenn sie nur Objekt Foo verwenden könnte? Um eine verknüpfte Liste zu implementieren, die jede Art von Objekt verarbeiten kann, die verknüpften Liste und die Knoten in einem hypothetischen Knoten innere Klasse generisch sein muß, wenn Sie die Liste wollen nur eine Art von Objekt enthalten.

Wenn Sie Ihre Sammlung Werttypen enthält, die sie benötigen, um auf Objekte nicht boxen / unbox wenn sie in die Sammlung eingefügt, so dramatisch Ihre Leistung erhöht. Coole Add-ons wie ReSharper können mehr Code generieren für Sie, wie foreach-Schleifen.

Ein weiterer Vorteil der Verwendung von Generika (insbesondere mit Sammlungen / Listen) ist Sie Compile Time Type Checking erhalten. Das ist wirklich nützlich, wenn eine generische Liste statt eine Liste von Objekten verwendet wird.

Single meisten Grund ist, bieten sie Typ Sicherheit

List<Customer> custCollection = new List<Customer>;

im Gegensatz zu,

object[] custCollection = new object[] { cust1, cust2 };

als ein einfaches Beispiel.

Insgesamt Generika können Sie mehr precisily angeben, was Sie zu tun beabsichtigen (stärkere Typisierung).

Das hat mehrere Vorteile:

  • Da die Compiler mehr über wissen, was Sie tun wollen, ermöglicht es Ihnen eine Menge Typ-Casting zu verzichten, da er bereits weiß, dass der Typ kompatibel sein wird.

  • Diese bekommt man auch früher Feedback über die Korrektheit des Programms. Dinge, die zur Laufzeit zuvor fehlgeschlagen (zB weil ein Objekt nicht in der gewünschten Art gegossen werden könnte) hätten, nicht jetzt zur Compile-Zeit, und Sie können den Fehler vor Ihrer Testabteilung Dateien einen kryptischen Fehlerbericht beheben.

  • Der Compiler kann Optimierungen mehr tun, wie Boxen zu vermeiden, etc.

Ein paar Dinge hinzufügen / erweitert auf (aus der .NET-Sicht gesprochen):

Allg Typen können Sie rollenbasierte Klassen und Schnittstellen erstellen. Dies ist gesagt worden, bereits in mehr Grundbegriffe, aber ich finde, Sie beginnen Ihren Code mit Klassen zu entwerfen, die in einer Art unabhängige Art und Weise umgesetzt werden -., Die in hohem Grade wieder verwendbaren Code ergibt

Allgemeine Argumente zu den Methoden kann das gleiche tun, sondern sie helfen auch, das Prinzip Casting „nicht sagen nicht fragen“ anwenden, das heißt: „Gib mir, was ich will, und wenn Sie nicht, Sie mir sagen, warum“ .

Ich benutze sie zum Beispiel in einem GenericDao umgesetzt mit SpringORM und Hibernate, die wie folgt aussehen

public abstract class GenericDaoHibernateImpl<T> 
    extends HibernateDaoSupport {

    private Class<T> type;

    public GenericDaoHibernateImpl(Class<T> clazz) {
        type = clazz;
    }

    public void update(T object) {
        getHibernateTemplate().update(object);
    }

    @SuppressWarnings("unchecked")
    public Integer count() {
    return ((Integer) getHibernateTemplate().execute(
        new HibernateCallback() {
            public Object doInHibernate(Session session) {
                    // Code in Hibernate for getting the count
                }
        }));
    }
  .
  .
  .
}

Mit dem Generika meine Implementierungen dieser mit DAOS die Entwickler zwingen, sie passieren nur die Entitäten sie ausgelegt sind, nur durch die GenericDao Subklassen

public class UserDaoHibernateImpl extends GenericDaoHibernateImpl<User> {
    public UserDaoHibernateImpl() {
        super(User.class);     // This is for giving Hibernate a .class
                               // work with, as generics disappear at runtime
    }

    // Entity specific methods here
}

Mein kleiner Rahmen ist robuster (haben Dinge wie Filterung, faul-Laden, Suchen). Ich habe hier vereinfacht, um Ihnen ein Beispiel

ich, wie Steve und Sie sagte am Anfang „Zu chaotisch und kompliziert“ aber jetzt sehe ich seine Vorteile

Offensichtliche Vorteile wie „Typ Sicherheit“ und „keine Casting“ sind bereits erwähnt, so kann ich vielleicht über einige andere „Vorteile“ sprechen, die ich hoffe, es hilft.

Zunächst einmal Generika ist ein sprachunabhängiges Konzept und IMO, könnte es mehr Sinn machen, wenn Sie regelmäßig darüber nachdenken (Runtime) Polymorphismus zugleich.

Zum Beispiel kann der Polymorphismus, wie wir von objektorientierten Design wissen hat eine Laufzeit Begriff in dem der Anrufer Objekt wird zur Laufzeit herausgefunden, wie die Programmausführung geht und das entsprechende Verfahren entsprechend in Abhängigkeit von dem Laufzeittyp aufgerufen wird. In Generika, ist die Idee, etwas ähnlich, aber alles geschieht bei der Kompilierung. Was bedeutet das und wie Sie davon Gebrauch machen?

(Lassen Sie sich mit generischen Methoden kleben bleiben kompakt) Es bedeutet, dass Sie immer noch die gleiche Methode auf separate Klassen haben können (wie Sie in polymorphen Klassen taten vorher), aber dieses Mal, wenn sie vom Compiler automatisch generiert sind, hängt von die Typen bei der Kompilierung festgelegt. Sie parametrisieren Ihre Methoden auf dem Typ, den Sie bei der Kompilierung geben. Anstatt also die Methoden von Grund auf neu zu schreiben für jeden einzelnen Typ Sie haben, wie Sie im Runtime-Polymorphismus (Methode überwiegendes) tun, können Sie Compiler die Arbeit während der Kompilierung zu tun. Dies hat einen offensichtlichen Vorteil, da Sie nicht alle möglichen Arten schließen müssen, die in dem System verwendet werden können, die es weit besser skalierbar ohne Codeänderung macht.

Klassen arbeiten, um die ziemlich gleiche Weise. Sie parametrieren die Art und der Code wird vom Compiler erzeugt wird.

Wenn Sie die Idee der „Kompilierung“ erhalten, können Sie verwenden „beschränkte“ Typen machen und beschränken, was als parametrisierte Typ durch Klassen übergeben werden können / Methoden. So können Sie steuern, was übergeben werden, durch die eine mächtige Sache ist vor allem haben Sie einen Rahmen von anderen Menschen verbraucht wird.

public interface Foo<T extends MyObject> extends Hoo<T>{
    ...
}

Keiner jetzt jemanden andere als MyObject einstellen können.

Sie können aber auch „erzwingen“ Typ Einschränkungen für Ihre Methodenargumente, was bedeutet, können Sie Ihre beiden Methodenargumente würde davon abhängen, vom gleichen Typ sicherstellen.

public <T extends MyObject> foo(T t1, T t2){
    ...
}   

Hope all dies macht Sinn.

Ich habe einmal einen Vortrag zu diesem Thema. Sie können meine Dias, Code und Audioaufzeichnung bei http://www.adventuresinsoftware.com/generics/ .

Mit Generika für Sammlungen ist nur einfach und sauber. Selbst wenn Sie auf es überall sonst Punt, der Gewinn aus den Sammlungen ist ein Gewinn für mich.

List<Stuff> stuffList = getStuff();
for(Stuff stuff : stuffList) {
    stuff.do();
}

vs

List stuffList = getStuff();
Iterator i = stuffList.iterator();
while(i.hasNext()) {
    Stuff stuff = (Stuff)i.next();
    stuff.do();
}

oder

List stuffList = getStuff();
for(int i = 0; i < stuffList.size(); i++) {
    Stuff stuff = (Stuff)stuffList.get(i);
    stuff.do();
}

Das allein lohnt sich die marginale „Kosten“ von Generika, und Sie haben keine Gattungs Guru sein, dies zu nutzen und Wert erhalten.

Generics gibt Ihnen auch die Möglichkeit, mehr wiederverwendbare Objekte / Methoden zu erstellen, während immer noch typspezifische Unterstützung. Sie erhalten auch eine Menge Leistung in einigen Fällen. Ich weiß nicht, die vollständige Spezifikation auf der Java Generics, aber in .NET kann ich Einschränkungen für die Typ-Parameter angeben, wie implementiert eine Schnittstelle, Constructor und Ableitung.

scroll top