黑马程序员_java之反射
反射
透彻分析反射的基础_Class类
JAVA类用于描述一类事物的共性,JAVA程序中的各个JAVA类属于同一类事物,类名就是Class.
Class类描述类的名字、访问属性、所属包名、字段、方法名称的列表等
一个类被类加载器加载到内存中,占用一个存储空间,不同类的字节码是不同的,但类型相同
得到字节码对应的实例对象?
类名.class; 对象.getClass(); Class.forName(“类名”)
作用:返回字节码
方式:字节码直接返回,加载后返回
九个预定义Class实例对象(八个基本类型+void
System.out.println(int.class.isPrimitive());//true 是否为原始类型
System.out.println(int.class = =Integer.class);//fasle
System.out.println(int.class = =Integer.TYPE);//true
System.out.println(int[].class.isPrimitive());//false 是否为原始类型
System.out.println(int[].class.isArray());//数组类型的Class实例对象用的是Class.isArray()
反射的概念
反射就是把JAVA类中的各种成分映射成相应的java类
一个类中的每个成员都可以用相应的反射API类的一个实例对象表示
构造方法的反射应用
Constructor类代表某个类的一个构造方法
得到所有的构造方法
Constructor<?>[] getConstructors()
得到某一个的构造方法
Constructor<T> getConstructor(Class<?>... parameterTypes)
创建实例对象
//new String(new StringBuffer("abc"));
//程序开发分为编译时和运行时 得到方法要类型,调用得到的方法要同样类型的对象
Constructor constructor1=String.class.getConstructor(StringBuffer.class);//得到构造方法
//反射方法创建实例
// 编译器不知道返回的是String的构造方法
String str2=(String)constructor1.newInstance(new StringBuffer("abc"));
System.out.println(str2.charAt(2));
Class. newInstance():
//得到默认的构造方法, 用该构造方法创建实例(用到了缓存机制来保存默认构造方法的实例对象)
String obj=(String) String.class.newInstance();
class-->constructor-->new object变成class -->new object
反射导致性能下降
成员变量的反射
Field类代表某个类中的一个成员变量
//成员变量的反射
ReflectPoint pt1=new ReflectPoint(3,5);
Field fieldy=pt1.getClass().getField("y");
//fieldy不是对象身上的变量,而是类上的变量
System.out.println(fieldy.get(pt1));
//x为私有,不可见
//Field fieldx=pt1.getClass().getField("x");
Field fieldx=pt1.getClass().getDeclaredField("x");
fieldx.setAccessible(true);//暴力反射
System.out.println(fieldx.get(pt1));
例:将任意一个对象中的所有String类型的成员变量所对应的字符串内容中的”b”改成”a”
private static void changeStringValue(Object obj) throws Exception{
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);
}
}
}
成员方法的反射
Method类代表某个类中的一个成员方法
得到类中的某一个方法
Method methodCharAt=String.class.getMethod("charAt", int.class);
调用方法
//通常方式str1.chaAt(1);
//反射方式
System.out.println(methodCharAt.invoke(str1, 1));// JDK1.5
System.out.println(methodCharAt.invoke(str1, new Object []{2}));//JDK1.4
//静态方法
//System.out.println(methodCharAt.invoke(null, 1));
对接受数组参数的成员方法进行反射
JDK1.5整个数组就是一个参数,JDK1.4数组中每一个元素对应一个参数
对接受数组参数的成员方法进行反射时会用JDK1.4
例:根据用户提供的类名,去执行该类的main方法
普通方法:
//TestArguments.main(new String[]{"11","22"});
反射方法:
//为什么要用反射?不知道类名,根据参数获得启动类名
String startingClassName=args[0];
Method mainMethod=Class.forName(startingClassName).getMethod("main", String[].class);
//mainMethod.invoke(null,new String[]{"11","22"});
方法掉用一:mainMethod.invoke(null,new Object[]{ new String[]{"11","22"}});
方法掉用二:mainMethod.invoke(null, (Object)new String[]{"11","22"});
数组与Object的关系及其反射类型
数组反射的Class跟数组的维数和类型有关
具有相同维数和元素类型的数组属于同一个类型;
代表数组的Class实例对象的getSuperclass()返回的父类为Object类对应的Class
基本类型的一维数组可被当做Object类型使用,不可当做Object[]类型使用
非基本类型的一维数组可被当做Object类型使用,可当做Object[]类型使用
int [] a1=new int[]{1,2,3};
int [] a2=new int[4];
int [][] a3=new int[2][3];
String [] a4=new String []{"a","b","c"};
System.out.println(a1.getClass()==a2.getClass());//true
System.out.println(a1.getClass()==a4.getClass());//false
System.out.println(a1.getClass()==a3.getClass());//false
System.out.println(a1.getClass().getSuperclass().getName());
//java.lang.Object
System.out.println(a4.getClass().getSuperclass().getName());
Object aobj1=a1;
Object aobj2=a4;
//Object [] aobj3=a1;基本类型不是object
Object [] aobj4=a3;
Object [] aobj5=a4;
System.out.println(a1);
System.out.println(a4);
数组的反射应用
Array工具类用于完成对数组的反射操作
private static void printObject(Object obj) {
Class clazz=obj.getClass();
if(clazz.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);
}
}
只能得到某一个元素的具体类型,不能得到整个数组的类型
Object[] a=new Object[]{"a",1};
System.out.println(a[0].getClass().getName());