1、反射的基础
反射的基石----》Class类
java程序中的各个java类属于同一类事物,描述这类事物的java类名就是Class
获取字节码对应的实例对象(Class类型)
class cls1 = Person.class//字节码1;
p1.getClass();
Class.forName("java.lang.String"); 主要用这种进行反射
8个基本类型,对应着8个Class对象
void.class 对象
String str1 = "abc"; Class cls1 = str1.getClass(); Class cls2 = String.class; Class cls3 = Class.forName("java.lang.String"); cls1==cls2 //true cls1==cls3 //true int.class.isPrimitive //true int.class == Integer.class //flase int.class == Integer.TYPE //true 数组类型的Class实例对象 Class.isArray()
2、反射的概念
反射就是把java类中的各种成分映射成对应的java类
例如:
成员变量---》Field对象
方法----》Method对象
构造方法---》Constructor对象
...
3、 构造方法的反射应用
Constructor类代表某一个构造方法
//new String(new StringBuffer("abc")) Constructor constructor1 = String.class.getConstructor(StringBuffer.class); String str2=(String)constructor1.newInstance(new StringBuffer("abc"))
class -> constructor -> new object
反射会导致程序性能下降
Class.newInstance()方法
例如:String obj = (Class)Class.forName("java.lang.String").newInstance();
该方法内部先得到默认的构造方法,然后用该构造方法创建实例对象
用了缓存机制来保存默认构造方法的实例对象
4、成员变量的反射
Field类代表某各类中的一个成员变量 public class ReflectPoint{ private int x; public int y; ...构造方法 } ReflectPoint pt1 = new ReflectPoint(3,5); //fieldY不是对象身上的变量,而是类上的,要用它取对应对象上的属性值 Field fieldY = pt1.getClass().getField("y"); //public fieldY.get(pt1); // 5 Field fieldX = pt1.getClass().getDeclaredField("x");//private filedX.setAccessible(true);//暴力反射 fieldX.get(pt1); public class ReflectPoint{ public String str1 ="ball"; public String str2 ="basketball"; public String str3 ="itcast"; } private static void changeStringValue(Object obj){ Field[] fields = obj.getClass.getFields(); for(Field field:fields){ //对字节码的比较用==号比 因为同一份字节码 if(field.getType() == String.class){ String oldValue =(String)field.get(obj); String newValue = oldValue.replace('b','a'); field.set(obj,newValue); } } }
5 、成员方法的反射
Method类代表某个类中的一个成员方法
Method methodCharAt = String.class.getMethod("charAt",int.class); //调用方法一定是在一个对象上 String str1="abc"; methodCharAt.invoke(str1,1);
如果传递给Method对象的invoke()方法的第一个参数为null,说明
该Method对象对应的是一个静态方法
6 、对接受数组参数的成员方法进行反射
用反射方式执行某个类中的main方法
public class TestArguments{ public static void main(String[] args){ for(String arg:args){ System.out.println(arg); } } } String clazz = "com.test.TestArguments"; Method mainMethod = Class.forName(clazz).getMethod("main",String[].class); mainMethod.invoke(null,new Object[](new String[]{"111","222"})); mainMethod.invoke(null,(Object)new String[]{"111","222"}); //编译器会做特殊处理,编译时不将参数作为数组看待,也就不会讲数组打算成若干参数了
7、 数组与Object的反射
相同的元素且相同的维度则是同一份字节码文件
int[] a1 = new int[3]; int[] a2 = new int[4]; int[][] a3 = new int[2][3]; String[] a4 = new String[3]; a1.getClass() == a2.getClass();//true a1.getClass() == a3.getClass();//false a1.getClass() == a4.getClass();//false
基本类型的数组是不能转为Object数组
Object[] aobj = a1//error
具有相同维数和元素类型的数组属于同一个类型,即具有相同的Class实例对象
代表数组的Class实例对象的getSuperclass()方法返回的父类为Object类对应的Class
基本类型的一维数组可以被当做Object类型使用,不能当作Object[]类型使用,非基本类型的一维数组,既可以当做Object类型使用,又可以当做Object[]类型使用
Arrays.asList()方法处理int[]和String[]存在差异Arrays工具类用于完成对数组的反射操作
private static void printObject(Object obj){ Class clazz = obj.getClass(); if(clazz.isArray()){ int len = Array.getLength(); for(int i=0;i<=len;i++){ System.out.println(Array.get(obj,i)); } }else{ System.out.println(obj); } }