cdx
cdx

Reputation: 99

java generic object construction within an anonymous subclass

I was playing around with anonymous subclasses and I found a problem that I can't get around.

EDIT: problem is solved thanks to thomas, the complete working code is on pastebin (Foo.java; FooTest.java)

2 Classes; Foo and FooTest... Code first:

class Foo {

    public Foo () {}

    public void whichClassAmI () {
        System.out.println(this.getClass());                                                 
    }

    public void say () {
        System.out.println("Foo says: nothing");                                             
    }   

    public <T extends Foo> T getAnotherFoo () {                                              

        try {                                                                                
            Class<? extends Foo> c = this.getClass();                                        
            T r = (T)(c.getConstructor().newInstance());                                     
            return r;                                                                        
        } catch (Exception e) {                                                              
            throw new RuntimeException(e);                                                   
        }
    }                                                                                        

}

_

class FooTest {                                                                              

    public static String stuff = "";                                                         

    public static void main (String[] args) {                                                

        Foo f1 = new Foo();                                                                  

        // instance of anon subclass                                                         
        Foo f2 = new Foo(){                                                                  
            public void say () {                                                             
                System.out.println("Modded Foo says: " + stuff);                             
            }                                                                                
        };                                                                                   

        f1.whichClassAmI();                                                                  
        f2.whichClassAmI();                                                                  

        stuff = "stuff";                                                                     
        f1.say();                                                                            
        f2.say();                                                                            

        Foo f3 = f1.getAnotherFoo();                                                         
        f3.say();                                                                            

        Foo f4 = f2.getAnotherFoo(); // <-- exception here
    }

}

So this code compiles with an unsafe operation warning, runs and throws an exception; output is:

Note: Foo.java uses unchecked or unsafe operations.
Note: Recompile with -Xlint:unchecked for details.
class Foo
class FooTest$1
Foo says: nothing
Modded Foo says: stuff
Foo says: nothing
Exception in thread "main" java.lang.RuntimeException: java.lang.NoSuchMethodException: FooTest$1.<init>()
    at Foo.getAnotherFoo(Foo.java:20)
    at FooTest.main(FooTest.java:23)
Caused by: java.lang.NoSuchMethodException: FooTest$1.<init>()
    at java.lang.Class.getConstructor0(Class.java:2723)
    at java.lang.Class.getConstructor(Class.java:1674)
    at Foo.getAnotherFoo(Foo.java:17)
    ... 1 more

what I don't understand is:

  1. f2 class is FooTest$1 and this class seems to be not extending Foo

  2. if (1) is true why does " Class c = [...] " can be set with FooTest$1

  3. if (1) is false and (2) works correct, why doesn't it find the method?

Upvotes: 2

Views: 1085

Answers (1)

Thomas
Thomas

Reputation: 88727

To 1): f2 is of type FooTest$1 which extends Foo but that isn't printed, you just get the current class and no superclasses or interfaces.

To 2): Since 1) is false, there's not question here :)

To 3): The problem is that the annonymous inner class FooTest$1 needs an external FooTest instance to be created. Calling the constructor via reflection would try to create a new instance without an enclosing instance of FooTest and such a method is not available (i.e. a method that creates an instance of an inner class without an instance of the enclosing class).

What you need to do is get the constructor that takes an instance of the enclosing class as its parameter. For more information have a look at this question: Is it possible to create an instance of nested class using Java Reflection?

Edit:

I read your code again and am ashamed I missed this: the FooTest$1 class is actually a static inner class since it is created in the static main method. Thus it doesn't have a constructor taking an enclosing class instance.

However, since you create the class and its constructor inline that constructor isn't publicly visible. Thus getClass().getConstructor() won't return it (this class will only return public constructors. In that case you have to use getClass().getDeclaredConstructor(). The same is true for fields and methods, just for the record.

Upvotes: 4

Related Questions