java 反射简介
2014-07-24 14:24
232 查看
反射 概述:反射就是把Java类中的各种成分映射成相应的java类。例如,一个Java类中用一个Class类的对象来表示,一个类中的组成部分:成员变量,方法,构造方法,包等等信息也用一个个的Java类来表示,就像汽车一个类,汽车中的发动机,变速箱等等也是一个个的类。表示java类的Class类显然要提供一系列的方法,来获得其中的变量,方法,构造函数,修饰符,包等信息,这些信息就是用相应类的实例对象来表示,它们是Fiele,Method,Contructor,Package等等。 反射的要点:获取Fiele,Method,Contructor,Package的对象,然后通过它们来干一些事情。 Constructor类: 得到某个类的所有构造方法,得到某一个构造方法,创建实例变量,相关api class--》constructor--》new object 注意: 得到构造方法时需要传递类型,调用这个构造方法创建对象时同样需要传递相同的类型的对象 反射会导致程序性能下降 Class.newInstance()方法:创建不带参数的构造方法,然后用那个构造方法创建对象(可以阅读源码) Field类:类的成员变量 获取对应对象上变量的值(私有的和公有的值) class--》Field--》传入对象获取值(私有的还需要调用另外的方法) 循环反射一个类的对象中的所有字段 Method类:一个类中的方法 用反射调用某个对象的方法(包括静态方法的调用) 实例:调用不知道方法名或者哪个对象的反射调用(运行时动态判断),传递数组参数的类型的兼容性问题 数组的反射: 概念: 具有相同维数和元素类型的数组属于同一个类型,即具有相同的Class实例对象。 代表数组的Class实例对象的getSuperClass()方法返回父类为Object类对应的Class 基本类型的一维数组可以被当做Object类型使用,不能当做Object[]使用,非基本类型的一维数组,既可以当做Object类型使用,又可以当做Object[]类型使用 Arrays.asList()在不同版本的兼容性问题(处理int[]和String[]的差异) 数组的反射的常用方法 数组与Object的关系 数组反射的应用: 根据对象的class动态判断该对象是不是数组,然后分别进行处理 通过反射无法得到数组的类型,只能得到数组中具体某个元素的类型 框架的概念及反射技术开发框架的原理 不要出现具体类的名字,从配置文件中读取出来的(用流读取文件转化为Properties对象,然后读取对应的值) 框架与框架要解决的核心问题: 我做房子卖给用户住,由用户自己安装门窗和空调,我做的房子就是框架,用户需要使用我的框架,把门窗插入进我提供的框架中。框架与工具类的区别,工具类被用户的类调用,而框架则是调用用户提供的类 框架要解决的核心问题: 我在写框架(房子)时,你这个用户可能还在上小学,还不会写程序?我写的框架程序怎样调用到你以后写的类(门窗)呢? 因为在写程序时无法知道要被调用的类名,所以,在程序中无法直接new某个类的实例对象,而要用反射方式来做。 框架加载资源文件的方式: 第一种:通过流读取文件(可以进行读写),需要完整的路径,但完整的路径不是硬编码,而是计算出来的 第二种:通过反射:通过类加载器读取资源文件或直接使用Class类对象读取资源文件 调用Class对象的.getClassLoader().getResourceAsStream()或者Class对象的.getResoureAsStream()以上为反射中涉及的知识点.
1.概念
Java反射机制是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法;对于任意一个对象,都能够调用它的任意一个方法和属性;这种动态获取的信息以及动态调用对象的方法的功能称为Java语言的反射机制。反射的概念是由Smith在1982年首次提出的,主要是指程序可以访问、检测和修改它本身状态或行为的一种能力。这一概念的提出很快引发了计算机科学领域关于应用反射性的研究。它首先被程序语言的设计领域所采用,并在Lisp和面向对象方面取得了成绩。当然反射本身并不是一个新概念,它可能会使我们联想到光学中的反射概念,尽管计算机科学赋予了反射概念新的含义,但是,从现象上来说,它们确实有某些相通之处,这些有助于我们的理解。
2.Java反射机制主要提供下面几种用途:
在运行时判断任意一个对象所属的类
在运行时构造任意一个类的对象
在运行时判断任意一个类所具有的成员变量和方法
在运行时调用任意一个对象的方法
生成动态代理。
3.反射的功能
3.反射机制的功能?
① 在运行时查询并调用任意一个类所具有的成员变量和方法;
② 在运行时判断任意一个对象所属的类。例如:
String str = new String("abc");
Class c = str.getClass();
Boolean flag = c.isInstance(new String())
③ 在运行时创建类的实例;
·运行时创建实例对象
有两种办法生成实例对象:
针对无参数的构造方法,可以使用Class类里的newInstance()方法,该newInstance()方法不带参。例如:
Class c = String.class;
Object obj = c.newInstance();
要调用有参数的构造方法,就需要通过Constructor类的newInstance(Object ... obj)方法带参。例如:
//获得String的Class实例
Class clazz=String.class;
//创建一个数组,这个数组用来放要实例化对象的构造器里的参数类型
Class[] param=new Class[1];
//放入构造器中的参数类型,如果有多个,按顺序放入
param[0]=String.class;
//实例化一个构造器对象,并把放着构造器参数类型的数组作为参数传进去
Constructor constructor=clazz.getConstructor(param);
//创建一个Object数组,用于放构造器中对应的值
Object[] obj=new Object[1];
//将值放入到数组中,这里要注意,param数组中放入的是什么类型,这里就要按顺序放入
obj[0]="zhang3";
//实例化对象,并把放着构造器要传入的参数的数组传到方法中
String str=(String)constructor.newInstance(obj)
这样,我们就通过java.lang.reflect.Constructor实例化出来了String类型的对象。
·newInstance()和new关键字创建实例的比较
在初始化一个类,生成一个实例的时候,newInstance()方法和new关键字除了一个 是方法,一个是关键字外,最主要的区别在于创建对象的方式不一样,前者是使用类加载机制,后者是创建一个新类。那么为什么会有两种创建对象方式?这主要考虑到软件的可伸缩、可扩展和可重用等软件设计思想。
从JVM的角度看,我们使用关键字new创建一个类的时候,这个类可以没有被加载。但是使用newInstance()方法的时候,就必须保证:
1、这个类已经加载;
2、这个类已经链接了(即为静态域分配存储空间,并且如果必须的话将解析这个类创建的对其他类的所有引用)。而完成上面两个步骤的正是Class的静态方法forName()所完成的,这个静态方法调用了启动类加载器,即加载javaAPI的那个加载器。
可以看出,newInstance()实际上是把new这个方式分解为两步,即首先调用Class加载方法加载某个类,然后实例化。+这样分步的好处是显而易见的。我们可以在调用class的静态加载方法forName时获得更好的灵活性,提供给了一种降耦的手段。
最后用最简单的描述来区分new关键字和newInstance()方法的区别: newInstance:弱类型。低效率。只能调用无参构造方法。
New:强类型。相对高效。能调用任何public构造。
jvm会执行静态代码段,只要记住一个概念,静态代码是和class绑定的,class装载成功就表示执行了你的静态代码了。而且以后不会再走这段静态代码了。
④ 当要调用的一个类的方法为private时,可以采用反射技术调用;
先根据完整类名加载该类——>利用newInstance或Constructor实例化——>通过getDeclaredMethods()得到私有的方法——>取消Java语言访问检查以访问private方法(即调用setAccessible(true)) ——>最后通过Method的invoke方法调用该私有方法。
⑤ 利用反射实现类的动态加载(实现java动态绑定的前提)
多态是Java面向对象语言的一个重要特性,而向上转型是实现多态的重要一步,对于面向接口或父类的引用,JVM是靠后期绑定(动态绑定)的机制进行对象类型的判定的,即在运行时才能确定调用哪些代码。而实现动态绑定的基础便是反射机制的应用,通过反射在运行时根据类名得到该类的具体信息。
3. 使用java的反射机制,一般需要遵循三步:
获得你想操作类的Class对象
通过第一步获得的Class对象去取得操作类的方法或是属性名
操作第二步取得的方法或是属性
Java运行的时候,某个类无论生成多少个对象,他们都会对应同一个Class对象,它表示正在运行程序中的类和接口。如何取得操作类的Class对象,常用的有三种方式:
调用Class的静态方法forName,如上例;
使用类的.class语法,如:Class<?> cls = String.class;
调用对象的getClass方法,如:String str = "abc";Class<?> cls = str .getClass();
下面将通过实例讲述如何通过前面所诉的三步来执行某对象的某个方法:
<span style="font-family:Microsoft YaHei;">package com.wanggc.reflection; import java.lang.reflect.Method; /** * Java 反射练习。 * * @author Wanggc */ public class ReflectionTest { public static void main(String[] args) throws Exception { DisPlay disPlay = new DisPlay(); // 获得Class Class<?> cls = disPlay.getClass(); // 通过Class获得DisPlay类的show方法 Method method = cls.getMethod("show", String.class); // 调用show方法 method.invoke(disPlay, "Wanggc"); } } class DisPlay { public void show(String name) { System.out.println("Hello :" + name); } }</span>
转载自:http://www.cnblogs.com/gulvzhe/archive/2012/01/27/2330001.html
http://blog.csdn.net/shakespeare001/article/details/8082634
详解参考:http://blog.csdn.net/yongjian1092/article/details/7364451
http://www.cnblogs.com/yaozhongxiao/archive/2013/05/21/3091353.html
用反射机制实现对数据库数据的增、查例子 :http://www.cnblogs.com/jqyp/archive/2012/03/29/2423112.html
反射安全性与性能分析:http://blog.csdn.net/l12345678/article/details/1849363
以下为师傅传授:(QQ交流群:293074111)
1 Class对象的认识
在每一个类被Java虚拟机加载时,都会创建该类的Class对象,用来保存这个类的相关信息。Class对象中存储了大量的关于类的信息,并且提供了相关的方法来获得这些信息。由于Class类的方法很多,用法也比较复杂,下面只举出一个简单的应用,通过Class对象来获取类中的公用方法、构造器和成员变量。
import java.lang.reflect.*;
class Factory
{
public String name;
protected int area;
int yield;
private String location;
public Factory(String name){this.name=name;}
protected Factory(int area){this(0,area);}
Factory(int yield,int area){this.yield=yield;}
private Factory(){}
public void setName(String name){this.name=name;}
protected void setArea(int area){this.area=area;}
void setYield(int yield){this.yield=yield;}
private void setLocation(String location){this.location=location;}
}
public class TestClass {
public static void main(String[] args) {
Factory f = new Factory("Some Factory");
Class<? extends Factory> c = f.getClass();
System.out.println("类的名称:"+c.getName());
Field [] fields= c.getFields();
System.out.println("类的公用域:");
for(Field field:fields){System.out.println(field);}
Constructor [] cons = c.getConstructors();
System.out.println("类的共有构造器:");
for(Constructor con:cons){System.out.println(con);}
Method [] methods =c.getMethods();
System.out.println("类中的公有方法:");
for(Method method:methods){System.out.println(method);}
}
}
运行结果: 类的名称:Factory 类的公用域: public java.lang.String Factory.name 类的共有构造器: public Factory(java.lang.String) 类中的公有方法: public void Factory.setName(java.lang.String) public native int java.lang.Object.hashCode() public final native java.lang.Class java.lang.Object.getClass() public final void java.lang.Object.wait() throws java.lang.InterruptedException public final void java.lang.Object.wait(long,int) throws java.lang.InterruptedException public final native void java.lang.Object.wait(long) throws java.lang.InterruptedException public boolean java.lang.Object.equals(java.lang.Object) public final native void java.lang.Object.notify() public final native void java.lang.Object.notifyAll() public java.lang.String java.lang.Object.toString()
本例利用类的Class对象输出该类的相关信息,包括共有的成员变量、构造器与方法。
其中方法包括自身定义的公用方法与从父类中继承的公用方法。
2 class对象的获取方式
每一个Class类的对象就代表一种被加载进入JVM的类,它代表了该类的一种信息映射。主要有三种方式可以获得:
Class类的forName方法
所有的类都拥有一个静态的class属性;
所有的对象都会有getClass方法;
注意:如果给是基本数据类型的包装类,还可以使用类名.TYPE
在Java中一个有9个包装类:
Boolean Byte Short Char Integer Long Float Double Void另外:包装类的Class对象与其对应的基本数据类型的Class对象,两者并不相等的。
public class TestClass {
public static void main(String[] args) {
Class c1= Integer.class;
Class c2 = Integer.TYPE;
Class c3 = int.class;
//没有这种写法
// Class c4=int.TYPE;
if(c1==c2){System.out.println("Integer.class==Integer.TYPE");}
if(c2==c3){System.out.println("Integer.TYPE==int.class");}
if(c1==c3){System.out.println("Integer.class==int.class");}
}
}
运行的结果为: Integer.TYPE==int.class
3 数组的class对象
public class ArrayClass { public static void main(String[] args) { int[] array1=new int[3]; int[] array2= new int[5]; int[][]array3=new int[3][5]; String [] array4= new String[8]; Class c1 = array1.getClass(); Class c2 = array2.getClass(); Class c3 = array3.getClass(); Class c4 = array4.getClass(); //只要数组的类型与维数相同,数组的Class对象就相同(即为同一个Class对象),与数组的长度无关 if(c1==c2)System.out.println("数组array1与array2的class对象相同"); if(c1==int[].class){System.out.println("c1==int[].class");} if(c2==int[].class){System.out.println("c2==int[].class");} //数组的维数不同,class对象也不同 if(c1==c3){System.out.println("数组array1与array3的class对象相同");} if(c3==int[][].class){System.out.println("c3==int[][].class");} //数组的类型不同,class对象也不同 if(c1==c4){System.out.println("数组array1与array4的class对象相同");} if(c4==String[].class){System.out.println("c4==String[].class");} } }
运行结果: 数组array1与array2的class对象相同 c1==int[].class c2==int[].class c3==int[][].class c4==String[].class
4 反射包
实现反射机制的API在java.lang.Reflect包中,常见的类有:
(1)Class类:代表一个类
(2)Filed类:代表类的成员变量
(3)Method类:代表类的方法
(4)Constructor类:代表类的构造方法
(5)Array类:提供动态创建数组以及访问数组的元素的静态方法。该类中所有的方法都是静态的。
内容要求:大家对这些内容要有一个初步的了解,然后有时间了看看jdk源码,刚开始不要要求看懂,没有必要的。