假设我们有如下两种方法:
public static <T> T genericReturn() { /*...*/ }
public static String stringReturn() { /*...*/ }
在调用任何方法时,无论是否有任何要求,都可以提供类型见证:
String s;
s = Internet.<String>genericReturn(); //Type witness used in return type, returns String
s = Internet.<Integer>stringReturn(); //Type witness ignored, returns String
但是,我没有看到它在Java中有任何实际的用途,除非无法推断类型(这通常表明存在更大的问题)。此外,如果不恰当地使用它,它就会被忽略,这一事实似乎违反了直觉。那么,在Java中使用它有什么意义呢?
这是因为向后和/或向前兼容(在源代码级别)。
想象一下在JDK 7中为Swing中的某些类引入泛型参数。方法也可能发生这种情况(即使有限制)。如果某个东西被证明是个坏主意,您可以删除它们,使用它的源代码仍然可以编译。在我看来,这就是为什么这是允许的,即使它没有被使用。
但灵活性有限。如果使用n
类型引入了类型参数,则在m!=0
或m!=n
。
(我知道这可能无法回答您的问题,因为我不是Java的设计者,这只是我的想法/观点。)
当类型推断无法工作时,您需要类型见证(菱形中的类型)(请参见http://docs.oracle.com/javase/tutorial/java/generics/genTypeInference.html)
举个例子,菊花链调用如下:
processStringList(Collections.emptyList());
其中,过程StringList定义为:
void processStringList(List<String> stringList)
{
// process stringList
}
这将导致错误,因为它无法强制转换列表
从JLS§15.2.12.1:
此子句意味着非泛型方法可能适用于提供显式类型参数的调用。事实上,它可能被证明是适用的。在这种情况下,类型参数将被忽略。
然后是辩护
这一规则源于兼容性问题和可替代性原则。由于接口或超类可以独立于其子类型进行泛型,因此我们可以用非泛型方法重写泛型方法。但是,重写(非泛型)方法必须适用于泛型方法的调用,包括显式传递类型参数的调用。否则,子类型将无法替换其泛化的超类型。
沿着这条推理路线,让我们构造一个示例。假设在Java1.4中,JDK有一个类
public class Foo
{
/** check obj, and return it */
public Object check(Object obj){ ... }
}
一些用户编写了一个专有类,该类扩展了Foo
,并重写了check
方法
public class MyFoo extends Foo
{
public Object check(Object obj){ ... }
}
当Java1.5引入泛型时,Foo。检查
被泛化为
public <T> T check(T obj)
雄心勃勃的向后可比性目标要求MyFoo
仍然在Java1.5编译而不修改;和MyFoo.check[Object-
现在,根据上述理由,由于这将编译:
MyFoo myFoo = new MyFoo();
((Foo)myFoo).<String>check("");
这也必须编译:
myFoo.<String>check("");
即使
MyFoo。检查
不是通用的。
听起来有点牵强。但即使我们接受这一观点,解决方案仍然过于宽泛和过度。JLS可以把它收紧,这样
myFoo。
问题内容: 说我们有以下两种方法: 在调用任何方法时,无论是否有任何要求,您都可以提供类型见证人: 但是,除非在无法推断出类型的情况下(通常表明存在更大的问题),否则我在Java中根本看不到任何实际用途。另外,当不适当使用它时将其简单忽略的事实似乎违反直觉。那么,在Java中完全有什么意义呢? 问题答案: 从JLS§15.2.12.1开始: 如果方法调用包括显式类型参数,并且成员是泛型方法,则类型
问题内容: 这是我的代码,但是我没有得到方法如何接受类型作为返回值。如何运作?谁能解释一下这种方法的工作原理? 提前致谢 :) 问题答案: 好的,所以首先要做的是: 这是一个不断扩大的原始类型转换,因此这是合法的。您可以: 但是您不能: 第二:它返回的根本不是ASCII码。Java执行Unicode。 碰巧的是,当创建Java时,Unicode仅定义了适合16位的代码点。因此,它被创建为2字节的无
问题内容: 使用“抽象方法”有什么意义?抽象类不能实例化,但是抽象方法呢?他们只是在这里说“您必须实现我”,如果我们忘记了它们,编译器会抛出错误? 这还意味着其他吗?我还阅读了有关“我们不必重写相同的代码”的内容,但是在抽象类中,我们仅“声明”了抽象方法,因此我们将不得不在子类中重写代码。 您能帮我多了解一点吗?我检查了有关“抽象类/方法”的其他主题,但没有找到答案。 问题答案: 除了提醒您必须实
问题内容: 可以有一个 实现所有方法 的抽象类-里面没有抽象方法。 例如。: 与拥有与具体类相同的类相比,拥有这样的抽象类(如果有)有什么优势? 我能想到的是,当我将其声明为抽象时,它将不会被实例化。但是,我可以通过将其具体化并将其构造函数设为私有来达到相同的效果。 TIA。 // ================== 编辑:我能想到的另一种用途: 它可能会扩展另一个抽象类或实现一个接口,而不实现
问题内容: 我正在进行代码审查,并遇到了一个使用所有静态方法的类。入口方法接受几个参数,然后开始调用其他静态方法,并传递入口方法接收到的所有或某些参数。 它不像具有大量不相关的实用程序功能的Math类。在我自己的常规编程中,我很少编写Resharper弹出并说“这可能是静态方法”的方法,而当我这样做时,它们往往是无用的实用方法。 这种模式有什么问题吗?如果类的状态保存在字段和属性中或使用参数在静态
问题内容: 当通过扩展或实现链接类时,将建立子类型。子类型也用于泛型。 如何区分子类型和子类? 问题答案: 在Java中,子类化是一种子类型化。 Java允许子类型化的方法有很多: 当时,是因为可以的子类型。 当时,是因为可以的子类型。 当时,是因为可以的子类型。 当时,是因为可以的子类型。 听起来您想要一种区分其他人的方法。下面应该这样做。 但是由于类型擦除,它不会处理泛型类的子类型化。 实例在