JAVA反射机制
Java反射机制是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法;对于任意一个对象,都能够调用它的任意一个方法和属性;这种动态获取的信息以及动态调用对象的方法的功能称为java语言的反射机制。
Java反射机制主要提供了以下功能: 在运行时判断任意一个对象所属的类;在运行时构造任意一个类的对象;在运行时判断任意一个类所具有的成员变量和方法;在运行时调用任意一个对象的方法;生成动态代理。
例子:正常情况下如果已经有一个类,则肯定可以通过类创建对象;那么如果现在要求通过一个对象找到一个类的名称,此时就需要用到反射机制。
1. 通过对象来找类。
看一个小程序:GetClassDemo01.java
package org.lxh.demo15.getclassdemo ;
class X{
};
public class GetClassDemo01{
public staticvoid main(String args[]){
X x =new X() ; // 实例化X类的对象
System.out.println(x.getClass().getName()); //得到对象所在的类
}
};
javac -d . GetClassDemo01.java
java org.lxh.demo15.getclassdemo.GetClassDemo01
理解class类:所有类的对象实际上都是class类的实例,所有的对象都可以转变为class类型表示。
2. 反射的源头:class类,三种实例化class类的方式。
看一个程序:GetClassDemo02.java
package org.lxh.demo15.getclassdemo ;
class X{
};
public class GetClassDemo02{
public staticvoid main(String args[]){
Class<?>c1 = null ; // 指定泛型
Class<?>c2 = null ; // 指定泛型
Class<?>c3 = null ; // 指定泛型
try{
//以下的操作形式是在开发中最常用的一种形式
c1= Class.forName("org.lxh.demo15.getclassdemo.X") ;
}catch(ClassNotFoundExceptione){
e.printStackTrace();
}
c2 =new X().getClass() ; //通过Object类中的方法实例化
c3 =X.class ; // 通过类.class实例化
System.out.println("类名称:" + c1.getName()) ; //得到类的名称
System.out.println("类名称:" + c2.getName()) ; //得到类的名称
System.out.println("类名称:" + c3.getName()) ; //得到类的名称
}
};
javac -d . GetClassDemo02.java
java org.lxh.demo15.getclassdemo.GetClassDemo02
3. 取得类的结构:
getInterfaces()
getSuperclass()
getConstructors()
getMethods()
getDeclaredFields() //本类属性
getFields() //父类公共属性
看一个小程序:GetMethodDemo:
package org.lxh.demo15.classinfodemo ;
import java.lang.reflect.Method ; // 导入构造方法的包
import java.lang.reflect.Modifier ; // 导入构造方法的包
public class GetMethodDemo{
public staticvoid main(String args[]){
Class<?>c1 = null ; // 声明Class对象
try{
c1= Class.forName("org.lxh.demo15.Person") ; //实例化对象
}catch(ClassNotFoundExceptione){
e.printStackTrace();
}
Methodm[] = c1.getMethods() ; //取得全部方法
for(inti=0;i<m.length;i++){
Class<?>r = m[i].getReturnType() ; //得到返回值类型
Class<?>p[] = m[i].getParameterTypes() ; //取得全部参数的类型
intxx = m[i].getModifiers() ; //得到修饰符
System.out.print(Modifier.toString(xx)+ " ") ; //输出修饰符
System.out.print(r+ " ") ;
System.out.print(m[i].getName());
System.out.print("(");
for(intj=0;j<p.length;j++){
System.out.print(p[j].getName()+ " " + "arg" + j) ;
if(j<p.length-1){
System.out.print(",");
}
}
System.out.print(")");
System.out.println();
}
}
};
Person类:
package org.lxh.demo15 ;
interface China{ //定义China接口
public staticfinal String NATIONAL = "China" ; //定义全局常量
public staticfinal String AUTHOR = "李兴华" ; //定义全局常量
public voidsayChina() ; // 无参的,没有返回值的方法
public StringsayHello(String name,int age) ; //定义有两个参数的方法,并返回内容
}
public class Person implements China{
private Stringname ;
private int age;
publicPerson(){ // 无参构造
}
publicPerson(String name){
this.name= name ; // 设置name属性
}
publicPerson(String name,int age){
this(name);
this.age= age ;
}
public voidsayChina(){ // 覆写方法
System.out.println("作者:" + AUTHOR + ",国籍:" + NATIONAL) ;
}
public StringsayHello(String name,int age){
returnname + ",你好!我今年:" +age + "岁了!" ;
}
public voidsetName(String name){
this.name= name ;
}
public voidsetAge(int age){
this.age= age ;
}
public StringgetName(){
returnthis.name ;
}
public intgetAge(){
returnthis.age ;
}
};
javac -d . GetMethodDemo.java
javac -d . Person.java
java org.lxh.demo15.classinfodemo.GetMethodDemo
介绍一下随笔提示功能。
4. 通过反射调用类中的的方法、setter/getter方法、属性、数组
看一个程序:InvokeSayChinaDemo
package org.lxh.demo15.invokedemo ;
import java.lang.reflect.Method ;
public class InvokeSayChinaDemo{
public static voidmain(String args[]){
Class<?>c1 = null ;
try{
c1= Class.forName("org.lxh.demo15.Person") ; //实例化Class对象
}catch(Exceptione){}
try{
Method met = c1.getMethod("sayChina") ; //找到sayChina()方法
met.invoke(c1.newInstance()); //调用方法。c1.newInstance()是通过无参构造实例化的对象
}catch(Exceptione){
e.printStackTrace();
}
}
};
javac -d . InvokeSayChinaDemo.java
javac -d . Person.java
java org.lxh.demo15.invokedemo.InvokeSayChinaDemo
看一个程序:InvokeSayHelloDemo
package org.lxh.demo15.invokedemo ;
import java.lang.reflect.Method ;
public class InvokeSayHelloDemo{
public staticvoid main(String args[]){
Class<?>c1 = null ;
try{
c1= Class.forName("org.lxh.demo15.Person") ; //实例化Class对象
}catch(Exceptione){}
try{
Method met =c1.getMethod("sayHello",String.class,int.class) ; //找到sayChina()方法
Stringrv = null ;
rv= (String)met.invoke(c1.newInstance(),"李兴华",30); //调用方法
System.out.println(rv);
}catch(Exceptione){
e.printStackTrace();
}
}
};
javac -d . InvokeSayHelloDemo.java
javac -d . Person.java
java org.lxh.demo15.invokedemo.InvokeSayHelloDemo
操作属性:要注意的是一般属性都是封装的,我们通过反射调用setget方法来实现对属性的操控。
看一个程序:InvokeSetGetDemo
package org.lxh.demo15.invokedemo ;
import java.lang.reflect.Method ;
public class InvokeSetGetDemo{
public staticvoid main(String args[]){
Class<?>c1 = null ;
Objectobj = null ;
try{
c1= Class.forName("org.lxh.demo15.Person") ; //实例化Class对象
}catch(Exceptione){}
try{
obj= c1.newInstance() ;
}catch(Exceptione){}
setter(obj,"name","钟汉良",String.class) ; //调用setter方法
setter(obj,"age",39,int.class); //调用setter方法
System.out.print("姓名:") ;
getter(obj,"name");
System.out.print("年龄:") ;
getter(obj,"age");
}
/**
Objectobj:要操作的对象
Stringatt:要操作的属性
Objectvalue:要设置的属性内容
Class<?>type:要设置的属性类型
*/
public staticvoid setter(Object obj,String att,Object value,Class<?> type){
try{
Methodmet = obj.getClass().getMethod("set"+initStr(att),type) ; //得到setter方法
met.invoke(obj,value); //设置setter的内容
}catch(Exceptione){
e.printStackTrace();
}
}
public staticvoid getter(Object obj,String att){
try{
Methodmet = obj.getClass().getMethod("get"+initStr(att)) ; //得到setter方法
System.out.println(met.invoke(obj)); //调用getter取得内容
}catch(Exceptione){
e.printStackTrace();
}
}
public staticString initStr(String old){ //将单词的首字母大写
Stringstr = old.substring(0,1).toUpperCase() + old.substring(1) ;
returnstr ;
}
};
javac -d . InvokeSetGetDemo.java
javac -d . Person.java
java org.lxh.demo15.invokedemo.InvokeSetGetDemo
5. 为什么、什么时候会用到反射机制:
反射 可以通过配置文件进行加载类
如果通过配置文件调用所需的方法(配置文件取出的值为字符串)正向是不可以调用的 所以需要反射。
显然学过spring的朋友一定明白了,为什么可以通过配置文件就可以让我们获得指定的方法和变量,在我们创建对象的时候都是通过传进string实现的,就好像你需要什么,我们去为你生产,还有我们一直在用Object,这就说明java语言的动态特性,依赖性大大的降低了。
我们在写程序的时候并不知道需要调用某个对象的哪个方法,只有程序运行后,我们才能够知道。或许我们需要根据客户端传过来的某个String参数的值来判断我们应该执行哪个方法。在这种情况下JAVA的反射执行就可以帮上忙了。