На this question есть хорошее обсуждение Generics и того, что они делают за кулисами, так что мы все знаем, что Vector<int[]>
- это вектор целочисленных массивов, а HashTable<String, Person>
- это таблица, ключами которой являются строки, а значениями Person
.
Однако, что ставит меня в тупик, так это использование Class<>
.
Предполагается, что java класс Class
также принимает имя шаблона, (или так мне говорит желтое подчеркивание в eclipse). Я не понимаю, что я должен туда вставить. Весь смысл объекта Class
в том, что когда у вас нет полной информации об объекте, для отражения и тому подобного. Почему я должен указывать, какой класс будет содержать объект Class
? Я явно не знаю, иначе я бы не использовал объект Class
, я бы использовал конкретный объект.
Все мы знаем, что есть "все экземпляры любой акции класса один и тот же объект java.lang.Class это типа класси"
е.г)
Student a = new Student();
Student b = new Student();
Затем А.getClass() == б.getClass () - это правда.
Теперь предположим,
Teacher t = new Teacher();
без генериков ниже, можно.
Class studentClassRef = t.getClass();
Но это не так сейчас ..?
е.общественные г) пустота printStudentClassInfo(studentClassRef класс) {}можно назвать
Teacher.class`
Этого можно избежать с помощью дженериков.
Class<Student> studentClassRef = t.getClass(); //Compilation error.
Сейчас какой Т ?? T-это параметры типа (также называемые переменные типа); разделенных угловых скобках (<>), следует имя класса.
<БР> Т-это просто символ, как и имя переменной (может быть любое имя) заявил во время записи файла класса. Позже, что T будет заменен на <БР>допустимое имя класса во время инициализации (хранилище HashMap и Л;строка> По карте = новый HashMap и Л;строка> В();
)
е.г) имя класса<Т1, Т2, ..., ТN>
Так Класс и л;т> представляет собой объект класса, определенного типа и класса ' Т'.
Предположим, что ваши методы класса для работы с неизвестными параметрами типа как ниже
/**
* Generic version of the Car class.
* @param <T> the type of the value
*/
public class Car<T> {
// T stands for "Type"
private T t;
public void set(T t) { this.t = t; }
public T get() { return t; }
}
Здесь t может быть использован как строка
тип CarName
Или T может быть использован как целое
типа как modelNumber,
Или T может быть использован в качестве объекта
вида а допустимый экземпляр автомобиля.
Теперь вот выше-это простой POJO-объект, который может быть использован по-разному во время выполнения. <БР>коллекции электронных.г) список, набор, хранилище HashMap лучшие примеры, которые будут работать с различными объектами в соответствии с декларацией т, но как только мы объявили Т как строку <БР>электронная.г) `хранилище HashMap и Л;строка> По карте = новый HashMap и Л;строка> В (); - тогда он будет принимать только строковые объекты экземпляра класса.
Универсальные Методы
Универсальные методы-это методы, которые вводят собственные параметры типа. Это похоже на объявление универсальный тип, но тип параметра'сферы деятельности ограничивается способ, в котором она объявлена. Статические и нестатические универсальных методов не допускается, а также универсальные конструкторы класса.
Синтаксис универсального метода включает в себя параметр типа, внутри угловых скобок, и предстает перед способ'возвращение тип. Для универсальных методов, разделе параметр типа должен предстать перед способ'возвращение тип.
class Util {
// Generic static method
public static <K, V, Z, Y> boolean compare(Pair<K, V> p1, Pair<Z, Y> p2) {
return p1.getKey().equals(p2.getKey()) &&
p1.getValue().equals(p2.getValue());
}
}
class Pair<K, V> {
private K key;
private V value;
}
Здесь в <К, В, З, М>
это объявление типов, используемых в аргументы метода, который стоит перед типом возвращаемого значения, который является логическое
здесь.
В указанных ниже; объявление типа в `<Т> не требуется на уровне метода, поскольку он уже объявлен на уровне класса.
class MyClass<T> {
private T myMethod(T a){
return a;
}
}
Но ниже-это неправильно, как на уровне класса параметры тип К, В, З, и Y не могут быть использованы в статическом контексте (статический метод).
class Util <K, V, Z, Y>{
// Generic static method
public static boolean compare(Pair<K, V> p1, Pair<Z, Y> p2) {
return p1.getKey().equals(p2.getKey()) &&
p1.getValue().equals(p2.getValue());
}
}
ДРУГИЕ ДОПУСТИМЫЕ СЦЕНАРИИ
class MyClass<T> {
//Type declaration <T> already done at class level
private T myMethod(T a){
return a;
}
//<T> is overriding the T declared at Class level;
//So There is no ClassCastException though a is not the type of T declared at MyClass<T>.
private <T> T myMethod1(Object a){
return (T) a;
}
//Runtime ClassCastException will be thrown if a is not the type T (MyClass<T>).
private T myMethod1(Object a){
return (T) a;
}
// No ClassCastException
// MyClass<String> obj= new MyClass<String>();
// obj.myMethod2(Integer.valueOf("1"));
// Since type T is redefined at this method level.
private <T> T myMethod2(T a){
return a;
}
// No ClassCastException for the below
// MyClass<String> o= new MyClass<String>();
// o.myMethod3(Integer.valueOf("1").getClass())
// Since <T> is undefined within this method;
// And MyClass<T> don't have impact here
private <T> T myMethod3(Class a){
return (T) a;
}
// ClassCastException for o.myMethod3(Integer.valueOf("1").getClass())
// Should be o.myMethod3(String.valueOf("1").getClass())
private T myMethod3(Class a){
return (T) a;
}
// Class<T> a :: a is Class object of type T
//<T> is overriding of class level type declaration;
private <T> Class<T> myMethod4(Class<T> a){
return a;
}
}
И, наконец, статический метод всегда должен явно в <Т> декларацию; его не вытекают из уровня класса класса в<Т>
. Это потому, что на уровне класса связан с экземпляром.
Читайте также ограничения на генерики
Использование обобщенной версии класса Class позволяет вам, помимо прочего, писать такие вещи, как
Class<? extends Collection> someCollectionClass = someMethod();
и тогда вы можете быть уверены, что полученный вами объект Class расширяет Collection
, и экземпляр этого класса будет (по крайней мере) коллекцией.
Из документации по Java:
[...] Более удивительно, что класс Class был генерирован. Литералы класса теперь функционируют как маркеры типов, предоставляя информацию о типе как во время выполнения, так и во время компиляции. Это позволяет использовать стиль статических фабрик, примером которого является метод getAnnotation в новом интерфейсе AnnotatedElement:
<T extends Annotation> T getAnnotation(Class<T> annotationType);
Это общий метод. Он определяет значение параметра типа T из своего аргумента и возвращает соответствующий экземпляр T, как показано в следующем фрагменте:
Author a = Othello.class.getAnnotation(Author.class);
До появления дженериков вам пришлось бы приводить результат к Author. Кроме того, у вас не было бы способа заставить компилятор проверить, что фактический параметр представляет собой подкласс Annotation. [...]
Ну, мне никогда не приходилось использовать такие вещи. Кто-нибудь?
Я нашел класс В<Т>` полезно при создании реестра сервисом поисков. Е. Г.
<T> T getService(Class<T> serviceClass)
{
...
}
Как и другие ответы указывают, есть много и хороших причин, почему этот "класс" был общим. Однако, есть много раз, что вы Don'Т есть какие-либо способ познания универсального типа для использования С класса в<Т>. В этих случаях, вы можете просто игнорировать желтые предупреждения Eclipse или вы можете использовать
класс И Л;?>, что's, как я делаю это ;)
Следующим на @Хирэ Haglin'ы ответ, еще один пример методов дженерики можно увидеть в документации для распаковки JAXB:
public <T> T unmarshal( Class<T> docClass, InputStream inputStream )
throws JAXBException {
String packageName = docClass.getPackage().getName();
JAXBContext jc = JAXBContext.newInstance( packageName );
Unmarshaller u = jc.createUnmarshaller();
JAXBElement<T> doc = (JAXBElement<T>)u.unmarshal( inputStream );
return doc.getValue();
}
Это позволяет распаковать
, чтобы вернуться в документ произвольного контента JAXB типа дерева.
В Java в `<Т> "означает" универсальный класс. Универсальный класс-это класс, который может работать на любой тип типа данных или другими словами, мы можем сказать, что это тип независимых данных.
public class Shape<T> {
// T stands for "Type"
private T t;
public void set(T t) { this.t = t; }
public T get() { return t; }
}
Где Т означает тип. Теперь, когда вы создаете экземпляр этого класса форму, вы должны сообщить компилятору, к какому типу данных это будет работать.
Пример:
Shape<Integer> s1 = new Shape();
Shape<String> s2 = new Shape();
Целое число тип и строки также тип.
в <Т>
специально стоит для универсального типа. По данным документов Java - универсальный тип универсального класса или интерфейса, параметризованная более типов.
Вы часто хотите использовать подстановочные знаки с Class
. Например, Class<? extends JComponent>
, позволит вам указать, что класс является некоторым подклассом JComponent
. Если вы получили экземпляр Class
из Class.forName
, то вы можете использовать Class.asSubclass
для приведения, прежде чем попытаться, скажем, создать экземпляр.
Просто бросить в другом примере непатентованное класса (класса в<Т>`) позволяет писать универсальные функции, как указано ниже.
public static <T extends Enum<T>>Optional<T> optionalFromString(
@NotNull Class<T> clazz,
String name
) {
return Optional<T> opt = Optional.ofNullable(name)
.map(String::trim)
.filter(StringUtils::isNotBlank)
.map(String::toUpperCase)
.flatMap(n -> {
try {
return Optional.of(Enum.valueOf(clazz, n));
} catch (Exception e) {
return Optional.empty();
}
});
}
Это сбивает с толку в начале. Но он помогает в ситуациях, приведенных ниже :
class SomeAction implements Action {
}
// Later in the code.
Class<Action> actionClass = Class.forName("SomeAction");
Action action = actionClass.newInstance();
// Notice you get an Action instance, there was no need to cast.
Просто использовать класс говядиной:
public <T> T beefmarshal( Class<beef> beefClass, InputBeef inputBeef )
throws JAXBException {
String packageName = docClass.getPackage().getBeef();
JAXBContext beef = JAXBContext.newInstance( packageName );
Unmarshaller u = beef.createBeef();
JAXBElement<T> doc = (JAXBElement<T>)u.beefmarshal( inputBeef );
return doc.getBeef();
}