---------------------- ASP.Net+Android+IO开发S、.Net培训、期待与您交流! ----------------------/*
* 一 Class
* 1 Class(反射的基石):众多java类的共同点,他就代表的是内存里,或者他的实例对象就是内存里的字节码文件。
* 2 字节码
* ----字节码:一个趔被加载到内存里面后所占用的空间里的内容就是字节码
* Person p1=new Person();
* --得到Person字节码的两种方式 Person.class/p.getClass();
* ---得到类的字节码的3种方式
* a:类名.class。
* b: 类的对象.getClass().
* c: Class.forname("classname") //静态方法,
* 1:如果这个类已经被加载到内存里面了,直接返回字节码。
* 2:如果类没有被加载到内存里面,先有加载器去加载,然会在返回加载进来的字节码。
* 3 九个预定义的Class实例对象。
* 其中8个基本类型和一个void类型对象。(Class cl=void.class();)
* Class.isPrimative()判断是非是一个原始类型。
* 注:int.class==Integer.TYPE;
* char.class==Character.TYPE;
* 4 数组类型的Class实例对象
*
* 二 反射()
* 1 反射就是把java类中各种成分编写为一个java类。比如说一个类的方法就用相应的反射API类的对象来表示。(反射也就是利用
* 各个java类的各个成分的的对象来完成我们需求。)
* */
public class ClassDemo {
public static void mehted_1()throws Exception {
String str=new String("bh");
Class cl1=String.class;
Class cl2=str.getClass();
Class cl3=Class.forName("java.lang.String");
System.out.println(cl1==cl2);//true
System.out.println(cl2==cl3);//true 结论:同一个类的字节码是相同的。
System.out.println(char.class==Character.TYPE);//true;基本数据类型;
}
public static void methed_2()throws Exception{//构造方法的反射应用。
Constructor[] con=Class.forName("java.lang.String").getConstructors();//获取String类型的字节码文件,
//然后在获取他的所有的构造方法。
for(Constructor c:con){
System.out.println(c.getName().toString());//java.lang.String
}
Constructor con2=Class.forName("java.lang.String").getConstructor(byte[].class);//怎么获取指定
//构造函数的够造方法。但是在jdk1.5之前,这个getConStructor(),里面要想接受可变参数的类型时,必须把这可变参数个数
//和类型定义在一起,组成一个数组。
System.out.println("返回的构造方法是什么"+con2.getName());
//获取一个字符串的构造函数。
Constructor con3=String.class.getConstructor(StringBuffer.class);
//利用构造方法去获取对象
String str2=(String) con3.newInstance(new StringBuffer("abc") );//为什么要强转为String,印在在编译时期
//还不知道这个构造方法是String类型,注:一定记住编译和运行的关系,在编译时只看代码的定义,不管代码的执行,如在这个
//里面他只知道con3是一个构造方法,对他属于什么类型去只有到执行完上面一句代码以后,就是是运行时才知道这类型。
//String str3=con3.newInstance("abc"); //Type mismatch:类型不匹配,这个报错为什么编译能够通过,而在运行
//时才报警,这个地方的构造方法只能够接收StringBuffer
//Class.newInstance(),newInstance()和new 的区别。
//field 字段,(类里面的成员变量方法)
ReflactPoint field=new ReflactPoint(3,5);
Field fie= field.getClass().getField("y");
//注:这个地方的fie的值不是5,这个变量不是对象上的,而是类上的。
int num=(Integer) fie.get(field);//得到fie这个字段在field对象上的值。
System.out.println(num);
//Field fie1= field.getClass().getField("x");//NoSuchFieldException:因为这个x是私有的。
Field fie2=field.getClass().getDeclaredField("x");//把这个私有的字段设置为可见的,
//int num2=(Integer)fie2.get(field);//java.lang.IllegalAccessException,非法访问,虽然上面改为了可见的,但是还是
//不能够访问。
fie2.setAccessible(true);//把fiel字段设置为可以看见的。
int num3=(Integer)fie2.get(field);//同个以上两个方法的修饰,这个私有的字段也能够被访问了。
System.out.println(num3);
}
public void change()throws Exception{//把ReflactPoint类中的所有的String类型的字段中的b换为a,
//思路:先获取String类型字段的集合,在对集合进行遍历。
ReflactPoint rp=new ReflactPoint(3,5);
Field[] field=ReflactPoint.class.getFields();
for(Field fs:field){
//if(fs.getType().equals(String.class)){}为什么此处不能用equals来比较,是因为比较的都是同一份字节码,用equals的语义不准确。
if(fs.getType()==String.class){
String oldValue=(String)fs.get(rp);//获取对象的String类型的字段
//IllegalArgumentException:曾经由于传递参数错误,而导致的。
String newValue=oldValue.replace('b', 'a');//更换掉b字符。
fs.set(rp,newValue);//把替换后的值返回去
System.out.println(fs);
System.out.println(fs.toString());
}
}
System.out.println(rp);}
public static void methed_3()throws Exception{//成员方法的反射。注:由于成员方法是作用与对象的,所以一定的的Mehtoh一定是有对象作为参数。
String str="bhjkluh";
Method md=String.class.getMethod("replace", CharSequence.class,CharSequence.class);//得到方法的字节码。
String[] args={"b","a"};
String Str1=(String)md.invoke(str, args);//Invoke(对象,参数),这是按1.4方法来调用的,因为传递的参数是一个数组,在1.5版本的是可变参数
//这就是是方法对象的方法。例如列车司机停火车,
//Invoke(null,args),说名这是一个静态方法的对象,
System.out.println(Str1);
}
public static void methodMain(){//main方法的反射。编写一个类,能够根据提供的main方法,
// 一Arguement.main(new String[]{"a","b","c"});//用普通方法条用Arguement的主函数。(由于其是静态的有类名调用。)
}
public static void arrayDemo(){//数组反射的应用
/* //特点:相同类型的相同维度的数组字节码是同一个。
int[] arr1=new int[]{1};
int[] arr2=new int[]{2};
int[][] arr3=new int[2][3];
String[] str4=new String[3];
System.out.println(arr2.getClass() == arr1.getClass());//true
// arr2.getClass() == arr1.getClass();// 报错:The left-hand side of an assignment must be a variable
System.out.println(arr1.getClass().getName());//class [I
System.out.println(arr1.getClass().getSuperclass().getName());//得到父类的名字
Object obj1=arr1;//Object[] obj4=arr1;注意连个的区别。
Object[] obj2=str4;
Object[] obj3=arr3;
//取出数组里面的元素,用的是arrays的asList(),
System.out.println(Arrays.asList(obj1));//[[I@1bc4459]
System.out.println(Arrays.asList(obj2));//[null, null, null]
//为什么打印的都是都转换为了List但是结果却不一样,是由于1.4与1.5的asList方法接受的参数类型不一样,1.4 asList(Object[] obj)
//1.5 asList(T/Object t)
*/
Object[] obj5=new Object[]{1,2,3,4};//怎么获取数组元素的类型。
System.out.println(obj5.getClass().getName());
System.out.println(obj5[0].getClass().getName());//获取元素的类型
}
public static void PrintObject(Object obj ){//获取一个对象的具体内容,注:要有一种思想,我不知道这歌Object是什么类型
Class cl=obj.getClass();
if(cl.isArray()){//判断这个Class对象是不是数组类型。
int len=Array.getLength(obj);
for(int x=0;x<len;x++){
System.out.println(Array.get(obj,x));
}}
else
System.out.println(obj);
}
public static void main(String[] args)throws Exception {
methodMain();
// 一Arguement.main(new String[]{"a","b","c"});//用普通方法条用Arguement的主函数。(由于其是静态的有类名调用。)
String startingClassName=args[0]; //ArrayIndexOutOfBoundsException:是由于我们在编译的时候没有传值所导致的。方式
Method mainMethod=Class.forName(startingClassName).getMethod("main",String[].class);
//mainMethod.invoke(null,new String[]{"1","2","3"});//方法对象去调用方法类的一个方法。
//java.lang.IllegalArgumentException: wrong number of arguments::原因main方法接收的是一个String[],但是收到的确实3个。
//其实我们传递的是一个String[]的数组,只不过是jdk1.5为了兼容1.4的特性,当我们传递一个String[]的数组他会对其拆包,可以用一下两种方法对其解决。
mainMethod.invoke(null,new Object[]{new String[]{"1","2","3"}});//为什么我们在这个main方法中能够传递的一个Object[].
mainMethod.invoke(null,(Object)new String[]{"1","2","3"});//强转为Object以后等于是给的事一个对象,不是一个数组,那他就不再拆包了,其实都是由于
//jdk的方法他会对数组进行拆包,因为,1.4以前的方法接受的参数是不可变的,为了应用就把参数装进一个数组里面,在运行是在打开。
// arrayDemo();
}
}
class Argument//创建一个类,用来练习main方法的反射。怎么利用运行对话框
{
public static void main(String[] args){
for(String str:args){
System.out.println(str);
}
}
}