java上乘武功入门--反射
作者:二当家的白帽子 发布时间:2021-06-08 21:32:27
标签: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是不变类。但是反射 * 却可以打破一切禁忌。
来源:https://blog.csdn.net/leyi520/article/details/118676211


猜你喜欢
- 通过本文你可以用非常简短的代码替代业务逻辑中的判null校验,并且很容易的在出现空指针的时候进行打日志或其他操作。注:如果对Java8新特性
- 1.元组(Tuple)元组(Tuple)在4.0 的时候就有了,但元组也有些缺点,如: 1)Tuple 会影响代码的
- (一)springboot web项目打jar包1、打包两种打包方式maven命令打包切换目录到工程根下,pom.xml所在位置,运行mav
- java.lang.NoClassDefFoundError错误解决办法前言在日常Java开发中,我们经常碰到java.lang.NoCla
- C#的timer与线程使用卡顿怎么处理,多线程。多线程比timer好读。看看timer和线程的关系。timer有3种1.winform 下的
- 本文包含3种隐藏顶部状态栏及标题栏和一种隐藏Android 4.0平板底部状态栏的方法,分享给大家供大家参考,具体内容如下方法一public
- JAVA中反射机制(JavaBean的内省与BeanUtils库)内省(Introspector) 是Java 语言对JavaBean类属性
- 最近研究了一下android摄像头开发相关的技术,也看了Google提供的Camera2Basic调用示例,以及网上一部分代码,但都是在Te
- 使用场景1、将用户信息导出为excel表格(导出数据....)2、将Excel表中的信息录入到网站数据库(习题上传....)大大减轻网站录入
- 网上关于java图片格式内容的文章不是很多,也不是很完整,小编搜集了三段java图片格式转换代码,分享给大家:第一段:java图片格式转换代
- idea默认带的equals和hashcode引起的bug最近因规范需要,统一使用idea,使用的版本为2017.4.建立一个实体类,在添加
- 具体代码如下所示:package zhangphil.test; import android.graphics.Bitmap; impor
- 本文实例为大家分享了java实现TCP聊天程序的具体代码,供大家参考,具体内容如下服务端代码:package com.test.server
- 这篇文章主要介绍了Java开发工具IntelliJ IDEA安装图解,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习
- 一、BroadcastState 的介绍广播状态(Broadcast State)是 Operator State 的一种特殊类型。如果我们
- 本文实例为大家分享了Java实现分页功能的具体代码,供大家参考,具体内容如下不用根据改变SQL的形式去查询; 直接查询所有的数据,根据页码自
- 内存对齐的基本原则:结构(struct/class)的内置类型数据成员,第一个数据成员放在offset为0的地方,以后每个数据成员的起始位置
- 本文实例为大家分享了Java实现递归计算n的阶乘的具体代码,供大家参考,具体内容如下问题描述利用递归的思想实现阶乘的计算,以 n!为例(一)
- 前言taptap-developer是一个spring boot框架驱动的纯Grpc服务,所以,只用了四步,移除了web和spring cl
- IDEA 全称 IntelliJ IDEA,是java编程语言开发的集成环境。IntelliJ在业界被公认为最好的java开发工具,尤其在智