
java反射
发布日期:2021-05-09 05:38:33
浏览次数:19
分类:原创文章
本文共 9294 字,大约阅读时间需要 30 分钟。
关联知识
在存在的编程语言中,大致分为动态语言与静态语言这两种。其中静态语言的代表是c,c++等,动态语言的代表则是js,python等。这两种语言的区别有很多,其中最重要的几点如下:
- 静态语言的运行速度要比动态语言更快。
- 动态语言的学习成本低于静态语言。
- 动态语言的开发效率要高于静态语言。
- .......
java是介于静态语言与动态语言之间的一门编程语言。它在书写后,需要先进行编译,这是静态语言的特性,编译后生成字节码文件,运行时jvm会将字节码文件加载到内存中,jvm会对字节码文件进行解释执行,这是动态语言的特性。其实,在真实的java环境,要比这些更加复杂。
反射简介
java的反射其实就是java程序在运行时动态的操作java代码的一门技术。通过这门技术,我们可以在运行时分析类的信息与结构,也可以在运行时检查对象等。java反射是功能十分强大的一门技术,虽然我们平时开发时并不会经常用到它,但反射却是框架最基层的一门技术。学习好反射,利于后期学习各种框架。
Class类的简介与获取
- Class类是java十分重要的一个类,我们想要使用反射,那就离不开这个类。
- 当jvm加载一个class文件后,就会在内存中生成一个与之相对应的Class对象,这个对象保存着该class文件的全部信息。
- 同一类型的多个实例对象,它们的Class对象都是同一个,即在内存中,每一个Class对象都是独一无二的。
- Class对象的获取方式
- 使用Class类的静态发放forName。如
Class c1 = Class.forName("java.lang.String");
- 使用完整类名.class获取,如
Class c2 = String.class;
- 使用实例对象的getClass()方法获取,如
Class c3 = "sssss".getClass();
- 基本数据类型可是使用类型名.TYPE获取。
示例代码如下:
/** * @Classname Demo1 * @Date 2020/11/21 12:13 * @author hzq */package com.hzq.reflection;public class Demo1 { public static void main(String[] args) throws ClassNotFoundException { Class c1 = Class.forName("java.lang.String"); Class c2 = String.class; Class c3 = "sssss".getClass(); Class c4 = "wwwww".getClass(); System.out.println(c1); System.out.println(c2); System.out.println(c3); System.out.println(c4); System.out.println(c3.equals(c4)); //输出结果// class java.lang.String// class java.lang.String// class java.lang.String// class java.lang.String// true }}
Class对象的使用
当我们获取了Class对象后,就可以通过调用Class对象的各种发放来对这个java类进行各种操作了。常见的操作有通过Class对象新建一个java类实例对象,操作字段,操作方法,获取各种信息等。
1. 新建对象
通过反射新建对象的方式有两种,方式1是通过Class对象调用newInstance()
方法,该方法要求类必须有公共级别的无参构造器。方式2是通过Class对象调用getConstructor()
方法获取该类的构造器,通过传入不同的参数来获取指定的构造器对象,然后通过构造器对象调用newInstance()
方法来新建对象。
demo如下:
/** * @Classname Demo2 * @Date 2020/11/21 12:58 * @author hzq */package com.hzq.reflection;import java.lang.reflect.Constructor;import java.lang.reflect.InvocationTargetException;public class Demo2 { public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException { Class<?> c1 = Class.forName("com.hzq.reflection.User"); //方式1 User o1 = (User) c1.newInstance(); //方式2 Constructor<?> constructor = c1.getConstructor(); User o2 = (User) constructor.newInstance(null); System.out.println(o1); System.out.println(o2); //输出结果// User{name='null', age=null, sex='null'}// User{name='null', age=null, sex='null'} }}class User{ private String name; private Integer age; private String sex; public User() { } public User(String name, Integer age, String sex) { this.name = name; this.age = age; this.sex = sex; } public String getName() { return name; } public void setName(String name) { this.name = name; } public Integer getAge() { return age; } public void setAge(Integer age) { this.age = age; } public String getSex() { return sex; } public void setSex(String sex) { this.sex = sex; } @Override public String toString() { return "User{" + "name='" + name + '\'' + ", age=" + age + ", sex='" + sex + '\'' + '}'; }}
2. 操作类的字段
demo示例:
/** * @Classname Demo3 * @Date 2020/11/21 13:14 * @author hzq */package com.hzq.reflection;import java.lang.reflect.Field;public class Demo3 { public static void main(String[] args) throws ClassNotFoundException, NoSuchFieldException, IllegalAccessException, InstantiationException { Class<?> c1 = Class.forName("com.hzq.reflection.User"); System.out.println("获取全部public字段,包括继承来的"); Field[] fields = c1.getFields(); for (Field field : fields) { System.out.println(field.getName()); } System.out.println("获取全部字段(不包括继承来的)"); fields = c1.getDeclaredFields(); for (Field field : fields) { System.out.println(field.getName()); } System.out.println("获取指定字段"); Field name = c1.getDeclaredField("name"); System.out.println(name.getName()); System.out.println("给通过反射创建的对象设置字段值"); Field age = c1.getDeclaredField("age"); Field sex = c1.getDeclaredField("sex"); User o = (User) c1.newInstance(); //因为字段都为private级别,不可以直接访问,所以我们需要关闭访问检查 name.setAccessible(true); age.setAccessible(true); sex.setAccessible(true); name.set(o,"小明"); sex.set(o,"男"); age.set(o,18); System.out.println(o); System.out.println("获取字段name与age的类型"); Class<?> c2 = name.getType(); Class<?> c3 = age.getType(); System.out.println(c2); System.out.println(c3); } //输出结果// 获取全部public字段,包括继承来的// 获取全部字段(不包括继承来的)// name// age// sex// 获取指定字段// name // 给通过反射创建的对象设置字段值// User{name='小明', age=18, sex='男'}// 获取字段name与age的类型// class java.lang.String// class java.lang.Integer}
3.操作类的方法(包含构造方法)
demo示例:
/** * @Classname Demo4 * @Date 2020/11/21 15:58 * @author hzq */package com.hzq.reflection;import java.lang.reflect.Constructor;import java.lang.reflect.Method;import java.util.Arrays;import java.util.List;import java.util.stream.Collectors;public class Demo4 { public static void main(String[] args) throws Exception{ Class<?> c1 = Class.forName("com.hzq.reflection.User"); //获取构造方法 Constructor<?> constructor = c1.getConstructor(String.class, Integer.class, String.class); System.out.println("通过反射获取构造方法来创建对象"); User o = (User) constructor.newInstance("小红", 18, "女"); System.out.println(o); System.out.println("获取类的全部方法对象,然后全部调用"); Method[] methods = c1.getDeclaredMethods(); //对方法对象的集合进行排序,是的set方法先被调用,然后再调用get方法 List<Method> collect = Arrays.stream(methods).filter(e -> { if (e.getName().contains("set") || e.getName().contains("get")) { if (e.getName().contains("getClass")) { return false; } return true; } else { return false; } }).sorted((x,y)->{ if (x.getName().contains("set")){ return -1; }else { return 1; } }).collect(Collectors.toList()); //对方法集合进行遍历调用 for (Method method : collect) { String name = method.getName(); if (name.contains("set")){ if (name.contains("Name")){ method.invoke(o,"小白"); }else if (name.contains("Age")){ method.invoke(o,22); }else { method.invoke(o,"男"); } }else if (name.contains("get")){ Object value = method.invoke(o); System.out.println(value); } } //输出结果// 通过反射获取构造方法来创建对象// User{name='小红', age=18, sex='女'}// 获取类的全部方法对象,然后全部调用// 小白// 22// 男 }}
4. 与注解配合使用
demo示例:
/** * @Classname Demo5 * @Date 2020/11/21 16:27 * @author hzq */package com.hzq.reflection;import java.lang.annotation.*;import java.lang.reflect.Field;public class Demo5 { public static void main(String[] args) throws Exception{ Class<?> c1 = Class.forName("com.hzq.reflection.Person"); //获取全部类注解 Annotation[] annotations = c1.getDeclaredAnnotations(); for (Annotation annotation : annotations) { //找出我们自定义的注解 if (annotation instanceof MyAnnotationType){ MyAnnotationType annotationType = (MyAnnotationType) annotation; //输出注解的属性 System.out.println(annotationType.tableName()); } } //获取全部字段 Field[] fields = c1.getDeclaredFields(); for (Field field : fields) { //获取字段上的注解 MyAnnotationField annotation = field.getAnnotation(MyAnnotationField.class); //输出注解属性 System.out.println(annotation.fieldName()); } } //输出结果// db_person// db_name// db_age// db_sex}/** * @author admin * 标注在字段上的注解 */@Target(ElementType.FIELD)@Retention(RetentionPolicy.RUNTIME)@interface MyAnnotationField { String fieldName();}/** * @author admin * 标注在类上的注解 */@Target(ElementType.TYPE)@Retention(RetentionPolicy.RUNTIME)@interface MyAnnotationType { String tableName();}@MyAnnotationType(tableName = "db_person")class Person{ @MyAnnotationField(fieldName = "db_name") private String name; @MyAnnotationField(fieldName = "db_age") private Integer age; @MyAnnotationField(fieldName = "db_sex") private String sex; public Person() { } public String getName() { return name; } public void setName(String name) { this.name = name; } public Integer getAge() { return age; } public void setAge(Integer age) { this.age = age; } public String getSex() { return sex; } public void setSex(String sex) { this.sex = sex; }}
ps:特别注意
getDeclaredxxx
方法获取的是只属于该类的全部方法或字段,getxxx
方法获取的是该类全部公共访问权限的方法或字段,不包含私有的。- 如果获取的字段或方法对象是私有的,无法直接进行访问,应该先关闭权限检查机制,调用
setAccessible(true)
方法并传入true进行关闭。
发表评论
最新留言
能坚持,总会有不一样的收获!
[***.219.124.196]2025年04月22日 16时05分50秒
关于作者

喝酒易醉,品茶养心,人生如梦,品茶悟道,何以解忧?唯有杜康!
-- 愿君每日到此一游!
推荐文章
laravel 5.5 -- Eloquent 模型关联
2023-01-30
laravel mix
2023-01-30
Laravel Passport
2023-01-30
laravel 之 Eloquent 模型修改器和序列化
2023-01-30
Laravel 使用 - artisan schedule使用
2023-01-30
Laravel 使用rdkafka
2023-01-30
Laravel 多环境配置
2023-01-30
laravel 学习之第二章
2023-01-30
Laravel 安装上传代码不完整的解决方法
2023-01-30
laravel 安装添加多站点
2023-01-30
Laravel 模型
2023-01-30
Laravel 深入理解路由和URL生成
2023-01-30
laravel 生命周期与框架精髓
2023-01-30
laravel 表单验证
2023-01-30
laravel 调试sql
2023-01-30
laravel 路由缓存
2023-01-30
laravel 通过令牌获取用户ID
2023-01-30
Laravel5.5 集成 mPDF
2023-01-30
laravel5.5中添加对分页样式的修改上一页和下一页
2023-01-30