您的位置:首页 > 编程语言 > Java开发

Java基础--反射、内省

2016-04-19 17:07 525 查看
反射就是把Java类中的各种成分映射成相应的Java类

例如,一个Java类中用一个Class类的对象来表示,
一个类中的组成部分:成员变量,方法,构造方法,包等等信息也用一个个的Java类来表示,

就像汽车是一个类,汽车中的发动机,变速箱等等也是一个个的类。

表示java类的Class类显然要提供一系列的方法,来获得其中的变量,方法,构造方法,修饰符,包等信息,

这些信息就是用相应类的实例对象来表示,它们是Field(成员变量)、Method(方法)、Contructor(构造方法)、Package等等。

个人对反射的理解

pt1.getClass()获取到的是一个Class对象,这个对象不同于new出来的对象,有点类似于继承的子父类的关系,

pt1.getClass()获取到的对象相当于父类对象,是一个由class类直接获取到的Class对象,而不同于new出来的对象

pt1.getClass().getField("y")是通过这个Class对象获取到这个class类里面成员变量的一个操作权限,但只是获取了一个权限,没什么实际的用处

必须通过get获取set方法获取到操作某个对象的操作权限

用生活中的例子理解:

就像修手机的人,一个修手机的人他只会修手机的屏幕,就是说明这个人拥有修手机屏幕的权限,就相当于pt1.getClass().getField("y");所获取到的对y的控制权限

但是有些手机在还有没有生产出来之间,这个人就已经会修理屏幕了,很符合反射的原理,在对象还没有new出来之前他就已经拥有了控制y的权限

但是你会修手机屏幕,但没有手机也是不行的,没有东西修,一定要有一个手机给你修才行,手机就相当于new出来的对象

如何得到各个字节码对应的实例对象( Class类型)

类名.class,例如,System.class

对象.getClass(),例如,new Date().getClass()

Class.forName("类名"),例如,Class.forName("java.util.Date");

九个预定义Class实例对象:八个基本数据类型加一个void

参看Class.isPrimitive方法的帮助

Int.class == Integer.TYPE

//反射
import java.lang.reflect.Array;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.Method;

public class ReflecDemo {

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);

/*
boolean isPrimitive()
判定指定的 Class 对象是否表示一个基本类型。
* */
System.out.println(cls1.isPrimitive());//判断是否是基本数据类型对象
System.out.println(int.class.isPrimitive());
System.out.println(int.class == Integer.class);//false
System.out.println(int.class == Integer.TYPE);//true,将Integer.TYPE后就是基数据类型了
System.out.println(int[].class.isPrimitive());//false数组不是基本数据类型
System.out.println(int[].class.isArray());//true,判断数组要用isArray

int[] a1 = new int[]{1,5,8};
int[] a2 = new int[4];
int[][] a3 = new int[3][4];
String[] a4 = new String[]{"a","c","b","d"};
System.out.println(a1.getClass() == a2.getClass());
//System.out.println(a1.getClass() == a4.getClass());
//System.out.println(a1.getClass() == a3.getClass());
System.out.println(a1.getClass().getName());
System.out.println(a1.getClass().getSuperclass().getName());
System.out.println(a4.getClass().getSuperclass().getName());

Object aObj1 = a1;
Object aObj2 = a4;
Object[] aObj4 = a3;
Object[] aObj5 = a4;

ArrayDemo(a4);
ArrayDemo("zxc");
}

//反射中数组的演示
public static void ArrayDemo(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);
}
}

//反射中Method(方法)的演示
public static void MethodDemo() throws Exception{
//getMethod(String name, Class<?>... parameterTypes)
//返回一个 Method 对象,它反映此 Class 对象所表示的类或接口的指定公共成员方法。
//name 参数是一个 String,用于指定所需方法的简称
//parameterTypes 参数是按声明顺序标识该方法形参类型的 Class 对象的一个数组。如果 parameterTypes 为 null,则按空数组处理。

//invoke(Object obj, Object... args)
//对带有指定参数的指定对象调用由此 Method 对象表示的底层方法。
String str1 = "abc";
Method methodCharSt = String.class.getMethod("charAt", int.class);//int.class为所获取方法所接收的数据类型,可用于分别重载方法
System.out.println(methodCharSt.invoke(str1, 1));//使用反射使用charAt方法返回1位置上的值
//invoke(null, 1) 如果第一个参数为null,则调用的是静态方法
}

//反射中Field(成员变量)的演示和说明
public static void FieldDemo() throws Exception{
ReflectPoint pt1 = new ReflectPoint(3,5);
//getField,返回一个 Field 对象,它反映此 Class 对象所表示的类或接口的指定公共成员字段
Field fieldY = pt1.getClass().getField("y");//getField的参数为字段名
System.out.println(fieldY.get(pt1));//得到fieldY在pt1这个对象上的值
/*个人对反射的理解
pt1.getClass()获取到的是一个Class对象,这个对象不同于new出来的对象,有点类似于继承的子父类的关系,
pt1.getClass()获取到的对象相当于父类对象,是一个由class类直接获取到的Class对象,而不同于new出来的对象
pt1.getClass().getField("y")是通过这个Class对象获取到这个class类里面成员变量的一个操作权限,但只是获取了一个权限,没什么实际的用处
必须通过get获取set方法获取到操作某个对象的操作权限
* */

//getDeclaredField,返回一个 Field 对象,该对象反映此 Class 对象所表示的类或接口的指定已声明字段。
Field fieldX = pt1.getClass().getDeclaredField("x");//获取已被私有的成员变量用getDeclaredField
//setAccessible,将此对象的 accessible 标志设置为指示的布尔值。值为 true 则指示反射的对象在使用时应该取消 Java 语言访问检查。
//值为 false 则指示反射的对象应该实施 Java 语言访问检查。
fieldX.setAccessible(true);//暴力反射
System.out.println(fieldX.get(pt1));

//演示使用反射替换字符串
changeStringValue(pt1);
System.out.println(pt1);
}

public static void changeStringValue(Object obj) throws Exception{
Field[] fields = obj.getClass().getFields();//获取Field操作权限
for (Field field : fields){
if (field.getType() == String.class){
String oldValue = (String)field.get(obj);//对obj对象的Field进行操作,获取值
String newValue = oldValue.replace('b','a');
field.set(obj, newValue);
}
}
}

//反射中构造方法的演示
public static void ConstructorDemo() throws Exception{

/*
* Constructor类代表某个类中的一个构造方法
得到某个类所有的构造方法:
例子:Constructor [] constructors= Class.forName("java.lang.String").getConstructors();

得到某一个构造方法:
例子:Constructor constructor = Class.forName(“java.lang.String”).getConstructor(StringBuffer.class);
//获得方法时要用到类型

创建实例对象:
通常方式:String str = new String(new StringBuffer("abc"));
反射方式: String str = (String)constructor.newInstance(new StringBuffer("abc"));
//调用获得的方法时要用到上面相同类型的实例对象

* */

//new String(new StringBuffer("abc"));
Constructor constructor1 = String.class.getConstructor(StringBuffer.class);//获取构造方法(根据参数来确定获取那个构造方法)
//使用此 Constructor 对象表示的构造方法来创建该构造方法的声明类的新实例,并用指定的初始化参数初始化该实例。
String str2 = (String)constructor1.newInstance(new StringBuffer("abc"));
System.out.println(str2.charAt(2));
}

}


内省

简单的说内省就是在javaBean中通过反射的机制来使用get,set方法

import java.beans.IntrospectionException;
import java.beans.PropertyDescriptor;
import java.lang.reflect.*;
import java.util.*;
import org.apache.commons.beanutils.BeanUtils;
import org.apache.commons.beanutils.PropertyUtils;

public class IntroSpectorDemo {

/**
* @param args
*/
public static void main(String[] args) throws Exception{
// TODO Auto-generated method stub
ReflectPoint pt1 = new ReflectPoint(3, 5);

String propertyName = "x";
//获取值
Object retVal = getProperty(pt1, propertyName);
System.out.println(retVal);
//使用架包
System.out.println(BeanUtils.getProperty(pt1, "x").getClass().getName());

//设置值
Object value = 7;
setPropertes(pt1, propertyName, value); //自动抽取方法,右键-->refactor-->Excract Method
BeanUtils.setProperty(pt1, "x", 9);
System.out.println(pt1.getX());

/*
//java7新特性
Map map = (name:"zxx",age:18);
BeanUtils.setProperty(map,"name", "lhm");
*/

BeanUtils.setProperty(pt1, "birthday.time", "111");
System.out.println(BeanUtils.getProperty(pt1, "birthday.time"));

PropertyUtils.setProperty(pt1, "x", 9);
System.out.println(PropertyUtils.getProperty(pt1, "x").getClass().getName());
}

//PropertyDescriptor 描述 Java Bean 通过一对存储器方法导出的一个属性。
//使用PropertyDescriptor不同于反射或者getX的区别在于,getX只能访问public权限的,
//而PropertyDescriptor则可以访问所有权限,包括private
private static void setPropertes(Object pt1, String propertyName,
Object value) throws IntrospectionException,
IllegalAccessException, InvocationTargetException {

PropertyDescriptor pd2 = new PropertyDescriptor(propertyName, pt1.getClass());
//getWriteMethod  获得应该用于写入属性值的方法。
Method methodeSetX = pd2.getWriteMethod();
methodeSetX.invoke(pt1,value);
}

private static Object getProperty(Object pt1, String propertyName)
throws IntrospectionException, IllegalAccessException,
InvocationTargetException {

PropertyDescriptor pd = new PropertyDescriptor(propertyName, pt1.getClass());
//getReadMethod()  获得应该用于读取属性值的方法。
Method methodeGetX = pd.getReadMethod();
Object retVal = methodeGetX.invoke(pt1);
return retVal;
}

}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: