18 理解反射的概念19构造方法的反射应用20成员变量的反射 21成员变量反射的综合案例22成员方法的反射...
18 理解反射的概念
反射
一、反射就是Java类中的各个成分映射成相应的java类。例如,一个java类用一个Class类的对象来表示,一个类中的组成部分:成员变量,方法,构造函数,包等等信息业用一个个的java类来表示,就像汽车是一个类,汽车中的发动机,变速箱等等也是一个个的类。表示java类的Class类显然要提供一系列的方法,来获得其中的变量,方法,构造函数,修饰符,包等信息,这些信息就是用相应的实例对象来表示,他们是Field、Method、Contructor、Package等等
二、一个类中的每个成员都是可以用相应的反射API类中的一个实例对象来表示,痛过调用Class类的方法可以得到这些实例对象。
19构造方法的反射应用
Constructor类代表某个类中的一个构造方法
<!--[if !supportLists]-->1、<!--[endif]-->得到某个类所有的构造方法:
例子:
Constructor[]cnstructor=Class.forName(“java.lang.String”).getConstructors();
2、得到某一个构造方法:
例子:
Constructor cnstructor=Class.forName(“java.lang.String”).getConstructor(StringBuffer.class);
//获得方法时要用到类型。例如
int.class,(int []).class
int [] ints = new int[0];
ints.getClass();
<!--[if !supportLists]-->3、<!--[endif]-->创建实例对象
通常方法:String str=new String(new StringBuffer("zyj"));
反射方法:String str=(String) constructor1.newInstance(new StringBuffer("zyj"));//通常获得的方法时要用到上面相同类型的实例对象
<!--[if !supportLists]-->4、<!--[endif]-->Class.newInstance()方法
例子:
String str =Class.forName(“java.lang.String”). newInstance();
*该方法内部先得到默认的构造方法,然后用该构造方法创建实例对象。
*该方法内部的具体代码时用到了缓存机制来保存默认构造方法的实例对象。所以反射比较消耗资源,利用了缓存,会导致系统性能严重下降。(看Class类中newInstance()方法)
示例代码:
//new String(new StringBuffer("zyj"));与下面的功能相同
Constructor<String>constructor=String.class.getConstructor(StringBuffer.class);
String str2=constructor.newInstance(new StringBuffer("zyj "));
System.out.println(str2.charAt(2));
20成员变量的反射 21成员变量反射的综合案例
Field类代表某个类中的一个成员变量
示例代码:
package cn.zyj2021.review;
public class ReflectPoint {
private int x;
public int y;
public String str1="ball";
public String str2="basketball";
public String str3="zyj";
public ReflectPoint(int x, int y) {
super();
this.x = x;
this.y = y;
}
@Override
public String toString() {
return "ReflectPoint [str1=" + str1 + ", str2=" + str2 + ", str3="
+ str3 + "]";
}
}
package cn.zyj2021.review;
import java.lang.reflect.Field;
public class ReflectTest {
public static void main(String[] args) throws Exception {
ReflectPoint reflectPoint=new ReflectPoint(3, 6);
Field fieldx=reflectPoint.getClass().getDeclaredField("x");//可以访问不可见的属性
fieldx.setAccessible(true);
System.out.println(fieldx.get(reflectPoint));
//fieldy的值是多少?是6,错!fieldY不是对象身上的变量,而是类上,代表某个字节码上的变量,要用它去取某个对象上对应的值
Field fieldy=reflectPoint.getClass().getField("y");//只能访问可见的属性
System.out.println(fieldy.get(reflectPoint));
changeStringValue(reflectPoint);
System.out.println(reflectPoint);
}
//将任意一个对象中的所有String类型的成员变量所对应的字符串内容中的"b"改成"a"。
private static void changeStringValue(Object object) throws Exception {
Field[] fields=object.getClass().getDeclaredFields();
for (Field field : fields) {
if (field.getType()==String.class) {//不用equals(),因为他们是只有一份字节码
field.setAccessible(true);
String temp=(String) field.get(object);
field.set(object, temp.replace('b', 'a'));
}
}
}
/*
一个问题,我把自己的变量定义成private,就是不想让人家访问,可是,现在人家用暴力反射还是能够访问我,这说不通啊,能不能让人家用暴力反射也访问不了我。
首先,private主要是给javac编译器看的,希望在写程序的时候,在源代码中不要访问我,是帮组程序员实现高内聚、低耦合的一种策略。你这个程序员不领情,非要去访问,那我拦不住你,由你去吧。
同样的道理,泛型集合在编译时可以帮助我们限定元素的内容,这是人家提供的好处,而你非不想要这个好处,怎么办?绕过编译器,就可以往集合中存入另外类型了。
*/
}
22成员方法的反射
<!--[if !supportLists]-->1、 <!--[endif]-->Method 代表某个类中的一个成员方法
<!--[if !supportLists]-->2、 <!--[endif]-->得到类中的一个方法:
例子:
Method method=String.class.getMethod("charAt",int.class);
<!--[if !supportLists]-->3、<!--[endif]-->调用方法:
通常方式:str1.charAt(1);
反射方式:method.invoke(str1, 1);
如果传递给Method对象的invoke()方法的第一个参数为null,这说明该Method对象对应的是一个静态方法。
<!--[if !supportLists]-->4、<!--[endif]-->jdk1.4和jdk1.5的invoke方法的区别:
jdk1.5:public Object invoke(Object obj,Object… args)//args参数用Class对象表示
jdk1.4:public Object invoke(Object obj,Object[] args)
//反射不能读这种非public类