26. januar 2009 - 01:23Der er
11 kommentarer og 1 løsning
subtilt newInstance() problem ved anonyme klasser.
Hej,
Jeg har et problem ved brugen af newInstance og anonyme klasser. Hvis jeg opretter den anonyme klasse i den statiske main funktion, finder dens Class (vha. getClass()) og derefter kalder newInstance på den er der ingen problemer. Hvis jeg til gengæld opretter et object først, kalder en metode på dette objekt, hvori jeg opretter en anonym klasse og gentager samme procedure, får jeg en InstantiationException. Noget kode til at demonstrere det:
public class Tester { public static void main(String[] main) { //Dette virker fint, ingen problemer Object scriptss = new Object() { }; Class pp = scriptss.getClass();
Object ss = null; try { ss = pp.newInstance(); System.out.println("Dette virker fint. Ingen problemer."); } catch (InstantiationException e) { e.printStackTrace(); } catch (IllegalAccessException e) { e.printStackTrace(); } catch (IllegalArgumentException e) { e.printStackTrace(); } catch (SecurityException e) { e.printStackTrace(); } //Her faar vi et problem, da vi nu oprettet et objekt. Tester ll = new Tester(); ll.foo(); }
public void foo() { Object scriptss = new Object() { }; Class pp = scriptss.getClass();
Object ss = null; try { ss = pp.newInstance(); System.out.println("Saa langt kommer vi dog ikke, for newInstance raiser en InstantiationException."); } catch (InstantiationException e) { e.printStackTrace(); } catch (IllegalAccessException e) { e.printStackTrace(); } catch (IllegalArgumentException e) { e.printStackTrace(); } catch (SecurityException e) { e.printStackTrace(); } }
}
Nogen, som har en forklaring? Og hvordan man kommer forbi det?
public class Tester2 { public static class Foo { } public class Bar { } public static void main(String[] main) { //Dette virker fint, ingen problemer Object scriptss = new Foo(); Class pp = scriptss.getClass();
Object ss = null; try { ss = pp.newInstance(); System.out.println("Dette virker fint. Ingen problemer."); } catch (InstantiationException e) { e.printStackTrace(); } catch (IllegalAccessException e) { e.printStackTrace(); } catch (IllegalArgumentException e) { e.printStackTrace(); } catch (SecurityException e) { e.printStackTrace(); } //Her faar vi et problem, da vi nu oprettet et objekt. Tester2 ll = new Tester2(); ll.foo(); }
public void foo() { Object scriptss = new Bar(); Class pp = scriptss.getClass();
Object ss = null; try { ss = pp.newInstance(); System.out.println("Saa langt kommer vi dog ikke, for newInstance raiser en InstantiationException."); } catch (InstantiationException e) { e.printStackTrace(); } catch (IllegalAccessException e) { e.printStackTrace(); } catch (IllegalArgumentException e) { e.printStackTrace(); } catch (SecurityException e) { e.printStackTrace(); } }
public class Tester3 { public static void main(String[] main) { //Dette virker fint, ingen problemer Object scriptss = new Object() { }; Class pp = scriptss.getClass();
Object ss = null; try { ss = pp.newInstance(); System.out.println("Dette virker fint. Ingen problemer."); } catch (InstantiationException e) { e.printStackTrace(); } catch (IllegalAccessException e) { e.printStackTrace(); } catch (IllegalArgumentException e) { e.printStackTrace(); } catch (SecurityException e) { e.printStackTrace(); } //Her faar vi et problem, da vi nu oprettet et objekt. Tester3 ll = new Tester3(); ll.foo(); }
public void foo() { Object scriptss = new Object() { }; Class pp = scriptss.getClass();
Object ss = null; try { Constructor m = pp.getDeclaredConstructor(new Class[] { Tester3.class }); ss = m.newInstance(new Object[] { this }); System.out.println("Saa langt kommer vi dog ikke, for newInstance raiser en InstantiationException."); } catch (InstantiationException e) { e.printStackTrace(); } catch (IllegalAccessException e) { e.printStackTrace(); } catch (IllegalArgumentException e) { e.printStackTrace(); } catch (SecurityException e) { e.printStackTrace(); } catch (NoSuchMethodException e) { e.printStackTrace(); } catch (InvocationTargetException e) { e.printStackTrace(); } }
Okay, så det virker tilsyneladende som om at ved instantieringen af en non-static inner class, skal den omgivende klasse/objekt med som argument. Giver mening når man tænker på closures. Tester lige om din løsning virker.
Det virker, gider du smide et svar. I tilfælde af at andre er min i situation, hvor classen skal instantieres et sted i koden, hvor man ikke "ved" hvilke klasse, som var den ydre klasse, kan man bruge det følgende: import java.lang.reflect.Constructor; import java.lang.reflect.InvocationTargetException;
public class Tester { public static void main(String[] main) { //Dette virker fint, ingen problemer Object scriptss = new Object() { }; Class pp = scriptss.getClass();
Hov, jeg var for hurtig der. Koden skulle ha' været: import java.lang.reflect.Constructor; import java.lang.reflect.InvocationTargetException;
public class Tester { public static void main(String[] main) { //Dette virker fint, ingen problemer Object scriptss = new Object() { }; Class pp = scriptss.getClass();
Det er rigtigt at du mister den statiske typecheckning, men der er dog visse tilfælde hvor du ikke kan komme udenom. F.eks. i mit tilfælde, hvor jeg vil dynamisk instantierer Java klasser, som implementerer et bestemt interface. Disse klasser kan både være almindelige, indre og anonyme klasser. Som jeg ser det er der ingen vej udenom end koden ovenfor.
En lille ting mere til løsningen: hvis den anonyme klasse og klassen som instantierer den ligger i 2 forskellige pakker, virker ovenstående kode ikke (man får en IllegalAccessException), da anonyme klasser pr. default er package private. Det kan ændres vha. flg. kode:
if (!Modifier.PUBLIC.equals(m.getModifiers())) Constructor.setAccessible(new AccessibleObject[] {m}, true);
Man ændrer simpelthen access niveauet på constructoren til public. Grimt, men virker.
Tilladte BB-code-tags: [b]fed[/b] [i]kursiv[/i] [u]understreget[/u] Web- og emailadresser omdannes automatisk til links. Der sættes "nofollow" på alle links.