有 Java 编程相关的问题?

你可以在下面搜索框中键入要查询的问题!

执行泛型Java类

我的理解是,泛型Java类在投入使用之前需要在类型上进行参数化。我很惊讶下面的示例代码没有参数化泛型类,执行时没有任何错误

public class Box<T> {
  private T t;

  public static void main(String[] args) {
    System.out.println("It actually executed!!!!");
  }

  public void set(T t) { this.t = t; }

  public T get() { return t; }
}  

java Box
产生输出
It actually executed!!!!

在这种情况下,是否存在传递给泛型类的隐式类型


共 (4) 个答案

  1. # 1 楼答案

    您询问的方法是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("");

  2. # 2 楼答案

    Java与C不同。没有“对于每个可想象的t/代码库中实际使用的每个t,都有一个Box类的变体”。只有一个盒子。例如:

    new Box<String>().getClass() == new Box<Integer>().getClass() // this is true
    

    您将不会加载单独的类等

    这确实有一些副作用:从变量x中导出String是不可能的。Box<?> x = new Box<String>();这些信息现在已经消失了。这叫做擦除

    实际上,泛型几乎完全是编译器想象出来的。这就像在typescript中键入信息一样:它在编译时就在那里,编译器会用它来告诉你,例如,类型没有对齐(编译器错误),但一旦编译器接受了它,它就会被编译成一种形式,这样在运行时,这个信息就会被完全消除*

    这就是为什么上面的代码可以毫无怨言地工作:您有一个静态方法,这里甚至不存在<T>

    让我们放大get和set方法以及“t”字段:如果它们读取:private Object t; public void set(Object o) { this.t = t; } public Object get() { return t; },那么它们就是正确的。只有一个例外:如果在编译时没有意义,编译器将拒绝编译它。此外,对于get调用的任何调用方,都会静默地包含一个cast

    *)不完全是;在签名中使用泛型,因此,字段的类型、类自己的定义、以及implementsextends行,以及方法的返回类型或参数类型中,泛型的任何用法都不会被消除,但这就像是对VM的注释:VM不关心这些东西;它的存在完全是为了,如果您使用类路径上的一些东西调用^{,javac在与这些成员交互时知道泛型是什么。仅此而已

  3. # 3 楼答案

    java内部的泛型旨在为对象提供编译时类型安全性。 对于您的情况,它根本不在类中的main()方法内访问t变量。所以java很乐意编译和运行这些程序

    如果在main()方法内实例化Box类:

    Box b = new Box(); // this is will produce "unsafe operations" note
    b.set("this is the string");
    System.out.println(b.get().getClass().getName());
    

    基于上一个变量赋值,您将在这里得到一个字符串

  4. # 4 楼答案

    你不是在“这里执行一个类”。而是在类中执行静态main()方法。允许您这样做的原因是因为类型擦除。泛型类型仅在编译代码时强制执行。如果不声明任何引用或创建Box<T>的实例,编译器就没有理由检查泛型类型。当您运行程序时,由于类型擦除,解释器对泛型代码一无所知,因此它可以愉快地运行程序