当前位置: 首页 > article >正文

27、Java 反射机制

15-1 Java 反射机制概述


Reflection(反射)是被视为动态语言的关键

动态语言:在运行时代码可以根据某些条件改变自身结构。如 C#\JavaScript\PHP

静态语言:运行时结构不可变的语言。如 Java\C\C++

问题:通过直接new的方式或反射的方式都可以调用公共的结构,开发中到底用哪个

建议:直接new的方式

反射特征:动态性


15-2 理解Class类并获取Class的实例


哪些类可以有Class对象?

1、class:外部类,成员(成员内部类,静态内部类),局部内部类,匿名内部类

2、interface:接口

3、[]:数组

4、enum:枚举

5、annotation:注解@interface

6、primitive type:基本数据类型

7、void


15-3类的加载与ClassLoader的理解

(主要了解即可)

CleanShot 2025-03-03 at 14.04.18


15-4 创建运行时类的对象

package com.java5.kcw;

import org.junit.Test;

/**通过反射创建对应的运行时类的对象
 * @author Jackson_kcw
 * @Time 2025-03-03  PM2:23
 */
public class NewInstanceTest {
    @Test
    public void test() throws InstantiationException, IllegalAccessException {
        Class clazz=Person.class;

        //newInstance():调用此方法,创建对应的运行时类的对象;内部调用了运行时类的空参构造器
        /*
        要想此方法正常的创建运行时类的对象,要求:
        1、运行时类必须提供空参的构造器
        2、空参的构造器的访问权限得够。通常,设置为 public

        在 javabean 中要求去提供一个 public 的空参构造器 原因:
        1、便于通过反射,创建运行时类的对象
        2、便于子类继承此运行时类,默认调用 super()时,保证父类有构造器
         */
        Object ob = clazz.newInstance();
        System.out.println(ob);
    }
}

体会反射的动态性,这是一个很重要的思想


15-5 调用运行时类的指定结构


package com.java5.kcw;

import org.junit.Test;

import java.lang.reflect.Field;
import java.lang.reflect.Method;

/**
 * @author Jackson_kcw
 * @Time 2025-03-03  PM2:51
 */
public class ReflectionTest1 {
    //这个方法现在已经很多不使用了,无需掌握
    @Test
    public void test1() throws Exception {
        Class clazz=Person.class;
        //创建运行时类的对象
        Person p=(Person)clazz.newInstance();

        //获取指定的属性:要求运行时类中属性声明为 public
        //通常不采用此方法
        Field id= clazz.getField("id");

        /*
        设置当前属性的值
        set():参数一:指明设置那个对象的属性    参数二:将此属性值设置为多少
         */
        id.set(p,1001);

        /*
        获取当前属性的值
        get() 参数一:获取哪个对象的当前属性值
         */
        int pId=(int)id.get(p);
        System.out.println(pId);


    }

    /*
    这个方法很重要的
     */
    @Test
    public void test2() throws Exception {
        Class clazz=Person.class;
        //创建运行时类的对象
        Person p=(Person)clazz.newInstance();

        //getDeclaredField(String fieldName):获取运行时类中指定变量名的属性
        Field name=clazz.getDeclaredField("name");

        //setAccessible(true) :保证当前属性是可访问的
        name.setAccessible(true);
        name.set(p,"Jackson");

        System.out.println(name.get(p));
    }

    //如何操作运行类中的指定方法
    @Test
    public void test3() throws Exception {
        Class clazz=Person.class;
        //创建运行时类的对象
        Person p=(Person)clazz.newInstance();

        Method setName = clazz.getDeclaredMethod("setName", String.class);
        setName.setAccessible(true);
        //invoke() 参数 1:方法的调用者  参数二:给方法形参赋值的实参
        //invoke()返回值即为对应类中调用的方法的返回值
        setName.invoke(p,"Kik");
        System.out.println(p.getName());
        System.out.println("****************如何调用静态方法*****************");


        Method showDesc = clazz.getDeclaredMethod("showDesc");
        showDesc.setAccessible(true);
        showDesc.invoke(p);
    }
}


15-6 反射的应用:动态代理


package com.java6.kcw;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;

/**动态代理
 * @author Jackson_kcw
 * @Time 2025-03-03  PM3:25
 */

interface Human{
    String getBelief();

    void eat(String food);

}
//被代理类
class SuperMan implements Human{


    @Override
    public String getBelief() {
        return "I believe I can Fly";
    }

    @Override
    public void eat(String food) {
        System.out.println("I like eat"+food);
    }
}
/*
想要实现动态代理,需要解决的问题?
问题一:如何根据加载到内存中的被代理类,动态的创建一个代理类及其对象
问题二:当通过代理类的对象调用方法时,如何动态的去调用被代理类中的同名方法

 */

class ProxyFactory{
    //调用此方法,返回一个代理类的对象,解决问题一
    public static Object getProxyInstance(Object obj){//obj:被代理类的对象
        MyInvocationHandler handle= new MyInvocationHandler();
        handle.bind(obj);

       return Proxy.newProxyInstance(obj.getClass().getClassLoader(), obj.getClass().getInterfaces(),handle);

    }
}
class MyInvocationHandler implements InvocationHandler {
    private Object obj;//需要使用被代理类的对象进行赋值
    public void bind(Object obj){
        this.obj = obj;
    }

    //当我们通过代理类的对象,调用方法 a 时,就会自动的调用如下的方法:invoke()
    //将被代理类要执行的方法 a 的功能就声明在 invoke()中
    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        //method:即为代理类对象调用的方法,此方法也就作为 被代理类对象要调用的方法
        //obj:被代理类的对象
        Object returnValue = method.invoke(obj, args);
        //上述方法的返回值就作为当前类中的 invoke()的返回值
        return returnValue;
    }
}
public class ProxyTest {
    public static void main(String[] args) {
        SuperMan superman = new SuperMan();
        //proxyInstance:代理类的对象
        Human human = (Human) ProxyFactory.getProxyInstance(superman);
        //当通过代理类对象调用方法时,会自动调用被代理类中同名的方法
        human.getBelief();
        human.eat("烧烤");

    }
}




http://www.kler.cn/a/570476.html

相关文章:

  • 数据结构(初阶)(五)----栈
  • 如何使用Python和SQLAlchemy结合外键映射来获取其他表中的数据
  • 迷你世界脚本组队接口:Team
  • C语言:51单片机 程序设计基础
  • 大模型学习笔记------LLM模型开发流程
  • Django与数据库
  • Docker 模拟 kubernetes 的 pod
  • STM32引脚类型
  • Linux IO编程核心要点解析:文件、流与缓冲区实战指南
  • Python配置文件的全面解析与使用
  • WEB10(CTFshow)
  • 算法题笔记(自用)——Python
  • 编程题 - 汽水瓶【JavaScript/Node.js解法】
  • 【含文档+PPT+源码】基于SpringBoot和Vue的编程学习系统
  • CentOS 7 IP 地址设置保姆级教程
  • 动态扩缩容引发的JVM堆内存震荡:从原理到实践的GC调优指南
  • Spark核心之02:RDD、算子分类、常用算子
  • cursor for linux
  • MySQL 索引深度解析手册
  • 【二分查找】_240. 搜索二维矩阵 II