管理通用外部 class 及其内部通用内部 class 实例化实例和声明各自引用的规则是什么?

What are rules governing instantiating instances of generic outer class and its inner generic inner class and declaring respective references?

1) 为什么obj4,obj6,obj7编译报错,obj5没问题?我在哪里可以阅读有关使用此类通用耦合外-内 classes 进行监管的规则?我没有找到任何直截了当的东西。

当我不为 obj3 中的 Inner class 提供任何类型参数时,它很好(而 Inner class 需要为其 S 类型的 fld3 字段提供一些东西),但是当我做同样的事情并且不为 Outer class 提供类型时 - 它不编译(obj4) - 尽管可以隐含对象...

2) 此外,为什么obj10 编译正常,但obj11 却失败了?在 obj10 行中,我还写了 outerInstance.new Inner<>(),暗示对于 Inner,S 是对象。但这对内部来说不是问题,但同样 "trick" 是外部问题...

        //in Class A of package com.sth
        public class MyGen<T> {
            T fld1;

            class GenInner<S> {
                T fld2;
                S fld3;
            }

                // within main of Class Driver of same package com.sth
                MyGen.GenInner obj1 = new MyGen<String>().new GenInner<Integer>();
                MyGen.GenInner obj2 = new MyGen<String>().new GenInner<>();
                MyGen.GenInner obj3 = new MyGen<String>().new GenInner();
                //MyGen.GenInner obj4 = new MyGen().new GenInner<String>();  //ERR !
                MyGen.GenInner obj5 = new MyGen<>().new GenInner<String>();

                //MyGen<String>.GenInner obj6;  // ERR
                //MyGen.GenInner<String> obj7;  // ERR
                MyGen<String>.GenInner<Integer> obj8;
                MyGen.GenInner obj9;     


  MyGen<String>.GenInner<Integer> obj10 = new MyGen<String>().new GenInner<>();

  //Type mismatch: cannot convert from MyGen<Object>.GenInner<Integer> to MyGen<String>.GenInner<Integer>
  //MyGen<String>.GenInner<Integer> obj11 = new MyGen<>().new GenInner<Integer>();  // ERR!

这些答案与我的问题有关,但没有提供任何线索:

  1. Answer 2
  2. Answer 3
  3. Answer 4
  4. Answer 5

不编译的例子大多是稀有类型的例子。 (此外,正如 John 在评论中指出的那样,obj3 示例也不应编译。)

A raw type 是通过使用没有附带类型参数列表的泛型类型形成的类型(例如 Set,与 Set<Float> 相对)。 稀有 类型是当你有一个通用外部 class 和通用内部 class 时,其中一个是原始的,另一个不是。

取自JLS 4.8 Raw Types:

More precisely, a raw type is defined to be one of:

  • The reference type that is formed by taking the name of a generic type declaration without an accompanying type argument list.

  • An array type whose element type is a raw type.

  • A non-static member type of a raw type R that is not inherited from a superclass or superinterface of R.

(请注意,粗体表示如果您有原始类型 MyGen,那么它的非 static 成员 class GenInner 也必须是原始类型, 所以没有 MyGen.GenInner<String>.)

这样的东西

Another implication of the rules above is that a generic inner class of a raw type can itself only be used as a raw type:

class Outer<T>{
    class Inner<S> {
        S s;
    }
}

It is not possible to access Inner as a partially raw type (a "rare" type):

Outer.Inner<Double> x = null;  // illegal
Double d = x.s;

because Outer itself is raw, hence so are all its inner classes including Inner, and so it is not possible to pass any type arguments to Inner.

It is a compile-time error to pass type arguments to a non-static type member of a raw type that is not inherited from its superclasses or superinterfaces.

It is a compile-time error to attempt to use a type member of a parameterized type as a raw type.

This means that the ban on "rare" types extends to the case where the qualifying type is parameterized, but we attempt to use the inner class as a raw type:

Outer<Integer>.Inner x = null; // illegal

This is the opposite of the case discussed above. There is no practical justification for this half-baked type. In legacy code, no type arguments are used. In non-legacy code, we should use the generic types correctly and pass all the required type arguments.

带有 obj11 = new MyGen<>().new GenInner<Integer>() 的示例并不罕见。它看起来像是钻石类型推断的常规失败,因为表达式 new MyGen<>() 没有分配给任何东西。在没有分配的情况下,通常假定 Object。 (从技术上讲,它可以是类型变量的上限,在这种情况下是 Object。)


此外,虽然与手头的问题没有直接关系,但以下是新代码中实际应该使用的仅有的两种形式:

MyGen<String>.GenInner<Integer> ok1 = new MyGen<String>().new GenInner<Integer>();
MyGen<String>.GenInner<Integer> ok2 = new MyGen<String>().new GenInner<>();

所有其他(编译)使用原始类型,不鼓励使用原始类型。