黑马程序员-反射
---------------------- ASP.Net+Unity开发、.Net培训、期待与您交流! ----------------------
概念:
反射是指运行时的类信息,它允许运行中的 Java 程序对自身进行检查,或者说"自省",并能直接操作程序的内部属性。可以在程序运行的时候动态装载类,查看类的信息,生成对象,或操作生成对象的一种机制。通俗的将就是一个类的每个成员都可以用java反射API类的一个实例来表示。
通过反射获取类的Class对象实例:
1.类名.class方式,这种为固定格式。任何一种类型都有对应的字节码对象,如int.class、void.class、int[].class。
2.Class.forName("类的全限定名")。
3.通过调用类实例的getClass()方法。该方法是Object类中的,需要实例对象。
什么是javabean:
javabean就是符合了某种特殊规范的一个普通的Java类,它要求类中的字段必须私有化,对外提供getter和setter属性访问,且属性名要按照驼峰式命名,并提供一个无参的构造函数。我们把符合了这种规范的Java类成为javabean。我们又通常把javabean的实例对象称之为值对象 (Value Object),因为这些bean中通常只有一些信息字段和存储方法,没有功能性方法。
什么是内省:
内省(IntroSpector)是java语言对javabean类属性、时间的一种缺省处理方法。Java 中提供了一套 API 用来访问某个属性的 getter/setter方法,通过这些 API 可以使你不需要了解这个规则,这些 API 存放于包 java.beans 中。
注意:当使用“.class”来创建对Class对象的引用时,不会自动地初始化该Class对象。实际上为了使用类的准备工作有三个步骤。
1.加载,这是由类加载器完成的,该步骤将查找字节码,并从这些字节码中创建一个Class对象。
2.链接,在链接阶段将验证类中的字节码,为静态域分配存储空间,并且如果必需的话,将解析这个类创建的对其他类的所有引用。
3.初始化,如果该类拥有父类,则对其初始化,执行静态初始化和静态代码块初始化。
所以“.class”这种写法不仅更简单,而且更安全,更高效。
代码示例:
反射一个类的构造函数:
public class ReflectDemo {
/**
* 反射类的构造函数
* @param args
*
*/
public static void main(String[] args) throws Exception {
//获取String类的Class实例,方式一
Class clazz=String.class;
//获取String类的Class实例,方式二
//Class clazz=Class.forName("java.lang.String");
//获取参数是String类型的构造函数
Constructor<String> cons=clazz.getConstructor(String.class);
//通过调用Constructor的newInstance方法创建实例对象。
String str=cons.newInstance("abc");
System.out.println(str);
}
}
反射字段:
public class ReflectBean {
private int age;
public String name;
public ReflectBean(int age, String name) {
super();
this.age = age;
this.name = name;
}
}
public class ReflectField {
/**
* 反射类的字段
* @param args
*/
public static void main(String[] args)throws Exception {
//创建自定义实例对象
ReflectBean bean=new ReflectBean(3, "名字");
//获取自定义类的Class实例
Class clazz=ReflectBean.class;
//获取指定的字段
Field fAge=clazz.getDeclaredField("age");//由于该字段是private的,所以调用getDeclaredField方法。
Field fName=clazz.getField("name");//getField方法只获取所有为public权限的方法。
fAge.setAccessible(true);//由于age字段是私有的,需要设置可访问。
System.out.println(fAge.get(bean));
System.out.println(fName.get(bean));
fAge.setInt(bean, 12);//给相应对象字段设置值
System.out.println(fAge.get(bean));
}
}
反射并调用方法:
public class ReflectMethod {
/**
* 反射方法
* @param args
*/
public static void main(String[] args)throws Exception {
String str="abc";
//获取Class实例对象。
Class clazz=String.class;
//反射指定的方法
Method method=clazz.getMethod("charAt", int.class);
//调用反射的方法
System.out.println(method.invoke(str, 2));
}
}
Array数组的反射类工具:
public class ArrayDemo {
/**
* 用Array类反射数组
* @param args
*/
public static void main(String[] args) {
int[] arr=new int[]{1,2,3};
pringObject(arr);
pringObject("aaa");
}
private static void pringObject(Object obj) {
//
Class clazz=obj.getClass();
if(clazz.isArray()){
int length=Array.getLength(obj);//痛过Array的getLength方法反射数组长度。
for(int i=0;i<length;i++){
System.out.println(Array.get(obj, i));//通过Array的get方法发射数组中的元素。
}
}else {
System.out.println(obj);
}
}
}
用反射结合配置文件:
public class ReflectDemo2 {
/**
* 结合配置文件反射实现
* @param args
*/
public static void main(String[] args)throws Exception {
//很多框架都是采用类装载器来读取配置文件,这就是为什么要将配置文件放在classpath下的原因。
//InputStream in=ReflectDemo2.class.getResourceAsStream("config.properties");//这种写法会到相对ReflectDemo2类所在的目录下查找配置文件。
//InputStream in=ReflectDemo2.class.getClassLoader().getResourceAsStream("cn/jiava/reflect/config.properties");
InputStream in=ReflectDemo2.class.getResourceAsStream("/cn/jiava/reflect/config.properties");//绝对路径写法
Properties prop=new Properties();
prop.load(in);//读取配置文件
in.close();//关闭资源
String className=prop.getProperty("className");//通过配置文件获取指定的键值。
Collection coll=(Collection) Class.forName(className).newInstance();
coll.add("abc");
coll.add("abd");
coll.add("abe");
coll.add("abc");
System.out.println(coll.size());
}
}
内省:
<pre class="java" name="code">public class Point { //javabean格式
private Integer x;
private Integer y;
public Point(Integer x, Integer y) {
super();
this.x = x;
this.y = y;
}
public Integer getX() {
return x;
}
public void setX(Integer x) {
this.x = x;
}
public Integer getY() {
return y;
}
public void setY(Integer y) {
this.y = y;
}
}
import java.beans.PropertyDescriptor;
import java.lang.reflect.Method;
public class Reflect {
public static void main(String[] args) throws Exception {
Point point = new Point(2, 5);
String proName = "x";
getProperty(point, proName);
setProperty(point, proName);
}
private static void setProperty(Point point, String proName) throws Exception {
//调用属性描述器获得对应的javabean属性
PropertyDescriptor proDescriptor = new PropertyDescriptor(proName, Point.class);
Method methodSetX = proDescriptor.getWriteMethod();
methodSetX.invoke(point, 8);
System.out.println(point.getX());// 8
}
private static void getProperty(Point point, String proName) throws Exception {
PropertyDescriptor proDescriptor = new PropertyDescriptor(proName, Point.class);
Method methodGetX = proDescriptor.getReadMethod();
Object objx = methodGetX.invoke(point);
System.out.println(objx);// 2
}
}
总结:
将 Java的反射以及内省应用到程序设计中去可以大大的提供程序的智能化和可扩展性。有很多项目都是采取这两种技术来实现其核心功能,其实应该说几乎所有的项目都或多或少的采用这两种技术。在实际应用过程中二者要相互结合方能发挥真正的智能化以及高度可扩展性。
---------------------- ASP.Net+Unity开发、.Net培训、期待与您交流! ----------------------