java反射
反射介绍:
反射,一种计算机处理方式。是程序可以访问、检测和修改它本身状态或行为的一种能力。
JAVA机制反射是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法;对于任意一个对象,都能够调用它的任意一个方法和属性;这种动态获取的信息以及动态调用对象的方法的功能称为java语言的反射机制。
要想解剖一个类,必须先要获取到该类的字节码文件对象。而解剖使用的就是Class类中的方法.所以先要获取到每一个字节码文件对应的Class类型的对象.
反射的作用:
通过java中的反射机制可以操作字节码文件(可以读和修改字节码文件。)
通过反射机制可以操作代码片段。(Class文件)
反射重要的类:
类 含义
java.lang.Class 代表整个字节码。代表一个类型,代表整个类。
java.lang.reflect.Method 代表字节码中的方法字节码。代表类中的方法。
java.lang.reflect.Constructor 代表字节码中的构造方法字节码。代表类中的构造方法。
java.lang.reflect.Field 代表字节码中的属性字节码。代表类中的成员变量(静态变量+实例变量)。
反射的三种实例化模式:
要想解剖一个类,必须先要获取到该类的class文件对象。而解剖使用的就是Class类中的方法.所以先要获取到每一个字节码文件对应的Class类型的对象.
Class类对象的三种实例化模式:
| 方式 |
备注 |
| Class.fromName() |
静态方法 |
| 对象.class() |
|
| 任何类型.class |
|
1.getClass()方法
该方法来自于Object类,并且是被native修饰,所以所有类都可以直接调用
native修饰的方法看不见方法体,native修饰的方法不是用java语言实现的,而是调用了底层c/c++的代码,这些代码被编译为.dll文件,让java来执行的

import java.util.Date;
public class test {
public static void main(String[] args) {
Date date=new Date();
System.out.println(date.getClass());
}
}
2.类.class
通过类名找到类
我们的程序中的每个类都有一个相应的Class对象。每当新的类被编译完成,就会产生一个Class对象存储与相同的.class文件内。执行期间当你想要产生该class的对象是,JVM便会检查该型别的Class对象是否被加载;如果没被加载,JVM会根据名称找到.class文件并加载它.
import java.util.Date;
public class test {
public static void main(String[] args) throws ClassNotFoundException, IllegalAccessException, InstantiationException {
//通过Date类的class文件,获取到一个class对象
Class cls = Date.class;
// 再将class对象转为Date对象,等同于Date的实例化操作
Date date = (Date) cls.newInstance();
}
}
3.使用Class类提供的方法
import java.lang.Class;
public static void main(String[] args) throws ClassNotFoundException, IllegalAccessException, InstantiationException {
// 根据类的路径,使用Class类中的forName方法,获取类的class对象
Class<?> tClass = Class.forName("java.util.Date");
//实例化对象,等价:new Date()
Date date = (Date) tClass.newInstance();
System.out.println(date.getMonth());
}
反射使用的类:
- Class类:代表一个类
- Field类:代表类的成员变量(类的属性)
- Method类:代表类的方法
- Constructor类:代表类的构造方法
- Array类:提供了动态创建数组,以及访问数组的元素的静态方法
Class类常用的方法:

package test.fanshe;
/**
* @program: day1
* @description:
* @author:
* @create: 2022-07-20 14:40
**/
public class Student {
public String address;
public String number;
private String name;
private int age;
public Student() {
}
public Student(String name, int age) {
this.name = name;
this.age = age;
}
@Override
public String toString() {
return "Student{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}
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;
}
public void run(){
System.out.println("调用run");
}
public void eat(String name,Integer age){
System.out.println("调用eat");
}
private void play(String name,Integer age){
System.out.println("调用play");
}
}
public static void main(String[] args) throws ClassNotFoundException, IllegalAccessException, InstantiationException, NoSuchFieldException, NoSuchMethodException {
//通过student类的class文件,获取到一个class对象
Class tclass = Student.class;
// 再将class对象转为Student对象,等同于Student的实例化操作
Student student = (Student) tclass.newInstance();
// 返回完整的类名和包名
System.out.println(tclass.getName());
// 返回类名
System.out.println(tclass.getSimpleName());
// 返回类中public修饰的属性
Field[] files = tclass.getFields();
for (Field f : files
) {
System.out.println("公共属性是:"+f);
}
// 返回类中所有的属性(包含:public和private修饰的属性)
Field[] fields = tclass.getDeclaredFields();
for (Field f: fields
) {
System.out.println("所有属性:"+f);
}
// 根据属性名称获取指定的属性
Field file = tclass.getDeclaredField("name");
System.out.println("获取到的属性名称是:"+file.getName());
// 返回类中所有的实例方法,除了构造方法
Method[] methods = tclass.getDeclaredMethods();
for (Method m: methods
) {
System.out.println("方法名称是"+m.getName());
}
// 根据方法名称和方法的形参类型,返回方法,注意:这里的方法参数类型必须是封装数据类,不能用基础数据
Method method = tclass.getDeclaredMethod("eat",String.class,Integer.class);
System.out.println("获取到的方法名称是"+method.getName());
}
}
Field类方法
Field对象是反射里面专门用来处理类对象的属性

public static void main(String[] args) throws ClassNotFoundException, IllegalAccessException, InstantiationException, NoSuchFieldException, NoSuchMethodException {
//通过student类的class文件,获取到一个class对象
Class tclass = Student.class;
// 再将class对象转为Student对象,等同于Student的实例化操作
Student student = (Student) tclass.newInstance();
// getModifiers 得到的就是 前面的 的修饰符 ,这个方法 字段和方法 都有。
// 这个方法的值是 修饰符 相加的到的值。
// 什么都不加 是0
// public 是1
// private 是 2
// protected 是 4
// static 是 8
// final 是 16
// 如果是 public static final 三个修饰的 就是3 个的加和 为 25
// 首先获取到当前类的所有属性列表
Field[] fields = tclass.getDeclaredFields();
for( Field field: fields) {
// 分别在获取对应属性的修饰符编号
System.out.println( field.getName() +":" + field.getModifiers() );
}
// 根据属性名称获取对应属性
Field field = tclass.getDeclaredField("address");
System.out.println("类型是"+field.getType());
// 为类对象设置属性值,属性是被public修饰的
field.set(student,"湖北武汉");
// 获取类对象的指定属性值
Object o = field.get(student);
System.out.println(o+"==========");
// field对象操作是被private修饰的属性
field = tclass.getDeclaredField("name");
// 私有属性就需要设置访问权限为true
// 打破封装(反射机制的缺点:打破封装,可能会给不法分子留下机会!!!)
field.setAccessible(true);
field.set(student,"张三");
Object o1 = field.get(student);
System.out.println(o1+"----------------");
}
Method类方法
Method对象是反射里面专门用来处理类的方法的

public static void main(String[] args) throws ClassNotFoundException, IllegalAccessException, InstantiationException, NoSuchFieldException, NoSuchMethodException, InvocationTargetException {
//通过student类的class文件,获取到一个class对象
Class tclass = Student.class;
// 再将class对象转为Student对象,等同于Student的实例化操作
Student student = (Student) tclass.newInstance();
// 获取方法名 默认为找到的第一个方法
String functionName = tclass.getName();
System.out.println(functionName);
// 获取该类中的所有方法
Method[] methods = tclass.getDeclaredMethods();
for (Method m: methods
) {
System.out.println("每个方法名为"+m.getName());
}
// 根据方法名找到指定的方法对象
// 参数分别为:方法名称 方法中参数的类型
Method method = tclass.getMethod("eat",String.class,Integer.class);
// 调用这个获取到的方法
method.invoke(student,"张三",20);
}
Constructor类方法:
public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException {
Class<?> aClass = Class.forName("test.fanshe.Student");
//调用student对象的无参构造创建对象
Constructor constructor = aClass.getDeclaredConstructor();
Student student1 = (Student) constructor.newInstance(); System.out.println(student1);
// 调用student对象的有参构造创建对象
Constructor constructor1 = aClass.getDeclaredConstructor(String.class,String.class,String.class,Integer.class); Student student2 = (Student) constructor1.newInstance("湖北武汉","123","张三",20); System.out.println(student2);}
反射的主要使用:
反射的功能:
反射的功能:通过反射可以使程序代码访问装载到JVM 中的类的内部信息
1) 获取已装载类的属性信息
2) 获取已装载类的方法
3) 获取已装载类的构造方法信息生成动态代理
主要用途:
反射最重要的用途就是开发各种通用框架,比如spring框架中关于对象的管理就是通过反射来创建对象
反射的缺点:
使用反射基本上是一种解释操作,用于字段和方法接入时要远慢于直接代码。因此Java反射机制主要应用在对灵活性和扩展性要求很高的系统框架上,普通程序不建议使用。
使用反射会模糊程序内部逻辑
程序人员希望在源代码中看到程序的逻辑,反射等绕过了源代码的技术,因而会带来维护问题。反射代码比相应的直接代码更复杂。
反射的实际使用:
反射案例1:对象的创建和使用
public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException {
Class<?> aClass = Class.forName("test.fanshe.Student");
//Student student = (Student) aClass.newInstance();// 使用class类的newInstance()
// 第二种:使用类的构造方法创建对象
Constructor constructor = aClass.getDeclaredConstructor(String.class,String.class,String.class,Integer.class);
Student student = (Student) constructor.newInstance("湖北武汉","123","张三",20);
student.run();
System.out.println(student);
}
反射案例2:支付的接口
package com.lmh;
/**提供支付接口
*/
public interface Payment {
void payOnline();
}
分别创建支付接口类的两个实现类:
public class weChat implements Payment{
@Override
public void payOnline() {
System.out.println("using wechat pay...");
}
}
public class AliPay implements Payment{
@Override
public void payOnline() {
System.out.println("using AliPay to pay...");
}
}
使用多态来实现对接口的使用:
public static void main(String[] args) {
//模拟前端提交支付方式
String str = "微信";
if ( "微信".equals(str)) {
pay(new weChat());
}
if ("支付宝".equals(str)) {
pay(new AliPay());
}
}
public static void pay(weChat weChat){
weChat.payOnline();
};
public static void pay(AliPay aliPay){
aliPay.payOnline();
}
思考:如果现在添加了更多的支付方式,比如云闪付,网上银行等等,那如何用最简单的方式实现支付
使用反射来实现:
public static void main(String[] args) throws Exception {
//模拟 前端传值
String str = "com.test.AliPay";
// 使用 class.forName(类全限定名) 获取对象
Class<?> clazz = Class.forName(str);
// 对象实例化
Object o = clazz.newInstance();
// 获取对象的 payOnline 方法
Method pay = clazz.getMethod("payOnline");
// 调用对象的 方法 method
pay.invoke(o);
}
反射案例3:Map转JavaBean
将一个Map集合转换为对应的Javabean
public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException {
Map map = new HashMap();
map.put("address","湖北武汉");
map.put("number","123456");
map.put("name","张三");
map.put("age",20);
Student student = new Student();
student = mapToBean(Student.class,map);
System.out.println(student);
}
public static <T> T mapToBean(Class<T> tClass, Map<String,Object> map) throws IllegalAccessException, InstantiationException {
// 将map对象根据传入的class的类型进行转换
// 先根据传来的class创建对象的实例
T c = tClass.newInstance();
// 循环map,可以使用lambda表达式进行foreach循环
map.forEach((k,v)->{ // k,v表示每个entry对象的key和value
// 获取对象属性名称
try {
Field field = tClass.getDeclaredField(k);
// 放开对属性的访问权限
field.setAccessible(true);
// 为对象的属性设置,值从map中取得
field.set(c,v);
} catch (NoSuchFieldException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
}
});
// 将设完值的对象返回
return c;
}