java的上乘武功,反射,好好玩哦,绝对值得收藏

简介: 各位大侠们知道Java的反射是什么吗?可不是反着发射什么的哈。反射是Java的一种机制,一般也叫做反射机制,本文会讲反射机制是什么和怎么使用。请先给二当家的一个三连,然后接着读下去吧,多谢。

前言

各位大侠们知道Java的反射是什么吗?可不是反着发射什么的哈。

反射是Java的一种机制,一般也叫做反射机制,本文会讲反射机制是什么和怎么使用。

请先给二当家的一个三连,然后接着读下去吧,多谢。


先来看一段魔法吧

public class Test {
    private static void changeStrValue(String str, char[] value) {
        // 只要执行魔法代码就可以达到下面的效果
        // 施展魔法的代码稍后揭秘
    }

    public static void main(String[] args) {
        changeStrValue("abc", new char[]{'d','e','f'});

        String abc = "abc";
        System.out.println("abc");
        System.out.println(abc);
        System.out.println("abc".equals(abc));
    }
}

在这里插入图片描述

在这里插入图片描述

二当家的第一次看到这个执行结果觉得很有意思。明明应该是"abc"怎么就变成了"def"呢?那是因为有一段神奇的代码,下文将会揭秘,只要接着读下去你就会明白了。


反射机制是个什么玩意儿?

Java的反射(reflection)机制是指在程序的运行状态中,可以构造任意一个类的对象,可以了解任意一个对象所属的类,可以了解任意一个类的成员变量和方法,可以调用任意一个对象的属性和方法。这种动态获取程序信息以及动态调用对象的功能称为Java语言的反射机制。反射被视为动态语言的关键。

以上就是百科的解释。可能有点抽象,接着看二当家的给你秀起来解释一下。


构造任意一个类的对象

一般情况下,我们如果想要创建一个类的对象,应该要用到new关键字。但是像spring这样的框架,我们只需要配置类名,就可以得到类的实例。他是怎么做到的呢?

import java.util.List;

public class Test {
    /**
     * 根据类名取得类实例
     * @author 二当家的白帽子 https://le-yi.blog.csdn.net/
     * @param className
     * @param <T>
     * @return
     * @throws InstantiationException
     * @throws IllegalAccessException
     * @throws ClassNotFoundException
     */
    public static <T> T getInstance(String className) throws InstantiationException, IllegalAccessException, ClassNotFoundException {
        Class<T> clazz = (Class<T>) Class.forName(className);
        return clazz.newInstance();
    }

    public static void main(String[] args) throws InstantiationException, IllegalAccessException, ClassNotFoundException {
        List<String> list = getInstance("java.util.ArrayList");
        list.add("abc");
        list.add("def");

        for (String v : list) {
            System.out.println(v);
        }
    }
}

类名可以在程序运行中从配置文件获取,甚至是从网络获取,然后动态创建一个类的实例。

了解任意一个对象所属的类

import java.util.ArrayList;

public class Test {
     /**
     * 打印对象的类名
     * @author 二当家的白帽子 https://le-yi.blog.csdn.net/
     * @param o
     */
    public static void printClass(Object o) {
        System.out.printf(o.getClass().getName());
    }

    public static void main(String[] args) {
        printClass(new ArrayList<>());
    }
}

在这里插入图片描述


了解任意一个类的成员变量和方法

我们一般要使用一个类,先要知道有什么方法和属性,先了解,后使用。但是像spring那样的框架为什么可以为我们自动注入呢?他怎么知道我们一个对象里有什么属性呢?

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

public class Test {
    /**
     * 打印类的属性
     * @author 二当家的白帽子 https://le-yi.blog.csdn.net/
     * @param clazz
     */
    public static void printFields(Class clazz) {
        System.out.println(clazz.getName() + "包含如下属性:");
        for (Field f : clazz.getDeclaredFields()) {
            System.out.println(f);
        }
    }

    /**
     * 打印类的方法
     * @author 二当家的白帽子 https://le-yi.blog.csdn.net/
     * @param clazz
     */
    public static void printMethods(Class clazz) {
        System.out.println(clazz.getName() + "包含如下方法:");
        for (Method m : clazz.getDeclaredMethods()) {
            System.out.println(m);
        }
    }

    public static void main(String[] args) {
        printFields(MyClass.class);
        printMethods(MyClass.class);
    }
}

class MyClass {
    private String name;

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }
}

在这里插入图片描述


调用任意一个对象的属性和方法

像spring这样的框架,即使一个属性是私有属性并且没有set方法,一样可以注入。

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

public class Test {
    /**
     * 调用一个对象的方法
     * @author 二当家的白帽子 https://le-yi.blog.csdn.net/
     * @param o
     * @param methodName
     * @throws NoSuchMethodException
     * @throws InvocationTargetException
     * @throws IllegalAccessException
     */
    public static void callMethod(Object o, String methodName) throws NoSuchMethodException, InvocationTargetException, IllegalAccessException {
        Method m = o.getClass().getDeclaredMethod(methodName);
        m.setAccessible(true);
        m.invoke(o);
    }

    /**
     * 修改一个对象的属性
     * @author 二当家的白帽子 https://le-yi.blog.csdn.net/
     * @param o
     * @param fieldName
     * @param value
     * @throws IllegalAccessException
     */
    public static void changeFieldValue(Object o, String fieldName, Object value) throws NoSuchFieldException, IllegalAccessException {
        Field f = o.getClass().getDeclaredField(fieldName);
        f.setAccessible(true);
        f.set(o, value);
    }

    public static void main(String[] args) throws InvocationTargetException, NoSuchMethodException, IllegalAccessException, NoSuchFieldException {
        MyClass o = new MyClass();

        // 修改任意属性,即使是私有的
        changeFieldValue(o, "name", "二当家的白帽子");

        // 调用任意方法,即使是私有的
        callMethod(o, "printName");
    }
}

class MyClass {
    // 私有属性,只可以调用set方法修改
    private String name;

    private void printName() {
        // 私有方法,只有本类自己的实例可以调用
        System.out.println("My name is " + name);
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }
}

在这里插入图片描述


魔法揭秘

是时候揭秘魔法的真面目了,没错,也是利用了反射。

import java.lang.reflect.Field;

public class Test {
    /**
     * 修改字符串内部的值
     * @author 二当家的白帽子 https://le-yi.blog.csdn.net/
     * @param str
     * @param value
     */
    private static void changeStrValue(String str, char[] value) {
        try {
            Field f = str.getClass().getDeclaredField("value");
            f.setAccessible(true);
            f.set(str, value);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    public static void main(String[] args) {
        changeStrValue("abc", new char[]{'d','e','f'});

        // 这里的"abc"字符串和上面调用changeStrValue的参数"abc"会指向同一块内存
        String abc = "abc";
        System.out.println("abc");
        System.out.println(abc);
        System.out.println("abc".equals(abc));
    }
}

要理解这段代码,除了反射机制还需要了解java对于字符串的处理。"字符串常量池"已经超出本文的范围,是另一个话题,本文就不多说了。

原本字符串内容是"abc",我们正常情况下无法修改这个内容,因为String是不变类。但是反射大法却可以打破一切禁忌。


尾声

一般的程序可能用不到写反射的代码。但是像spring这样的框架,如果没有反射,我真的想不出如何实现呢。哪怕永远不需要用反射,了解机制对我们都有着莫大的好处。


非常感谢你阅读本文~
放弃不难,但坚持一定很酷~
希望我们大家都能每天进步一点点~
本文由 二当家的白帽子:https://developer.aliyun.com/profile/sqd6avc7qgj7y 博客原创~
相关文章
|
17天前
|
监控 Java
Java基础——反射
本文介绍了Java反射机制的基本概念和使用方法,包括`Class`类的使用、动态加载类、获取方法和成员变量信息、方法反射操作、以及通过反射了解集合泛型的本质。同时,文章还探讨了动态代理的概念及其应用,通过实例展示了如何利用动态代理实现面向切面编程(AOP),例如为方法执行添加性能监控。
|
1月前
|
Java
Java的反射
Java的反射。
26 2
|
2月前
|
存储 Java
[Java]反射
本文详细介绍了Java反射机制的基本概念、使用方法及其注意事项。首先解释了反射的定义和类加载过程,接着通过具体示例展示了如何使用反射获取和操作类的构造方法、方法和变量。文章还讨论了反射在类加载、内部类、父类成员访问等方面的特殊行为,并提供了通过反射跳过泛型检查的示例。最后,简要介绍了字面量和符号引用的概念。全文旨在帮助读者深入理解反射机制及其应用场景。
27 0
[Java]反射
|
3月前
|
安全 Java 索引
Java——反射&枚举
本文介绍了Java反射机制及其应用,包括获取Class对象、构造方法、成员变量和成员方法。反射允许在运行时动态操作类和对象,例如创建对象、调用方法和访问字段。文章详细解释了不同方法的使用方式及其注意事项,并展示了如何通过反射获取类的各种信息。此外,还介绍了枚举类型的特点和使用方法,包括枚举的构造方法及其在反射中的特殊处理。
67 9
Java——反射&枚举
|
2月前
|
安全 Java 测试技术
🌟Java零基础-反射:从入门到精通
【10月更文挑战第4天】本文收录于「滚雪球学Java」专栏,专业攻坚指数级提升,希望能够助你一臂之力,帮你早日登顶实现财富自由🚀;同时,欢迎大家关注&&收藏&&订阅!持续更新中,up!up!up!!
29 2
|
3月前
|
安全 Java API
【Java面试题汇总】Java基础篇——String+集合+泛型+IO+异常+反射(2023版)
String常量池、String、StringBuffer、Stringbuilder有什么区别、List与Set的区别、ArrayList和LinkedList的区别、HashMap底层原理、ConcurrentHashMap、HashMap和Hashtable的区别、泛型擦除、ABA问题、IO多路复用、BIO、NIO、O、异常处理机制、反射
【Java面试题汇总】Java基础篇——String+集合+泛型+IO+异常+反射(2023版)
|
2月前
|
IDE Java 编译器
java的反射与注解
java的反射与注解
17 0
|
3月前
|
Java 程序员 编译器
Java的反射技术reflect
Java的反射技术允许程序在运行时动态加载和操作类,基于字节码文件构建中间语言代码,进而生成机器码在JVM上执行,实现了“一次编译,到处运行”。此技术虽需更多运行时间,但广泛应用于Spring框架的持续集成、动态配置及三大特性(IOC、DI、AOP)中,支持企业级应用的迭代升级和灵活配置管理,适用于集群部署与数据同步场景。
|
3月前
|
存储 安全 Java
扫盲java基础-反射(一)
扫盲java基础-反射(一)
|
3月前
|
Java
扫盲java基础-反射(二)
扫盲java基础-反射(二)