是否可以使用 Java 反射创建嵌套类的实例?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/2097982/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Is it possible to create an instance of nested class using Java Reflection?
提问by kars7e
Sample of code:
代码示例:
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?
}
}
Is it possible to create new instance of class Bar giving its name? I tried to use:
是否可以创建类 Bar 的新实例并为其命名?我尝试使用:
Class c = Class.forName("Foo$Bar")
it finds the class, but when i use c.newInstance() it throws InstantiationException.
它找到了类,但是当我使用 c.newInstance() 时它会抛出 InstantiationException。
采纳答案by skaffman
You need to jump through a few hoops to do this. First, you need to use Class.getConstructor()to find the Constructor
object you want to invoke:
你需要跳过几个圈才能做到这一点。首先,您需要使用Class.getConstructor()来查找Constructor
要调用的对象:
Returns a Constructor object that reflects the specified public constructor of the class represented by this Class object. The parameterTypes parameter is an array of Class objects that identify the constructor's formal parameter types, in declared order. If this Class object represents an inner class declared in a non-static context, the formal parameter types include the explicit enclosing instance as the first parameter.
返回一个 Constructor 对象,该对象反映了此 Class 对象表示的类的指定公共构造函数。parameterTypes 参数是一个 Class 对象数组,这些对象按照声明的顺序标识构造函数的形参类型。如果此 Class 对象表示在非静态上下文中声明的内部类,则形参类型包括显式封闭实例作为第一个参数。
And then you use Constructor.newInstance():
然后你使用Constructor.newInstance():
If the constructor's declaring class is an inner class in a non-static context, the first argument to the constructor needs to be the enclosing instance
如果构造函数的声明类是非静态上下文中的内部类,则构造函数的第一个参数需要是封闭实例
回答by Tom Hawtin - tackline
Yes. Remember you need to feed the outer instance to an inner class. Use javap
to find the constructor. You will need to go through java.lang.reflect.Constructor
rather than rely upon the evil Class.newInstance
.
是的。请记住,您需要将外部实例提供给内部类。使用javap
查找构造函数。你需要经历java.lang.reflect.Constructor
而不是依赖邪恶Class.newInstance
。
Compiled from "Foo.java"
public class Foo$Bar extends java.lang.Object{
final Foo thispublic Foo$Bar(Foo);
Code:
0: aload_0
1: aload_1
2: putfield #1; //Field thisFoo.Bar.class.getConstructors()[0].newInstance(new Foo());
:LFoo;
5: aload_0
6: invokespecial #2; //Method java/lang/Object."<init>":()V
9: return
;
public Foo$Bar(Foo);
public void printMesg(java.lang.String);
}
javap -c
is interesting on the constructor because (assuming -target 1.4
or later, now implicit) you get an assignment of an instance field before calling the super constructor (used to be illegal).
javap -c
在构造函数上很有趣,因为(假设-target 1.4
或以后,现在是隐式的)在调用超级构造函数之前你得到了一个实例字段的赋值(过去是非法的)。
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[] {});
}
}
}
}
回答by meriton
Quick and dirty code:
快速而肮脏的代码:
Nested constructed Inner constructed Nested constructed Inner constructed Nested constructed
Explanation: You must tell the Bar about its enclosing Foo.
说明:您必须将其封闭的 Foo 告诉 Bar。
回答by BalusC
Inner classes can indeed not be constructed without constructing the parent class first. It cannot exist outside the parent class. You'll have to pass an instance of the parent class in when doing reflection. Nested classes are static
and they can be used independently from the parent class, thus also when doing reflection.
如果不先构造父类,确实无法构造内部类。它不能存在于父类之外。在进行反射时,您必须传入父类的一个实例。嵌套类是static
并且它们可以独立于父类使用,因此也可以在进行反射时使用。
Here's an SSCCEwhich demonstrates all the stuff.
这是一个展示所有内容的SSCCE。
Class.forName(somePackage.innerClass$outerClass).getConstructor().newInstance();
This should produce
这应该产生
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 );
}
}
回答by Stephen C
Other answers have explained how you can to what you want to do.
其他答案已经解释了如何去做你想做的事。
But I want to suggest to you that the fact that you need to do this at all is an indication that there is something a bit wrong with your system design. I would suggest that you either need a (non-static) factory method on the enclosing class, or you need to declare the inner class as static.
但是我想向您建议,您完全需要这样做的事实表明您的系统设计存在一些问题。我建议您在封闭类上需要一个(非静态)工厂方法,或者您需要将内部类声明为静态。
Creating a (non-static) inner class instance reflectively has a "smell" of broken encapsulation.
反射性地创建(非静态)内部类实例具有封装破坏的“气味”。
回答by dermoritz
Here a answer for nested class (static inner): In my case i need to acquire the type by its fully qualified name
这是嵌套类(静态内部)的答案:在我的情况下,我需要通过其完全限定名称获取类型
##代码##the '$' is crucial!
' $' 至关重要!
with a dot you'll get ClassNotFoundException for class "package.innerClass.outerClass". The exception is missleading :-(.
用一个点,你会得到 ClassNotFoundException 类“package.innerClass.outerClass”。例外是误导:-(。
回答by mrswadge
This isn't entirely optimal, but it works for depths of inner classes and inner static classes.
这不是完全最优的,但它适用于内部类和内部静态类的深度。
##代码##