JAVA高新技术反射机制的原理之构造函数、普通方法和字段

本文深入讲解Java反射机制,包括Class类的基本概念、如何通过不同方式获取类的字节码、Class对象提供的常用方法及其实现的功能。并通过具体的代码示例演示了如何利用反射操作类的构造方法、普通方法及字段。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >


Java中有一个Class类用于代表某个类的字节码(如果读者不了解反射、字节码和类Class,可以看下我写的JAVA反射机制原理中的字节码和类Class)

Class类既然代表某个类的字节码,它当然就要提供加载摸个字节码的方法:forName(),forName方法用于加载某个类的字节码到内存中。

另外2种得到类字节码的方法:

类名.class和对象.getClass()

Class对象提供了如下常用方法:

下面是获取某个类中public修饰的成员

//根据参数,确定反射出哪个构造函数

public Constructor  getConstructor(Class<?>  ...parameterTypes)

//第一个参数:获取某个类中哪个方法;第二个参数:方法所需要的参数类型

//例如有一个方法叫void  method(String  name,int age)

//那么getMethod要传入的参数分别是getMethod("method",String.class,int.class);

public Method  getMethod(String  name,Class<?>  ...parameterTypes)

//获取某个类中的某个字段(即某个属性)

public Field  getField(String  name)

下面是获取某个类中private修饰的成员,还有一个setAccessible是设置最大的访问权限,即暴力反射。

public Constructor  getDeclaredConstructor(Class<?>  ...parameterTypes)

public Method  getDeclaredMethod(String  name,Class<?>  ...parameterTypes)

public Field  getDeclaredField(String  name)

下面是获取某个类中所有的成员

public Constructor[]  getConstructors(Class<?>  ...parameterTypes)

public Method[]  getMethods(String  name,Class<?>  ...parameterTypes)

public Field[]  getFields(String  name)

下面看具体代码分析,解释都在代码中:主要讲三点构造方法的反射、普通方法的反射和字段的反射。

先写个Person类,里面主要有字段、构造函数和普通方法,我们就是对这个类进行反射。

public class Person {
	
	public String name="lisi";
	private int age=233;
	private static int id=10023421;
	public Person(){}
	
	public Person(String name){
		System.out.println("name:"+name);
	}
	
	public Person(String name,int age)
	{
		System.out.println("name:"+name+"age:"+age);
	}
	
	private Person(List list){}
	
	public void run()
	{
		System.out.println("run.....");
	}
	
	public void run(String name,int age)
	{
		System.out.println("name"+name+"age:"+age);
	}
	
	public Class[] run(String name,int[] arr)
	{
		return new Class[]{String.class};
	}
	
	private void run(InputStream in)
	{
		System.out.println(in);
	}
	
	public static void run(int num)
	{
		System.out.println(num);
	}
	
	public static void main(String[] args)
	{
		System.out.println(args.length);
	}
}

下面对Person类中的成员进行反射操作,(这里用到了junit测试)

public class TestPerson {
//反射Person类中的构造函数(Constructor)
	//反射构造函数:public Person()
	@Test
	public void test1() throws Exception
	{
		//你要使用一个类,就必须将其字节码加载到内存,然后给这个字节码取个名字(clazz)
		//下面的做法就是获取某个类的字节码,通常我们采用下面这种方式
		Class clazz=Class.forName("day16.reflect.base.Person");
		//有了Person类在字节码后就可以用这个字节码得到Person类中的某个构造函数了
		//传入参数是什么就是获取什么构造函数
		Constructor con=clazz.getConstructor(null);
		//有了构造函数后就可以创建对象了,
		Person p=(Person) con.newInstance(null);
		//下面是测试,用创建好的p对象,访问Person类的name属性
		System.out.println(p.name);
		
	}
	
	//反射构造函数:public Person(String name)
	@Test
	public void test2()throws Exception
	{
		Class clazz=Class.forName("day16.reflect.base.Person");
		//获取哪个构造函数,当然是参数是String name的构造函数了
		Constructor con=clazz.getConstructor(String.class);
		//实例化一个Person类的一个实例对象,怎么做,要传入一个name,就像
		//Person p=new Person("李四");
		Person p=(Person) con.newInstance("李四");
		System.out.println(p.name);
	}
	
	//反射构造函数:public Person(String name,int age)
	@Test
	public void test3()throws Exception
	{
		Class clazz=Class.forName("day16.reflect.base.Person");
		Constructor con=clazz.getConstructor(String.class,int.class);
		Person p=(Person) con.newInstance("王五",12);
		System.out.println(p.name);
	}
	
	//反射构造函数:private Person(List list)
	@Test
	public void test4()throws Exception
	{
		Class clazz=Class.forName("day16.reflect.base.Person");
		//getDeclaredConstructor方法是获取private修饰的构造函数
		Constructor con=clazz.getDeclaredConstructor(List.class);
		//此方法是给Constructor最大的权利,就是强暴访问Person类的private的东西
		con.setAccessible(true);
		Person p=(Person) con.newInstance(new ArrayList());
		System.out.println(p.name);
	}
	
	//创建无参对象的另一种途径
	@Test
	public void test5()throws Exception
	{
		Class clazz=Class.forName("day16.reflect.base.Person");
		//看到了创建Person类的无参对象时,直接用Class类中的newInstance方法创建对象了
		//而不是用Constructor类中的newInstance方法创建对象,这是简化的操作,可以直接用Class
		//类中的方法去创建对象,不过Person类要有一个无参的构造函数。
		Person p=(Person) clazz.newInstance();
		System.out.println(p.name);
	}
反射Person类中的普通方法(Method)
	//反射方法:public void run()
	@Test
	public void test6()throws Exception
	{
		
		Class clazz=Class.forName("day16.reflect.base.Person");
		//创建Person类的一个对象,这里就不用反射的方式创建对象了,演示太麻烦
		Person p=new Person();
		/*Constructor con=clazz.getConstructor(null);
		Person p=(Person) con.newInstance(null);*/
		//利用Class类的getMethod方法获取Perosn类中的普通方法,返回值是Method类型
		//第一个参数是要反射Person类中的那个方法,第二个参数是反射方法的要传入的参数类型
		//第二个参数是决定到底调用Person类中同名方法的哪个方法
		Method method=clazz.getMethod("run", null);
		//利用Method类的invoke方法来运行反射得到的method方法,
		//第一个参数是method要作用于哪个对象上,第二个参数是run方法的参数
		method.invoke(p, null);
	}
	
	//反射方法:public void run(String name,int age)
	@Test
	public void test7()throws Exception
	{
		Class clazz=Class.forName("day16.reflect.base.Person");
		Person p=new Person();
		Method method=clazz.getMethod("run", String.class,int.class);
		method.invoke(p, "时将",22);
		
	}
	
	//反射方法:public Class[] run(String name,int[] arr)
	@Test
	public void test8()throws Exception
	{
		Class clazz=Class.forName("day16.reflect.base.Person");
		Person p=new Person();
		Method method=clazz.getMethod("run", String.class,int[].class);
		method.invoke(p, "都了",new int[]{1,23,3});
	}
	
	//反射方法:private void run(InputStream in)
	@Test
	public void test9()throws Exception
	{
		Class clazz=Class.forName("day16.reflect.base.Person");
		Person p=new Person();
		//注意run是private
		Method method=clazz.getDeclaredMethod("run", InputStream.class);
		//暴力反射
		method.setAccessible(true);
		method.invoke(p, new FileInputStream("e:\\test.txt"));
	}
	
	//反射方法:public static void run(int num)
	@Test
	public void test10()throws Exception
	{
		Class clazz=Class.forName("day16.reflect.base.Person");
		Person p=new Person();
		Method method=clazz.getMethod("run",int.class);
		//因为run方法是static,类名可以直接调用,所以invoke中第一个参数可以不传入参数,
		//如果有最好
		method.invoke(null, 44);
		//method.invoke(p, 44);
	}
	
	//反射方法:public static void main(String[] args)
	@Test
	public void test11()throws Exception
	{
		Class clazz=Class.forName("day16.reflect.base.Person");
		Person p=new Person();
		Method method=clazz.getMethod("main",String[].class);
		//method.invoke(null, new String[]{"aaa","bbb"});//如果写成这样,会出错,看说明
		//下面两个方法都可以
		//method.invoke(null, (Object)new String[]{"aaa","bbb"});
		method.invoke(null, new Object[]{new String[]{"aaa","bbb"}});
		
		/*
		 说明:
		 jdk1.5: Method.invoke(String methodName,Object ...args)
		 jdk1.4: Method.invoke(String methodName,Object[] args)
		 1.5兼容1.4的做法,当你将new String[]{"aaa","bbb"}传入后,1.4会按照Object[] args
		 的方式把String数组拆开,变成了("aaa","bbb"),可是main(String[] args)函数要的是一个数组,你却传了("aaa","bbb")
		 那么main函数怎么能受得了。
		 * */
	}
//反射Person类的字段(Filed)
	//反射Person类字段:public String name="lisi";
	@Test
	public void test12()throws Exception
	{
		Class clazz=Class.forName("day16.reflect.base.Person");
		Person p=new Person();
		//使用Person类的字节码clazz获得字段的名字,返回的类型是Field
		Field field=clazz.getField("name");
		//获得字段的值,作用于Person类的一个实例对象p上
		String value=(String) field.get(p);
		System.out.println("字段的值:"+value);
		
		//获取字段的类型
		Class cValue=field.getType();
		System.out.println("字段的类型"+cValue);
		
		//我们获取到字段有什么好处,有什么用?看下面示例
		//以后我们可以判断获取字段的类型是不是自己想要的,如果是就对其进行设值
		if(cValue.equals(String.class))
		{
			field.set(p, "点击");
			System.out.println("设置字段值,并获取:"+field.get(p));
		}
	}
	
	//反射Person类字段:private int age;
	@Test
	public void test13()throws Exception
	{
		Class clazz=Class.forName("day16.reflect.base.Person");
		Person p=new Person();
		//age是private
		Field field=clazz.getDeclaredField("age");
		field.setAccessible(true);//暴力访问
		System.out.println(field.get(p));
		
	}
	
	//反射Person类字段:private static int id;
	@Test
	public void test14()throws Exception
	{
		Class clazz=Class.forName("day16.reflect.base.Person");
		Person p=new Person();
		//int age 是private
		Field field=clazz.getDeclaredField("id");
		field.setAccessible(true);//暴力访问
		//注意这里,id是static修饰的,可是我们利用field获取字段值时,还要传入一个对象
		System.out.println(field.get(p));
		
	}
}



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值