------------android培训、java培训、-----------
1 如何得到字节码对应的实例对象(Class类型)
方式一:类名.class 例如:System.class
方式二:getClass() 例如:new Date().getClass()
方式三:Class.forName("类名") 例如:Class.forName("java.util.Date");注意:这里的类名要用全名
2 9个预定义的Class实例对象
boolean.class,byte.class,short.class,int.class,long.class,float.class,double.class,char.class,void.class
int.class==Integer.TYPE
3 数组类型的Class实例对象
Class.isArray()
只要是在源程序中出现的类型,都有各自的Class实例对象,例如int[],void
4 反射就是把Java类中的各种成分映射成相应的java类(Method,Field,Constructor,Package等等)
System.exit()-->Methodobj1
System.getProperty()-->Methodobj2
5 得到某个类所有的构造方法
Constructor[] cons = Class.forName("java.lang.String").getConstructors();
6 得到某一个构造方法
Constructor con = Class.forName("java.lang.String").getConstructor(StringBuffer.class);//表示得到构造方法String(StringBuffer sb)注意:由于反射加载都很消耗内存,所以一般把反射后生成的常用的构造方法之类存储成变量形式,提高效率,这就是优化
(String)con.newInstance(new StringBuffer("abc"));//相当于new String(new StringBuffer("abc"));
Class.forName("java.lang.String").newInstance();//相当于 new String();
7 成员变量反射
ReflectPoint pt1 = new ReflectPoint(3,5);
Field fieldY = pt1.getClass().getField("y");//fieldY不是对象身上的变量,而是类上的成员变量,所以必须对应到具体的某个对象上的成员变量值;getField()只能对public修饰的成员变量进行访问
System.out.println(fieldY.get(pt1));
Field fieldX = pt1.getClass().getDeclaredField("x");//getDeclaredField()可以对声明过的任何成员变量访问
fieldX.setAccesible(true);//强制获取变量值
System.out.println(fieldX.get(pt1));
8 利用反射改变对象中原成员变量的值
changeStringValue(Object obj){
Field[] fields = obj.getClass().getFields();//获得对象对应的类中所有的成员变量
for(Field field : fields){//遍历成员变量数组
if(field.getType()==String.class){//因为String类在内存中就一份字节码文件所以这里用==
String oldValue = (Sring)field.get(obj);//获得对象中字符串成员变量的值
String newValue = oldValue.replace('b','a');//将字符串成员变量值中的b字符替换成a字符
field.set(obj,newValue); //改变对象中字符串变量的值
}
}
}
9 利用反射调用具体某个方法
Method methodCharAt = String.class.getmethod("charAt",int.class);//第一个参数表示方法名,第二个参数表示方法中参数的类型字节码,方法中有几个参数就写几个对应的类型字节码
System.out.println(methodCharAt.invoke(str,1));//相当于str.charAt(1);
注意:invoke()中的第一个参数如果为null,则表示该被调用的方法是静态方法static,不需要指明哪个对象调用
10 调用main()
String startingClassName = args[0];
Method methodMain = Class.forName(startingClassName).getmethod("main",String[].class);
methodMain.invoke(null,new Object[]{new String[]{"123","456","789"}});//等同于methodMain.invoke(null,(Object)new String[]{"123","456","789"});
11 数组在内存中的字节码
两个数组只有在元素类型相同,且数组维度相同的情况下,他们在内存中的字节码才是同一份字节码
int[] a1 = new int[3];
int[] a2 = new int[4];
int[][] a3 = new int[2][3];
String[] a4 = new String[3];
System.out.println(a1.getClass() == a2.getClass());//true
System.out.println(a1.getClass() == a3.getClass());//false 维度不同
System.out.println(a1.getClass() == a4.getClass());//false 元素类型不同
Arrays.asList(Object[]) //如果参数是int[]则把整体作为一个Object对象,如果是String[]则把它看作是Object[],如果是int[][]则同样看成Object[]因为会把其中的一位数组int[]看作是一个Object对象
12 数组的反射应用
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);
}
}
13java中的内存泄露
Collection coll = new HashSet();
ReflectPoint pt1 = new ReflectPoint(1,2);//提示:ReflectPoint类中的hashCode()是用成员变量x,y进行计算的,覆写了系统的哈希码算法
ReflectPoint pt2 = new ReflectPoint(3,4);
ReflectPoint pt3 = new ReflectPoint(1,2);
coll.add(pt1);
coll.add(pt2);
coll.add(pt3);
coll.add(pt1);
pt1.y = 7;
coll.remove(pt1);//由于pt1的y值已经发生改变,所以其哈希码也会发生变化,对应的哈希值区域就会改变,而删除的时候会去原来哈希值所在区域查找,所以会删除失败,导致内存无端被占用,内存泄露
System.out.println(coll.size());//打印结果是2
14 反射的作用-->>实现框架功能(自己写的程序调用未知的类)
假设配置文件是config.properties这样写的className=java.util.ArrayList
InputStream ips = new FileInputStream("config.properties");
Properties props = new Properties();
props.load(ips);
ips.close();
String className = props.getProperty(className);
Collection coll = (Collection)Class.forName(className).newInstance();
ReflectPoint pt1 = new ReflectPoint(1,2);//提示:ReflectPoint类中的hashCode()是用成员变量x,y进行计算的,覆写了系统的哈希码算法
ReflectPoint pt2 = new ReflectPoint(3,4);
ReflectPoint pt3 = new ReflectPoint(1,2);
coll.add(pt1);
coll.add(pt2);
coll.add(pt3);
coll.add(pt1);
System.out.println(coll.size());//打印结果是4