java面试:知道java的反射机制吗

java的反射机制是java当中十分主流的技术,java的核心底层思想之一IOC就是基于反射技术实现的,正因如此,在面试当中反射常常作为一个常考的问题来考察面试者的素养,今天小编就来和大家分享这一方面的知识,希望大家都能有所收获。

1.反射的概念

反射是指在程序的运行期间,可以实时的获取到类的信息,并将类的成分当作对象来操作,而这种动态获取并调用信息的能力就叫做反射。

2.反射的应用场景

  • 运行时获取任意对象的类信息

  • 动态创建对象

  • 读写私有字段

  • 调用私有方法

  • 绕过泛型擦除

  • 实现通用框架

3.反射的使用

Class类的常用方法:

  1. 拿字节码:String.class、obj.getClass()、Class.forName("全限定名")

  2. 看名字:getName() 得全限定名,getSimpleName() 得类简称,getPackageName() 得包名

  3. 看血统:getSuperclass() 拿父类,getInterfaces() 拿直接实现的接口数组

  4. 看字段:getFields() 只给 public(含继承),getDeclaredFields() 本类全权限(含 private)

  5. 拿单个字段:getField("age") 仅 public,getDeclaredField("age") 可破私有,之后 setAccessible(true) 即可读写

  6. 看方法:getMethods() 给 public(含继承),getDeclaredMethods() 本类全权限(含 private)

  7. 拿单个方法:getMethod("foo", int.class) 仅 public,getDeclaredMethod("foo", int.class) 可破私有,invoke 调用

  8. 看构造:getConstructors() 仅 public,getDeclaredConstructors() 含私有;getDeclaredConstructor(param...) 拿指定构造,newInstance(args) 建对象

  9. 创实例:clazz.getDeclaredConstructor().newInstance() 替代已过时的 clazz.newInstance()

  10. 看注解:getAnnotation(Anno.class) 取注解,isAnnotationPresent(Anno.class) 判断有无

  11. 类型判断:isInterface()、isEnum()、isArray()、isPrimitive()、isSynthetic() 快速识别

  12. 数组:Array.newInstance(int.class, 5) 动态建数组,Array.set/get 读写元素

  13. 泛型残留:getGenericSuperclass() 再强转 ParameterizedType,可读到父类泛型实参

  14. 类加载器:getClassLoader() 拿定义加载器,Bootstrap 返回 null

  15. 模块:getModule() 拿 Module 对象,JDK 9+ 可用

实现代码:

java 复制代码
import java.lang.reflect.*;
import java.util.ArrayList;
import java.util.List;

/**
 * 反射机制一次性演示
 */
public class ReflectionProof {

    /* ============ 1. 任意对象都能拿到 Class ============ */
    public static void obtainClass() throws ClassNotFoundException {
        // 三种常见写法
        Class<?> c1 = User.class;              // 类字面量
        Class<?> c2 = new User().getClass();   // 对象.getClass()
        Class<?> c3 = Class.forName("User");   // 全限定名
        System.out.println("c1==c2? " + (c1 == c2));
        System.out.println("c2==c3? " + (c2 == c3));
    }

    /* ============ 2. 动态创建对象 ============ */
    public static void createObject() throws Exception {
        Class<User> clz = User.class;
        // 公有无参构造
        User u1 = clz.getDeclaredConstructor().newInstance();
        // 私有有参构造
        Constructor<User> c = clz.getDeclaredConstructor(int.class, String.class);
        c.setAccessible(true);                 // 暴力破门
        User u2 = c.newInstance(18, "Tom");
        System.out.println("u2 = " + u2);
    }

    /* ============ 3. 读写私有字段 ============ */
    public static void manipulateField() throws Exception {
        User u = new User(20, "Alice");
        Field ageField = User.class.getDeclaredField("age");
        ageField.setAccessible(true);
        ageField.setInt(u, 30);                // 把年龄改成 30
        System.out.println("修改后 age = " + ageField.get(u));
    }

    /* ============ 4. 调用私有方法 ============ */
    public static void callPrivateMethod() throws Exception {
        User u = new User();
        Method m = User.class.getDeclaredMethod("secret", String.class);
        m.setAccessible(true);
        String result = (String) m.invoke(u, "hello");
        System.out.println("私有方法返回: " + result);
    }

    /* ============ 5. 绕过泛型擦除 ============ */
    @SuppressWarnings("unchecked")
    public static void breakGeneric() throws Exception {
        List<Integer> list = new ArrayList<>();
        list.add(1);

        // 拿到原始字节码后,泛型信息被擦除
        Method add = list.getClass().getMethod("add", Object.class);
        add.invoke(list, "我不是 Integer");      // 成功塞进去

        System.out.println("list 内容 = " + list);
        for (Object o : list) {
            System.out.println("元素类型: " + o.getClass() + ", 值: " + o);
        }
    }

    public static void main(String[] args) throws Exception {
        obtainClass();
        createObject();
        manipulateField();
        callPrivateMethod();
        breakGeneric();
    }
}

/* ==================== 被操作的小可怜 ==================== */
class User {
    private int age;
    private String name;

    public User() {}

    private User(int age, String name) {
        this.age = age;
        this.name = name;
    }

    private String secret(String msg) {
        return "私有方法收到: " + msg;
    }

    @Override
    public String toString() {
        return "User{age=" + age + ", name='" + name + "'}";
    }
}

今天的分享就到这里了,希望这篇博客能给你一些帮助,让你对关于java反射机制的问题得到进一步的提升,在面试的时候能从容面对面试官。

相关推荐
Jeremy爱编码2 小时前
实现 Trie (前缀树)
开发语言·c#
laocooon5238578862 小时前
插入法排序 python
开发语言·python·算法
你的冰西瓜2 小时前
C++中的list容器详解
开发语言·c++·stl·list
java1234_小锋2 小时前
Java进程占用的内存有哪些部分?
java
就不掉头发2 小时前
I/O复用
运维·服务器·c语言·开发语言
sxlishaobin3 小时前
Spring Bean生命周期详解
java·后端·spring
曹牧3 小时前
Java:Assert.isTrue()
java·前端·数据库
梦里小白龙3 小时前
JAVA 策略模式+工厂模式
java·开发语言·策略模式
安_3 小时前
js 数组splice跟slice
开发语言·前端·javascript