Welcome to OStack Knowledge Sharing Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
268 views
in Technique[技术] by (71.8m points)

java - Create instance of generic class member: Class<T>.newInstance() throws exception

I want to make a generic class which stores a pool of temporary objects (such as 2D vector Vec2d ) so that I don't have to dynamically allocate them during my simulations. Based on these answers [1] [2] I come to this solution:

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--; }
  }

But when I try to use

class Vec2d{ double x,y; }

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

it it throws exception Exception thrown :java.lang.InstantiationException: Boulders_rigid$Vec2d in TempPool()

question from:https://stackoverflow.com/questions/66063587/create-instance-of-generic-class-member-classt-newinstance-throws-exception

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Answer

0 votes
by (71.8m points)

Inner classes do not work how you think they work.

An inner class looks like this:

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

Inner class have a secret, invisible final field that looks like:

private final Outer magicThis;

that cannot be null. Every constructor that Inner has, has as first parameter Outer magicThis, but this parameter is also hidden. To pass it, you use this weird syntax:

outerInstance.new Inner();

and, crucially, which makes it 'magic', in the sense that you didn't know it worked this way, if Outer.this was a legal expression (which it is, in any non-static method inside Outer, for exmaple), Outer.this is silently assumed as outerInstance: In those contexts, and only in those, just new Inner() works.

Now that you know all this, you then understand that invoking newInstance() on a non-static inner class does not work: That requires a no-args constructor and there isn't one: All constructors have that secret, invisible Outer magicThis parameter.

You can observe all this by using the javap tool.

The solution is simple: Mark your inner class as static. In fact, go ahead and mark all your inner classes as static. Only make non-static inner class if you really know what you are doing and you are absolutely sure you really want that - the magic stuff tends to throw people off and make it easy to make wrong assumptions about code. For example, that secret ref to the outer? That can really trip you up with garbage collection (it prevents the outer instance from being collected!).

Note that your code has very crappy quality. A few things to look into:

  1. The correct "I have no idea what to do" exception handler is NEVER to just log it and forget it, and System.out is not an appropriate logging locatino. Just e throws away almost all relevant information - in particular the cause which is what you do NOT want to throw away. The right I dunno handler for an exception block is always this: throw new RuntimeException("Unhandled", e);. This is short, simple, does not cause code to continue to run in an unknown state, and preserves all information. Fix this.

  2. Don't call newInstance() on a class; it is deprecated. It has crazy exception behaviour. You want c.getConstructor().newInstance() instead.

  3. objs[-1] = null of course throws ; there is no -1 index. Presumably you want objs[icur] = null? Or perhaps objs[objs.length - 1] = null;? I'm not sure what repay is trying to accomplish.


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome to OStack Knowledge Sharing Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...