反射
反射的基石:Class类
概念:反射就是把Java类中的各种成分映射成相应的java类。
Java程序中的各个Java类属于同一类事物,描述这类实物的Java类名Class.
Class类代表Java类,它的各个实例对象对应各个类在内存中的字节码。例如,Person类的字节码,ArrayList类的字节码。
一个类被类加载器加载到内存中,占用一片存储空间,这个空间里面的内容就是类的字节码,不同的类的字节码是不同的,所以它们在内存中的内容是不同的。这一个个的空间可分别用一个个的的对象来表示。
各个字节码对应的实例对象的获取:
类名.classeg:System.class
对象.getClass()eg:new Date().getClass()
Class.forName(“类名”)eg:Class.forName(“java.util.Date”)
Class类描述的信息:类的名字,类的访问权限,类所属于的报名,字段名称的列表,方法名称的列表。
九个预定义Class实例对象:8种基本类型与void.
Int.class=Integer.Type
数组类型的Class实例对象
Class.isArray()
总之,只要是在源程序中出现的类型,都有各自的Class实例对象,例如:int[],void
反射概念:反射就是把Java类中的各种成分映射成相应的Java类。
表示Java类的Class类显然要提供一系列的方法,来获取其中的变量、方法、构造方法、修饰符、包等信息,这些信息就是用相应类的实例对象来表示。它们是Field、Method、Constructor、Package等。
一个类中的每个成员都可以用相应的反射API类的一个实例对象来表示,通过调用Class类的方法可以得到这些实例对象。
Constructor类:Constructor类表示某个类中的一个构造方法。
获取某个类所有的构造方法:
Eg:Constructor [] constructors=Class.forName(“java.util.String”).getConstructors();//获得方法时要用到类型
获取某一个构造方法:
Eg:Constructor constructor=Class.forName(“java.util.String”).getConstructor(StringBuffer.class);
创建实例对象:
通常方法:String str=new String(new StringBuffer(“abc”));
反射方法:String str=(String)constructor.newInstance(new StringBuffer(“abc”));
//调用获取的方法要用到上面相同类型的实例对象
Class.newInstance()方法:
Eg:String str=(String)Class.forName(“java.lang.String”).newInstance();该方法内部先得到默认的构造方法,然后用该构造方法创建实例对象。//class----construcot----new object
Field类:Field类表示某个类中的一个成员变量
Eg:
Field field=pt.getClass().getField("y");//field不是对象身上的变量,而是类身上的变量
System.out.println(field.get(pt));//取值,即y得值
Mehtod类:Method类代表某个类的一个成员方法
获取类中的某个方法:
Eg:Method charAt=Class.forName(“java.util.String”).getMethod(“charAt”,int.class);
调用方法:
通常方法:System.out.println(str.charAt(1));
反射方法:System.out.println(charAt.invoke(str,1));
如果传递给Method对象的invoke()方法的一个参数为null,说明Method对象对应的是一个静态对象
JDK1.4和JDK1.5invoke方法的区别:
JDK1.5:public Object invoke(Object obj,Object...args)
JDK1.4:public Object invoke(Object obj,Object[]aegs)
数组的反射:
具有相同维数和元素类型的数组属于同一个类型,即具有相同的Class实例对象。
代表数组的Class实例对象的getSuperClass()方法返回的父类为Object类对应的Class
基本类型的一维数组可以当作Object类型使用,不能当作Object[]类型使用;非基本类型的一维数组,即可以当作Object类型使用,又可以当作Object[]类型使用。
实例:
package cn.itcast.day1;
public class ReflectPoint {
private int x;//定义私有变量x
public int y;//定义公有变量
//定义字符串str1,str2,str3
public String str1="ball";
public String str2="basketball";
public String str3="itcast";
//构造函数
public ReflectPoint(int x, int y) {
super();
this.x = x;
this.y = y;
}
public String toString()
{
return str1+":"+str2+":"+str3;
}
}
package cn.itcast.day1;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.Arrays;
public class ReflectTest {
public static void main(String[]args) throws Exception
{
//定义字符串str1
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
System.out.println(int.class.isPrimitive());//是不是原始类型true
System.out.println(int.class==Integer.class);//false
System.out.println(int.class==Integer.TYPE);//true
System.out.println(int[].class.isArray());//true
//总之,只要是在源程序中出现的类型,都有各自的Class实例对象,例如int[],void
//获取构造函数
Constructor<String> constructor=String.class.getConstructor(StringBuffer.class);
//获取实例对象
String ss=(String)constructor.newInstance(new StringBuffer("abc"));
System.out.println(ss.charAt(2));
ReflectPoint pt=new ReflectPoint(3,5);
//获取成员变量
Field field=pt.getClass().getField("y");//field不是对象身上的变量,而是类身上的变量
System.out.println(field.get(pt));//取值,即y得值
Field field1=pt.getClass().getDeclaredField("x");//因为x为私有变量,所以用getDeclaredField()方法
field1.setAccessible(true);//暴力反射
System.out.println(field1.get(pt));//取值,即x的值
changeStringValue(pt);
System.out.println(pt.toString());
//Method
//通常方法str1.charAt();
Method method=String.class.getMethod("charAt",int.class);//第一个参数是方法名
System.out.println(method.invoke(str1, 1));//JDK1.5invoke()方法
System.out.println(method.invoke(str1, new Object[]{2}));//JDK1.4invoke()方法
/*
通常方法:
Test.main(new String[]{});
Test.main(new String[]{"111","222"});*/
//调用Test的main()方法
String ss1="cn.itcast.day1.Test";
Method method1=Class.forName(ss1).getMethod("main",String[].class);
System.out.println(method1.invoke(null, new Object[]{new String[]{"111","222"}}));
//数组的反射
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().equals(a3.getClass()));//false
System.out.println(a1.getClass().equals(a4.getClass()));//false
System.out.println(a1.getClass().getName());//获取类名[I
System.out.println(a1.getClass().getSuperclass().getName());//获取父类名java.lang.Object
System.out.println(a4.getClass().getSuperclass().getName());//获取父类名java.lang.Object
//比较数组与Object
Object obj1=a1;
Object obj4=a4;
Object[] obj3=a3;
Object[] obj5=a4;
//Arrays.asList()方法处理int[]与String[]的不同
System.out.println(Arrays.asList(a1));//[[I@1690726]
System.out.println(Arrays.asList(a4));//[null, null, null]
}
////将任意一个对象中的所有String类型的成员变量所对应的字符串内容的"b"改成"a"
private static void changeStringValue(Object obj) throws Exception {
// TODO Auto-generated method stub
Field[] fields=obj.getClass().getFields();
for(Field field:fields)
{
//字节码用等号.因为相同的字节码
if(field.getType()==String.class)
{
String oldString=(String)field.get(obj);
String newString=oldString.replace('b','a');
field.set(obj, newString);
}
}
}
}
class Test{
public static void main(String[]args)
{
for(String arg:args)
{
System.out.println(arg);
}
}
}