Answers:
我们所知道的是“ 任何类的所有实例共享该类类型的相同java.lang.Class对象 ”
例如)
Student a = new Student();
Student b = new Student();
那a.getClass() == b.getClass()
是真的。
现在假设
Teacher t = new Teacher();
没有泛型,下面是可能的。
Class studentClassRef = t.getClass();
但这是错误的..?
例如)public void printStudentClassInfo(Class studentClassRef) {}
可以用Teacher.class
使用泛型可以避免这种情况。
Class<Student> studentClassRef = t.getClass(); //Compilation error.
现在什么是T ?? T是类型参数(也称为类型变量);类名后面用尖括号(<>)分隔。
T只是一个符号,就像在编写类文件时声明的变量名(可以是任何名称)一样。之后,
在初始化(HashMap<String> map = new HashMap<String>();
)时,T将被有效的类名替换
例如) 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; }
}
在这里T可以String
用作CarName的类型
OR T可以用作modelNumber的Integer
类型,
OR T可以用作有效的汽车实例的Object
类型。
现在,上面是简单的POJO,可以在运行时以不同的方式使用它。
集合,例如List,Set,Hashmap是最好的示例,它们将根据T的声明与不同的对象一起工作,但是一旦我们将T声明为String
例如)HashMap<String> map = new HashMap<String>();
,则它将仅接受String类实例对象。
通用方法
泛型方法是引入其自身类型参数的方法。这类似于声明泛型类型,但是类型参数的范围仅限于声明它的方法。允许使用静态和非静态通用方法,以及通用类构造函数。
通用方法的语法包括类型参数,尖括号内,并且出现在方法的返回类型之前。对于泛型方法,类型参数部分必须出现在方法的返回类型之前。
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;
}
这<K, V, Z, Y>
是方法参数中使用的类型声明,该声明应在boolean
此处的返回类型之前。
在下面;<T>
在方法级别不需要类型声明,因为它已经在类级别声明了。
class MyClass<T> {
private T myMethod(T a){
return a;
}
}
但是下面是错误的,因为类级别的类型参数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());
}
}
其他有效场景
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;
}
}
最后,静态方法始终需要显式<T>
声明;它不会从课堂上衍生出来Class<T>
。这是因为类级别T与实例绑定。
另请参阅泛型限制
从Java文档中:
[...]更令人惊讶的是,类Class已被泛化。现在,类文字可以用作类型标记,同时提供运行时和编译时类型信息。这将启用一种新的AnnotatedElement接口中的getAnnotation方法示例的静态工厂样式:
<T extends Annotation> T getAnnotation(Class<T> annotationType);
这是一种通用方法。它从其参数推断其类型参数T的值,并返回T的适当实例,如以下代码段所示:
Author a = Othello.class.getAnnotation(Author.class);
在使用泛型之前,您必须将结果强制转换为Author。另外,您将无法使编译器检查实际参数是否表示Annotation的子类。[...]
好吧,我从来没有用过这种东西。任何人?
Class<? extends X>
我认为的表示法,我可以将其限制为仅“服务”类型。除非没有通用的“服务”类型,所以我只能使用Class<?>
。唉。
继@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();
}
这允许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; }
}
其中T表示类型。现在,当您创建此Shape类的实例时,您将需要告诉编译器它将处理哪种数据类型。
例:
Shape<Integer> s1 = new Shape();
Shape<String> s2 = new Shape();
整数是一个类型,字符串也是一个类型。
<T>
专门代表泛型。根据Java Docs-泛型类型是通过类型进行参数化的泛型类或接口。
仅举另一个例子,Class(Class<T>
)的泛型版本允许编写诸如下面的泛型函数。
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.
Action a = new Action()
?Action
我是一个接口,这是SomeAction
我们正在尝试获取实例。我们只有SomeAction
在运行时可用的名称。
只需使用牛肉课:
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();
}