Java反射

前言

以前一直觉得反射这一块非常的难,没用在上面花费太多时间,平时工作中也使用的很少,因此,对这一块来说掌握的也不太好,最近有时间整理一下Java基础知识点,把这一块内容进行了复习,发现还是很有趣的,在此整理一些知识点,方便再次复习。

知识点

背景

Java反射是非常重要的一块Java知识点,没用它就没有Java准动态语言的说法,它被大量使用在框架、设计模式中,是框架诞生的基石。

概念

反射:允许程序在执行期间借助Reflection API获取任何类的内部信息(比如:变量、方法、构造方法),并能操作对象的属性及方法。

类加载

此处借用韩老师的一张图,上面详细的描述了类加载的过程。首先,Java源码通过javac编译成为字节码文件,再通过java运行字节码文件加载到内存中。
在这里插入图片描述
类加载后内存中的布局是方法区中有类的字节码文件二进制数据,也就是元数据,并指向堆中的类的Class对象。

分别阐明各阶段任务。
在这里插入图片描述
验证:
在这里插入图片描述
准备:
在这里插入图片描述
解析:
在这里插入图片描述

相关类

反射所使用到的类基本都在java.lang.reflect包中,主要有以下几个类。
1、java.lang.Class 代表一个类 Class的对象表示某个类加载到堆中的对象
2、java.lang.reflect.Field 代表类的属性
3、java.lang.reflect.Method 代表类的方法
4、java.lang.reflect.Constructor 代表类的构造方法

API

此处列举常用API,其他API可看源码或手册查询。

//、、、、、、、、、、 获取Class对象的四种方式
// 方式一:类名.class
Class c1 = Test2.class;
// 方式二:对象.getClass()
Class c2 = new Test2().getClass();
// 方式三:Class.forName()
Class c3 = Class.forName("Test2");
// 方式四:类加载器
ClassLoader classLoader = Test2.class.getClassLoader();
Class c4 = classLoader.loadClass("Test2");

//、、、、、、、、、、、获取Class对象的其他内容
//获取Class对象的全类名
String name = c1.getName();
//获取简单类名
String simpleName = c1.getSimpleName();
//获取包名
Package package1 = c1.getPackage();
//获取父类
Class<? super Test2> superclass = c1.getSuperclass();
//获取注解
Annotation[] annotations = c1.getAnnotations();



//、、、、、、、、、、、获取构造方法
//获取Class对象及其父类所有的public的构造方法
Constructor[] constructors = c1.getConstructors();
//获取Class对象所有的构造方法
Constructor[] declaredConstructors = c1.getDeclaredConstructors();
//获取Class及其父类对象指定public的构造方法
Constructor<Test2> constructor = c1.getConstructor();
//获取Class对象指定的构造方法
Constructor<Test2> declaredConstructor = c1.getDeclaredConstructor();

//、、、、、、、、、、、获取类的实例对象
//方式一:
Object obj = c1.newInstance();
Test2 t1 = (Test2) obj;
//方式二:
Test2 t2 = (Test2) c1.newInstance();
//方式三:
Test2 t3 = declaredConstructor.newInstance();

//、、、、、、、、、、、获取对象属性(见名知意,如构造方法)
Field[] fields = c1.getFields();
Field field = c1.getField("name");

Field[] declaredFields = c1.getDeclaredFields();
Field declaredField = c1.getDeclaredField("name");

//、、、、、、、、、、、获取对象方法(见名知意,如构造方法)
Method[] methods = c1.getMethods();
Method method = c1.getMethod("getName");

Method[] declaredMethods = c1.getDeclaredMethods();
Method declaredMethod = c1.getDeclaredMethod("getName");
// 方法执行,方法的返回值就是Object的invoke
Object invoke = declaredMethod.invoke(c1);

//获取方法修饰符。返回值是int,需要将int转为对象的类似public等修饰符
int modifiers = declaredMethod.getModifiers();
String string = Modifier.toString(modifiers);
//获取方法返回类型
Class<?> type = declaredMethod.getReturnType();
//返回方法的参数类型,无法获取参数名
Class<?>[] parameterTypes = declaredMethod.getParameterTypes();

练习

这里记录两个小练习,非常基础,不过也能用到一些常用API。
练习一
定义一个类,有私有属性name,值为“helloKitty”,提供getName公共方法,使用反射修改name值并打印。

public class PrivateTest {
	private String name="hellokitty";
	public String getName(){
		return name;
	}
}
public class Test {
	public static void main(String[] args) throws Exception {
		Class<PrivateTest> cls = (Class<PrivateTest>) Class.forName("reflectDemo.PrivateTest");
		PrivateTest o = cls.newInstance();
		Field field = cls.getDeclaredField("name");
		field.setAccessible(true);
		field.set(o, "你好Kitty");
		Method declaredMethod = cls.getDeclaredMethod("getName");
		String name = (String) declaredMethod.invoke(o);
		System.out.println(name);
	}
}

练习二
使用反射打印File所有的构造器,并使用newInstance创建“D://test.txt”文件。

public class Test {
	public static void main(String[] args) throws Exception {
		Class<File> cls = (Class<File>) Class.forName("java.io.File");
		Constructor[] constructors = cls.getDeclaredConstructors();
		for(Constructor c:constructors){
			c.setAccessible(true);
			// 拼接构造方法
//			System.out.print(Modifier.toString(c.getModifiers())+"\t");
//			System.out.print(c.getName()+"(");
//			Parameter[] parameters = c.getParameters();
//			for (int i = 0; i < parameters.length; i++) {
//				if(i==parameters.length-1){
//					System.out.print(parameters[i].getType().getName()+" "+parameters[i].getName());
//					break;
//				}
//				System.out.print(parameters[i].getType().getName()+" "+parameters[i].getName()+",");
//			}
//			System.out.println(")");

			// 直接打印构造方法
			System.out.println(c);
		}
		
		Constructor<File> declaredConstructor = cls.getDeclaredConstructor(String.class);
		File file = declaredConstructor.newInstance("D://mytest.txt");
		Method declaredMethod = cls.getDeclaredMethod("createNewFile");
		declaredMethod.invoke(file);
		System.out.println("创建成功");
		
		
	}
}

此处使用了两种打印构造方法的方式,第一种是拼接,将构造方法的各部分信息拿到,并手动拼接,第二种是直接打印,但是第二种方式没用参数名,只有参数类型。
创建文件我使用的是public java.io.File(java.lang.String)构造方法,该方法是public的,因此不需要爆破,当然,也可以使用其他构造方法创建实例。

参考

本文参考于B站韩顺平老师的视频内容。地址为https://www.bilibili.com/video/BV1g84y1F7df,有兴趣的可以区看看,讲的挺不错。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值