从一个例子开始,
public static <T> T method(T str){
return (T)str;
}
// T is deduced to be a String
// This fails at compile time
Integer integer = method("Trial");
//Object obj = method("Trial"); // Old example
和
public static <T> T method(String str){
return (T)str;
}
// What type does T gets deduced to in this case?
// This compiles but gives an error at run-time.
Integer integer = method("Trial");
//Object obj = method("Trial"); // Old example
两个代码段都可以正常编译。在第二个示例中,T被推导为哪种类型?
答案 0 :(得分:0)
未指定的通用类型被视为Object
,因此在两种情况下返回的类型都是正确的。
那么使用哪种方法呢?
实际上,最精确的匹配类型将首先被接受。对于您来说,method(String str)
和"Trial"
是String
。
// Will rename for understanding
// method(T str) => method1
// method(String str) => method2
public static <T> T method1(T str){
return (T)str;
}
public static <T> T method2(String str){
return (T)str;
}
// This is your implementation
Object obj = <Object> //as undefined
method2("Trial"); // as mentionned above
// BUT
Object obj = <Object> // as undefined
method1(1); // as 1 is an int upperbounded to Object
// AND
Object obj = <String>
method2("Trial");
Object obj = <String>
method(1); // will not compile
您应该检查此post以获得有关优先级超载的更多详细信息
答案 1 :(得分:0)
无论如何,我还是很难过。
在您的第一个示例中,返回类型由方法参数的传入类型(即String
)确定(推断)。考虑以下示例:
public static <T> T something(T something) {
return something;
}
和两个调用示例:
String something = something("string");
Integer someOther = something("something");
第一个可以正常工作,但是第二个会出错,因为动态推断的返回类型为String
,而我们尝试将其存储为Integer
变量。
现在,当您将两个值都分配给Object
变量时,此方法工作正常的原因是-如上所述-这是String
和{{1的上限}}。实际上,您使用Integer
查看了一个反汇编的类文件,您会看到方法的签名如下:
javap
请注意,由于Java的类型擦除,以上所有内容在编译后实际上将成为public static <T extends java.lang.Object> T something(T)
类型。
另一方面,您的示例还将传入的参数强制转换为Object
冗余,因为这是由编译器推断类型的能力处理的。
我建议您看看以下内容:
https://www.baeldung.com/java-type-erasure https://www.tutorialspoint.com/java_generics/java_generics_type_inference.htm
现在让我们考虑第二个示例:
在那种情况下,T
将有效地达到T
类型,就像我上面提到的那样。这仍然是该方法的上限,但是这里有一个警告。此方法错误,因为它接受Object
对象并尝试将其(再次错误)转换为推断的类型。
例如,我可以执行此操作(编译正常),但在运行时会生成String
:
ClassCastException
此呼叫
public static <T> T something2(String something) {
return (T) something;
}
现在如上所述,分配给Integer somethingOther = something2("sas");
时起作用的原因是它是Object
的父类以及其他所有内容。
答案 2 :(得分:0)
在您的情况下,第一个函数的参数数据类型和函数的返回类型均为T
,这意味着它们都可以是任何类型。它们可以是字符串,整数,浮点数,字符,数组或其他任何形式。这种T
类型的范围仅限于此特定功能。
第二个函数的数据类型参数为String
,而返回类型为T
,这意味着只能将String类型的值传递给该函数。
例如,
public static <T> T func1 (T var)
{
return var;
}
以上函数可以具有a = func1("String")
或b = func1(2)
或其他任何函数。 a将为String
类型,b将为int
类型。另一方面,
public static <T> T func2 (String var)
{
return var;
}
将在func2(2)
上返回错误。
请参阅Oracle Docs,以深入了解通用方法。
编辑为注释:调用函数时,Java编译器会自动从方法参数中推断出参数的类型。在示例中调用func1()
时,我写的是func1("ABC")
。 Java编译器非常聪明,现在可以理解参数T
的类型为String。同样,我从func1
返回一个String类型,因此编译器现在将知道该返回类型必须为String。
您还可以通过https://docs.oracle.com/javase/tutorial/java/generics/genTypeInference.html学习更多内容。
答案 3 :(得分:0)
所以我在这里回答我自己的问题。已知
public static <T> T method(String str){
return (T)str;
}
Integer x = method("String");
该方法可以很好地编译,这意味着编译器能够推断出模板参数的类型。但是,无法查看在编译过程中将其推导为哪种类型。相反,我们可以查看运行时错误。运行上面的代码时,出现以下错误,
Exception in thread "main" java.lang.ClassCastException: class java.lang.String cannot be cast to class java.lang.Integer
这意味着T
的类型是从分配给它的变量的类型推导出来的。所以它在内部变成了
public static Integer method(String str){
return (Integer)str;
}
现在
public static <T> T method(T str){
return (T)str;
}
Integer integer = method("Trial");
是另外一个故事。它不会编译。我的IDE(Intelij)抱怨no instance(s) of type variable(s) exist so that String conforms to Integer
。 可能表示该功能变为
public static String method(String str){
return (String)str;
}
由编译器执行。总而言之,当只有返回类型是通用类型时,则根据分配给该函数的变量的类型进行推导。当函数参数具有通用变量时,则根据传递给函数的变量进行推论。