首页 > 解决方案 > 创建泛型类成员的实例:Class.newInstance() 抛出异常

问题描述

我想创建一个通用类来存储临时对象池(例如 2D 矢量 Vec2d ),这样我就不必在模拟期间动态分配它们。基于这些答案[1] [2]我得出了这个解决方案:

import java.lang.reflect.Array;

class TempPool<T>{
  T[] objs;

  public TempPool(Class<T> c, int n) {
    T[] a = (T[])Array.newInstance(c, n);                // initialize the array
    try{ // Compiler forces me to use try fo handling                     
      for(int i=0; i<n; i++) a[i]=(T)c.newInstance();   // initialize fields in the array
    }catch(Exception e){
      System.out.println("Exception thrown  :" + e +" in TempPool()" );
    }
    objs = a;
  }

  T    borrow(  ){ return objs[icur++];    };
  void repay(T o){ 
    if( o != objs[icur] ) objs[-1]=null; // Throws exeption
    }else{ icur--; }
  }

但是当我尝试使用

class Vec2d{ double x,y; }

tmpVec2d   = new TempPool       (Vec2d.class,10);   // tried both
//tmpVec2d = new TempPool<Vec2d>(Vec2d.class,10);   // tried both

它抛出异常 Exception thrown :java.lang.InstantiationException: Boulders_rigid$Vec2d in TempPool()

标签: javagenericsreflection

解决方案


内部课程并不像您认为的那样运作。

内部类如下所示:

class Outer /* must be a class; not an interface */ {
    class Inner /* A class (not an interface), AND, not static {
    }
}

内部类有一个秘密的、不可见的 final 字段,如下所示:

private final Outer magicThis;

那不可能null。每个Inner具有的构造函数都有第一个参数Outer magicThis,但这个参数也是隐藏的。要传递它,您可以使用这种奇怪的语法:

outerInstance.new Inner();

并且,至关重要的是,这使它变得“神奇” ,从某种意义上说,你不知道它是这样工作Outer.this的as outerInstance:在那些上下文中,并且只有在那些上下文中,才有效。OuterOuter.thisnew Inner()

既然你知道了这一切,那么你就会明白newInstance()在非静态内部类上调用是行不通的:这需要一个无参数的构造函数,而且没有一个:所有构造函数都有那个秘密的、不可见的Outer magicThis参数。

您可以使用该javap工具观察所有这些。

解决方案很简单:将您的内部类标记为static. 事实上,继续将所有内部类标记为静态。只有当你真的知道你在做什么并且你绝对确定你真的想要它时才创建非静态内部类 - 神奇的东西往往会让人们失望,并且很容易对代码做出错误的假设。例如,外部的秘密参考?这真的会让你陷入垃圾收集(它会阻止收集外部实例!)。

请注意,您的代码质量非常糟糕。需要研究的几件事:

  1. 正确的“我不知道该怎么做”异常处理程序永远不会只记录它并忘记它,并且 System.out 不是适当的记录位置。只是e扔掉几乎所有相关信息——尤其是你不想扔掉的原因。我不知道异常块的正确处理程序始终是:throw new RuntimeException("Unhandled", e);. 这简短、简单,不会导致代码继续在未知状态下运行,并保留所有信息。解决这个问题。

  2. 不要newInstance()去上课;它已被弃用。它有疯狂的异常行为。你想要c.getConstructor().newInstance()

  3. objs[-1] = null当然抛出;没有-1索引。想必你想要objs[icur] = null?或者也许objs[objs.length - 1] = null;?我不确定repay要完成什么。


推荐阅读