反射学习笔记
反射
反射机制有什么用?
通过java语言中的反射机制可以操作字节码文件。有点类似于黑客(可以读和修改字节码文件)
通过反射机制可以操作代码片段
反射机制的相关类在哪个包下
java.lang.reflect
反射机制相关的类有哪些
java.lang.class //代表整个字节码,代表一个类型
java.lang.reflect.Method //代表字节码中的方法字节码,类中的方法
java.lang.reflect.Constructor //代表字节码中的构造方法字节码,类中的构造方法
java.lang.reflect.Field //代表字节码中的属性字节码,类中的成员变量
关于类加载器
JDK自带3个类加载器
启动类加载器
扩展类加载器
应用类加载器
假设有这样一段代码:
String s = "abc";
代码在开始执行之前,会将所需要的类全部加载到JVM当中。通过类加载器加载,看到以上代码类加载器会找String.class文件,找到就加载
首先通过启动类加载器加载
注意:启动类加载器专门加载:.\jdk1.8.0\jre\lib\rt.jar中rt.jar都是JDK最核心的类库。
如果通过启动类加载器加载不到时
会通过扩展类加载器加载
注意:扩展类加载器专门加载:.\jdk1.8.0\jre\lib\ext\*.jar
如果扩展类加载器没有加载到
那么会通过应用类加载器加载
注意:扩展类加载器专门加载:classpath中的jar包(class文件)
java中为了保证类加载的安全,使用了双亲委派机制,父:启动类加载器,母:扩展类加载器
反射属性Field
//获取整个类
Class c = Class.forName("misson.reflection.net.ReflectTest04");
//完整类名
System.out.println("完整类名:"+c.getName());
System.out.println("简类名:"+c.getSimpleName());
//获取类中所有的属性名字(获取的值与权限有关)
Field[] fields = c.getFields();
System.out.println(fields.length);// 1
Field[] fields1 = c.getDeclaredFields();
System.out.println(fields1.length);// 4
for (Field field : fields1) {
//获取修饰符(每一个数字是一个修饰符的代号)
int i = field.getModifiers();
//修饰符转换成字符串
System.out.print(Modifier .toString(i)+": ");
//获取类型名
String typeName = field.getType().getSimpleName();
System.out.print(typeName+":");
//获取属性的名字
System.out.println(field.getName());
}
反编译Field
public static void main(String[] args) {
try {
//拼接字符串
StringBuilder s = new StringBuilder();
Class c = Class.forName("misson.reflection.net.ReflectTest05");
//类名
s.append(Modifier.toString(c.getModifiers()) +" class "+c.getSimpleName() +"{\n");
//成员变量
Field[] fields = c.getDeclaredFields();
for (Field field : fields) {
s.append("\t");
//每一行成员变量
s.append(Modifier.toString(field.getModifiers())+" "+field.getType().getSimpleName()+" "+field.getName()+"\n");
}
s.append("}");
System.out.println(s);
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
}
访问对象属性(重要!)
不使用反射机制(三要素:obj对象,age属性,属性值)
ReflectTest06 reflectTest06 = new ReflectTest06();
//给属性赋值
reflectTest06.age = 20;
//读取属性值
System.out.println(reflectTest06.age);
使用反射机制(三要素:obj对象,age属性,属性值)
// 调用无参数构造方法
Object obj = c.newInstance();
// 根据属性名称获取Field
Field agefield = c.getDeclaredField("age");
// 给obj对象的age属性赋值
agefield.set(obj,30);
// 读取属性值
System.out.println(agefield.get(obj));
是否可以访问private的?不行!
但是可以用field.setAccessible(true)打破封装,设置完后,在外部也是可以访问private的
可变长度参数
public static void m(int... args){
}
//args可以做一个数组
public static void m2(int i,String... args){
}
//可变长度参数要求的参数个数是0-n个
public static void main(String[] args) {
m();
m(10);
m(10,20);
m2(100);
m2(100,"sa");
m2(100,"dsa","dsa");
m2(100,"Dsa","Dsa","dsvds");
//也可以直接传一个数组
m2(200,new String[]{"我","是","中","国","人"});
}
报错!
public static void m(String... args,int... args){
//错误可变长参数只能在最后一个,只能出现一个
}
反射属性Method
反编译Method
public class ReflectTest07 {
public static void main(String[] args) {
try {
Class c = Class.forName("misson.reflection.net.UserService");
Method[] methods = c.getDeclaredMethods();
StringBuilder s = new StringBuilder();
for (Method method : methods) {
//修饰符
s.append("方法:"+Modifier.toString(method.getModifiers()));
//返回值名称
s.append(" "+method.getReturnType().getSimpleName());
//方法名
s.append(" "+method.getName());
//参数类型数组
Class[] cmethods = method.getParameterTypes();
s.append("(");
//参数类型
for (Class cmethod : cmethods) {
s.append(cmethod.getSimpleName()+",");
}
s.deleteCharAt(s.length()-1);
s.append(")");
s.append("{\n");
s.append("}\n");
}
System.out.println(s);
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
}
}
class UserService{
public String login(String userName,String passWord){
return ";";
}
public void add(int i){
}
}
调用方法(最重要的!)
Class c = Class.forName("misson.reflection.net.UserService");
Object obj = c.newInstance();
//获取方法不能只用方法名
Method loginmethod = c.getDeclaredMethod("login",new Class[]{String.class,String.class});
//调用方法(要素:对象,方法名,实参列表,返回值)
Object s = loginmethod.invoke(obj,"admin","124");
System.out.println(s);
反射机制很具有通用性,让可变化的内容都是写到配置文件当中,就算对象不一样了,调用的方法不同了,但是java代码不需要做任何改变
反射属性Constructor
反编译Constructor
//拼接构造方法
Constructor[] constructors = c.getDeclaredConstructors();
for (Constructor constructor : constructors) {
s.append("\t");
s.append(Modifier.toString(constructor.getModifiers())+" ");
s.append(c.getSimpleName());
//参数参数
Class[] classes = constructor.getParameterTypes();
s.append("(");
for (Class aClass : classes) {
s.append(aClass.getSimpleName()+",");
}
if (classes.length!=0) {
s.deleteCharAt(s.length() - 1);
}
s.append(")");
s.append("{");
s.append("}\n");
}
调用构造方法
通过反射机制,调用构造方法实例化java对象
Class c = Class.forName("misson.reflection.net.ReflectTest09");
//无参
Object obj = c.newInstance();
//有参
Constructor constructor = c.getDeclaredConstructor(int.class,String.class,int.class,boolean.class);
Object obj1 = constructor.newInstance(110,"jackson",150,true);
System.out.println(obj1.toString());
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· AI与.NET技术实操系列:基于图像分类模型对图像进行分类
· go语言实现终端里的倒计时
· 如何编写易于单元测试的代码
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 25岁的心里话
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列01:轻松3步本地部署deepseek,普通电脑可用
· 按钮权限的设计及实现