![](/img/trans.png)
[英]Is it possible in java to create 'blank' instance of class without no-arg constructor using reflection?
[英]Is it possible to create an instance of nested class using Java Reflection?
代碼示例:
public class Foo
{
public class Bar
{
public void printMesg(String body)
{
System.out.println(body);
}
}
public static void main(String[] args)
{
// Creating new instance of 'Bar' using Class.forname - how?
}
}
是否可以創建類Bar的新實例給它的名字? 我試着用:
Class c = Class.forName("Foo$Bar")
它找到了類,但是當我使用c.newInstance()時它會拋出InstantiationException。
你需要跳過幾個箍才能做到這一點。 首先,您需要使用Class.getConstructor()來查找要調用的Constructor
對象:
返回一個Constructor對象,該對象反映此Class對象所表示的類的指定公共構造函數。 parameterTypes參數是一個Class對象數組,它按聲明的順序標識構造函數的形式參數類型。 如果此Class對象表示在非靜態上下文中聲明的內部類,則形式參數類型包括顯式封閉實例作為第一個參數。
然后使用Constructor.newInstance() :
如果構造函數的聲明類是非靜態上下文中的內部類,則構造函數的第一個參數需要是封閉的實例
如果不首先構造父類,確實不能構造內部類。 它不能存在於父類之外。 在進行反射時,您必須傳遞父類的實例。 嵌套類是static
,它們可以獨立於父類使用,因此也可以在進行反射時使用。
這是一個展示所有東西的SSCCE 。
package mypackage;
import java.lang.reflect.Modifier;
public class Parent {
public static class Nested {
public Nested() {
System.out.println("Nested constructed");
}
}
public class Inner {
public Inner() {
System.out.println("Inner constructed");
}
}
public static void main(String... args) throws Exception {
// Construct nested class the normal way:
Nested nested = new Nested();
// Construct inner class the normal way:
Inner inner = new Parent().new Inner();
// Construct nested class by reflection:
Class.forName("mypackage.Parent$Nested").newInstance();
// Construct inner class by reflection:
Object parent = Class.forName("mypackage.Parent").newInstance();
for (Class<?> cls : parent.getClass().getDeclaredClasses()) {
if (!Modifier.isStatic(cls.getModifiers())) {
// This is an inner class. Pass the parent class in.
cls.getDeclaredConstructor(new Class[] { parent.getClass() }).newInstance(new Object[] { parent });
} else {
// This is a nested class. You can also use it here as follows:
cls.getDeclaredConstructor(new Class[] {}).newInstance(new Object[] {});
}
}
}
}
這應該產生
Nested constructed Inner constructed Nested constructed Inner constructed Nested constructed
快速而臟的代碼:
Foo.Bar.class.getConstructors()[0].newInstance(new Foo());
說明:您必須告訴Bar其封閉的Foo。
是。 請記住,您需要將外部實例提供給內部類。 使用javap
查找構造函數。 您將需要通過java.lang.reflect.Constructor
而不是依賴邪惡的Class.newInstance
。
Compiled from "Foo.java"
public class Foo$Bar extends java.lang.Object{
final Foo this$0;
public Foo$Bar(Foo);
public void printMesg(java.lang.String);
}
javap -c
在構造函數上很有意思,因為(假設-target 1.4
或更高版本,現在是隱式的)在調用超級構造函數之前得到了一個實例字段的賦值(以前是非法的)。
public Foo$Bar(Foo);
Code:
0: aload_0
1: aload_1
2: putfield #1; //Field this$0:LFoo;
5: aload_0
6: invokespecial #2; //Method java/lang/Object."<init>":()V
9: return
其他答案已經解釋了如何做到你想做的事情。
但我想告訴你,你需要這樣做的事實表明你的系統設計有點不對勁。 我建議您在封閉類上需要(非靜態)工廠方法,或者需要將內部類聲明為靜態。
反射地創建(非靜態)內部類實例具有破壞封裝的“氣味”。
這不是完全最優的,但它適用於內部類和內部靜態類的深度。
public <T> T instantiateClass( final Class<T> cls ) throws CustomClassLoadException {
try {
List<Class<?>> toInstantiate = new ArrayList<Class<?>>();
Class<?> parent = cls;
while ( ! Modifier.isStatic( parent.getModifiers() ) && parent.isMemberClass() ) {
toInstantiate.add( parent );
parent = parent.getDeclaringClass();
}
toInstantiate.add( parent );
Collections.reverse( toInstantiate );
List<Object> instantiated = new ArrayList<Object>();
for ( Class<?> current : toInstantiate ) {
if ( instantiated.isEmpty() ) {
instantiated.add( current.newInstance() );
} else {
Constructor<?> c = current.getConstructor( instantiated.get( instantiated.size() - 1 ).getClass() );
instantiated.add( c.newInstance( instantiated.get( instantiated.size() - 1 ) ) );
}
}
return (T) instantiated.get( instantiated.size() - 1 );
} catch ( InstantiationException e ) {
throw new CustomClassLoadException( "Failed to load class.", e );
} catch ( IllegalAccessException e ) {
throw new CustomClassLoadException( "Failed to load class.", e );
} catch ( SecurityException e ) {
throw new CustomClassLoadException( "Failed to load class.", e );
} catch ( NoSuchMethodException e ) {
throw new CustomClassLoadException( "Failed to load class.", e );
} catch ( IllegalArgumentException e ) {
throw new CustomClassLoadException( "Failed to load class.", e );
} catch ( InvocationTargetException e ) {
throw new CustomClassLoadException( "Failed to load class.", e );
}
}
這里是嵌套類(靜態內部)的答案:在我的情況下,我需要通過其完全限定名稱獲取類型
Class.forName(somePackage.innerClass$outerClass).getConstructor().newInstance();
' $ '至關重要!
使用一個圓點,您將獲得類“package.innerClass.outerClass”的ClassNotFoundException。 例外是誤導:-(。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.