Java jenerikleri T ve Object


127

Aşağıdaki iki yöntem bildirimi arasındaki farkın ne olduğunu merak ediyordum:

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

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

Biriyle yapabileceğiniz / yapacağınız, ancak diğeriyle yapamayacağınız bir şey var mı? Bu soruyu bu sitenin başka bir yerinde bulamadım.

Yanıtlar:


112

Bağlamdan izole - fark yok. Her ikisinde de tve objyalnızca yöntemlerini çağırabilirsiniz Object.

Ancak bağlamla - genel bir sınıfınız varsa:

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

Sonra:

Foo newFoo = my.doSomething(foo);

Nesne ile aynı kod

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

İki avantaj:

  • yayınlamaya gerek yok (derleyici bunu sizden gizler)
  • işe yarayan zaman güvenliğini derleyin. Eğer Objectsürüm kullanılır, emin yöntem her zaman döndüren olmayacaktır Foo. Dönerse Bar, ClassCastExceptionçalışma zamanında bir olacaksınız .

14

Buradaki fark, ilkinde, çağıranın bir Object örneğini (herhangi bir sınıf) iletmesi gerektiğini ve başka bir Object (herhangi bir sınıf, aynı türden olması gerekmez) geri alacağını belirtmemizdir.

İkincisinde, döndürülen tür, sınıf tanımlandığında verilenle aynı tür olacaktır.

Example ex = new Example<Integer>();

Burada, bir sınıf veya yöntem üzerinde daha fazla kısıtlama uygulamamıza izin veren T türünün ne olacağını belirtiyoruz. Örneğin, a LinkedList<Integer>veya örneğini başlatabiliriz LinkedList<Example>ve bu yöntemlerden birini çağırdığımızda, bir Tamsayı veya Örnek örneğini geri alacağımızı biliyoruz.

Buradaki ana amaç, çağıran kodun, bunu zorlamak için tür çevrimine güvenmek yerine, bir sınıfın hangi tür nesneler üzerinde çalışacağını belirtebilmesidir.

Oracle'dan Java Generics * konusuna bakın .

* Güncellenmiş Bağlantı.


13

Aradaki fark, genel yöntemlerle döküm yapmam gerekmemesi ve yanlış yaptığımda bir derleme hatası almam:

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

Nesneyi kullanarak her zaman döküm yapmam gerekiyor ve yanlış yaptığımda herhangi bir hata almıyorum:

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

Android 6'dan itibaren artık nesne dökmek zorunda olmadığınızı belirtmek gibi.
John Lord

2

Ek sınıf ataması yapmanıza gerek yoktur. İlk durumda, her zaman sınıfınıza çevirmeniz gereken java.lang.Object sınıfının bir nesnesini alacaksınız. İkinci durumda T, genel imzada tanımlanan sınıfla değiştirilecek ve sınıf atamasına gerek kalmayacaktır.


2

Çalışma zamanında hiçbir şey. Ancak derleme zamanında ikincisi, T türü ne olursa olsun, parametrenin türünün ve dönüş değerinin türünün eşleştiğinden (veya alt türleri olduğundan) emin olmak için tür denetimi yapar (ilk örnek aynı zamanda tür denetimi yapar, ancak her nesne bir Nesne alt türü böylece her tür kabul edilecektir).


2

T, genel bir türdür. Yani çalışma zamanında herhangi bir niteleyici nesne ile değiştirilebilir. Böyle bir yöntemi aşağıdaki gibi çağırabilirsiniz:

String response = doSomething("hello world");

VEYA

MyObject response = doSomething(new MyObject());

VEYA

Integer response = doSomething(31);

Gördüğünüz gibi burada polimorfizm var.

Ancak, Object döndürdüğü bildirilirse, cast şeyler yazmadıkça bunu yapamazsınız.


<T>Otomatik kutulama olmadığını söyleyebilir miyiz?
SMUsamaShah

0

ilk durumda, herhangi türde bir egstring parametresini alır ve bir tür foo döndürür. İkinci durumda, foo türünde bir parametre alır ve foo türünde bir nesne döndürür.


Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.