4 回答
TA贡献1770条经验 获得超3个赞
您询问的方法是main(),如下所示(我将类和方法编辑到最低限度)。正如您所发现的,它有效。
class Box<T> {
public static void main(String[] args) {
// do something
}
}
该方法很好,因为它与泛型类型没有关联T。这里,main是一个静态方法,这意味着它在没有对象实例的情况下被调用。
泛型不适用于静态方法(或字段),但上面的示例并没有这样做。这是一个不同的示例,尝试定义一个也使用的静态方法T(但它不起作用):
class Box<T> {
public static void bar(T args) {
// do something
}
}
这个例子是一个静态方法,将在没有对象实例的情况下被调用 - 就像这样:Box.bar(someArgs)- 但这是无效的。如果不首先创建某个泛型类型的实例Box,编译器如何知道它T是什么?
可以定义一个静态方法来使用泛型类型,但该方法完全独立于T您的示例。对于某些单独的泛型类型,有一种方法可以做到这一点X:
class Box<T> {
public static <X> void foo(X input) {
// do something
}
}
你可以这样称呼它:Box.foo("");
TA贡献1828条经验 获得超6个赞
您不是“在这里执行课程”。main()
相反,您正在类中执行静态方法。允许您这样做的原因是类型擦除。泛型类型仅在编译代码时强制执行。在不声明任何引用或创建Box<T>
编译器实例的情况下,没有理由检查泛型类型。当您运行程序时,由于类型擦除,解释器对通用代码一无所知,因此它愉快地运行程序。
TA贡献1946条经验 获得超4个赞
Java 与 C 不同。不存在“对于每一个可以想象到的 T/代码库中实际使用的每一个 T 都有一个 Box 类的变体”。只有盒子。例如:
new Box<String>().getClass() == new Box<Integer>().getClass() // this is true
您不会加载单独的类等。
这确实有一些副作用: 不可能从String
变量 x 中导出: Box<?> x = new Box<String>();
- 该信息现在已经消失了。这称为擦除。
实际上,泛型几乎完全是编译器想象的产物。这就像在打字稿中输入信息等:它在编译时就存在,编译器将使用它来告诉您类型未对齐(编译器错误),但是一旦编译器接受所有信息,它就会被编译为一种在运行时完全消除此信息的形式*。
这就是为什么上面的代码可以毫无抱怨地工作:你有一个静态方法,<T>
这里甚至不存在。
让我们放大一下 get 和 set 方法以及 't' 字段: 它们完全是这样的:private Object t; public void set(Object o) { this.t = t; } public Object get() { return t; }
只有一个例外:如果在编译时,它没有意义,编译器将拒绝编译它。此外,对于呼叫的任何呼叫者get
,都会默默地包含一个演员表。
*)不完全是;签名中泛型的任何使用,因此,字段的类型、类自己的定义、和implements
行extends
以及方法的返回类型或参数类型中,都不会被消除,但它就像是对VM:VM不关心这些东西;它存在的唯一目的是,如果您调用javac
类路径上的某些内容,javac 在与这些成员交互时知道泛型是什么。就这些。
TA贡献1831条经验 获得超10个赞
Java 内部的泛型旨在为您的对象提供编译时类型安全性。对于您的情况,它根本不访问类中方法t内部的变量。main()这样java就会愉快地编译并运行程序了。
如果您Box在main()方法内实例化该类:
Box b = new Box(); // this is will produce "unsafe operations" note
b.set("this is the string");
System.out.println(b.get().getClass().getName());
根据最后一个变量赋值,您将在此处获得一个字符串。
添加回答
举报