代码示例:
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。
答案 0 :(得分:54)
你需要跳过几个箍才能做到这一点。首先,您需要使用Class.getConstructor()来查找要调用的Constructor
对象:
返回一个Constructor对象 反映了指定的公众 代表的类的构造函数 通过这个Class对象。该 parameterTypes参数是一个数组 标识的类对象 构造函数的形式参数类型, 按声明的顺序。 如果这个班级 object表示内部类 在非静态上下文中声明的 形式参数类型包括 显式封闭实例作为 第一个参数。
然后你使用Constructor.newInstance():
如果构造函数声明了类 是一个非静态的内部类 上下文,第一个参数 构造函数需要是封闭的 实例
答案 1 :(得分:25)
如果不首先构造父类,确实不能构造内部类。它不能存在于父类之外。在进行反射时,您必须传递父类的实例。嵌套类是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
答案 2 :(得分:7)
快速而肮脏的代码:
Foo.Bar.class.getConstructors()[0].newInstance(new Foo());
说明:您必须告诉Bar其封闭的Foo。
答案 3 :(得分:2)
是。请记住,您需要将外部实例提供给内部类。使用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
答案 4 :(得分:1)
其他答案已经解释了如何做到你想做的事情。
但是我想告诉你,你需要这样做的事实表明你的系统设计有点不对劲。我建议您在封闭类上需要(非静态)工厂方法,或者需要将内部类声明为静态。
反射地创建(非静态)内部类实例具有破坏封装的“气味”。
答案 5 :(得分:0)
这不是完全最优的,但它适用于内部类和内部静态类的深度。
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 );
}
}
答案 6 :(得分:-1)
这里是嵌套类(静态内部)的答案: 在我的情况下,我需要通过其完全限定名称获取类型
Class.forName(somePackage.innerClass$outerClass).getConstructor().newInstance();
' $ '至关重要!
使用点,您将获得类“package.innerClass.outerClass”的ClassNotFoundException。例外是误导: - (。