(泛型)不能对非静态类型T进行静态引用

时间:2016-04-03 13:57:04

标签: java generics

运行Demo类将调用SomeClass中的静态方法newInstance来调用构造函数并打印hello

定义方法将包含带参数

的返回类型+方法名称

newInstance的返回类型是< T> SomeClass< T>对我来说似乎很奇怪 因为我的班级被称为SomeClass< T>而不是< T> SomeClass< T>

  

为什么我需要< T>在SomeClass< T>前面?   似乎如果我不包括它将会有一个常见的错误   called不能对非静态类型T

进行静态引用

要指出的另一件事是我可以在< T>之间放置许多空格了。和SomeClass< T>所以看起来他们不需要在一起。

public class SomeClass<T> {

    public static <T>SomeClass<T> newInstance(Class<T> clazz){
        return new SomeClass<T>(clazz);
    }

    private SomeClass(Class<T> clazz){
        System.out.println("hello");
    }
}

public class Demo {

    public static void main(String args[])
    {
        SomeClass<String> instance = SomeClass.newInstance(String.class);
    }
}

2 个答案:

答案 0 :(得分:8)

什么是静态方法?适用于类的方法,而不是特定的实例。类签名T中的泛型参数public class SomeClass<T>仅适用于特定实例(因此non-static type T)。例如SomeClass<String> [T = String]<T>

public static <T>SomeClass<T> newInstance(Class<T> clazz)包含在T的方法签名中。你这么说;对于此方法,存在泛型类型参数T。此T与类签名中的C分开。所以它可能是public static <C> SomeClass<C> newInstance(Class<C> clazz),即<T>。或者完全不同的东西。

但是如果你没有在方法中包含T,编译器会认为你正在尝试在类签名中使用if (@{$edges{$location}}[0]) 。这是非法的。

答案 1 :(得分:0)

在我看来,这个问题非常有趣,它解决了几个不同的问题,值得不止一个答案,尽管那个答案可能是完全正确的。

<块引用>

为什么我需要在 SomeClass 前面 [Otherwise] 会有一个......错误......无法对非静态类型进行静态引用 T

静态成员、方法和字段的使用,在泛型类has certain restrictions中,参见“不能声明类型为类型参数的静态字段”一节。尽管本节讨论的是字段而不是方法,但也可以将推理扩展到方法。事实上,如果我们同意声明

 private static T foo = null;

没有意义,因为编译器无法创建实例独立变量 foo,因为泛型类可以用任何类型参数化(请记住,Java 泛型不是 C++ 模板,并且由于类型擦除前者在运行时只有一个(每个类加载器)泛型类的实例),那么为什么会像

public static T get() {
    return null;
}

应该更有意义吗?

其次,当您在 TSomeClass 方法中声明泛型类型 newInstance 时,实际上您隐藏第一个 T与第二个,并且两者互不相关。对于非静态类型,类型隐藏更为明显。在示例中

class Foo<T> {
    <T> T get(){ // a warning "The type parameter T is hiding the type T" 
        return null;
    }
}

第二个 T,在方法中声明,隐藏第一个,为类声明,这就是您收到警告 The type parameter T is hiding the type T 的地方。要消除警告,您必须将方法中的 T 替换为另一个类型变量,例如Z,因此两者之间的区别变得明显。

class Foo<T> {
    <Z> Z get(){ // no warning, T and Z are different type variables
        return null;
    }
}

在静态方法的情况下,编译器不会发出警告(可能是因为它认为对于静态事物是隐藏的?),但在这种情况下也存在类型隐藏。在您带来的示例中,您成功地欺骗了 Java 通用机器(恭喜 :)),但是如果我们想象以下场景(我稍微重构了您示例的语义,比如说,更传统的)

static class Factory <T extends Number> { 
    private T t;

    public static <T> T getInstance(){
        return null;
    }

    public T get(){
        return t;
    }
}

,这两行都会编译

Number n1 = longFactory.get();
Number n2 = Factory.getInstance();

,但是你在第二个上失去了类型安全,所以行

String s1 = longFactory.get(); // fails to compile with "Type mismatch: cannot convert from Long to String" error message 

失败,这很好,但是行

String s2 = longFactory.getInstance(); // compiles only with a warning "static method should be accessed in a static way"

如果您错过了类型参数隐藏的重点,这不是很好,也不是您所期望的。

(在幕后,T longFactory.get() type-erasesNumber longFactory.get(),而 static <T> T getInstance() type-erases 到 {{1 }},例如

static Object getInstance()

Type Erasure 是另一回事)