【问题标题】:Can I store the generics attribute into an object's field我可以将泛型属性存储到对象的字段中吗
【发布时间】:2008-11-20 08:31:14
【问题描述】:

假设以下类存根:

public class Foo<T> {
  private Class<T> type;

  public Foo<T> () {}
}

我可以将泛型类型T 存储到构造函数中的字段type 中,而无需将构造函数的签名更改为“public Foo&lt;T&gt; (Class&lt;T&gt; type)”吗?

如果是,怎么做?如果不是,为什么?

type = T”似乎不起作用。

【问题讨论】:

    标签: java generics


    【解决方案1】:

    否 - 类型擦除意味着您必须在执行时提供 something。您可以提供TClass&lt;T&gt; 的实例,但类本身只会将每次出现的T 替换为Object

    这种事情是 Java 的泛型与 .NET 中的泛型相比的最大缺点之一。 (另一方面,Java 中的差异故事比 .NET 中的差异更大——如果更令人困惑的话。)

    【讨论】:

      【解决方案2】:

      正如thread中所说,

      例如列表

      list.get (index).getClass() 
      

      不会为您提供存储在列表中的对象类型:

      • 当列表为空时
      • 即使列表不为空,因为任何元素都可以是泛型类型参数的任何子类。

      由于类型参数在编译时被删除,它们在运行时不存在(对不起,Jon,execution time):因此您无法通过 java 中的反射获取泛型类型信息。

      有更多reification 的案例在桌面上(Java 7 ?),并且会促进您追求的目标。

      人们可能希望转换为 T 的错误类型会引发 Cast 异常,该异常会在执行时显示用于 T 的原始类型,但可惜这也不起作用。

      考虑以下测试类:

      import java.util.ArrayList;
      
      /**
       * @param <T>
       */
      public class StoreGerenericTypeInField<T>
      {
      
          private T myT = null;
          private ArrayList<T> list = new ArrayList<T>();
      
          private void setT(final T aT) { myT = aT; }
          /**
           * Attempt to do private strange initialization with T, in the hope to provoke a cast exception
           */
          public StoreGerenericTypeInField()
          {
              StringBuilder aFirstType = new StringBuilder();
              StringBuffer aSecondType = new StringBuffer();
              this.list.add((T)aFirstType);
              this.list.add((T)aSecondType);
              System.out.println(this.list.get(0).getClass().getName());
              System.out.println(this.list.get(1).getClass().getName());
      
              setT((T)aFirstType);
              System.out.println(this.myT.getClass().getName());
              setT((T)aSecondType);
              System.out.println(this.myT.getClass().getName());
          }
          /**
           * @param args
           */
          public static void main(String[] args)
          {
              StoreGerenericTypeInField<Integer> s = new StoreGerenericTypeInField<Integer>();
          }
      }
      

      构造函数试图将讨厌的东西存储到它的 T 变量(或它的 T 列表)中......并且一切都运行顺利!?

      打印出来:

      java.lang.StringBuilder
      java.lang.StringBuffer
      java.lang.StringBuilder
      java.lang.StringBuffer
      

      类型擦除本身就是not to blame...,这是类型擦除(java 的新特性)和不安全类型转换组合 strong>(java 遗留的旧功能)这使得 T 在执行时真正遥不可及(直到您实际尝试将它与 'T' 特定方法一起使用)

      【讨论】:

      • 投赞成票主要是因为您不仅阅读了那段内容,而且还记得它并费心寻找正确的链接 :) (哦,因为您当然是正确的!)
      • 嗯....这主要是因为我正在观看您的哥本哈根视频(我在 DEL 4)msmvps.com/blogs/jon_skeet/archive/2008/11/19/…。您通过提醒听众注意这一区别开始了该演示。
      • 你越来越打扰我了...很遗憾我几乎每次在白天提到运行时间/执行时间时都弄错了...
      • 是的,乔恩,我会买你的书,我保证;)
      • 我不同意类型擦除不是问题的想法。这意味着你不能做 T.class 等 so 方便。这个特定的代码可能没有错,但它仍然很痛苦:(
      【解决方案3】:

      那么,为什么不在你的类中有一个 T 的实例呢?我的意思是,如果不是这种情况,T 会给你买什么?所以如果你有 T x,你可以做一个 x.GetType()。

      【讨论】:

      • 嗯,我以为这是.Net。我忘记了 Java 作为不同的泛型。
      【解决方案4】:

      type = T.getClass();
      

      工作?

      【讨论】:

      • 不,它不起作用,因为我无法在方法内部引用 T(“T 无法解析”)
      【解决方案5】:

      你应该试试这个:

      type = T.GetType();
      

      【讨论】:

      • 不,它不起作用,因为我无法在方法内部引用 T(“T 无法解析”)。
      猜你喜欢
      • 2012-11-29
      • 1970-01-01
      • 1970-01-01
      • 2011-03-22
      • 1970-01-01
      • 2021-06-03
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多