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

java反射机制

2014-07-28 20:54 134 查看
动态语言都是指在程序运行时允许改变程序结构或变量类型。从这个角度看java和C++一样都不是动态语言。
但java拥有一个非常突出的动态相关机制:反射。通过反射,java可以于运行时加载、探知和使用编译期间完全未知的类,生成其对象实体。调用方法或对属性设值。
反射的概念:在java中的反射机制是指在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法;对于任意一个对象,都能够调用它的任意一个方法;这种动态获取信息以及动态调用对象的方法的功能称为java语言的反射机制。
java的反射机制是java特性之一,反射机制是构建框架技术的基础所在。
java的反射机制能够知道类的基本结构,这种对java类结构探知的能力,我们称为java类的“自审”。
java反射有三个动态性质:1、运行时生成对象实例。2、运行期间调用方法。3、运行时更改属性。
java反射可以实现的功能:1、运行时,判断任意一个对象所属的类;2、在运行时构造任意一个类的对象。3、在运行时判断任意一个类所具有的方法和属性。4、在运行时调用任意一个对象的方法。5、生成动态代理。
java反射应用的场合:java程序中许多对象在运行时都会出现两种类型:(编译时类型)和(运行时类型),编译时的类型由声明该对象是使用的类型决定,运行时类型由实际赋给该对象的类型决定,如:Person p = new Student();此时p的编译时类型为Person,运行时类型为Student;因为对象P是引用类型,在编译时其类型有Person来决定,而程序运行后发现p引用的内容实际是Student,因为只有在程序运行的时候才能知道p引用的内容改为了Student,所以称为运行时类型。
除此之外,程序在运行时还可能接收到外部传入的一个对象,该对象的编译时类型是Object,但程序又需要调用该对象运行时类型的方法。为了解这些问题,程序需要在运行时发现对象和类的真实信息。然而,如果编译时根本无法预知该对象和类可能属于那些类,程序只能靠运行时信息来发现该对象和类的真实信息,此时必须用到反射。
java反射API用来生成在当前java虚拟机中的类,接口或者对象的信息。
Class类是反射的核心类,反射所有的操作都是围绕该类来生成的。可以获取类的属性和方法等内容信息。Field类,表示类的属性,可以获取和设置类中的属性的值。Method类表示类的方法,他可以用来获取类中方法的信息,或者执行方法。Constructor类表示类的构造方法。
使用java反射机制,需要遵循的三个步骤:1、获取你想操作的类的java.lang.Class对象。2、调用Class的方法,用来得到对象的方法和属性等信息。3、使用反射API来操作这些信息。
java程序中获取Class对象通常有一下三种方式:1、调用某个对象的getClass()方法(Person p= new Person();Class cla = p.getClass();)。2、调用某个类的class属性来获取该类对应的Class对象。(Classcla = Person.class;)这种方式需要在编译期就知道类的名字。3、使用Class类的forName()静态方法,该方法需要传入一个字符串参数,该字符串参数的值是某个类的全名。(Class cla =
Class.forName("包名.类名"))如果不是完整的全名,则会抛出一个ClassNotFoundException异常。
使用类名.class方法与Class.forName(str)相比有两个优势:1、代码更安全,程序在编译阶段就可以检查需要访问的Class对象是否存在。2、程序性能更高,因为这种方式无须调用方法,所以程序性能更好。也就是说大部分的时候我们都应该采用调用某个类的Class属性的方式,来获取指定类的Class对象,但如果只有一个表示类名的全名字符串,而我们不知道字符串的具体内容,此时我们只能使用Class类的forName()方法.
访问Class对应的类所包含的构造方法:1、getConstructor方法,将获得所表示类的指定的public构造方法(Cinstructor co = cla.gerContructor(String.class,list.class))2、getCinstructors()方法,这个方法将返回此Class对象所表示的类的所有public构造方法。3、getDeclaredConstructor方法,返回此Class对象所表示的类的指定构造方法,与构造方法的访问级别无关。4、getDeclaredCinstructors()方法,返回Class对象所表示的类的全部方法,与方法的访问级别无关。
访问Class对应的类所包含的方法:1、getMethod方法(有两个参数name和params),返回此Class对象表示的类的指定的public方法,name参数用于指定方法名称,params参数是按声明顺序表示该方法参数类型的Class。例如:cla.getMethod("info",String.class)表示访问cla表示的类中,名称为info的方法,而这个info方法有一个String类型的参数。2、getMethods()方法,将返回class对象所代表的类的所有public方法,而返回类型将是Method数组。3、getDeclaredMethod(String
name,Class[]params)方法,与getMethod方法类似,都是返回指定方法,但与访问级别无关。4、getDeclaredMethods()方法,返回类全部方法,与方法的访问级别无关。
getdeclaredClasses()方法,返回该对象所对应类里包含的全部内部类。
getDeclaringClass()方法,返回Class对象所在的外部类。
通过反射来生成对象有如下两种方式:1、使用newInstance()创建对象(这种方式要求该Class对象的对应类有默认构造方法,而执行newInstance()方法时实际上是利用默认构造方法来创建该类的对象)。2、使用Constructor对象创建对象(要先使用Class对象获取指定的Constructor对象,在调用Constructor对象的newInstance()方法来创建该Class对象对应的实例。通过这种方式可以选择使用某个类的指定构造方法来创建实例)。
利用Constructor对应的某个构造方法来创建java对象需要以下三个步骤:1、获取该类的Class对象。2、利用Class对象的getConstructor()方法来获取指定的构造方法。3、调用Constructor的newInstance()方法来创建java对象。
使用反射调用方法:
通过invoke()方法来调用Method对象对应的方法;invoke()方法有两个参数,一个代表执行该方法的对象,另一个则代表执行该方法时要传入该方法的参数,
调用私有方法(setAccessible(Booleanflag)):将Method对象的accessible标志为指示的布尔值,值为true则表示该Method在使用时应该取消java语言访问权限设置。值为false则表示该Method在使用时应该实施java语言访问权限检查。
/**
* 从Class中获取信息
*/

import java.lang.annotation.Annotation;
import java.lang.reflect.Constructor;
import java.lang.reflect.Method;
@SuppressWarnings(value="unchecked")
public class ReflectionTest {
//为该类定义一个私有的构造方法

private ReflectionTest(){

}
//定义一个有参数的构造方法
public ReflectionTest(String name){
System.out.println("执行有参数的构造方法");
}

//定义一个无参数的info方法
public void info(){
System.out.println("执行无参数的info方法");
}

//定义一个有参数的info方法
public void info(String str){
System.out.println("执行有参数的info方法,str为"+str);
}

//定义两个参数的info方法
public void info(String name,int age){
System.out.println("执行有两个参数的info方法,"+name+" "+age);
}

//定义一个测试用的内部类
class Inner{

}

public static void main(String[] args) throws Exception{
//下面的代码可以获取ReflectionTest对应的Class
Class<ReflectionTest> cla=ReflectionTest.class;
//获取该Class对象所对应类的全部构造方法
Constructor[] co=cla.getDeclaredConstructors();
System.out.println("ReflectionTest的全部构造方法如下: ");
for(Constructor c:co){
System.out.println(c);
}

//获取该Class对象所对应类的全部public构造方法
Constructor[] pubco=cla.getConstructors();
System.out.println("ReflectionTest的全部public构造方法如下: ");
for(Constructor c:pubco){
System.out.println(c);
}

//获取该class对象指定参数构造方法:
Constructor<ReflectionTest> cr = cla.getConstructor(String.class);
System.out.println("获取指定的构造方法:"+cr);

//获取该Class对象所对应类的全部public方法
Method[] pubmt=cla.getMethods();
System.out.println("ReflectionTest的全部public方法如下: ");
for(Method mt:pubmt){
System.out.println(mt);
}

//获取该Class对象所对应类的指定方法
System.out.println("ReflectionTest里带一个字符串参数的info方法为: "+cla.getMethod("info", String.class));

//获取该Class对象对应类的指定方法
System.out.println("ReflectionTest里带有两个参数的info方法为"+cla.getMethod("info", String.class,int.class));

//获取该Class对象所对应类的全部注释
Annotation[] anno=cla.getAnnotations();
System.out.println("ReflectionTest的全部Annotation如下: ");
for(Annotation an:anno){
System.out.println(an);
}

System.out.println("该Class元素上的@SuppressWarnings注释为: "+cla.getAnnotation(SuppressWarnings.class));

//获取该Class对象所对应类的全部注释
Class<?>[] inners=cla.getDeclaredClasses();
System.out.println("ReflectionTest的全部内部类如下: ");
for(Class c:inners){
System.out.println(c);
}

//使用Class.forName方法加载ReflectionTest的Inner内部类
Class incla=Class.forName("ReflectionTest$Inner");

//获取该Class对象所对应类的外部类
System.out.println("incla对应类的外部类为: "+incla.getDeclaringClass());

System.out.println("ReflectionTest的包为: "+cla.getPackage());
System.out.println("ReflectionTest的父类为: "+cla.getSuperclass());

}

}


Field类提供了两组方法来访问属性:get方法和set方法。其中get(getXxx(Object obj),Xxx代表八个基本数据类型,如果该属性是引用数据类型则取消get后的Xxx)方法有一个参数,就是class对象对应类的实例对象。通过get方法可以获取obj对象中的该属性的属性值。
set方法:(SetXxx(Object obj,Xxx val)),通过set方法,可以将obj对象的该属性值设为参数val,此处Xxx对应8个基本类型,如果该属性的类型为引用类型,则省略Xxx。
对获取到的私有属性调用方法setAccessible(true),便可以使用这两个方法随意的访问指定对象的所有值。
import java.lang.reflect.Method;

public class Person {

private String name;
private String gender;
private int age;

/**
* @return the name
*/
private String getName() {
return name;
}
/**
* @param name the name to set
*/
private void setName(String name) {
this.name = name;
}
/**
* @return the gender
*/
public String getGender() {
return gender;
}
/**
* @param gender the gender to set
*/
public void setGender(String gender) {
this.gender = gender;
}
/**
* @return the age
*/
public int getAge() {
return age;
}
/**
* @param age the age to set
*/
public void setAge(int age) {
this.age = age;
}

public String toString(){
return "Person name is "+name+", age is "+age;
}

}


import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.Date;

public class Test {

public static void main(String[] args) throws Exception{

//创建一个Person对象
Person p = new Person();
//获取Person对应的Class对象
Class cla=Person.class;

//获取Person类的name属性,使用getDeclaredField()方法,表明可获取各种访问级别的属性
Field nameField = cla.getDeclaredField("name");
//设置通过反射访问 该Field时取消权限检查
nameField.setAccessible(true);
//调用set方法为p对象的指定Field设置值
nameField.set(p, "Jack");

//获取Person类的name属性,使用getDeclaredField()方法,表明可获取各种访问级别的属性
Field ageField = cla.getDeclaredField("age");
//设置通过反射访问 该Field时取消权限检查
ageField.setAccessible(true);
//调用setInt方法为p对象的指定Field设置值
ageField.setInt(p, 20);
System.out.println(p);
}

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