反射:
反射就是把java类中的各种成分映射成相应的java类
第一要先了解Class这个类
如何得各个字节码对应的实力对象(Class类型)
* (1)类名.class,例如:System.class
* (2)对象.getClass(),例如:new Date().getClass();
* (3)Class.forName("类名")。例如:Class.forName("java.util.Date");
*
* 有九个预定义的Class实例对象:
* 包括八个基本数据类型: 整型:long,int,short,byte 布尔型:boolean 字符型:char 浮点型:float,double
* 还有一个void也是预定义Class实例对象 Class cl=void.Class;
* 一共九个
*
* isPrimitive():是判断是否是预定义对象
*
* int.class==Integer.TYPE:true
* 数组类型的Class实例对象:int[].class.isArray():true
*
* 总之,只要在源程序中出现的类型,都有各自的Class实例对象,例如,int[],void....
String str1="abc";
Class cls1=str1.getClass();
Class cls2=String.class;
Class cls3=Class.forName("java.lang.String");
System.out.println(cls1==cls2); true
System.out.println(cls1==cls3); true//他们都是同一个字节码
System.out.println(cls1.isPrimitive()); false//isPrimitive():是判断是否是预定义对象
System.out.println(int.class.isPrimitive()); true
System.out.println(int.class==Integer.class); false
System.out.println(int.class==Integer.TYPE); true//TYPE:表示基本类型 int 的 Class 实例。
System.out.println(int[].class.isArray()); true//判断是不是数组
第二要知道反射中的Constructor类(构造函数)
得到某个类所有的构造方法:Constructor[] constructors=Class.forName("java.lang.String").getConstructors();
* 得到某一个构造方法:Constructor constructor=Class.forName("java.lang.String").getConstructor(StringBuffer.class);获得方法时要用到类型
* 创建实例对象:
* 通常方式:String str =new String(new StringBuffer("abc"));
* 反射方式:String str=(String)constructor.newInstance(new StringBuffer("abc"))
* 调用获得的方法时要用到上面相同类型的实例对象(如这里的StringBuffer)
例子:
Constructor<String> constructor1=String.class.getConstructor(StringBuffer.class);//这里的StringBuffer是表示选择哪个构造方法
String str2=constructor1.newInstance(new StringBuffer("abc"));//这里的StringBuffer是表示在用这个构造方法时还要传一个StringBuffer的对象进去
第三要知道Field类(字段)
写一个类
public class ReflectPoint {
private int x;
public int y;
public String str1="sasadafaaaaaaaaaa";
public String str2="abcd";
public String str3="dcfg";
public String toString ()
{
return str1+" "+str2+" "+str3;
}
public ReflectPoint(int x, int y) {
super();
this.x = x;
this.y = y;
}
}
private static void changeStringValue(ReflectPoint pt1) throws Exception {
Field [] fields=pt1.getClass().getFields();//得到pt1对象中的所有字段
for(Field field:fields)
{
if(field.getType()==String.class)//.getType()返回一个 Class 对象,它标识了此 Field 对象所表示字段的声明类型。
//这里使用==,因为是同一份字节码。只要是字节码比较就用==比较
{
String oldValue=(String) field.get(pt1);
String newValue=oldValue.replace('a', 'o');//replace(CharSequence target, CharSequence replacement)
//使用指定的字面值替换序列替换此字符串所有匹配字面值目标序列的子字符串。
field.set(pt1, newValue);//set(Object obj, Object value)
// 将指定对象变量上此 Field 对象表示的字段设置为指定的新值。
}
}
}
//访问pt1对象中public变量y。
ReflectPoint pt1=new ReflectPoint(3,5);
Field fieldY=pt1.getClass().getField("y");
//fieldY的值是多少?5,错!fieldY不是对象身上的变量,而是类上的,要用它去取某个对象上对应的值
System.out.println(fieldY.get(pt1)); 打印的是:5
//访问pt1对象中私有的变量x。
Field fieldX=pt1.getClass().getDeclaredField("x");//这里因为访问的是private,所以要使用getDeclaredField方法
fieldX.setAccessible(true);//一定要有
System.out.println(fieldX.get(pt1)); 打印的是:3
changeStringValue(pt1); //用反射编写一个方法将pt1对象中的所有字段中是字符串的将他们中的a变成b
System.out.println(pt1);
第四要知道Method类(方法)
Method methodCharAt=String.class.getMethod("charAt", int.class);//"charAt"是方法名。你要得到那个方法就输入相应的方法名。
System.out.println(methodCharAt.invoke(str1, 1));//invoke调用由此 Method 对象表示的底层方法。
//str1:是在谁的身上调用这个方法,1:是给方法传的参数
//如果invoke的第一个参数是null那么说明该method对象对应的是一个静态方法。
写一个类。在另一个类中调用main方法
class TestArguments{
public static void main(String[] args) {
for(String arg:args)
{
System.out.println(arg);
}
}
}
直接调用的话是
TestArguments.main(new String[]{"111","222","333"});
//通过反射调用main方法
Method mainMethod=Class.forName("com.day1.TestArguments").getMethod("main", String[].class);
// mainMethod.invoke(null, new Object[]{new String[]{"111","222","333"}});//第一种方法(必须要封装下)
mainMethod.invoke(null, (Object)new String[]{"111","222","333"});//第二种方法
最后就是一些常规知识
private static void printArray(Object obj) {//判断传进来的是不是数组。是的话就将数组中的每个数据打印,不是的话就直接将他打印出来
Class objclass=obj.getClass();
if(objclass.isArray())//判断传进来的是不是数组
{
int len=Array.getLength(obj);//得到数组的长度
for(int i=0;i<len;i++)
{
System.out.println(Array.get(obj, i));//得到数组中下标为i的数据
}
}else{
System.out.println(obj);
}
}
int a1[]=new int[]{1,23,3};
int a2[]=new int[5];
int a3[][]=new int[6][2];
String a4[]=new String[]{"a","b","c"};
System.out.println(a1.getClass()==a2.getClass()); true//他们是属于同一个字节码,相同类型的数组使用的都是同一个字节码
// System.out.println(a1.getClass()==a3.getClass());
// System.out.println(a1.getClass()==a4.getClass());
System.out.println(a1.getClass().getName());
System.out.println(a3.getClass().getName());
System.out.println(a1.getClass().getSuperclass().getName()); java.lang.Object
System.out.println(a4.getClass().getSuperclass().getName()); java.lang.Object
Object aObj1=a1;//a1是int类型的数组。是Object类型的
Object aObj2=a4;//a4是Stirng类型的数组。是Object类型的
// Object[] aObj3=a1;//a1是int类型的数组。int不是Object类型的。编译时就会出错
Object[] aObj4=a3;//a3是int类型的多维数组。int类型的数组是Object类型的
Object[] aObj5=a4;//a4是Stirng类型的数组。Stirng是Object类型的
System.out.println(a1);
System.out.println(a4);
System.out.println(Arrays.asList(a1));//a1是int类型的数组。asList接收的是一个Object[]或者是一个Object类型,因为int不是Object。所以直接将a1[]作为Object传人,直接装入集合
System.out.println(Arrays.asList(a4));//这里可以输出[a, b, c],是因为asList方法将String[]传人,是以Object[]传人,那么将将Stirng[]中的数据分开装入集合
printArray(a1);
printArray(1);//这时这里的1经过装箱,new Integer(1);操作。变成了Object类型,所以可以编译通过,直接打印出1