Java 黑马程序员学习笔记(进阶篇31)

一、获取 Class 对象的 3 种方式(重点)

1. 方式 1:Class.forName("全类名")(最常用)

**(1) 作用:**通过类的 "全类名"(包名 + 类名)动态加载类,生成 Class 对象。

(2) 代码示例

java 复制代码
// 示例:加载 java.lang.String 类
Class<?> clazz1 = Class.forName("java.lang.String");
2. 方式 2:类名.class

**(1) 作用:**通过类名直接获取 Class 对象。

(2) 代码示例:

java 复制代码
// 示例:获取 String 类的 Class 对象
Class<?> clazz2 = String.class;
3. 方式 3:对象.getClass()

(1) 作用: 通过已有对象的 getClass() 方法获取 Class 对象。

(2) 代码示例:

java 复制代码
// 示例:通过 String 对象获取 Class 对象
String str = "hello";
Class<?> clazz3 = str.getClass();

二、反射核心操作

以自定义 User 类为示例,演示反射的核心操作:

java 复制代码
// 目标类:包含公有/私有属性、构造器、方法
public class User {
    // 公有属性
    public String username;
    // 私有属性
    private int age;

    // 无参构造器(公有)
    public User() {}

    // 有参构造器(私有)
    private User(String username, int age) {
        this.username = username;
        this.age = age;
    }

    // 公有方法
    public void show() {
        System.out.println("username: " + username + ", age: " + age);
    }

    // 私有方法
    private String getInfo(String prefix) {
        return prefix + ": " + username + "-" + age;
    }

    // getter/setter(省略)
}
1. 操作构造器(创建对象)

通过 Class 对象的方法获取构造器,再通过构造器创建对象。

方法名 作用
getConstructor(Class<?>... parameterTypes) 获取公有的指定参数类型的构造器
getConstructors() 获取所有公有构造器
getDeclaredConstructor(Class<?>... parameterTypes) 获取任意访问权限的指定参数类型的构造器(包括私有)
getDeclaredConstructors() 获取所有构造器(包括私有)

示例1:通过公有无参构造器创建对象

java 复制代码
// 1. 获取 User 类的 Class 对象
Class<?> userClass = Class.forName("com.itheima.reflect.User");

// 2. 获取公有无参构造器(参数类型为 null,可省略)
Constructor<?> constructor = userClass.getConstructor();

// 3. 创建对象(newInstance() 方法)
User user = (User) constructor.newInstance();

// 4. 操作对象
user.username = "张三";
user.show(); // 输出:username: 张三, age: 0

示例2:通过私有有参构造器创建对象

私有构造器需要先通过 setAccessible(true) 打破封装(忽略访问权限检查):

java 复制代码
// 1. 获取私有有参构造器(参数类型:String.class, int.class)
Constructor<?> privateConstructor = userClass.getDeclaredConstructor(String.class, int.class);

// 2. 打破封装(关键:否则无法访问私有构造器)
privateConstructor.setAccessible(true);

// 3. 创建对象(传入构造器参数)
User user2 = (User) privateConstructor.newInstance("李四", 20);

// 4. 调用方法
user2.show(); // 输出:username: 李四, age: 20
2. 操作成员变量(获取 / 修改属性值)

通过 Class 对象的方法获取成员变量,再通过 get()/set() 方法操作属性值。

方法名 作用
getField(String name) 获取公有的指定名称的成员变量
getFields() 获取所有公有成员变量
getDeclaredField(String name) 获取任意访问权限的指定名称的成员变量(包括私有)
getDeclaredFields() 获取所有成员变量(包括私有)

示例:调用私有方法 getInfo(String prefix)

java 复制代码
// 1. 获取 User 类的 Class 对象
Class<?> userClass = Class.forName("com.itheima.reflect.User");

// 2. 创建对象(通过无参构造器)
User user = (User) userClass.getConstructor().newInstance();

// 3. 获取私有属性 age
Field ageField = userClass.getDeclaredField("age");

// 4. 打破封装
ageField.setAccessible(true);

// 5. 修改属性值(set(对象, 新值))
ageField.set(user, 25);

// 6. 获取属性值(get(对象))
int age = (int) ageField.get(user);
System.out.println("修改后的 age: " + age); // 输出:25

// 7. 操作公有属性 username(无需打破封装)
Field usernameField = userClass.getField("username");
usernameField.set(user, "王五");
System.out.println("username: " + usernameField.get(user)); // 输出:王五
3. 操作成员方法(调用方法)

通过 Class 对象的方法获取成员方法,再通过 invoke() 方法调用。

方法名 作用
getMethod(String name, Class<?>... parameterTypes) 获取公有的指定名称和参数类型的方法
getMethods() 获取所有公有方法(包括父类继承的)
getDeclaredMethod(String name, Class<?>... parameterTypes) 获取任意访问权限的指定名称和参数类型的方法(包括私有)
getDeclaredMethods() 获取所有方法(不包括父类继承的,只含当前类定义的)

示例:调用私有方法 getInfo(String prefix)

java 复制代码
// 1. 获取 User 类的 Class 对象
Class<?> userClass = Class.forName("com.itheima.reflect.User");

// 2. 创建对象
User user = (User) userClass.getConstructor().newInstance();
user.username = "赵六";

// 3. 获取私有方法 getInfo(方法名:"getInfo",参数类型:String.class)
Method getInfoMethod = userClass.getDeclaredMethod("getInfo", String.class);

// 4. 打破封装
getInfoMethod.setAccessible(true);

// 5. 调用方法(invoke(对象, 方法参数))
String result = (String) getInfoMethod.invoke(user, "用户信息");

System.out.println(result); // 输出:用户信息: 赵六-0(age 未赋值,默认 0)

三、动态代理

1. 核心概念

① 动态代理指运行时动态生成目标类的代理对象,在不修改目标类源码的前提下,对目标方法进行增强(如日志、权限校验)。

② 核心要求: 目标类必须实现至少一个接口(JavaSE 原生限制)。

③ 核心类:
  • java.lang.reflect.Proxy:生成代理对象的工具类;
  • java.lang.reflect.InvocationHandler:定义增强逻辑的接口。
2. 代码示例

ProxyUtil.java

java 复制代码
package demo1;

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

public class ProxyUtil {

    public static Star createProxy(BigStar bigStar) {
        Star star = (Star) Proxy.newProxyInstance(ProxyUtil.class.getClassLoader(),
                new Class[]{Star.class},
                new InvocationHandler() {
                    @Override
                    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                        if("sing".equals(method.getName())){
                            System.out.println("准备话筒,收钱");
                        }else if("dance".equals(method.getName())){
                            System.out.println("准备场地,收钱");
                        }

                        method.invoke(bigStar,args);
                        return null;
                    }
                });
        return star;
    }
}

Star.java

java 复制代码
package demo1;

public interface Star {
    public abstract String sing(String name);

    public abstract void dance();
}

test.java

java 复制代码
package demo1;

public class test {
    public static void main(String[] args) {
        BigStar bigStar = new BigStar("鸡哥");
        Star proxy = ProxyUtil.createProxy(bigStar);

        String result = proxy.sing("只因你太美");
        System.out.println(result);
    }
}

BigStar.java

java 复制代码
package demo1;

public class BigStar implements Star {
    private String name;

    public BigStar() {
    }

    public BigStar(String name) {
        this.name = name;
    }

    /**
     * 获取
     * @return name
     */
    public String getName() {
        return name;
    }

    /**
     * 设置
     * @param name
     */
    public void setName(String name) {
        this.name = name;
    }

    @Override
    public String sing(String name) {
        System.out.println(this.name + "正在唱" + name);
        return "谢谢";
    }

    @Override
    public void dance() {
        System.out.println(this.name + "跳舞");
    }
    

    public String toString() {
        return "BigStar{name = " + name + "}";
    }
}
相关推荐
傻小胖16 小时前
13.BTC-思考-北大肖臻老师客堂笔记
笔记·区块链
好奇龙猫16 小时前
【日语学习-日语知识点小记-日本語体系構造-JLPT-N2前期阶段-第一阶段(9):単語文法】
学习
Java天梯之路16 小时前
Spring Boot 钩子全集实战(七):BeanFactoryPostProcessor详解
java·spring boot·后端
AI浩16 小时前
约束模型下的目标检测置信学习
学习·目标检测·目标跟踪
wr20051417 小时前
第二次作业,渗透
java·后端·spring
m0_7482299917 小时前
ThinkPHP快速入门:从零到实战
c语言·开发语言·数据库·学习
風清掦17 小时前
【江科大STM32学习笔记-04】0.96寸OLED显示屏
笔记·stm32·学习
阿蒙Amon17 小时前
C#每日面试题-Thread.Sleep和Task.Delay的区别
java·数据库·c#
胡西风_foxww17 小时前
ObsidianAI_学习一个陌生知识领域_建立学习路径和知识库框架_写一本书
人工智能·笔记·学习·知识库·obsidian·notebooklm·写一本书
Haooog17 小时前
AI应用代码生成平台
java·学习·大模型·langchain4j