简体中文 繁體中文 English Deutsch 한국 사람 بالعربية TÜRKÇE português คนไทย Français Japanese

站内搜索

搜索

活动公告

通知:为庆祝网站一周年,将在5.1日与5.2日开放注册,具体信息请见后续详细公告
04-22 00:04
通知:本站资源由网友上传分享,如有违规等问题请到版务模块进行投诉,资源失效请在帖子内回复要求补档,会尽快处理!
10-23 09:31

Java高级--反射

SunJu_FaceMall

938

主题

835

科技点

1325

积分

白金月票

积分
1325

未来的小说家柴到了立华奏无人之境【一阶】小樱(小丑装)

发表于 2025-3-21 02:02:36 | 显示全部楼层 |阅读模式

马上注册,结交更多好友,享用更多功能,让你轻松玩转社区。

您需要 登录 才可以下载或查看,没有账号?立即注册

x

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来执行的

1658729138102.png

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());
    }

反射使用的类:

  1. Class类:代表一个类
  2. Field类:代表类的成员变量(类的属性)
  3. Method类:代表类的方法
  4. Constructor类:代表类的构造方法
  5. Array类:提供了动态创建数组,以及访问数组的元素的静态方法

Class类常用的方法:

1658730390555.png

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对象是反射里面专门用来处理类对象的属性

1658730760328.png

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对象是反射里面专门用来处理类的方法的

1658730796005.png

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;
    }
可爱小樱
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

关闭

站长推荐上一条 /1 下一条

手机版|联系我们|小黑屋|TG频道|RSS |网站地图

Powered by Pixtech

© 2025-2026 Pixtech Team.

>