Java程序中的各个Java类属于同一类事物,描述这类事物的Java类就是Class。
Class类代表Java类,它的各个实例对象对应各个类在内存中的字节码。
一个类被类加载器加载到内存中,占用一片内存空间,这个空间里面的内容就是类的字节码,
不同的类的字节码是不同的,所以他们在内存中内容是不同的,这一个个空间可以分别用一个
个对象来表示,这些对象显然具体有相同的类型。
---------------------------------------------------------------------
如何得到各个字节码对应的实例对象(Class类型)
1.类名.class,例如 System.class
2.对象.getjClass(),例如 new Date().getClass()
3,Class.forName("类名"), 例如 Class.forName("java.util.Date"): //这种用得比较多
一共有九个预定义Class实例对象:八个基本数据类型和 void.class
int.class == Integer.TYPE
数组类型的Class实例对象是 Class.isArray()
总之,只要在源程序中出现的类型,都有各自的Class实例对象,例如int[].class void.class
---------------------------------------------------------------
例子:
String str1 = "abc";
Class cls1 = str1.getClass();
Class cls2 = String.class;
Class cls3 = Class.forName("java.lang.String");
System.out.println(cls1 == cls2); //ture
System.out.println(cls1 == cls3); //ture
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.isPrimitive()); //false
System.out.println(int[].class.isArray()); //true
---------------------------------------------
反射就是把java中各种成分反映成相应的java类。
构造方法的反射:Constructor类
Constructor代表某个类中的一个构造方法。
得到某个类所有的构造方法:
Constructor[] constructors = Class.forName("java.lang.String").getConstructors();
得到某一个构造方法:
Construtor constructor = Class.forName("java.lang.String").getConstructors(StringBuffere.class);
创建实例对象:
通常方式:String str = new String(new StringBuffer("abc"));
反射方式:String str = (String)constructor.newInstance(new StringBuffer("abc"));
调用获得的方法时要用到上面相同类型的实例对象。
--------------------------------------------
Class.newInstance()方法:
例子:String obj = (String)Class.forName("java.lang.String").newInstance();
该方法内部先得到默认的构造方法,然后用该构造方法创建实例对象。
该方法内部的具体代码是用到了缓存机制来保存默认构造方法的实例对象。
说明,反射中创建实例是比较消耗资源的。
-------------------------------------------------
成员变量的反射:Field类
Field类代表某个类中的一个成员变量。
例子:
ReflectPoint pt1 = new ReflectPoint(3,5);
Field fieldY = pt1.getClass().getField("y");
//fieldY不是对象身上的变量,而是类上,要用它去取某个对象上对应的值
System.out.println(fieldY.get(pt1));
// 通过get方法取出具体值
Field fieldX = pt1.getClass().getDeclaredField("x");
// 因为x变量时private的,所以要用 getDeclaredField("x")
fieldX.setAccessible(true);
// 称为暴力取出, 如果没有setAccessible(true) 则不能取出x 的具体值
System.out.println(fieldX.get(pt1));
例子:
private static void changeStringValue(Object obj) throws Exception {
Field[] fields = obj.getClass().getFields();
for(Field field : fields){
if(field.getType() == String.class){ //因为是同一个字节码文件,所以用==比equals更专业
String oldValue = (String)field.get(obj);
String newValue = oldValue.replace('b', 'a');
field.set(obj, newValue);
}}}}
----------------------------------------------------------
成员方法的反射:Method类
Method类代表某一个类中 一个成员方法。
得到类中的某一个方法:
Method charAt = Class.forName("java.lang.String").getMethod("charAt", int.class);
调用方法:
通常方式:System.out.println(str.charAt(1));
反射方式:System.out.println(charAt.invoke(str,1));
如果传递给Mothod对象的invoke()方法的第一个参数为null,说明该方法对象对应的是一个静态方法。
例子:
Method methodChatAt = String.class.getMethod("ChatAt", int.class);
System.out.println(methodChatAt.invoke(str1, 1)); //取出str1对象中的第1个字母
---------------------------------------------------------------------------------------
用反射方式执行某一个类中的卖main方法:
用处:能够根据用户提供的类名,去执行该类中的main方法。
例子:
String startingClassName = args[0];
Method mainMethod = Class.forName(startingClassName).getMethod("main", String[].class);
mainMethod.invoke(null, new Object[]{new String[]{"111","222","333"}});// 参数null表示方法时静态的。
----------------------------------------------------
数组的反射:
具有相同维数和元素类型的数组属于同一个类型,即具有相同的Class实例对象。
代表数组的Class实例对象的getSuperClass()方法返回的父类为Object类对应的Class。
基本类型的一维数组可以被当作Object类型使用,不能当作Object[]类型使用。
非基本类型的一维数组,既可以当做Object类型使用,又可以当做Object[]类型使用。
Array工具类用于完成对数组的反射操作。Array在long.reflect的包中.
问题:给一个数组,把数组内容打印出来。
代码实现:
private static void printObject(Object obj) {
Class clazz = obj.getClass();
if(clazz.isArray()){
int len = Array.getLength(obj);
for(int i=0;i<len;i++){
System.out.println(Array.get(obj, i));
}
}else{
System.out.println(obj);
}
}
--------------------------------------
数组反射中的例子:
int [] a1 = new int[]{1,2,3};
int [] a2 = new int[4];
int[][] a3 = new int[2][3];
String [] a4 = new String[]{"a","b","c"};
System.out.println(a1.getClass() == a2.getClass()); //true
System.out.println(a1.getClass() == a4.getClass()); //false
System.out.println(a1.getClass() == a3.getClass()); //false
System.out.println(a1);//对象内存地址
System.out.println(a4);//对象内存地址
System.out.println(Arrays.asList(a1));
//Arrays.asList方法接收的参数是Object[]
//把a1当成是一个对象,因为a1里面的是基本数据类型
System.out.println(Arrays.asList(a4));
//把a4拆包,当成是多个对象。
--------------------------------------------------
反射的作用:实现框架功能
框架与工具类的区别:工具类被用户的类调用,而框架则是调用用户提供的类。
因为在写程序时无法知道要被调用的类名,所以,在程序中无法直接new某个类的实例对象了,则要用反射的方式来做。
例子:
new一个File 配置文件,写成一个Properties文件,然后把文件通过io加载进类 如: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 collections = (Collection)Class.forName(className).newInstance();
------- android培训、 java培训、期待与您交流! ----------