反射机制

Posted xiaokw

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了反射机制相关的知识,希望对你有一定的参考价值。

反射机制的相关类

  • java.lang.reflect.*
  • java.lang.Class
    • 代表整个字节码,代表一个类型
  • java.lang.reflect.Method
    • 代表字节码中的方法字节码
  • java.lang.reflect.Constructor
    • 代表字节码中的构造方法字节码
  • java.lang.reflect.Field
    • 代表字节码中的属性字节

获取类字节码的三种方式

  • 第一种:Class c = Class.forName("完整的类名带包名,如:java.lang.String");
  • 第二种:Class c = 对象.getClass();
  • 第三种:Class c = 任何类型.class;
package cn.xiaokw.java.reflect;
public class Demo_1 {
    public static void main(String[] args) {
        //第一种方式
        Class c1 = null;
        Class c2 = null;
        Class c3 = null;
        try {
            c1 = Class.forName("java.lang.String");
            c2 = Class.forName("java.util.Date");
            c3 = Class.forName("java.lang.Integer");
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }
        //第二种方式
        String str = "abc";
        Class x = str.getClass();
        Date date = new Date();
        Class y = date.getClass();
        Integer integer = 10;
        Class z = integer.getClass();

        System.out.println(x == c1); //true
        System.out.println(y == c2); //true
        System.out.println(z == c3); //true
        //第三种方式
        Class a = String.class;
        Class b = Date.class;
        Class c = int.class;
        Class d = double.class;

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

获取到Class,能干什么

通过Class的newInstance()方法来实例化对象。

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

package cn.xiaokw.java.reflect;
public class Demo_2 {
    public static void main(String[] args) {
        try {
            Class c = Class.forName("cn.xiaokw.java.reflect.User");//同样可用 Class c = User.class;
            //newInstance() 这个方法是调用User这个类的无参构造方法,完成对象的创建
            //重点是:newInstance()调用的是无参构造,必须保证无参构造是存在的!
            User user = (User) c.newInstance();
            System.out.println(user.a); //abc
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        } catch (InstantiationException e) {
            e.printStackTrace();
        }
    }
}
class User {
    String a = "abc";
    User(){
        System.out.println("这里是无参构造方法");
    }
}

反射机制的灵活性

技术图片

package cn.xiaokw.java.reflect;
public class Demo_3 {
    public static void main(String[] args) throws Exception{
        FileReader reader = new FileReader("src\\cn\\xiaokw\\java\\reflect\\classinfo.properties");
        //Properties是一个Map集合,key和value都是String类型
        //通过使用Properties将classinfo.properties文件加载到Peroperties对象当中
        Properties properties = new Properties();
        //加载
        properties.load(reader);
        //关闭流
        reader.close();
        String className = properties.getProperty("className");//对应classinfo.properties文件中的key来获取value
        Class c = Class.forName(className);
        Object obj = c.newInstance();
        System.out.println(obj); //Tue Jun 30 11:47:57 CST 2020
    }
}

Class.forName()发生了什么

重点

? 如果你只是希望一个类的静态代码块执行,其他代码一律不执行

? 你可以使用:

? Class.forName("完整类名");

? 这个方法的执行会导致类加载,类加载时,静态代码块执行

package cn.xiaokw.java.reflect;
public class Demo_4 {
    public static void main(String[] args) {
        try {
            Class.forName("cn.xiaokw.java.reflect.MyClass"); //MyClass类中的静态代码块执行了....
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }

    }
}
class MyClass {
    static {
        System.out.println("MyClass类中的静态代码块执行了....");
    }
}

获取文件的绝对路径

package cn.xiaokw.java.util;
/*
    获取类根路径下文件的绝对路径
    适用于Windows Linux
 */
public class AbsolutePath {
    public static void main(String[] args) {
        //采用以下的代码可以拿到一个文件的绝对路径
        //从类的根路径(src)下作为起点开始
        String path = Thread.currentThread().getContextClassLoader()
                .getResource("cn/xiaokw/java/util/userinfo").getPath();
        /*
        解释:
            Thread.currentThread()  当前线程对象
            getContextClassLoader() 是线程对象的方法,可以获取到当前类加载器的对象。
            getResource()   [获取资源] 这是类加载器对象的方法,当前线程的类加载器默认从类的根路径下加载资源
         */
        System.out.println(path);
        ///C:/Users/20131/IdeaProjects/StudyJava/out/production/StudyJava/cn/xiaokw/java/util/userinfo
    }
}

以流的形式返回

InputStream is = Thread.currentThread().getContextClassLoader().getResourceAsStream("cn/xiaokw/java/reflect/classinfo.properties");
package cn.xiaokw.java.reflect;
import java.io.IOException;
import java.io.InputStream;
import java.util.Properties;

public class Demo_5 {
    public static void main(String[] args) throws IOException {
        //以流的形式返回,前提是需要把文件放在src类的根目录下
        InputStream is = Thread.currentThread().getContextClassLoader()
                .getResourceAsStream("cn/xiaokw/java/reflect/classinfo.properties");
        Properties properties = new Properties();
        properties.load(is);
        String className = properties.getProperty("className");
        System.out.println(className);
    }
}

资源绑定器

资源绑定器:只能绑定xxx.properties文件。并且这个文件必须在类src路径下。文件扩展名必须是properties

并且在写路径的时候,路径后面的扩展名不能写

package cn.xiaokw.java.reflect;
import java.util.ResourceBundle;
public class Demo_6 {
    public static void main(String[] args) {
        ResourceBundle bundle = ResourceBundle.getBundle("cn/xiaokw/java/reflect/classinfo");

        String className = bundle.getString("className");
        System.out.println(className);
    }
}

获取类的父类和父接口

package cn.xiaokw.java.reflect;

public class Demo_13 {
    public static void main(String[] args) throws Exception{
        Class myClass = Class.forName("java.lang.String");

        //获取String类的父类
        Class superclass = myClass.getSuperclass();
        System.out.println(superclass.getSimpleName());

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

属性 Field

获取Field(属性)

package cn.xiaokw.java.reflect;

import java.lang.reflect.Field;
import java.lang.reflect.Modifier;
import java.util.Date;

public class Demo_7 {
    public static void main(String[] args) throws Exception {
        //获取整个类
        Class c = Class.forName("cn.xiaokw.java.reflect.Student");
        //获取类中的所有Field(属性)
//        Field[] fields = c.getFields(); //getFields()方法只能获取public修饰的属性
        Field[] fields = c.getDeclaredFields(); // 获取全部属性
        //获取类的名字
//        String StudentName = c.getName(); //获取的完整名字 cn.xiaokw.java.reflect.Student
        String StudentName = c.getSimpleName(); //获取的简名字 Student
        System.out.println(StudentName + "中有" + fields.length + "个属性");
        System.out.println("-----------------------------");
        for (Field f : fields) {
            //获取属性的修饰符
            int fModifiers = f.getModifiers();//获取对应修饰符的代号
            String modifiers = Modifier.toString(fModifiers); //实现代码转修饰符字符串
            System.out.print(modifiers + "	");
            
            //获取属性的类型 如:int String double...
            Class fieldType = f.getType();
//            String fileTypeName = fieldType.getName(); //java.lang.String int java.util.Date...
            String fileTypeName = fieldType.getSimpleName(); //获取类型简单名称
            System.out.print(fileTypeName + "	");

            //获取属性的名称
            String fieldName = f.getName();
            System.out.print(fieldName);
            System.out.println();
        }
    }
}

class Student {
    private String name;
    public int age;
    protected Date birthday;
    String sex;
    public final static double PI = 3.14159265;
}

执行结果

Student中有5个属性
---------------------------
private	String	name
public	int	age
protected	Date	birthday
	String	sex
public static final	double	PI

利用反射机制,反编译一个类的属性

package cn.xiaokw.java.reflect;

import java.lang.reflect.Field;
import java.lang.reflect.Modifier;
import java.util.Date;

public class Demo_7_1 {
    public static void main(String[] args) throws Exception {
        StringBuilder sb = new StringBuilder();
        Class person = Class.forName("cn.xiaokw.java.reflect.Person");
        sb.append(Modifier.toString(person.getModifiers()) + " class " + person.getSimpleName() + "{
");
        Field[] fields = person.getDeclaredFields();
        for (Field field : fields) {
            sb.append("	");
            sb.append(Modifier.toString(field.getModifiers())); //获取属性的修饰符
            sb.append(" ");
            sb.append(field.getType().getSimpleName()); //获取属性的类型
            sb.append(" ");
            sb.append(field.getName()); //获取属性的名字
            sb.append(";
");
        }
        sb.append("}");
        System.out.println(sb);
    }
}

class Person {
    private String name;
    private String sex;
    private int age;
    private Date birthday;
}

输出结果

 class Person{
	private String name;
	private String sex;
	private int age;
	private Date birthday;
}

反射机制访问对象属性,给属性赋值

package cn.xiaokw.java.reflect;

import java.lang.reflect.Field;
import java.util.Date;

public class Demo_8 {
    public static void main(String[] args) throws Exception{
        Class person = Class.forName("cn.xiaokw.java.reflect.Person1");
        Object obj = person.newInstance();
        Field field = person.getDeclaredField("name");//获取name属性 无法获取private私有属性
//        field.setAccessible(true); //如果是private私有属性则加上这句“打破封装”,缺点,这样设置完后,在外部也是可以访问private的
        field.set(obj , "张三"); //给obj对象中name属性赋值
        System.out.println(field.get(obj)); //获取obj中name的值 输出:张三
    }
}
class Person1 {
    public String name;
    public String sex;
    public int age;
    public Date birthday;
}

方法 Method

反射Method

package cn.xiaokw.java.reflect;

import java.lang.reflect.Method;
import java.lang.reflect.Modifier;

public class Demo_9 {
    public static void main(String[] args) throws Exception {
        Class myClass = Class.forName("cn.xiaokw.java.reflect.MyClass1");
        Method[] methods = myClass.getDeclaredMethods(); //获取类的全部方法
        for (Method method : methods) {
            //获取方法的修饰符
            int modifiers = method.getModifiers();
            String s = Modifier.toString(modifiers);
            System.out.print(s + " ");
            //获取方法的返回类型
            Class returnType = method.getReturnType();
            String simpleName = returnType.getSimpleName();
            System.out.print(simpleName + " ");
            //获取方法名
            String name = method.getName();
            System.out.print(name + "(");
            //获取方法的参数列表
            //获取方法的参数列表类型
            Class[] parameterTypes = method.getParameterTypes();
            for (Class c : parameterTypes) {
                System.out.print(c.getSimpleName() + " ");
            }
            System.out.println(")");
        }
    }
}

class MyClass1 {
    public boolean method1(String a, int b) {
        return true;
    }

    public void method2() {
        System.out.println("method2");
    }
}

反编译Method

package cn.xiaokw.java.reflect;

import java.lang.reflect.Method;
import java.lang.reflect.Modifier;

public class Demo_9_1 {
    public static void main(String[] args) throws Exception {
        StringBuilder sb = new StringBuilder();
        Class myClass = Class.forName("cn.xiaokw.java.reflect.MyClass1");
        Method[] methods = myClass.getDeclaredMethods(); //获取类的全部方法
        sb.append(Modifier.toString(myClass.getModifiers()) + " class " + myClass.getSimpleName() + "{
");

        for (Method method : methods) {
            sb.append("	");
            sb.append(Modifier.toString(method.getModifiers())); //获取方法修饰符
            sb.append(" ");
            sb.append(method.getReturnType()); //获取方法返回值类型
            sb.append(" ");
            sb.append(method.getName()); //获取方法名
            sb.append("(");
            Class<?>[] parameterTypes = method.getParameterTypes(); //获取方法参数列表类型
            for (Class parameterType : parameterTypes) {
                sb.append(parameterType.getSimpleName());
                sb.append(",");
            }
            if(parameterTypes.length != 0) //判断 如果方法参数列表为空则不删除","号
                sb.deleteCharAt(sb.length() - 1);
            sb.append("){}
");
        }
        sb.append("}");
        System.out.println(sb);
    }
}

反射机制调用方法

package cn.xiaokw.java.reflect;

import java.lang.reflect.Method;

public class Demo_10 {
    public static void main(String[] args) throws Exception {
        Class myClass = Class.forName("cn.xiaokw.java.reflect.MyClass1");
        //获取Method
        Method method = myClass.getMethod("method1", String.class, int.class);//使用形参区分重载的方法
        Object obj = myClass.newInstance();
        /*
        调用方法的四要素:
            对象是 obj
            参数是 "abc" 10
            方法是 method
            返回值是    abc
         */
        Object abc = method.invoke(obj, "abc", 10); //使用obj对象调用MyClass1类中的method1方法
        System.out.println(abc); //true
    }
}

构造方法 Constructor

反编译Constructor

package cn.xiaokw.java.reflect;

import java.lang.reflect.Constructor;
import java.lang.reflect.Modifier;

public class Demo_11 {
    public static void main(String[] args) throws Exception{
        Class myClass = Class.forName("cn.xiaokw.java.reflect.Person2");
        Constructor[] constructor = myClass.getConstructors();
        StringBuilder sb = new StringBuilder();
        sb.append(Modifier.toString(myClass.getModifiers())+" class " +myClass.getSimpleName() + " {
");

        for (Constructor con :constructor){
            sb.append("	");
            sb.append(Modifier.toString(con.getModifiers())); //获取构造方法的修饰符
            sb.append(" ");
            sb.append(myClass.getSimpleName()); //构造方法名就是类名
            sb.append("(");
            Class[] parameterTypes = con.getParameterTypes(); //获取构造方法的参数
            for (Class c :parameterTypes){
                sb.append(c.getSimpleName());
                sb.append(",");
            }
            if (parameterTypes.length >0)
                sb.deleteCharAt(sb.length() -1);
            sb.append("){}
");
        }
        sb.append("}");
        System.out.println(sb);
    }
}
class Person2 {
    private String no;
    private String name;
    private int age;
    public Person2() {
    }

    public Person2(String no) {
        this.no = no;
    }

    public Person2(String no, String name) {
        this.no = no;
        this.name = name;
    }

    public Person2(String no, String name, int age) {
        this.no = no;
        this.name = name;
        this.age = age;
    }
}

输出结果

 class Person2 {
	public Person2(String,String,int){}
	public Person2(String,String){}
	public Person2(String){}
	public Person2(){}
}

反射机制调用构造方法

package cn.xiaokw.java.reflect;

import java.lang.reflect.Constructor;

public class Demo_12 {
    public static void main(String[] args) throws Exception {
        Class teacher = Class.forName("cn.xiaokw.java.reflect.Teacher");

        //调用无参构造方法一:
        Object obj = teacher.newInstance();
        System.out.println(obj); //Teacher{name=‘null‘, id=‘null‘, sex=‘null‘}
        //调用无参构造方法二:
        Constructor c = teacher.getDeclaredConstructor();
        Object o = c.newInstance();
        System.out.println(o); //Teacher{name=‘null‘, id=‘null‘, sex=‘null‘}

        //调用有参构造方法
        //使用形参区分构造方法
        Constructor c1 = teacher.getDeclaredConstructor(String.class, String.class);
        Object zhangsan = c1.newInstance("张三", "100001");
        System.out.println(zhangsan); //Teacher{name=‘张三‘, id=‘100001‘, sex=‘null‘}

        Constructor c2 = teacher.getDeclaredConstructor(String.class, String.class, String.class);
        Object lishi = c2.newInstance("李四", "100002", "男");
        System.out.println(lishi); //Teacher{name=‘李四‘, id=‘100002‘, sex=‘男‘}
    }
}

class Teacher {
    String name;
    String id;
    String sex;

    public Teacher() {
    }

    public Teacher(String name, String id) {
        this.name = name;
        this.id = id;
    }

    public Teacher(String name, String id, String sex) {
        this.name = name;
        this.id = id;
        this.sex = sex;
    }

    @Override
    public String toString() {
        return "Teacher{" +
                "name=‘" + name + ‘‘‘ +
                ", id=‘" + id + ‘‘‘ +
                ", sex=‘" + sex + ‘‘‘ +
                ‘}‘;
    }
}

以上是关于反射机制的主要内容,如果未能解决你的问题,请参考以下文章

反射机制入门

反射机制入门

java 反射代码片段

python反射机制实现

Java核心技术梳理-类加载机制与反射

Java反射机制