java反射学习

java反射机制的核心是在程序运行时动态的加载类并获取类的详细信息,从而操作类或对象的属性和方法。
java反射机制可以绕过java封装、直接调用私有属性的类或者方法

反射类的三种方法:
1、Class xxx = 类名.class,当表示类类型的时候Class需要大写
2、使用getClass()方法、需要已知该类的对象
3、使用forName(类的全称)方法、在使用forName方法时需要包含在try{}catch(){}异常处理中进行使用
public class Phone {
    //属性
    String screen = "qwer";
    int cpu;
    //方法
    public void method01(){
        System.out.println("第一个公有方法");
    }
    private void method02(){
        System.out.println("第二个私有方法");
    }

    public static void main(String[] args) {
        //获取类类型(Class对象)
        //第一个表达式
        Class c1 = Phone.class;
        //第二个表达方式,已知该类的对象
        Phone phone = new Phone();
        Class c2 = phone.getClass();
        //第三个表达式
        //Class c3 = null;
        try {
           Class<?> c3 = Class.forName("Phone");
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }
    }
}
如果直接使用forName()方法,会报一个未处理的错误、需要添加到try/catch异常处理中
public class Phone {
    //属性
    String screen = "qwer";
    int cpu;
    //方法
    public void method01(){
        System.out.println("第一个公有方法");
    }
    private void method02(){
        System.out.println("第二个私有方法");
    }

    public static void main(String[] args) {
        //第三个表达式
        Class c3 = null;
        c3 = Class.forName("Phone");	//在这里forName()会报错,需要写到异常处理方法内、参数为类的全称
    }
}
在IDEA中我们可以选中forName()方法,然后使用Ctrl+Alt+T,选中try/catch
添加一个异常处理方法,就可以正常使用了。

实例化对象:
newinstance()实例化对象,它生成的对象只能反射无参的构造函数
Constructor.newinstance()可以反射所有构造函数,包括私有的
//实例化类的对象
        //第一个表达式
        try {
            Phone.class.newInstance();
        } catch (InstantiationException e) {
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        }
        //第二个表达式
        try {
            Class.forName("Phone").newInstance();
        } catch (InstantiationException e) {
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }
        //第三个表达式
        try {
            Phone.class.getConstructor().newInstance();
        } catch (InstantiationException e) {
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        } catch (InvocationTargetException e) {
            e.printStackTrace();
        } catch (NoSuchMethodException e) {
            e.printStackTrace();
        }
方法:
Method类,方法的对象,一个成员方法就是一个Method对象
getMethods()方法获取的是所有的public,包括父类继承的,不能获取私有方法
getDeclaredMethods()获取的是所有该类自己声明的方法,无视访问权限
invoke执行方法
如果这个方法是普通方法,那么第一个参数时类对象
如果这个方法是静态方法,那么第一个参数时类
//调用方法
        try {
            //获取方法
            Method m1 = c2.getDeclaredMethod("method02");
            //执行方法
            try {
                m1.invoke(c2.newInstance());
            } catch (IllegalAccessException e) {
                e.printStackTrace();
            } catch (InvocationTargetException e) {
                e.printStackTrace();
            } catch (InstantiationException e) {
                e.printStackTrace();
            }
        } catch (NoSuchMethodException e) {
            e.printStackTrace();
        }

        try {
                Method m2 = c2.getMethod("method01");
            try {
                m2.invoke(c2.newInstance());
            } catch (IllegalAccessException e) {
                e.printStackTrace();
            } catch (InvocationTargetException e) {
                e.printStackTrace();
            } catch (InstantiationException e) {
                e.printStackTrace();
            }
        } catch (NoSuchMethodException e) {
                e.printStackTrace();
        }
属性(成员变量):
getFields()方法获取的是所有的Public的成员变量的信息
getDeclaredFields()获取的是该类所有声明的成员变量信息
//获取类的属性(成员变量)的信息
        //getFields()方法获取的是所有的Public的成员变量的信息
        Field[] fs01 = c1.getFields();
        for (Field field : fs01){
            //成员变量的类型的类类型
            Class fieldType = field.getType();
            String typeName = fieldType.getName();
            //成员变量的名称
            String fieldName = field.getName();
            System.out.println(typeName+" "+fieldName);
        }

        //getDeclaredFields()获取的是该类所有声明的成员变量信息
        Field[] fs02 = c1.getDeclaredFields();
        for (Field field:fs02){
            //得到成员变量的类型的类类型
            Class fieldType = field.getType();
            String typeName = fieldType.getName();
            //得到成员变量的名称
            String fieldName = field.getName();
            System.out.println(typeName+" "+fieldName);
        }
从结果可以看出,getFields()只能获取到类的公开的成员变量信息
getDeclaredFields()可以获取该类所有声明的成员变量信息


实例:
通过反射调用java.lang.runtime类,并执行系统命令。
一开始是这么写的,出现错误说是java.lang为私有属性、不可以访问。
原因是Runtime类的构造器是私有修饰的,无法直接获取runtime类的实例,只能通过getRuntime()方法来间接获取一个Runtime类的实例
运行一下,可以成功执行命令打开记事本
但是当我们执行cmd命令时无法打开cmd窗口
网上存在一些方法,可以解决这个问题。测试了一下发现只能执行dir命令,执行其他命令运行完成后cmd窗口会闪退,但是不影响程序的运行。
我们可以直接使用echo函数写入一个文件
当我们需要运行一个应用程序的时候,需要在写入这个程序的绝对路径
如果该应用程序添加了环境变量或者在system32目录下,则不用写入绝对路径
这样就可以直接打开远程桌面程序。
原文地址:https://www.cnblogs.com/Excellent-person/p/14021917.html