问题:实例化对象时一定要用new调用构造方法吗?
答案:用普通的创建方法(new)是要调用构造方法,如果使用反射或者克隆这些就可以绕过构造函数直接创建对象
实例:
/*
* ClassTest.java -- JDK 1.8
*/
package T20190328;
import java.io.File;
import java.io.IOException;
import java.lang.reflect.AccessibleObject;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Type;
import java.util.ArrayList;
import java.util.List;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import org.junit.Test;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import org.xml.sax.SAXException;
/**
* Description:
* <p>
* 通过反射访问私有构造方法 例如:
*
* <pre>
* <code>
* // 1.获取类A中声明的构造器
* Class clazz = Class.forName("T20190328.A");
* Constructor constructor = clazz.getDeclaredConstructor(); // 假设A中只有一个私有构造方法
* // 2.设置私有访问权限
* constructor.setAccessible(true);
* constructor.newInstance();
* </code>
* </pre>
* <p>
* @author shuvidora
* @date 2019-03-28 Thu PM 14:22:07
*/
public class ClassTest {
static List<A> list = new ArrayList<A>();
@SuppressWarnings("unchecked")
public static <T> T[] cast(Object[] obj) {
return (T[]) obj;
}
public static void showTypes(Type[] arr) {
int len = arr.length;
if (len == 0) {
System.out.print("无元素");
return;
}
for (int i = 0; i < len; i++) {
if (i == 0)
System.out.print("(");
if (i == len - 1)
System.out.print(arr[i] + ")");
else
System.out.print(arr[i] + ",");
}
}
@SuppressWarnings("unchecked")
@Test
public void test()
throws InstantiationException, IllegalAccessException, IllegalArgumentException, InvocationTargetException {
Constructor<A> constructor = null;
try {
constructor = (Constructor<A>) Class.forName("T20190328.A")
.getDeclaredConstructor(String.class, String.class);
} catch (NoSuchMethodException e) {
e.printStackTrace();
} catch (SecurityException e) {
e.printStackTrace();
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
constructor.setAccessible(true);
constructor.newInstance("x", "y");
}
String clsPathFromXml() throws ParserConfigurationException, SAXException, IOException {
DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance(); // 创建DOM解析器工厂对象
DocumentBuilder builder = factory.newDocumentBuilder(); // 创建DOM解析器对象
String path = this.getClass().getResource("om.xml").getPath();
Document doc = builder.parse(new File(path)); // 解析XML文档,并获取该XML文档的Document对象
Element component = doc.getDocumentElement(); // 获取根节点元素的Element对象
NodeList nodeList = component.getElementsByTagName("package");
Node pkg = nodeList.item(0);
Node pkgAttr = pkg.getAttributes()
.getNamedItem("name");
String pkgName = pkgAttr.getNodeValue();
Node cls = pkg.getFirstChild();
String clsName = cls.getNodeValue();
return pkgName + "." + clsName;
}
@Test
public void testXml() {
try {
System.out.println(clsPathFromXml());
} catch (ParserConfigurationException | SAXException | IOException e) {
e.printStackTrace();
}
}
public static void main(String[] args) {
String className = null;
ClassTest ct = new ClassTest();
try {
className =ct.clsPathFromXml();
} catch (ParserConfigurationException | SAXException | IOException e1) {
e1.printStackTrace();
}
Constructor<A>[] constructors = null;
try {
constructors = cast(Class.forName(className) // 从类路径下加载并连接类T20190328.A
.getDeclaredConstructors());
} catch (SecurityException | ClassNotFoundException e) {
e.printStackTrace();
}
AccessibleObject.setAccessible(constructors, true); // 批量授予访问私有访问权限
// 按类中定义的顺序输出构造器
for (int i = 0; i < constructors.length; i++) {
Constructor<A> constructor = constructors[i];
System.out.print(constructor + "--->");
// 构造器参数全部类型
Type[] types = constructor.getGenericParameterTypes();
int typeNum = types.length;
showTypes(types);
System.out.print("===>");
// constructor.setAccessible(true); // 允许私有访问权限, 否则无法实例化对象
// 实例化对象
A a;
try {
if (typeNum == 1) {
a = (A) constructor.newInstance(1);
a.b();
} else if (typeNum == 2) {
a = (A) constructor.newInstance("hello", "world");
a.b();
} else {
a = (A) constructor.newInstance();
a.b();
}
list.add(a);
} catch (InstantiationException | IllegalAccessException | IllegalArgumentException
| InvocationTargetException e) {
e.printStackTrace();
}
}
// 打印生成对象的内存地址哈希值
for (A a : list) {
System.out.println(a);
}
}
}
class A extends B {
private A(String x, String y) {
System.out.println("has two params : " + x + "," + y);
}
private A(int i) {
System.out.println("has one param : " + i);
}
private A() {
System.out.println("has zero param");
}
// private A(String... strings) {
// System.out.println(strings);
// }
public void a() {
System.out.println("A");
}
}
class B {
String name;
int age;
public void b() {
System.out.println("B");
}
}
om.xml
<?xml version="1.0" encoding="UTF-8"?>
<component>
<package name="T20190328">
<class>A </class>
</package>
</component>
问题来源:
https://www.nowcoder.com/questionTerminal/a3f14638ac2e432b884351840f42d80f?toCommentId=1111154