【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 仅用于个人学习和总结,如有侵权,联系删除,感谢感谢。