我遇到了以下使用泛型的代码片段。
public class Generics<T> {
public static <T> T replaceIfNull(T objectToCheck, T defaultValue) {
return objectToCheck == null ? defaultValue : objectToCheck;
}
public static <T> boolean CheckIfNull(T objectToCheck) {
return objectToCheck == null ? true : false;
}
}
我很难真正理解泛型如何工作,形成和使用。我有一个高层次的理解,这意味着我知道泛型的定义。根据定义,我对此代码片段的解释是replaceIfNull方法检查任何对象的空值,然后返回默认值(无论是什么)。并且CheckIfNull方法类似,因为它检查任何对象的空值。
但这是如何运作的?为什么该方法由<T>
形成,它似乎是一种类型,然后有T
。我不明白这种语法,<T> T
是什么意思? T
如何成为参数中的类型?例如,为什么这种方法不能写成
public static Object replaceIfNull(Object objectToCheck, Object defaultValue) {
return objectToCheck == null ? defaultValue : objectToCheck;
}
提前感谢您的澄清。
答案 0 :(得分:2)
泛型的主题非常广泛,您可以在Oracle的网站或Stack Overflow上广泛阅读。
为什么该方法由
<T>
构成,它似乎是一种类型,然后有T
。
这是一种通用方法。 <T>
声明一个没有边界的新类型变量。
// v return type
public static <T> T replaceIfNull(T objectToCheck, T defaultValue) {
// ^ new type variable ^ type variable used as a type
在方法体内,由于类型变量没有边界,T
最多可以解释为Object
。您只能访问Object
类型T
表达式T
中声明的方法。
在方法之外,即。在调用上下文中,类型变量replaceIfNull(someStringVar, otherStringVar);
将接收具体的类型值。也就是说,它将从其调用上下文推断它,或者它将被明确提供。
例如,在
中T
类型变量String
将绑定到T
,因此String
的所有用法都将被解释为String notNull = replaceIfNull(someStringVar, " not null ");
。你可以这样做
Generics.<String>replaceIfNull(nullVar, " not null ");
您还可以明确提供类型参数
String
现在再次将类型变量绑定到T
。
请注意,在类型级别
声明的类型变量public class Generics<T>
T
与方法中声明的类型变量{{1}}完全不同。
答案 1 :(得分:2)
让我们开始回答你的上一个问题。使用Object
而不是泛型重写的方法有两个缺点。首先,它不适用于原语(在这种情况下可能不是真正的缺点,因为你正在检查null
,而原语不能取空值,但仍然......)。其次,它需要铸造。例如,如果你在两个字符串上使用这个方法,比如replaceIfNull(myString, "Default Value")
,那么你希望得到一个String作为输出,对吧?但是声明返回Object
的方法;因此,编译器无法知道它将返回一个String,并且每次使用它时都必须进行转换:`String result =(String)replaceIfNull(myString,&#34;默认值&#34;) ;&#39;特别介绍了泛型来解决这种情况。
您可以将泛型视为模板;无论何时使用类型参数,您在角度括号中放置的任何类型都将在代码中稍后使用。所以,<T>
意味着:&#34;这将是某种类型;在代码中随处替换T
&#34;。
最后一个问题是方法签名。我想在这里你混淆了两种使用泛型的方法 - 在类级别和方法级别。由于您已经在类级别引入了类型参数,因此无需在方法级别上再次执行此操作,因此我认为您可以安全地从方法声明中删除<T>
。
我建议您在此处阅读有关泛型的更详细说明:http://docs.oracle.com/javase/tutorial/java/generics/