【问题标题】:Why is anonymous class required in "super type token" pattern in javajava - 为什么Java中的“超类型令牌”模式需要匿名类
【发布时间】:2014-05-01 04:05:56
【问题描述】:

在 Neal Gafter 的“超级类型令牌”模式 (http://gafter.blogspot.com/2006/12/super-type-tokens.html) 中,使用匿名对象传入参数化类型:

class ReferenceType<T>{}

/* anonymous subclass of "ReferenceType" */
ReferenceType<List<Integer>> referenceType = new ReferenceType<List<Integer>>(){

};
Type superClass = b.getClass().getGenericSuperclass();
System.out.println("super type : " + superClass);
Type genericType = ((ParameterizedType)superClass).getActualTypeArguments()[0];
System.out.println("actual parameterized type : " + genericType);

那么结果是:

super type : com.superluli.test.ReferenceType<java.util.List<java.lang.Integer>>
actual parameterized type : java.util.List<java.lang.Integer>

我的问题是,匿名对象“referenceType”有什么魔力使它起作用?如果我定义一个“ReferenceType”的显式子类并使用它而不是匿名样式,它不会像预期的那样。

class ReferenceType<T>{}
class ReferenceTypeSub<T> extends ReferenceType<T>{}

/* explicitly(or, named) defined subclass of "ReferenceType" */
ReferenceType<List<Integer>> b = new ReferenceTypeSub<List<Integer>>();
Type superClass = b.getClass().getGenericSuperclass();
System.out.println("super type : " + superClass);
Type genericType = ((ParameterizedType)superClass).getActualTypeArguments()[0];
System.out.println("actual parameterized type : " + genericType);

结果是:

super type : com.superluli.test.ReferenceType<T>
actual parameterized type : T

【问题讨论】:

  • 不清楚您不理解文章的哪一部分(具体而言),因为它很好地解释了这一点。他介绍的类是抽象的,因为由于类型擦除(在文章中对此进行了解释)......这就是它的工作方式。这就是这篇文章的全部内容。您的第二个示例基本上就是重点 - 由于类型擦除,它无法在 Java 中工作。
  • 嗨,Brian,我认为这与类型擦除无关,如果我错了,请纠正我。类型擦除意味着在编译期间从源代码中删除泛型类型,JVM 不会在运行时使用它们进行类型检查。但另一方面,这些信息都没有“真正丢失”:它们在编译期间仍然保存在 .class 文件中,因此由类加载器加载到类对象池中。 Java 反射提供了接口让我们检索这些信息。
  • 因此,在这两个示例中,类型都被删除了。实际区别在于第一个示例中的“ReferenceType>”之类的内容被保存在匿名类的 .class 文件中,而在第二个示例中,“ReferenceType”被保存。
  • 基本上,你的层次太深了。您只能从直接超类中获取泛型类型,并且仅当子类在声明中提供具体类型时。类型擦除会导致你喝酒(相信我)。

标签: java generics types anonymous parameterized-types


【解决方案1】:

这个

ReferenceType<List<Integer>> referenceType = new ReferenceType<List<Integer>>(){

等价于

public class AnonymousReferenceType extends ReferenceType<List<Integer>> {}
...
ReferenceType<List<Integer>> referenceType = new AnonymousReferenceType();

黑客围绕Class#getGenericSuperclass() 工作

返回代表实体直接超类的Type (类、接口、原始类型或 void)由该类表示。 如果超类是参数化类型,则返回Type 对象 必须准确反映源中使用的实际类型参数 代码。创建表示超类的参数化类型,如果 它以前没有被创建。见声明 ParameterizedType 用于创建过程的语义 参数化类型。如果这个 Class 代表 Object 类, 接口、原始类型或void,然后返回null。如果 此对象表示一个数组类,然后是 Class 对象 代表Object 类被返回。

换句话说,AnonymousReferenceType 的超类是代表ReferenceType&lt;List&lt;Integer&gt;&gt;ParameterizedType。这个ParameterizedType 有一个实际的类型参数,即源代码中出现的List&lt;Integer&gt;


在您的第二个示例中,与您的第一个示例不同

class ReferenceType<T>{}
class ReferenceTypeSub<T> extends ReferenceType<T>{}

ReferenceTypeSub 的超类(超类型)是一个ReferenceType&lt;T&gt;,它是一个ParameterizedType,其中实际的类型参数是一个名为TTypeVariable,它出现在源代码中。


要回答您的问题,您不需要匿名课程。您只需要一个子类来声明您要使用的类型参数。

【讨论】:

  • 那么参数化类型“List”的信息将保存在AnonymousReferenceType.class文件中。问题是,为什么在第二个示例中,将文字“T”保存在那里而不是我声明的实际类型“List”?另请参阅我发布自己的想法但不确定其是否正确的原始问题的 cmets。
  • 一段时间后我明白了。就像你说的那样,这一切都来自类声明。在第一个示例中,""List" 在匿名类的声明中。而在第二个示例中,它是 T。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-09-30
  • 2011-01-09
  • 2019-03-16
  • 1970-01-01
相关资源
最近更新 更多