/** 反射 与 Class类
* 一 Class类
* 1:就是java字节码所属的类,字节码就是他的对象
* 2: 获取字节码的方法
* a:Class.forName("Java.util.Date")返回一个字节码,情况一:当内存中已经有了这个类的字节码,情况二:当内存
* 中不存在时就要去加载了。此种常用类的名字在写的时候不需要知道,
* b:类名.class。
* c:new String.getClass();
*
* 3:九个Class预定义对象:八个基本数据类型和void类型。
*
*二 反射 ————会导致程序性能严重下降
* 1 :反射就是把java类的各种成分映射成相应的Java类。//我们所得到的是那种成分所对应的对象。
* @throws NoSuchMethodException
* @throws SecurityException
*
* 2:利用反射创建对象流程
* a: class字节码————Constructor对象——————传入参数
* b: class字节码————new Instance().
*
*3: 反射有什么用:实现框架
*
*4;数组反射的特点:
* a:相同元素类型和相同维度的数组的Class是同一的。
* b: 基本类型的一维数组无法转换为Object[],但是能作为Object使用
* c:Arrays.toList()处理Int[] 和String的差异
* d:无法利用反射去获取一个数组的类型。————只能通过数组元素获取每个元素的类型。
*/
public static void main(String[] args) throws Exception {
/*// TODO Auto-generated method stub
System.out.println(int.class == Integer.class);//false
System.out.println(int.class == Integer.TYPE);//true Integer.type返回的是包装类型的字节码
System.out.println(String.class.isPrimitive());//false
*/
/*------------------数组的反射和Arrays类 -----------------------*/
int[] arr1 = {1, 2};
int[][] arr2 = {{1, 3}, {1}};
String[] arr3 = {"a", "b"};
//数组转换为Object
Object obj1 = arr1;
//Object[] obj2 = arrr1; 无法转换,里面的是int不是Object
Object obj3 = arr2 ;
Object[] obj4 = arr2;
Object obj5 = arr3;
Object[] obj6 = arr3;
//转换为List,用到了Arrays的
System.out.println(Arrays.asList(arr1));//[[I@dc8569] 先调用1.4在调用的1.5版本的方法
System.out.println(Arrays.asList(arr3));//[a, b] 调用的是1.4版本的方法
// 1.5版本 public static <T> List<T> asList(T... a)
// 1.4 版本 public static List asList(Object[]... a)
//获取一个数组的类型
Object[] obj = new Object[]{1, "AA"};
Object getObj = obj.getClass();//无法返回具体的类型
System.out.println(obj[0].getClass());
System.out.println(obj[1].getClass());
/*------------------获取未知类的main方法类(把这个未知类的类名传入dos命令行) -----------------------*/
String StringName = args[0];//传入的是一个字符串,只不过恰好为类名
Method main = Class.forName(StringName).getMethod("main", String[].class);//获取SetingName类的main方法。
/*main.invoke(null, new String[]{"aa", "bb", "cc"}); 此时报 :java.lang.IllegalArgumentException:
wrong number of arguments,由于1.5版本要兼容1.4版本(把数组中的每个元素当作参数),所以他会对String[]自动拆箱。
*/
main.invoke(null,new Object[]{ new String[]{"aa", "bb", "cc"}});//让他拆
main.invoke(null, (Object)new String[]{"aa", "bb", "cc"});//不要让他拆
/*--------------------------------Methodl类 -----------------------*/
//当invoke(null,new Object[])时,说明所得到的是静态方法。
Method method = String.class.getMethod("charAt", int.class);
char ch =(Character) method.invoke("abc", 2);
System.out.println(ch);//c 这个按1.5版本,
System.out.println(method.invoke("abc", new Object[]{2}));//c 这个按1.4版本传入的参数是数组
/*------------------Field类 字节码身上的变量-----------------------*/
//查看public 的字段。
ReflectPoint rp1 = new ReflectPoint(3,5);
Field fieldY = rp1.getClass().getField("y");//得到这个类的变量y,注:返回的不是对象的变量,而是这个类的变量
fieldY.get(rp1);//5,
//查看私有的字段
ReflectPoint rp2 = new ReflectPoint(3,5);
/*Field fieldX = rp2.getClass().getField("x");//得到这个类的变量y,注:返回的不是对象的变量。
*/
Field fieldX = rp2.getClass().getDeclaredField("x");//注意与getField()的区别,这个能够看到私有变量。
fieldX.setAccessible(true);//把私有的设置为可以获取。
int x =(Integer)fieldX.get(rp2);//5,
System.out.println(x);
/*------------------Constructor 反射应用-----------------------*/
Constructor c1 = String.class.getConstructor(byte[].class);//得到构造方法String(byte b)的构造方法。
//用得到的Constructor对象创建对应的String对象。
c1.newInstance(new byte[]{'a'});
Class[] c = {byte[].class, Charset.class};
Constructor c2 =String.class.getConstructor(c);//在1.5版本以前按可变的数组传入
ReflectPoint rp3 = new ReflectPoint(4,6);
changeChar(rp3);
System.out.println(rp3);
}
/*------实现一个方法跟换掉对象字段中字符串的字符a----*/
public static void changeChar(Object obj)throws Exception{
Field[] fields = obj.getClass().getFields();
for(Field field : fields){
//if(field.getType().equals(String.class));此处由于是同一份字节码所以用equals()语义不对。
if(field.getType() == (String.class)){
String oldValue = (String)field.get(obj);
String newValue = oldValue.replace('a', 'p');
field.set(obj, newValue);//设置新的字段