2015-01-13 3 views
3

Итак, я вникаю в Java и интересуюсь этим использованием параметра.<T> T getInstance (конечный класс <T> тип) почему не класс <T> для обоих?

<T>T getInstance 

, а затем агд

Class<T> type 

Я немного запутался здесь, потому что, если нам требуется тип возврата, таким образом, обозначим через T, то почему не аргумент такой же ... например

private static String getInstance(String arg) 

Так что я полагаю, что это было бы

private static Class<T> getInstance(final Class<T> type) 

так что я смущен, почему разница в выражении типа возврата против аргумента

+0

'T' называется параметром типа, а не подстановочным знаком. Подстановочный знак - '?'. – manouti

+0

oops. Благодарю. я исправлю это. –

+1

'String' - это тип. «Класс» - это тип. «Класс» не является заполнителем для другого типа. –

ответ

7

Нет необходимости иметь тип возвращаемого значения так же, как тип параметра, и никоим образом не означает, что это правило.

Когда метод определен как

private static <T> T getInstance(final Class<T> type) 

это означает, что возвращение объект будет иметь тип T, в то время как аргумент, передаваемый методу является экземпляром общего типа java.lang.Class параметризованного к T.

Это означает, что метод может быть вызван следующим образом:

String string = getInstance(String.class); 

Следовательно, этот метод принимает экземпляр типа Class и возвращает объект типа, соответствующее этому Class аргумента.

С другой стороны, когда метод определяется как

private static <T> T getInstance(final T type) 

тогда вы вынуждены передать объект типа T для того, чтобы получить экземпляр. Представьте себе, что будет называться следующим образом:

String string = getInstance("a"); 

Обратите внимание, как объект «а» типа String совершенно иная, чем String.class типа Class.

3

Подумайте, что делает этот метод: он возвращает instance от Class.

Использование:

final String string = getInstance(String.class); 

Так что возвращение - ну это String. И какой аргумент - это class String, который представлен Class<String>.

Так метод подписи становится:

String getInstance(Class<String> string); 

Параметрирование вне String как T дает подпись в вашем вопросе.

4

T и Class<T> совершенно разные.

Первый говорит: «объект определенного типа, Т.» Второй говорит: «Объект типа java.lang.Class, который представляет класс для некоторого типа T».

Другими словами, здесь два возможных реализаций:

Class<T> getInstance(Class<T> type) { 
    return type; 
} 

T getInstance(Class<T> type) { 
    return type.newInstance(); 
} 

Например, если T является String, то первый из них вернется String.class, а второй возвращает пустую строку, "".

2

Это трюк, который была реализована Java для борьбы с проблемой курица и яйцо, когда вы должны создать объект внутри универсального метода с типом.

Class<T> сделана общей, чтобы вы могли позвонить по телефону getInstance безопасным образом. Без <T> в Class всех ваших T с бы стираются, оставляя вас с

Object getInstance() {...} 

и никоим образом получить ссылку класса T, который был стерт.

Передача Class<T> решает эту проблему, потому что теперь стертый подпись выглядит следующим образом:

Object getInstance(Class cl) {...} 

Хотя тип стерт снова, теперь у вас есть Class объект, который может быть использован в качестве «фабрики» в создавать новые объекты класса T. Тот факт, что Class<T> является общим по типу, который он создает, позволяет компилятору Java выполнять проверку типов, гарантируя, что приведение, введенное неявно компилятором, будет успешным во время выполнения.

+0

hmm. Это довольно запутанно. Оффлайн, у вас есть какие-то ссылки, которые немного вникают в это? Я «получаю» то, что вы говорите, но детали/нюансы ускользают от меня. –

+1

@jamesemanon Вот статья о дженериках, объясняющих использование объектов класса как токенов типа времени выполнения (http://docs.oracle.com/javase/tutorial/extra/generics/literals.html). – dasblinkenlight

2

Следует отметить класс от его экземпляра. Это может быть сложно, потому что в Java классы также являются объектами, и поэтому они также имеют класс (класс класса!). Скажи:

class Foo { ... } 
  • Экземпляр Foo имеет тип Foo;
  • Сам класс Foo является экземпляром (только) другого класса, точно Class<Foo>.

Таким образом, в приведенной выше декларации, слева направо:

  • <T> является общим параметром, что делает метод, универсальный метод;
  • T - тип возврата: метод возвращает экземпляр класса T;
  • getInstance - название метода;
  • Class<T> означает, что вы должны передать в качестве параметра экземпляр (только) класса T, который сам имеет класс Class<Foo>.

Вы можете получить доступ к экземпляру singleton с помощью неявного статического поля Foo.class. У каждого объявленного класса есть это, хотя вы не найдете его в исходном коде (сложные проблемы с отражением).

И наконец, почему Class является общим? Ну, что-то вроде этого:

package java.lang; 

public final class Class<T> { 
    public static T newInstance(); 
    ... 
} 

так Foo.class.newInstance() возвращает Foo, Baz.class.newInstance() возвращает Baz, и так далее. Аккуратно, не так ли?

Смежные вопросы