【问题标题】:JLS as related to type castingJLS 与类型转换有关
【发布时间】:2016-01-10 11:19:45
【问题描述】:

我尝试更基本地理解 Java 中的类型转换,但无法理解 JLS 的某些部分。
特别是这个(在将类类型 S 转换为类或接口类型 T 的意思):

此外,如果存在 T 的超类型 X 和 S 的超类型 Y,使得 X 和 Y 都可证明是不同的参数化类型(第 4.5 节),并且 X 和 Y 的擦除相同,则发生编译时错误。

还有这个(将接口类型 S 转换为最终类类型 T):

否则,S 要么是参数化类型,它是对某个泛型类型声明 G 的调用,要么是对应于泛型类型声明 G 的原始类型。那么必须存在 T 的超类型 X,这样 X 就是一个调用G,或发生编译时错误。 此外,如果 S 和 X 可证明是不同的参数化类型,则会发生编译时错误。

也许有人可以举一些简短的例子来澄清这些摘录?

附:经过@ErickGHagstrom 的一些考虑和指导后,我想我可以澄清一下这两个棘手的 JLS 摘录。

提取 1。

JLS 说:

如果以下任一情况为真,则可证明两种参数化类型是不同的:

  • 它们是不同泛型类型声明的参数化。

  • 它们的任何类型参数都可以证明是不同的。

和:

如果满足以下条件之一,则可证明两个类型参数是不同的:

  • 参数都不是类型变量或通配符,并且两个参数不是同一类型。

  • 一个类型参数是类型变量或通配符,其上限(来自捕获转换(第 5.1.10 节),如有必要)为 S;并且另一个类型参数 T 不是类型变量或通配符;也没有|S| <:>

  • 每个类型参数都是一个类型变量或通配符,具有 S 和 T 的上限(如果需要,来自捕获转换);也没有|S| <:>

因此List&lt;Integer&gt;List&lt;Number&gt; 可证明是不同的,但List&lt;? extends Integer&gt;List&lt;? extends Number&gt; 不是(所有列出的类型都有相同的擦除)。

关键点是两个可证明不同的具有相同擦除的参数化类型之间的子类型关系在任何情况下都是不可能的。

具有相同擦除的两个可证明不同的参数化类型的子类型之间的子类型关系也以任何方式都不可能。如果S &lt;: List&lt;Integer&gt;T &lt;: List&lt;Number&gt; 然后铸件(T)S(S)T 甚至在理论上都是不可能的。所以编译器会抱怨。

提取 2。

这是我想出的例子(编译和运行没有错误):

    static final class T extends ArrayList<Number>{
    }

    static T t;

    static List<?> l1 = new T();
    static List<? extends Number> l2 = new T();
    static List<String> l3;

    public static void main(String[] args) {
        t = (T)l1;
        t = (T)l2;
//        t = (T)l3; //error
    }

您可以看到List&lt;?&gt;List&lt;? extends Number&gt; 可以转换为最终的T,而T 没有(也不能)实现这些接口中的任何一个。

T &lt;: List&lt;Number&gt;List&lt;Number&gt; 是对List&lt;E&gt; 的调用,例如List&lt;?&gt;List&lt;? extends Number&gt;List&lt;Number&gt;List&lt;?&gt;List&lt;? extends Number&gt; 不能证明是不同的(见上文)。

如果我们想将参数化接口类型S 转换为最终类类型T,则T 不需要显式或隐式地实现S。但是这个T 必须 实现另一个与S 有子类型关系的参数化接口类型。关键是参数化类型之间的子类型关系不仅通过扩展或实现来定义,而且通过类型参数包含来定义。

【问题讨论】:

    标签: java generics casting


    【解决方案1】:

    第一种情况:

    ArrayList&lt;String&gt;ArrayList&lt;Integer&gt; 具有相同的擦除,ArrayList,但可证明是不同的,因为没有 String 可以转换为 Integer,也没有 Integer 可以转换为 @ 987654327@.

    第二种情况:

    GList&lt;T&gt;SList&lt;String&gt;。假设我有一个类 MyFinalArrayList 像这样:

    public final class MyFinalIntArrayList extends ArrayList<Integer> {
        ...
    }
    

    还有一个喜欢

    public final class MyFinalStrArrayList extends ArrayList<String> {
        ...
    }
    

    我可以将第一个转换为List&lt;Integer,将第二个转换为List&lt;String,但反之则不行。

    【讨论】:

    • 那么,参数化类型可以证明是不同的,如果它们的类型参数不相关?好的。似乎理解至少从第一次提取开始:如果两种类型具有可证明不同的参数化超类型,则意味着这两种类型不能以任何方式位于同一层次结构分支中。
    • 截至您对第二次提取的回答。将MyFinalStrArrayList 转换为List&lt;String&gt; 是微不足道的。我认为你的意思是:List&lt;Integer&gt; li1 = new MyFinalIntArrayList(); MyFinalIntArrayList mfli1 = (MyFinalIntArrayList) li1; 这段代码编译并运行是因为MyFinalIntArrayList 通过扩展ArrayList&lt;Integer&gt; 有效地实现了List&lt;Integer&gt;。但是我仍然无法将想法成形并理解第二次提取的确切含义。
    • 这个 JLS 真是令人兴奋。参数化类型可证明是不同的,如果它们的类型参数是 a) 不是通配符 and 不相同或 b) 通配符 and 哪些边界不相关。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-01-21
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多