反射机制

反射机制有什么用?

通过反射机制可以操作代码片段(class文件),可以让程序更加灵活

反射机制的相关类在哪个包下?

java.lang.reflect.*;

反射机制相关的重要的类有哪些?


   java.lang.Class:代表整个字节码文件
   java.lang.reflect.Method:代表字节码中的方法字节码
   java.lang.reflect.Constructor:代表字节码中的构造方法字节码
   java.lang.reflect.Field:代表字节码中的属性字节码,代表类中的成员变量(静态变量 + 实例变量)
   

获取Class的三种方式

第一种方式

	
 public static void main(String[] args) {
        /*
        Class.forName()
            1.静态方法
            2.方法的参数是一个字符串
            3.字符串需要的是一个完整类名
            4.完整类名必须带有包名,java.lang也不能省略
         */
        Class c1 = null;
        Class c2 = null;
        try {
            c1 = Class.forName("java.lang.String"); // c1代表String.class文件,或者说c1代表String类型
            c2 = Class.forName("java.util.Date");// c2代表Date类型
            Class c3 = Class.forName("java.lang.Integer");
            Class c4 = Class.forName("java.lang.System");
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }
    }
	

第二种方式:

 //java中任何一个对象都有一个方法:getClass()
        String s = "abc";
        Class x = s.getClass(); // x代表String.class字节码文件,x代表String类型
        System.out.println(c1 == x);// true( == 判断的是对象的内存地址)

        Date time = new Date();
        Class t = time.getClass();
        System.out.println(t == c2);// true(c2和t中保存的内存地址都是一样的,都指向方法区当中的字节码文件)

第三种方式

//java语言中任何一种类型,他都有.class属性
 Class a = String.class; //a代表String类型
        Class b = Date.class;
        Class c = int.class;
        Class d  = double.class;

        System.out.println(a ==  x); //true

获取Class之后,可以调用无参数构造方法来实例化对象

    public static void main(String[] args) {
        try {
            //  通过反射机制获取Class,通过Class来实例化对象
            Class u = Class.forName("com.cedric.java.been.User");

            // newInstance()这个方法会调用User这个类的无参数构造方法,完成对象的创建
            // 重点:newInstance()调用的是无参构造,必须保证无参构造是存在的
            Object o = u.newInstance();
            System.out.println(o);
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        } catch (InstantiationException e) {
            e.printStackTrace();
        }
    }

注意:newInstance()方法内部实际上调用了无参构造方法,必须保证无参构造存在才可以

如果只想让一个类的“静态代码块”执行的话,可以这样

Class.forName("该类的类名"); 这样类就加载了,类加载的时候静态代码块执行!!

关于路径问题?

 String path = Thread.currentThread().getContextClassLoader().
                  getResourse("写相对路径,但是这个相对路径从src触发开始找").getPath()

    这种方式是为了获取一个文件的绝对路径(通用方式,不会受到环境移植的影响)
    但是该文件要求放在类路径下,也就是放在src下,src是类的根路径

    直接以流的形式返回:
    InputStream in = Thread.currentThread().getContextClassLoader.
                     getResourseAsStream("com/cedric/test.properties");

IO + Properties,怎么快速绑定属性资源文件?

 public static void main(String[] args) {
        try {
            // 代码是灵活的,不需要改动,可以修改配置文件,配置文件修改之后,可以创建出不同的实例对象
            // 通过IO读取classinfo.properties文件
            FileReader read = new FileReader("Reflex/classinfo.properties");
            // 创建属性类对象Map
            Properties pro = new Properties();
            // 加载
            pro.load(read);
            // 关闭
            read.close();
            // 通过key获取value
            String s = pro.getProperty("className");

            // 通过反射机制实例化对象
            Class c = Class.forName(s);
            Object o = c.newInstance();
            System.out.println(o);
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        } catch (InstantiationException e) {
            e.printStackTrace();
        }
    }

Filed

反射Student类中所有的Filed

 public static void main(String[] args) {
        // 获取整个类
        try {
            Class studentClass = Class.forName("com.cedric.java.been.Student");

            //com.cedric.java.been.Student
            String scName = studentClass.getName();
            System.out.println("完整类名:" + scName);

            // 简类名
            String simpleName = studentClass.getSimpleName();
            System.out.println("简类名:" + simpleName);
            // 获取到所有的public修饰的Filed
            Field[] files = studentClass.getFields();
            System.out.println(files.length); // 测试数组中只有一个元素

            // 取出这个Filed
            Field fileds = files[0];
            // 取出这个Field他的名字
            String s = fileds.getName();
            System.out.println(s);


            // 获取所有的Field
            Field[] fs = studentClass.getDeclaredFields();
            System.out.println(fs.length); //4

            System.out.println("====================");

            // 遍历
            for(Field field : fs){
                // 获取属性的修饰符列表
                int i = field.getModifiers(); // 返回的修饰符是一个数字,每一个数字是修饰符的代号
                System.out.println(i);
                // 将代号数字转换成字符串
                String modifierString = Modifier.toString(i);
                System.out.println(modifierString);
                // 获取属性的类型
                Class fieldType = field.getType();
                //String fieldName = fieldType.getName();
                String fieldName = fieldType.getSimpleName();
                System.out.println(fieldName);
                // 获取属性的名字
                System.out.println(field.getName());
            }
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }
    }

反编译

通过反射机制,反编译一个类的属性Field
public static void main(String[] args) {
        try {
            StringBuilder s = new StringBuilder();

            Class studentClass = Class.forName("com.cedric.java.been.Student");

            s.append(Modifier.toString(studentClass.getModifiers()) +  " "  + "class" + " "  + studentClass.getSimpleName() + "{" + '\n');

            Field[] fields = studentClass.getDeclaredFields();
            for(Field field : fields){
                s.append('\t');
                s.append(Modifier.toString(field.getModifiers()));
                s.append(" ");
                s.append(field.getType().getSimpleName());
                s.append(" ");
                s.append(field.getName());
                s.append(";\n");
            }
            s.append("}");
            System.out.println(s);


        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }
    }
反编译Method(反编译一个类的方法)
 public static void main(String[] args) {
        try {
            StringBuilder s = new StringBuilder();
            Class userServiceClass = Class.forName("com.cedric.java.been.UserService");
            s.append(Modifier.toString(userServiceClass.getModifiers()) + "  class  " +userServiceClass.getSimpleName() + "{\n");

            Method[] methods = userServiceClass.getDeclaredMethods();
            for(Method method : methods){
                s.append("\t");
                s.append(Modifier.toString(method.getModifiers()));
                s.append(" ");
                s.append(method.getReturnType().getSimpleName());
                s.append(" ");
                s.append(method.getName());
                s.append("(");
                // 参数列表
                Class[] parameterTypes = method.getParameterTypes();
                for(Class parameterType : parameterTypes){
                    s.append(parameterType.getSimpleName());
                    s.append(",");

                }
                // 删除指定下标位置上的字符
                s.deleteCharAt(s.length() - 1);
                s.append("){}\n");

            }
            s.append("}");
            System.out.println(s);
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }
    }
反编译Constructor
 public static void main(String[] args) {
        StringBuilder s = new StringBuilder();
        try {
            Class vipClass = Class.forName("com.cedric.java.been.Vip");
            s.append(Modifier.toString(vipClass.getModifiers()));
            s.append(" class ");
            s.append(vipClass.getSimpleName());
            s.append("{\n");

            // 拼接构造方法
            Constructor[] constructors = vipClass.getDeclaredConstructors();
            for(Constructor constructor : constructors){
                s.append("\t");
                s.append(Modifier.toString(constructor.getModifiers()));
                s.append(" ");
                s.append(vipClass.getSimpleName());
                s.append("(");
                // 拼接参数
                Class[] parameter = constructor.getParameterTypes();
                for(Class parameterType : parameter){
                    s.append(parameterType.getSimpleName());
                    s.append(",");
                }
                if(parameter.length > 0){
                    // 删除最后下标位置上的字符
                    s.deleteCharAt(s.length() - 1);
                }

                s.append("){}\n");
            }
            s.append("}");
            System.out.println(s);
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }

怎么通过反射机制访问一个java对象的属性?

 // 使用反射机制,怎么去获取一个对象的属性(set get)
            Class studentClass = Class.forName("com.cedric.java.been.Student");
            Object obj = studentClass.newInstance(); // obj就是Student对象(底层调用无参数构造方法)

            // 获取name属性
           Field noFiled =  studentClass.getDeclaredField("name");

           // 给obj对象(Student对象)的name属性赋值
           noFiled.set(obj,"zhangsan"); // 给obj对象的no属性赋值1111

            // 读取属性的值
            System.out.println(noFiled.get(obj));

//打破封装 反射机制访问java私有属性: noField.setAccessible(true);

Method

 // 获取类
            Class userServiceClass = Class.forName("com.cedric.java.been.UserService");
            // 获取所有的Method(包括私有的)
            Method[] methods = userServiceClass.getDeclaredMethods();

            // 遍历Method
            for(Method method : methods){
                // 获取修饰符列表
                System.out.println(Modifier.toString(method.getModifiers()));
                // 获取方法的返回值类型
                Class methodType = method.getReturnType();
                System.out.println(methodType.getSimpleName());
                // 获取方法名
                System.out.println(method.getName());
                // 方法的修饰符列表(一个方法的参数可能会有多个)
                Class[] parameterType = method.getParameterTypes();
                for(Class parameter : parameterType){
                    System.out.println(parameter.getSimpleName());
                }

通过反射机制怎么调用一个对象的方法

  public static void main(String[] args) {
        /*
            要素分析:
                要素1:对象userService
                要素2:login方法名
                要素3:实参列表
                要素4:返回值
             */
        // 使用反射机制来调用一个对象的方法该怎么做
        try {
            Class userServiceClass = Class.forName("com.cedric.java.been.UserService");
            // 创建对象
            Object obj = userServiceClass.newInstance();
            // 获取Method
            Method loginMethod = userServiceClass.getDeclaredMethod("login",String.class,String.class);
            //调用方法
            // 反射机制中最重要的方法

            /*
             四要素:
            loginMethod方法
            obj对象
            “admin”,“123”实参
            retValue返回值
             */
            Object retValue = loginMethod.invoke(obj,"admin","123");
            System.out.println(retValue);

通过反射机制调用构造方法实例化java对象

   try {
            Class c =  Class.forName("com.cedric.java.been.Vip");
            // 调用无参构造
            Object o = c.newInstance();
            System.out.println(o);
            // 调用有参数构造方法
            // 第一步:先获取到这个有参数的构造方法
           Constructor con =  c.getDeclaredConstructor(int.class,String.class,String.class,boolean.class);
           // 第二步,调用构造方法new对象
            Object obj = con.newInstance(110,"Jack","2001-01-01",true);
            System.out.println(obj);

            // 获取无参构造方法
            Constructor con1 = c.getDeclaredConstructor();
            Object obj1 = con1.newInstance();
            System.out.println(obj1);
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
		}

给你一个类,怎么获取这个类的父类,已经实现了哪些接口?

 // String
        try {
            Class stringClass = Class.forName("java.lang.String");

            // 获取String的父类
            Class stringSuper = stringClass.getSuperclass();
            System.out.println(stringSuper);

            //  获取String类实现的所有接口
            Class[] interfaces = stringClass.getInterfaces();
            for(Class in : interfaces){
                System.out.println(in.getName());
            }

        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }

资源绑定器

/*
java.util包下提供了一个资源绑定器,便于获取属性配置文件中的内容
使用以下这种方式的时候,属性配置文件xx.Properties必须放到类路径下
 */
public class ResourceBundleTest {
    public static void main(String[] args) {
        // 资源绑定器,只能绑定xx.Properties文件,并且这个文件必须在类路径下,文件扩展名也必须是Properties
        // 并且在写路径的时候,路径后面的扩展名不能写
        ResourceBundle bundle = ResourceBundle.getBundle("classinfo2");

        String className = bundle.getString("className");
        System.out.println(className);
    }
}
posted @ 2021-08-27 22:27  guided  阅读(34)  评论(0)    收藏  举报