反射
反射就是把Java类中的各种成分映射成相应的java类。例如,一个Java类中用一个Class类的对象来表示,一个类中的组成部分:成员变量,方法,构造方法,包等等信息也用一个个的Java类来表示,就像汽车是一个类,汽车中的发动机,变速箱等等也是一个个类。表示java类的Class类显然要提供一系列的方法来获得其中的变量,方法,构造方法,修饰符,包等信息。这些信息就是用相应类的实例对象来表示,他们是Field、Method、Constructor、Package等
eg:
System.exit
System.getProperties()
就相当于Method-->methodObj1
-->methodObj2
-------------------------------------------------------------------------
Constructor类代表某个类中的一个构造方法
得到某个类所有的构造方法:
Constructor [] constructors = Class.forName("java.lang.String").getConstructor(StringBuffer.class);
//获得方法时要用到类型
创建实例对象:
通常方法:
// new String(new StringBuffer("abc"));用StringBuffer对象传给String这个构造方法,然后再new出一个实例对象
反射方法:
Constructor constructor1 = String.class.getConstructor(StringBuffer.class);//反射的方式实现,得到Constructor类型的对象;靠参数类型识别哪一个构造方法,(运行的时候才执行这行代码,在翻译的时候只是语法检查)
// constructor1.newInstance(initargs);//字节码的对象,编译时到底对应String哪一个构造方法,不知道,
constructor1.newInstance(new StringBuffer("abc"));
//第一个StringBuffer是选择哪个构造方法;第二个是表示用这个构造方法的时候,传一个StringBuffer的对象进去
// String str2 = constructor1.newInstance(new StringBuffer("abc"));//编译时不知道是谁的构造方法
String str2 = (String)constructor1.newInstance(/*"abc"//这是String类型*/new StringBuffer("abc"));
System.out.println(str2.charAt(2));
Class也提供newInstance,是为了提供便利
class-->constructor-->new object
Class.newInstance()寻找不带参数的构造方法,用构造方法创建实例对象。
反射导致程序性能严重下降。
--------------------------------------------------------------------
Filed类(字段,成员变量)
建一个类
public class ReflectPoint {
private int x;
public int y;
public ReflectPoint(int x, int y) {
super();
this.x = x;
this.y = y;
}
}
ReflectPoint pt1 = new ReflectPoint(3,5);
Field fieldY = pt1.getClass().getField("y"); //pt1.class类的字节码.getField("y")用变量名字来区别成员变量
//fieldY的值是多少;不是5,这个y代表的是字节码上的变量,并没有对应到对象身上,fieldY不代表具体的值,只代表某个变量,不代表这个变量上面 某个对象的值、(fieldY不是对象身上的变量,而是类上,要用它去取某个对象上对应的值)
System.out.println(fieldY.get(pt1));
Field fieldX = pt1.getClass().getDeclaredField("x");//声明过的就能看见
fieldX.setAccessible(true);//暴力反射
System.out.println(fieldX.get(pt1));
---------------------------------------------------------
做一个扫描,对所有的a替换成b
思路简要分析:
我们要先把所有字段得到,也就是成员变量;然后遍历循环取值,然后替换,最后再set到fields里面
完整代码如下:
package com.itheima;
public class ReflectPoint {
private int x;
public int y;
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;
}
@Override
public String toString() {
return "ReflectPoint [x=" + x + ", y=" + y + ", str1=" + str1
+ ", str2=" + str2 + ", str3=" + str3 + "]";
}
}
package com.itheima;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
public class ReflectTest {
/**
* @param args
*/
public static void main(String[] args) throws Exception {
// TODO Auto-generated method stub
String str1 = "abc";
Class cls1 = str1.getClass();
Class cls2 = String.class;
Class cls3 = Class.forName("java.lang.String");
System.out.println(cls1==cls2);
System.out.println(cls1==cls3);
System.out.println(cls1.isPrimitive());
System.out.println(int.class.isPrimitive());
System.out.println(int.class==Integer.class);
System.out.println(int.class==Integer.TYPE);//定义一个常量TYPE,代表包装类型所包装的基本类型的字节码
System.out.println(int[].class.isPrimitive());//数组也是类型,但是不是原始类型
System.out.println(int[].class.isArray());
// new String(new StringBuffer("abc"));用StringBuffer对象传给String这个构造方法,然后再new出一个实例对象
Constructor constructor1 = String.class.getConstructor(StringBuffer.class);//反射的方式实现,得到Constructor类型的对象;靠参数类型识别哪一个构造方法,(运行的时候才执行这行代码,在翻译的时候只是语法检查)
// constructor1.newInstance(initargs);//字节码的对象,编译时到底对应String哪一个构造方法,不知道,
constructor1.newInstance(new StringBuffer("abc"));
//第一个StringBuffer是选择哪个构造方法;第二个是表示用这个构造方法的时候,传一个StringBuffer的对象进去
// String str2 = constructor1.newInstance(new StringBuffer("abc"));//编译时不知道是谁的构造方法
String str2 = (String)constructor1.newInstance(/*"abc"//这是String类型*/new StringBuffer("abc"));
System.out.println(str2.charAt(2));
//Class.newInstance();
ReflectPoint pt1 = new ReflectPoint(3,5);
Field fieldY = pt1.getClass().getField("y"); //pt1.class类的字节码.getField("y")用变量名字来区别成员变量
//fieldY的值是多少;不是5,这个y代表的是字节码上的变量,并没有对应到对象身上,fieldY不代表具体的值,只代表某个变量,不代表这个变量上面 某个对象的值、(fieldY不是对象身上的变量,而是类上,要用它去取某个对象上对应的值)
System.out.println(fieldY.get(pt1));
Field fieldX = pt1.getClass().getDeclaredField("x");//声明过的就能看见
fieldX.setAccessible(true);//暴力反射
System.out.println(fieldX.get(pt1));
changeStringValue(pt1);
System.out.println(pt1);
}
private static void changeStringValue(Object obj)throws Exception {
Field[] fields = obj.getClass().getFields();//得到所有字段
for(Field field:fields){//给一个对象给我,然手扫面到所有成员变量,之后把值b改成a
if(field.getType()==String.class){//同一份字节码要用==
//field.getType()/*field是一个字段,是有类型的,所以.getType()*/.equals(String.class)
String oldValue = (String)field.get(obj);//在对象身上取值,(String)我们知道他是String类型
String newValue = oldValue.replace('b', 'a');//替换
field.set(obj, newValue);
}
}
}
}