Kar*_*arl 237 java generics templates class
有一个很好的讨论泛型和他们在这个问题的幕后真正做了什么,所以我们都知道这Vector<int[]>
是一个整数数组的向量,并且HashTable<String, Person>
是一个表,其键是字符串和值Person
s.然而,困扰我的是使用Class<>
.
java类Class
也应该采用模板名称,(或者我在eclipse中通过黄色下划线告诉我).我不明白我应该放在那里.Class
对象的整个要点是当您没有完全拥有关于对象,反射等的信息时.为什么它让我指定Class
对象将保持哪个类?我显然不知道,或者我不会使用该Class
对象,我会使用具体的一个.
Kan*_*mar 170
我们所知道的是" 任何类的所有实例都共享该类类型的java.lang.Class对象 "
例如)
Student a = new Student();
Student b = new Student();
Run Code Online (Sandbox Code Playgroud)
那a.getClass() == b.getClass()
是真的.
现在假设
Teacher t = new Teacher();
Run Code Online (Sandbox Code Playgroud)
没有泛型,下面是可能的.
Class studentClassRef = t.getClass();
Run Code Online (Sandbox Code Playgroud)
但现在这是错的..?
例如)public void printStudentClassInfo(Class studentClassRef) {}
可以调用Teacher.class
使用泛型可以避免这种情况.
Class<Student> studentClassRef = t.getClass(); //Compilation error.
Run Code Online (Sandbox Code Playgroud)
现在什么是T ?? T是类型参数(也称为类型变量); 由尖括号(<>)分隔,跟在类名后面.
T只是一个符号,就像在编写类文件时声明的变量名(可以是任何名称).稍后
在初始化期间T将被有效的类名替换(HashMap<String> map = new HashMap<String>();
)
例如) class name<T1, T2, ..., Tn>
所以Class<T>
代表一个特定类类型' T
' 的类对象.
假设您的类方法必须使用下面的未知类型参数
/**
* 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; }
}
Run Code Online (Sandbox Code Playgroud)
这里T可以String
用作CarName类型
OR T可以用作modelNumberInteger
类型,
OR T可以用作有效汽车实例的Object
类型.
现在,上面是简单的POJO,它可以在运行时以不同的方式使用.
集合例如List,Set,Hashmap是根据T的声明使用不同对象的最佳示例,但是一旦我们将T声明为String,
例如)HashMap<String> map = new HashMap<String>();
然后它将只接受String Class实例对象.
通用方法
通用方法是引入其自己的类型参数的方法.这类似于声明泛型类型,但类型参数的范围仅限于声明它的方法.允许使用静态和非静态泛型方法,以及泛型类构造函数.
泛型方法的语法包括一个类型参数,在尖括号内,并出现在方法的返回类型之前.对于泛型方法,类型参数部分必须出现在方法的返回类型之前.
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;
}
Run Code Online (Sandbox Code Playgroud)
下面<K, V, Z, Y>
是方法参数中使用的类型声明,它应该在返回类型之前boolean
.
在下面; <T>
方法级别不需要类型声明,因为它已在类级别声明.
class MyClass<T> {
private T myMethod(T a){
return a;
}
}
Run Code Online (Sandbox Code Playgroud)
但是下面的错误是因为类级别的参数K,V,Z和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());
}
}
Run Code Online (Sandbox Code Playgroud)
其他有效的情景是
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;
}
}
Run Code Online (Sandbox Code Playgroud)
最后静态方法总是需要显式<T>
声明; 它不会来自班级Class<T>
.这是因为类级别T与实例绑定.
另请阅读泛型限制
Yuv*_*val 128
使用类的类的通用版本允许您(除其他外)编写类似的东西
Class<? extends Collection> someCollectionClass = someMethod();
Run Code Online (Sandbox Code Playgroud)
然后你可以确定你收到的Class对象扩展了Collection
,这个类的一个实例将是(至少)一个Collection.
rau*_*ach 32
从Java文档:
[...]更令人惊讶的是,班级已经普及.类文本现在用作类型标记,提供运行时和编译时类型信息.这样可以在新的AnnotatedElement接口中使用getAnnotation方法示例的静态工厂样式:
<T extends Annotation> T getAnnotation(Class<T> annotationType);
Run Code Online (Sandbox Code Playgroud)
这是一种通用方法.它从参数中推断出其类型参数T的值,并返回一个适当的T实例,如下面的代码片段所示:
Author a = Othello.class.getAnnotation(Author.class);
Run Code Online (Sandbox Code Playgroud)
在泛型之前,您必须将结果转换为Author.此外,您无法让编译器检查实际参数是否表示Annotation的子类.[...]
好吧,我从来没有使用过这种东西.任何人?
我class<T>
在创建服务注册表查找时发现有用.例如
<T> T getService(Class<T> serviceClass)
{
...
}
Run Code Online (Sandbox Code Playgroud)
根据 @Kire 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();
}
Run Code Online (Sandbox Code Playgroud)
这允许unmarshal
返回任意 JAXB 内容树类型的文档。
在java中的<T>
意思是泛型类。泛型类是可以处理任何类型的数据类型的类,换句话说,我们可以说它是独立于数据类型的。
public class Shape<T> {
// T stands for "Type"
private T t;
public void set(T t) { this.t = t; }
public T get() { return t; }
}
Run Code Online (Sandbox Code Playgroud)
其中T表示类型。现在,当您创建此 Shape 类的实例时,您需要告诉编译器它将处理什么数据类型。
例子:
Shape<Integer> s1 = new Shape();
Shape<String> s2 = new Shape();
Run Code Online (Sandbox Code Playgroud)
Integer是一种类型,String也是一种类型。
<T>
特指泛型类型。根据 Java 文档 - 泛型类型是通过类型参数化的泛型类或接口。
正如其他答案所指出的那样,为什么这class
是通用的有很多很好的理由.但是,很多时候您无法知道要使用的泛型类型Class<T>
.在这些情况下,您可以简单地忽略黄色日食警告,或者您可以使用Class<?>
......这就是我的方式;)