---------------------- ASP.Net+Unity开发、.Net培训、期待与您交流! ----------------------
在学习反射之前我们先说一说反射的基石:字节码文件,什么是字节码文件呢,就是存储在硬盘上的二进制文件,也是编译生成的 .class文件。如何获取字节码文件使我们讲述的重点。
第一种:类名.class
例如:String.class、Math.class、Object.class、int.class等等。
第二种:getClass()方法
例如:Class cl=obj.getClass();
第三种:Class.forName(String className);
例如:Class cl=Class.forName("java.lang.String");
看看关于字节码生成的代码:
public class ReflectTest1 {
public static void main(String[] args) throws Exception{
// TODO Auto-generated method stub
String s1="abc";
Class cl1=s1.getClass();
Class cl2=String.class;
Class cl3=Class.forName("java.lang.String");//此方法会抛异常
System.out.println(cl1==cl2);//true
System.out.println(cl1==cl3);//true
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
System.out.println(Void.class.isPrimitive());//false
}
}
下面我开始介绍反射了。
反射就是把Java类中的各种成分映射成相应的Java类。例如,一个Java类中用一个Class类的对象来表示,一个类中的组成部分:成员变量,方法,构造方法包等等信息也用一个个的Java类来表示,就像汽车是一个类,汽车中的发动机,变速箱等等也是一个个类。表示Java类的Class类显然要提供一系列的方法,来获取其中的变量,方法,构造方法,修饰类,包等信息,这些信息就是用相应类的实例对象来表示,它们是Field(成员变量),Method(方法),Contructor(构造函数),Package(包)等等。 一个类中的每个成员都可以用相应的反射API类的一个实例对象来表示,通过调用Class类的方法可以得到这些实例对象后,得到这些实例对象后有什么用呢?怎么用呢?这正是学习和反射的要点。
一、 构造方法的反射
Constructor类代表某个类中的一个构造方法。
得到某个类中所有构造方法:
* 例:Constructor[] constructor=Class.forName("java.lang.String").getConstructors();
得到某一个构造方法:
* 例: Constructor constructor=
Class.forName("java.lang.String").getConstructor(StringBuffer.class);//接收的参数类型,构造函数接收的是StringBuffer类
* 创建实例对象:
* 通常方式: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();
* 该方法内部先得到默认的构造方法,然后用该构造方法创建实例对象。
例:用反射实现:new String(new StringBuffer("abc"));
public class ReflectTest {
public static void main(String[] args)throws Exception {
//new String(new StringBuffer("abc"));
Constructor constructor1=Class.forName("java.lang.String").getConstructor(StringBuffer.class);//获取指定类型的构造函数
String str =(String)constructor1.newInstance(new StringBuffer("abc"));
System.out.println(str);
}
}
二、Field类
Field类代表某个类中的一个成员变量。
JAVA 的Class<T>类提供了几个方法获取类的属性。
public Field getField(String name) 返回一个 Field 对象,它反映此 Class 对象所表示的类或接口的指定公共成员字段。。
public Field[] getFields() 返回一个包含某些 Field 对象的数组,这些对象反映此 Class 对象所表示的类或接口的所有可访问公共字段。
public Field getDeclaredField(Stringname) 返回一个 Field 对象,该对象反映此 Class 对象所表示的类或接口的指定已声明字段。
public Field[] getDeclaredFields() 返回 Field 对象的一个数组,这些对象反映此 Class 对象所表示的类或接口所声明的所有字段。
例:
//演示反射的一个辅助类
public class ReflectPoint {
private int x;
public int y;
public String str1="bbbb";
public String str2="123bbc";
public ReflectPoint(int x, int y) {
super();
this.x = x;
this.y = y;
}
@Override
public String toString(){
return str1+"....."+str2;
}
public int add(int a,int b){
return a+b;
}
public int add(int a,int b,int c){
return a+b+c;
}
}
public class ReflectField {
public static void main(String[] args) throws Exception {
// TODO Auto-generated method stub
//利用工具类ReflectPoint.class演示Field
ReflectPoint p1=new ReflectPoint(3,5);
ReflectPoint p2=new ReflectPoint(4,6);
Field fieldY=p1.getClass().getField("y");//此时并不能明确fieldY中存放的是哪个对象中的y值,所以需要调用get(Object obj);来指明对象
System.out.println(fieldY.get(p1));
Field fieldX=p1.getClass().getDeclaredField("x");
fieldX.setAccessible(true);//暴力反射,不管你可不可以得到,都设置成可以得到的。
System.out.println(fieldX.get(p1));
}
}
输出结果是:
练习:将任意一个对象中的String类型的成员变量中所对应的字符内容中的“b”改为“a”;
public class ReflectTestField {
public static void main(String[] args)throws Exception{
ReflectPoint p1=new ReflectPoint(3,5);
replaceNum(p1);
System.out.println(p1.toString());
}
public static void replaceNum(Object obj)throws Exception{
Field[] fields=obj.getClass().getFields();
for(Field field:fields){
if(field.getType()==String.class){
String oldValue=(String) field.get(obj);
String newValue=oldValue.replace('b', 'a');
field.set(obj, newValue);
}
}
}
}
输出结果是:
三、Method类
通过反射机制得到某个类的某个方法,然后调用对应于这个类的某个实例的该方法
Class<T>类提供了几个方法获取类的方法。
public Method getMethod(String name,Class<?>... parameterTypes) 返回一个Method对象,它反映此Class对象所表示的类或接口的指定公共成员方法
public Method[] getMethods() 返回一个包含某些 Method 对象的数组,这些对象反映此Class对象所表示的类或接口(包括那些由该类或接口声明的以及从超类和超接口继承的那些的类或接口)的公共 member 方法
public Method getDeclaredMethod(Stringname,Class<?>... parameterTypes) 返回一个Method对象,该对象反映此Class对象所表示的类或接口的指定已声明方法
public Method[] getDeclaredMethods() 返回Method对象的一个数组,这些对象反映此Class对象表示的类或接口声明的所有方法,包括公共、保护、默认(包)访问和私有方法,但不包括继承的方法。
package com.itheima;
import java.lang.reflect.Method;
public class ReflcetTest4Method {
public static void main(String[] args) throws Exception{
// TODO Auto-generated method stub
ReflectPoint p1=new ReflectPoint(1,3);
Method md=p1.getClass().getMethod("add",int.class,int.class);
int sum=(int) md.invoke(p1, 1,2);
System.out.println(sum);
Method md1=p1.getClass().getMethod("add", int.class,int.class,int.class);
int sum1=(int) md1.invoke(p1,1,2,3);//调用此对象的方法,如果此方法的第一个参数为NULL,说明该Method对象对应的是一个静态方法。
System.out.println(sum1);
//以下语句实现:ArgumentTest.main(new String[]{"aaa","bbb","ccc"});
String startingClassName=args[0];
Method mainMethod=Class.forName(startingClassName).getMethod("main",String[].class);
mainMethod.invoke(null, (Object)new String[]{"aaa","bbb","ccc"});
}
}
class ArgumentTest{
public static void main(String[] args){//对接收数组参数的成员方法进行反射
for(String str:args){
System.out.println(str);
}
}
}
输出结果:
---------------------- ASP.Net+Unity开发、.Net培训、期待与您交流! ----------------------