Java-Generika T vs Object

127

Ich habe mich gefragt, was der Unterschied zwischen den folgenden beiden Methodendeklarationen ist:

public Object doSomething(Object obj) {....}

public <T> T doSomething(T t) {....}

Gibt es etwas, das du mit dem einen machen kannst / würdest, aber nicht mit dem anderen? Ich konnte diese Frage an keiner anderen Stelle auf dieser Website finden.

Abidi
quelle

Antworten:

112

Vom Kontext isoliert - kein Unterschied. Auf beiden tund objSie können nur die Methoden von aufrufen Object.

Aber mit Kontext - wenn Sie eine generische Klasse haben:

MyClass<Foo> my = new MyClass<Foo>();
Foo foo = new Foo();

Dann:

Foo newFoo = my.doSomething(foo);

Gleicher Code mit Objekt

Foo newFoo = (Foo) my.doSomething(foo);

Zwei Vorteile:

  • kein Casting erforderlich (der Compiler verbirgt dies vor Ihnen)
  • Kompilierzeitsicherheit, die funktioniert. Wenn die ObjectVersion verwendet wird, sind Sie nicht sicher, ob die Methode immer zurückgegeben wird Foo. Wenn es zurückkehrt Bar, haben Sie ClassCastExceptionzur Laufzeit eine.
Bozho
quelle
14

Der Unterschied besteht darin, dass wir im ersten Schritt angeben, dass der Aufrufer eine Objektinstanz (eine beliebige Klasse) übergeben muss und ein anderes Objekt (eine beliebige Klasse, die nicht unbedingt vom gleichen Typ ist) zurückerhält.

Im zweiten Fall entspricht der zurückgegebene Typ dem Typ, der bei der Definition der Klasse angegeben wurde.

Example ex = new Example<Integer>();

Hier geben wir an, welcher Typ T sein wird, wodurch wir mehr Einschränkungen für eine Klasse oder Methode erzwingen können. Zum Beispiel können wir ein LinkedList<Integer>oder instanziieren LinkedList<Example>und wissen, dass wir beim Aufrufen einer dieser Methoden eine Integer- oder Example-Instanz zurückerhalten.

Das Hauptziel hierbei ist, dass der aufrufende Code angeben kann, welche Art von Objekten eine Klasse bearbeiten soll, anstatt sich auf Typumwandlung zu verlassen, um dies zu erzwingen.

Siehe Java Generics * von Oracle.

* Link aktualisiert.

Adam
quelle
13

Der Unterschied besteht darin, dass ich mit generischen Methoden keine Umwandlung vornehmen muss und einen Kompilierungsfehler erhalte, wenn ich etwas falsch mache:

public class App {

    public static void main(String[] args) {

        String s = process("vv");
        String b = process(new Object()); // Compilation error
    }

    public static <T> T process(T val) {

        return val;
    }
}

Wenn ich ein Objekt verwende, muss ich es immer umwandeln und bekomme keine Fehler, wenn ich etwas falsch mache:

public class App {

    public static void main(String[] args) {

        String s = (String)process("vv");
        String b = (String)process(new Object());
    }

    public static Object process(Object val) {

        return val;
    }
}
user1883212
quelle
Nur um zu erwähnen, dass Sie ab Android 6 auch keine Objekte mehr werfen müssen.
John Lord
2

Sie müssen kein zusätzliches Klassencasting durchführen. Im ersten Fall erhalten Sie immer ein Objekt der Klasse java.lang.Object, das Sie in Ihre Klasse umwandeln müssen. Im zweiten Fall wird T durch die in der generischen Signatur definierte Klasse ersetzt, und es ist kein Klassencasting erforderlich.

Andrey Adamovich
quelle
2

Zur Laufzeit nichts. Zur Kompilierungszeit führt die zweite jedoch eine Typprüfung durch, um sicherzustellen, dass der Typ des Parameters und der Typ des Rückgabewerts mit dem Typ T übereinstimmen (oder Untertypen sind), in den der Typ T aufgelöst wird (das erste Beispiel führt auch eine Typprüfung durch, aber jedes Objekt ist a Subtyp des Objekts, so dass jeder Typ akzeptiert wird).

Jonathan
quelle
2

T ist ein generischer Typ. Dies bedeutet, dass es zur Laufzeit durch ein beliebiges qualifizierendes Objekt ersetzt werden kann. Sie können eine solche Methode wie folgt aufrufen:

String response = doSomething("hello world");

ODER

MyObject response = doSomething(new MyObject());

ODER

Integer response = doSomething(31);

Wie Sie sehen können, gibt es hier Polymorphismus.

Wenn jedoch deklariert wird, dass Object zurückgegeben werden soll, können Sie dies nur tun, wenn Sie Cast-Dinge eingeben.

adarshr
quelle
Können wir sagen, dass <T>es kein Autoboxing gibt?
SMUsamaShah
0

Im ersten Fall wird ein Parameter eines beliebigen Typs egstring verwendet und ein Typ foo zurückgegeben. Im zweiten Fall wird ein Parameter vom Typ foo verwendet und ein Objekt vom Typ foo zurückgegeben.

fastcodejava
quelle