文档

Java™ 教程
隐藏目录
创建新的类实例
路径: 反射API
课程: 成员
章节: 构造函数

创建新的类实例

创建类的实例有两种反射方法:java.lang.reflect.Constructor.newInstance()Class.newInstance()。前者是首选,并且在这些示例中使用,原因如下:

有时候,可能希望从构造后才设置的对象中检索内部状态。考虑一个需要获取java.io.Console使用的内部字符集的场景。(Console字符集存储在一个私有字段中,并且不一定与java.nio.charset.Charset.defaultCharset()返回的Java虚拟机默认字符集相同)。ConsoleCharset示例展示了如何实现这一目标:

import java.io.Console;
import java.nio.charset.Charset;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import static java.lang.System.out;

public class ConsoleCharset {
    public static void main(String... args) {
	Constructor[] ctors = Console.class.getDeclaredConstructors();
	Constructor ctor = null;
	for (int i = 0; i < ctors.length; i++) {
	    ctor = ctors[i];
	    if (ctor.getGenericParameterTypes().length == 0)
		break;
	}

	try {
	    ctor.setAccessible(true);
 	    Console c = (Console)ctor.newInstance();
	    Field f = c.getClass().getDeclaredField("cs");
	    f.setAccessible(true);
	    out.format("控制台字符集          :  %s%n", f.get(c));
	    out.format("默认字符集            :  %s%n",
		       Charset.defaultCharset());

        // 正式代码应更优雅地处理这些异常
	} catch (InstantiationException x) {
	    x.printStackTrace();
 	} catch (InvocationTargetException x) {
 	    x.printStackTrace();
	} catch (IllegalAccessException x) {
	    x.printStackTrace();
	} catch (NoSuchFieldException x) {
	    x.printStackTrace();
	}
    }
}

注意: 

Class.newInstance()只能在构造函数没有参数且已经可访问时成功。否则,必须像上面的示例中使用Constructor.newInstance()


UNIX系统的示例输出:

$ java ConsoleCharset
控制台字符集          :  ISO-8859-1
默认字符集            :  ISO-8859-1

Windows系统的示例输出:

C:\> java ConsoleCharset
控制台字符集          :  IBM437
默认字符集            :  windows-1252

Constructor.newInstance()的另一个常见应用是调用带有参数的构造函数。"RestoreAliases"示例找到特定的单参数构造函数并调用它:

import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;
import static java.lang.System.out;

class EmailAliases {
    private Set<String> aliases;
    private EmailAliases(HashMap<String, String> h) {
	aliases = h.keySet();
    }

    public void printKeys() {
	out.format("邮件键:%n");
	for (String k : aliases)
	    out.format("  %s%n", k);
    }
}

public class RestoreAliases {

    private static Map<String, String> defaultAliases = new HashMap<String, String>();
    static {
	defaultAliases.put("Duke", "duke@i-love-java");
	defaultAliases.put("Fang", "fang@evil-jealous-twin");
    }

    public static void main(String... args) {
	try {
	    Constructor ctor = EmailAliases.class.getDeclaredConstructor(HashMap.class);
	    ctor.setAccessible(true);
	    EmailAliases email = (EmailAliases)ctor.newInstance(defaultAliases);
	    email.printKeys();

        // 生产代码应该更优雅地处理这些异常
	} catch (InstantiationException x) {
	    x.printStackTrace();
	} catch (IllegalAccessException x) {
	    x.printStackTrace();
	} catch (InvocationTargetException x) {
	    x.printStackTrace();
	} catch (NoSuchMethodException x) {
	    x.printStackTrace();
	}
    }
}

这个例子使用Class.getDeclaredConstructor()来查找具有单个参数类型为java.util.HashMap的构造函数。请注意,只需要传递HashMap.class,因为get*Constructor()方法的参数只需要类型即可。由于类型擦除,以下表达式将评估为true

HashMap.class == defaultAliases.getClass()

例子然后使用此构造函数使用Constructor.newInstance()创建类的新实例。

$ java RestoreAliases
邮件键:
  Duke
  Fang

上一页: 检索和解析构造函数修饰符
下一页: 故障排除