施进超

导航

笔试:通过反射机制访问私有化构造器例子

问题:实例化对象时一定要用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

posted on 2019-06-11 22:48  jinzhaoshi  阅读(218)  评论(0编辑  收藏  举报