java反射

目录

Class类

获取Class实例

动态加载

Class的一些成员方法

1.反射实例

[2. 反射成员方法](#2. 反射成员方法)

[3. 反射成员变量](#3. 反射成员变量)

4.反射类结构

[动态代理(Dynamic Proxy)](#动态代理(Dynamic Proxy))


反射Reflection,Java的反射是指程序在运行期可以拿到一个对象的所有信息,解决在运行期,对某个实例一无所知的情况下,如何调用其方法

Class类

只能由JVM创建的类,当JVM去加载某个class时,会new 一个Class实例 记录 该class的所有信息

我们可以通过这个Class实例获取到该实例对应的class的所有信息,即为 反射

获取Class实例

1.通过 某class 的静态变量 获取 Class实例

java 复制代码
Class cls = String.class;
  1. 通过该实例变量提供的getClass()方法获取
java 复制代码
String s = "Hello";
Class cls = s.getClass();

3.完整类名,可通过静态方法Class.forName()获取

java 复制代码
Class cls = Class.forName("java.lang.String");

Class实例在JVM中是唯一的,所以,上述方法获取的Class实例是同一个实例

动态加载

"一次编写,到处运行"

动态加载是指JVM在程序运行期间根据需要加载、链接和初始化类的机制,减少了程序的初始加载时间,只有真正使用到的类才会被加载

Commons Logging总是优先使用Log4j,只有当Log4j不存在时,才使用JDK的logging。利用JVM动态加载特性,大致的实现代码如下:

java 复制代码
// Commons Logging优先使用Log4j:
LogFactory factory = null;
if (isClassPresent("org.apache.logging.log4j.Logger")) {
    factory = createLog4j();
} else {
    factory = createJdkLog();
}

boolean isClassPresent(String name) {
    try {
        Class.forName(name);
        return true;
    } catch (Exception e) {
        return false;
    }
}

Class的一些成员方法

1.反射实例

java 复制代码
import java.lang.reflect.Constructor;

public class ReflectionNewInstance {
    public static void main(String[] args) throws Exception {
        Class<?> cls = Class.forName("java.util.Date");
        
        // 方式1:调用无参构造(已过时)
        Object obj1 = cls.newInstance();
        System.out.println(obj1); // 当前日期

        // 方式2:通过Constructor对象(推荐)
        Constructor<?> constructor = cls.getConstructor();
        Object obj2 = constructor.newInstance();
        System.out.println(obj2); // 当前日期

        // 方式3:调用有参构造
        Constructor<?> strConstructor = String.class.getConstructor(String.class);
        String str = (String) strConstructor.newInstance("Hello");
        System.out.println(str); // Hello
    }
}

newInstance()已过时,推荐使用Constructor.newInstance()

2. 反射成员方法

java 复制代码
import java.lang.reflect.Method;

public class InvokeMethodExample {
    public static void main(String[] args) throws Exception {
        Class<?> cls = Class.forName("java.lang.String");
        Object str = cls.getConstructor(String.class).newInstance("Hello");

        // 获取并调用方法
        Method method = cls.getMethod("toUpperCase");
        String result = (String) method.invoke(str);
        System.out.println(result); // HELLO

        // 调用私有方法(需设置accessible)
        Method privateMethod = cls.getDeclaredMethod("indexOf", String.class, int.class);
        privateMethod.setAccessible(true);
        int index = (int) privateMethod.invoke(str, "l", 0);
        System.out.println(index); // 2
    }
}

getMethod获取公共方法,getDeclaredMethod可获取私有方法(需setAccessible(true)

调用 静态方法,invoke方法传入的第一个参数永远为null

3. 反射成员变量

java 复制代码
import java.lang.reflect.Field;

class Person {
    private String name = "Alice";
}

public class FieldExample {
    public static void main(String[] args) throws Exception {
        Class<?> cls = Class.forName("Person");
        Object obj = cls.newInstance();

        // 获取并修改私有字段
        Field field = cls.getDeclaredField("name");
        field.setAccessible(true);
        System.out.println(field.get(obj)); // Alice
        field.set(obj, "Bob");
        System.out.println(field.get(obj)); // Bob
    }
}

4.反射类结构

getInterfaces()只返回当前类直接实现的接口类型

两个Class实例,要判断一个向上转型是否成立,可以调用isAssignableFrom()

java 复制代码
class ClassStructure {
    public static void main(String[] args) throws ClassNotFoundException {
        Class<?> cls = Class.forName("java.util.ArrayList");

        // 获取类名和修饰符
        System.out.println("Class: " + cls.getName());
        System.out.println("Modifiers: " + Modifier.toString(cls.getModifiers()));

        // 获取父类和接口
        System.out.println("Superclass: " + cls.getSuperclass().getName());
        for (Class<?> iface : cls.getInterfaces()) {
            System.out.println("Implements: " + iface.getName());
        }

        ArrayList arrayList = new ArrayList<>();
        System.out.println(arrayList instanceof List);
        System.out.println(arrayList.getClass().isAssignableFrom(List.class));
        System.out.println(List.class.isAssignableFrom(arrayList.getClass()));
    }
}

动态代理(Dynamic Proxy)

动态代理:绕过interface的实现类 ,可以在运行期动态创建某个interface的实例

静态代码 就是 编写接口的实现类,然后自动向上转型赋值

java 复制代码
public interface Hello {
    void morning(String name);
}

public class HelloWorld implements Hello {
    public void morning(String name) {
        System.out.println("Good morning, " + name);
    }
}

Hello hello = new HelloWorld();
hello.morning("Bob");

简单实现动态代理

java 复制代码
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;

public class Main {
    public static void main(String[] args) {
        InvocationHandler handler = new InvocationHandler() {
            @Override
            public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                System.out.println(method);
                if (method.getName().equals("morning")) {
                    System.out.println("Good morning, " + args[0]);
                }
                return null;
            }
        };
        Hello hello = (Hello) Proxy.newProxyInstance(
            Hello.class.getClassLoader(), // 传入ClassLoader
            new Class[] { Hello.class }, // 传入要实现的接口
            handler); // 传入处理调用方法的InvocationHandler
        hello.morning("Bob");
    }
}

interface Hello {
    void morning(String name);
}

上面的动态代理改写为静态实现类大概长这样:

java 复制代码
public class HelloDynamicProxy implements Hello {
    InvocationHandler handler;
    public HelloDynamicProxy(InvocationHandler handler) {
        this.handler = handler;
    }
    public void morning(String name) {
        handler.invoke(
           this,
           Hello.class.getMethod("morning", String.class),
           new Object[] { name }
        );
    }
}

动态代理是通过Proxy创建代理对象,然后将接口方法"代理"给InvocationHandler完成的。

相关推荐
cui_hao_nan1 小时前
JVM——如何对java的垃圾回收机制调优?
java·jvm
熟悉的新风景3 小时前
springboot项目或其他项目使用@Test测试项目接口配置-spring-boot-starter-test
java·spring boot·后端
心平愈三千疾3 小时前
学习秒杀系统-实现秒杀功能(商品列表,商品详情,基本秒杀功能实现,订单详情)
java·分布式·学习
玩代码3 小时前
备忘录设计模式
java·开发语言·设计模式·备忘录设计模式
BUTCHER54 小时前
Docker镜像使用
java·docker·容器
岁忧4 小时前
(nice!!!)(LeetCode 面试经典 150 题 ) 30. 串联所有单词的子串 (哈希表+字符串+滑动窗口)
java·c++·leetcode·面试·go·散列表
技术猿188702783514 小时前
实现“micro 关键字搜索全覆盖商品”并通过 API 接口提供实时数据(一个方法)
开发语言·网络·python·深度学习·测试工具
放飞自我的Coder4 小时前
【colab 使用uv创建一个新的python版本运行】
开发语言·python·uv
艾莉丝努力练剑5 小时前
【数据结构与算法】数据结构初阶:详解顺序表和链表(四)——单链表(下)
c语言·开发语言·数据结构·学习·算法·链表
zyhomepage5 小时前
科技的成就(六十九)
开发语言·网络·人工智能·科技·内容运营