构造函数、成员变量、成员方法、静态方法、数组的反射应用

时间:2022-09-20 19:28:51

1、     反射就是通过Class类提供的方法获取所有class类的构造函数(Constructor)、成员变量(Field)、成员方法(Method)、静态方法等;

2、Class类和class类的区别:描述所有人的类是Person类(class类),描述所有java类的的类是Class类Person类的实例是张三、李四; Class类的实例是各个类在内存中的字节码; 每个类在内存中的字节码是不同的,若每个类空间都用一个个对象来表示, 那么这些对象就具有相同的类型,那么这个类型就是Class

3、获取Sting字节码对应的实例对象(Class类型)的三种方法如下:

public class ReflectDemo {

	public static void sop(Object obj) {
		System.out.println(obj);
	}

	public static void main(String[] args) throws Exception {
		String s = "abcd";
		// 三种获取String字节码对应的实例对象(Class类型),
		//1、实例对象的getClass()方法获取
		Class<? extends String> cla = s.getClass();
		// 2、类名.class获取
		Class<String> clb = String.class;
		// 3、Class.forName("类名")方法获取
		Class<?> clc = Class.forName("java.lang.String");
		sop(cla == clb);
		sop(clb == clc);
		sop(cla);
		sop(clb);
		sop(clc);
	}
}
运行结果是:

true
true
class java.lang.String
class java.lang.String
class java.lang.String
通过结果知道三个获取的字节码是一致的,都是【 class java.lang.String
4、通过反射的原理写出构造方法

// 创造String实例的普通方法
		sop(new String(new StringBuffer("abc")));
		/*
		 * 创造String实例的反射方法,首先获取到String字节码的构造方法StringBuffer.class,
		 * 调用获得的构造方法时要用到相同类型的实例对象, 编译时没有使用cons后面的语句, 所以编译时若没有指定(String)则报错
		 * 
		 * Constructor类代表构造函数的类,通过字节码可以获取到任意一个类的构造函数
		 */
		// 通过类名.class获得的String字节码
		Constructor cons = String.class.getConstructor(StringBuffer.class);
		String str = (String) cons.newInstance(new StringBuffer("abc"));
		sop(str);
		// 通过Class.forName("类名")获得类名String的字节码
		Constructor cons1 = Class.forName("java.lang.String").getConstructor(
				StringBuffer.class);
		String str1 = (String) cons1.newInstance(new StringBuffer("bcd"));
		sop(str1);
		// 通过实例对象的获得
		String s1 = new String();
		Constructor cons2 = s1.getClass().getConstructor(StringBuffer.class);
		String str2 = (String) cons.newInstance(new StringBuffer("efg"));
		sop(str2);

		// 该方法获得是获得String类的无参构造函数
		String str3 = (String) Class.forName("java.lang.String").newInstance();
结果是:

abc
abc
bcd
efg
通过结果知道通过获取的String字节码调用Constructor类获取String类的构造方法结果是一致的


5、成员常量和成员方法的反射应用如下:

成员常量的类是Field类,成员方法的类是Method类

		/*
		 * Field类代表成员变量的类,通过二阶码可以获取任何类内的成员变量
		 */
		FieldClass fic = new FieldClass(4, 8);
		// public修饰的常量y,通过Field参数获取
		Field fa = fic.getClass().getField("y");
		sop(fa.get(fic));
		// private修饰的常量x,通过Field参数获取
		Field fb = fic.getClass().getDeclaredField("x");
		fb.setAccessible(true);
		sop(fb.get(fic));

		/*
		 * Method类代表成员方法的类,通过二节码可以获取任何类内的成员方法
		 */
		String st = "5678";
		Method mt = Class.forName("java.lang.String").getMethod("charAt",
				int.class);
		sop(mt.invoke(st, 2));
		//静态成员方法用反射的类调用,需要在invoke(null,)的第一个参数为空
		Method mta = Class.forName("java.lang.String").getMethod("valueOf",
				int.class);
		sop("静态成员方法:" + mta.invoke(null, 2));

6、反射调用另外一个类的main函数

import java.lang.reflect.Method;

public class ReflectMain {

	public static void main(String[] args) throws Exception {
		//调用主函数的参数,设置主函数的参数为newStudy.template(通过F2查看template的路径)
		String startClassName = args[0];
		Method mainMethod = Class.forName(startClassName).getMethod("main",
				String[].class);
		/*
		 * jdk1.5中是可变参数形式Object invoke(Object obj, Object...args).
		 * jdk1.4中是参数数组形式Object invoke(Object obj, Object[] obj).
		 * jdk1.5为了兼容jdk1.4,invoke()方法要接收到一个参数数组时,也会将数组进行拆分,当成方法的多个参数
		 */
		mainMethod.invoke(null, new Object[] { new String[] { "1", "2", "3" } });
		mainMethod.invoke(null, (Object) new String[] { "a", "b", "c" });
	}
}

class template {
	public static void main(String[] args) {
		for (String arg : args) {
			System.out.println(arg);
		}
	}
}
7、int[]等基本数据类型数组和String[]等引用数据类型数据在反射处理上是有些不同的,int[]等基本数据类型是按照一个整体处理,String[]等引用类型则自动进行拆分

import java.lang.reflect.Array;
import java.util.Arrays;

public class ArrayReflectDemo {

	public static void main(String[] args) {
		int[] a = new int[] { 1, 3, 5 };
		int[] b = new int[2];
		int[][] c = new int[2][];
		String[] s = new String[] { "sf", "wfw" };
		sop(a.getClass() == b.getClass());
		// 打印的[I 代表的是int类型的数组
		sop(a.getClass().getName());
		sop(s.getClass().getName());
		/*
		 * Incompatible operand types Class<capture#4-of ? extends int[]> and
		 * Class<capture#5-of ? extends int[][]> 下面两个都是互相不兼容的操作数据类型,不允许编译通过
		 */
		/*
		 * sop(a.getClass() == c.getClass()); sop(a.getClass() == s.getClass());
		 */
		sop(a.getClass().getSuperclass().getName());
		sop(s.getClass().getSuperclass().getName());

		Object aobj = a;
		Object bobj = b;
		Object cobj = c;
		Object sobj = s;
		/*
		 * 下面三个的打印结果是[[I@15db9742] 
		 * [I@15db9742 
		 * [[I@15db9742] 
		 * [I代表是整型的数组,[]代表的是集合
		 */
		sop("********");
		sop(Arrays.asList(a));
		//如果sop方法判断是否是数组,则可以逐个打印出来
		sop(a);
		sop(Arrays.asList(aobj));

		/*
		 * 下面三个打印的结果是:[sf, wfw] 
		 * [Ljava.lang.String;@6d06d69c
		 * [[Ljava.lang.String;@6d06d69c] 
		 * 基本数据类型的数组转换成集合后不能打印出来集合内的元素,
		 * String类型的可以转换成集合后且可以打印出集合内的元素
		 */
		sop("********");
		sop(Arrays.asList(s));
		//如果sop方法判断是否是数组,则可以逐个打印出来
		sop(s);
		sop(Arrays.asList(sobj));

	}
/*	private static void sop(Object obj){
		System.out.println(obj);
	}*/

	private static void sop(Object obj) {
		Class<? extends Object> a = obj.getClass();
		if(a.isArray()){
			int len = Array.getLength(obj);
			for(int i=0; i < len; i++){
				System.out.println(Array.get(obj, i));
			}
		}else{
			System.out.println(obj);
		}
	}

}

总结:

反射原理就是通过Class类型获取字节码内的构造方法、成员常量、成员方法赋予一个类(Constructor、Field、Method),再通过对应的类的方法获取java类的数据