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 + "}";
    }
}
相关推荐
CHANG_THE_WORLD6 小时前
C++ vs Python 参数传递方式对比
java·c++·python
talenteddriver6 小时前
java: 4种API 参数传递方式
java·开发语言
sdkingz6 小时前
cursor学习笔记
java
Element_南笙6 小时前
吴恩达新课程:Agentic AI(笔记11)
大数据·人工智能·笔记·算法·机器学习
小王师傅666 小时前
【轻松入门SpringBoot】从 0 到 1 搭建 SpringBoot 工程-中
java·spring boot·spring
懵萌长颈鹿7 小时前
Tkinter 学习文档
学习
YJlio7 小时前
Active Directory 工具学习笔记(10.1):AdExplorer 实战(一)— 连接到域与界面总览
笔记·学习·安全
豐儀麟阁贵7 小时前
9.5格式化字符串
java·开发语言·前端·面试
崇山峻岭之间7 小时前
C++ Prime Plus 学习笔记025
c++·笔记·学习