【java】反射总结

一、什么是类对象

类的对象:基于某个类new出来的对象,也称为实例对象 一个类我们可以创建无数个对象。

类对象:类加载的产物. 这个类从硬盘上加载到内存中就会生成一个与类相关的对象 就叫做类对象. 封装了一个类的所有的信息(类名、父类、接口、属性、方法、构造方法)

每个类加载到内存后都对应一个Class对象,每个类有且只有一个Class对象  

显示加载类  -verbose:class 可以看出当前程序运行所加载的所有类

二、获取类对象的方法

//1.通过类的对象,获取类对象 
Student s = new Student();
Class c = s.getClass();
//2.使用类名获取类对象
Class c = 类名.class;
//3.通过静态方法获取类对象(推荐使用 原因是参数是字符串,程序在编译的时候不会报错,前两种依赖性太强)
Class c = Class.forName("包名.类名");

三、反射常用方法

//1. public String getName()                    //获取类的名字
//2. public Package getPackage()                //获取当前类的包
//3. public Class<? super T> getSuperclass()     //获取类的父类
//4. public Class<?>[] getInterfaces            //获取当前类所实现的接口 返回是个数组
//5. public Constructor<?>[] getConstructors()    //
//6. public T newInstance()                        //使用当前类对象创建一个实例
//7. public Method[] getMethods()                //获取当前类中的方法
//8. public Field[] getFields()                    //获取当前类中的属性

四、反射常见操作

 

//使用反射获取类的名字、包名、父类、接口

//实体类
package com.company;
import java.io.Serializable;
public class Student implements Serializable {
    private static final long serialVersionUID = -8778349856468359639L;
    private String name;
    private int age;
    //有参构造
    public Student(String name, int age) {
        this.name = name;
        this.age = age;
    }
    //无参构造
    public Student() {
    }
    //普通方法
    public void eat(){
        System.out.println("吃东西");
    }
    //带参的方法
    public void eat(String food){
        System.out.println(name+"开始吃---"+food);
    }
    //私有的方法
    private void privateMethod(){
        System.out.println("这是一个私有方法");
    }
    //静态方法
    public static void staticMethod(){
        System.out.println("这是一个静态方法");
    }
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    public int getAge() {
        return age;
    }
    public void setAge(int age) {
        this.age = age;
    }
    @Override
    public String toString() {
        return "Student{" +
                "name='" + name + '\'' +
                ", age=" + age +
                '}';
    }
}


package com.company;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.Properties;

public class Main {

    //使用反射
    public static void main(String[] args) throws Exception{
        //1. 获取类对象
        Class<?> class1 = Class.forName("com.company.Student");
        //2. 创建对象
        Student student = (Student)class1.newInstance();

        //2. 获取类属性 单个
        Field nameField = class1.getField("name");//获取类的单个属性 (要求属性类型是public,否则获取不到)
        Field nameField1 = class1.getDeclaredField("name");//获取类的单个属性(要求属性类型为public、default、private、protect)
        nameField1.setAccessible(true);//如果属性类型是private,需要使其访问权限失效
        // 多个
        Field[] fields = class1.getFields();//获取类的所有属性(要求属性类型是public或者父类继承的字段)
        Field[] fields1 = class1.getDeclaredFields();//获取类的所有属性(要求属性类型为public、default、private、protect)
        for(Field f:fields1){
            System.out.println(f.toString());
        }

        //3. 获取类的构造方法
        Constructor<?> con = class1.getConstructor();//获取类的无参构造方法(单个)
        Constructor<?> con2 = class1.getConstructor(String.class,int.class);//获取类的有参构造方法,需要指定参数类型(单个)
        Constructor<?>[] cons = class1.getConstructors();//获取类的所有构造方法(多个)
        for(Constructor<?> contemp:cons){
            System.out.println(contemp.toString());
        }

        //4. 获取类中的方法并调用(单个)
        Method method = class1.getMethod("eat");//获取单个方法(无参无返回值、无参有返回值)
        method.invoke(student);//调用
        Method method1 = class1.getMethod("eat",String.class);//获取单个方法 (有参无返回值)
        method1.invoke(student,"苹果");//调用
        Method method2 = class1.getDeclaredMethod("privateMethod");//获取私有的方法
        method2.setAccessible(true);//私有的方法调用需要设置访问权限无效
        method2.invoke(student);//调用
        Method method3 = class1.getMethod("staticMethod");//获取静态的方法
        method3.invoke(null);//调用,直接传null即可
        //多个
        Method[] methods = class1.getMethods();//getMethods方法只能获取公开的方法,包括从父类继承的方法
        for(Method me:methods){
            System.out.println(me.toString());
        }
        Method[] methods1 = class1.getDeclaredMethods();//获取类中的所有方法,包括私有的,默认,保护的,不包含继承的
        for(Method me1:methods1){
            System.out.println(me1.toString());
        }

        //5. 使用反射实现一个可以调用任何对象方法的通用方法
        Properties properties = new Properties();
        properties.setProperty("name", "zhangsan");
        invokeAny(properties,"setProperty", new Class[]{String.class, String.class},"username","张三");
        System.out.println(properties.toString());
    }

    public static Object invokeAny(Object obj,String methodName,Class<?>[] types,Object...args) throws Exception{
        //1. 获取类对象
        Class<?> class1 = obj.getClass();
        //2. 获取方法
        Method method = class1.getMethod(methodName, types);
        //3. 调用
        return method.invoke(obj,args);
    }
}

五、实战

需求:获取user表的所有字段,包括私有字段。并获取每个字段的类型和值。

实体类:

@Data
@AllArgsConstructor
public class User {
    private String name;
    private Integer age;
    private Integer sex;
    private String email;
    private HeadMaster headMaster;
    private List<Teacher> teacherList;
}
//-------------------------
@Data
@AllArgsConstructor
public class HeadMaster {
    //校长类

    //校长名字
    private String name;
    //校长年龄
    private Integer age;
}
//-------------------------
@Data
@AllArgsConstructor
public class Teacher {
    //老师类

    //老师姓名
    private String name;
    //老师年龄
    private Integer age;
}

演示代码:

public static void main(String[] args) {//这里虚拟几条数据
    User user = new User("张三", 11,1,"123456@qq.com",
            new HeadMaster("校长",50),
            Arrays.asList(new Teacher("老师1",30),new Teacher("老师2",40)));
    //这里转换为object的原因是,如果将来是多个类型的对象都调用下面的方法,那么可以都先转成Object类型,来让方法通用
    Object object = user;
    //调用反射测试方法
    reflectTest(object.getClass().getName(),object);
}

private static void reflectTest(String classame,Object object) {
    try {
        //通过反射获取类对象  格式:com.tm.test.User
        Class<?> clazz = Class.forName(classame);
        //获取user表所有字段
        Field[] fields = clazz.getDeclaredFields();
        //遍历user表字段
        for (Field field : fields) {
            //设置是否允许访问,不是修改原来的访问权限修饰词。
            field.setAccessible(true);
            //获取每个字段的名称和类型
            if(field.getClass().isPrimitive()){
                //isPrimitivef方法只能验证java的8中基本数据类型 byte short int long float double char boolean 不包含包装类
            }else if("java.lang.String".equals(field.getType().getTypeName())){
                //字段名称为:name 类型为:java.lang.String 值为:张三  字段名称为:email 类型为:java.lang.String 值为:123456@qq.com
                System.out.println("字段名称为:"+field.getName()+" 类型为:"+field.getType().getTypeName()+" 值为:"+field.get(object));
            }else if("java.lang.Integer".equals(field.getType().getTypeName())) {
                //字段名称为:age 类型为:java.lang.Integer 值为:11  字段名称为:sex 类型为:java.lang.Integer 值为:1
                System.out.println("字段名称为:"+field.getName()+" 类型为:"+field.getType().getTypeName()+" 值为:"+field.get(object));
            }else if("com.tm.test.HeadMaster".equals(field.getType().getTypeName())){
                //字段名称为:headMaster 类型为:com.tm.test.HeadMaster 值为:HeadMaster(name=校长, age=50)
                System.out.println("字段名称为:"+field.getName()+" 类型为:"+field.getType().getTypeName()+" 值为:"+field.get(object));
            }else if("java.util.List".equals(field.getType().getTypeName())){
                //字段名称为:teacherList 类型为:java.util.List 值为:[Teacher(name=老师1, age=30), Teacher(name=老师2, age=40)]
                System.out.println("字段名称为:"+field.getName()+" 类型为:"+field.getType().getTypeName()+" 值为:"+field.get(object));
                //获取list里面的类型
                Type t = field.getGenericType();
                if (t instanceof ParameterizedType) {
                    ParameterizedType pt = (ParameterizedType) t;
                    //得到对象list中实例的类型
                    Class clz = (Class) pt.getActualTypeArguments()[0];
                    //获取类名+表名 结果:com.tm.test.Teacher
                    System.out.println(clz.getTypeName());
                    //劫取到最后的类名  结果:Teacher
                    System.out.println(clz.getTypeName().substring(clz.getTypeName().lastIndexOf(".") + 1));
                    //这里要注意:如果想要再次获取list中的teache里的字段和值,可以采用递归的方式循环reflectTest方法
                }
            }
            //此外还有一些其它类型可以列举
            //"java.time.LocalDateTime" "java.lang.Long" "java.math.BigDecimal" "java.util.Date" 等
        }
    } catch (Exception e) {
        e.printStackTrace();
    }
}

 

 

 

持续更新!!!

注意:

本篇文章大部分内容来自bilibili视频网站千锋教育和百度,地址:https://www.bilibili.com/video/BV1Qt4y1972Z 仅用于个人学习和总结,如有侵权,联系删除,感谢感谢。

posted @ 2020-09-12 12:12  夏夜凉凉  阅读(187)  评论(0编辑  收藏  举报