java:Class类与java反射
1 介绍
通过java反射机制,可以在程序中访问已经装载到JVM中的java对象的描述,实现访问、检测和修改描述java对象本身信息的功能。java反射机制的功能,在java.lang.reflect包中提供了对该功能的支持。
2 初识
所有java类均继承了Object类,在Object类中定义了一个getClass()方法,该方法返回一个类型为Class的对象,如下:
public class RefUtils {
public static void main(String[] args) {
RefUtils ins_r=new RefUtils();
Class<? extends RefUtils> r=ins_r.getClass();
}
}
利用Class类的对象r,可以访问用来返回该对象的类对象的描述信息,信息如下:
组成部分: 访问方法: 返回值类型: 说明:
包路径: getPackage():Package对象:获得该类的存放路径
类名称: getName():String对象:获得该类的名称
继承类: getSuperclass():Class对象:获得该类继承的类
实现接口: getInterfaces():Class型数组:获得该类实现的所有接口
package com.base;
import java.util.Arrays;
public class RefUtils {
public static void main(String[] args) {
RefUtils ins_r=new RefUtils();
Class<? extends RefUtils> r=ins_r.getClass();
System.out.println(r.getPackage());
System.out.println(r.getName());
System.out.println(r.getSuperclass());
System.out.println(Arrays.toString(r.getInterfaces()));
}
}
class R{}
class R2{}
interface MyR{}
interface MyR2{}
package com.base
com.base.RefUtils
class java.lang.Object
[]
java中没有多继承(类),只有多实现(接口)
package com.base
com.base.RefUtils
class com.base.R
[interface com.base.MyR, interface com.base.MyR2]
构造方法:
getConstructors():Constructor型数组:获得所有权限为public的构造方法
getConstructor(Class<?>… parameterTypes):Constructor对象:获得权限为public的指定构造方法
拓展:java方法中,把多个参数聚合为数组的方式:
public class RefUtils extends R implements MyR,MyR2{
public static void main(String[] args) {
RefUtils.aaa("1223","2");
}
public static void aaa(String... tys){
System.out.println(Arrays.toString(tys));
}
}
[1223, 2]
错误方式:
JavaScript:扩展运算符
扩展运算符(spread)是三个点(…)。它好比 rest 参数的逆运算,将一个数组转为用逗号分隔的参数序列。
getDeclaredConstructors():Constructor型数组:获得所有构造方法,按声明顺序返回
getDeclaredConstructor(Class<?>… parameterTypes)():Constructor对象:获得指定构造方法
方法:
getMethods():Method型数组:获得所有权限为public的方法
getMethod(String name, Class<?>… parameterTypes)():Method对象:获得权限为public的指定方法
getDeclaredMethods():Method型数组:获得所有方法,按声明顺序返回
getDeclaredMethod(String name, Class<?>… parameterTypes)():Method对象:获得指定方法
成员变量:
getFields():Field型数组:获得所有权限为public的成员变量
getField(String name)():Field对象:获得权限为public的指定成员变量
getDeclaredFields():Field型数组:获得所有成员变量,按声明顺序返回
getDeclaredField(String name)():Field对象:获得指定成员变量
内部类:
getClasses():Class型数组:获得所有权限为public的内部类
getDeclaredClasses():Class型数组:获得所有内部类
内部类的声明类:
getDeclaringClass():Class对象:如果该类为内部类,则返回它的成员类,否则返回null
说明:
在通过getFields()和getMethods()方法依次获得权限为public的成员变量和方法时,将包含从超类中继承到的成员变量和方法;而通过方法getDeclaredFields()和getDeclaredMethods()只是获得在本类中定义的所有成员变量和方法。
3 访问构造方法
在通过下列一组方法访问构造方法时,将返回Constructor类型的对象或数组。每个Constructor对象代表一个构造方法,利用Constructor对象可以操纵相应的构造方法。
getConstructors():Constructor型数组:获得所有权限为public的构造方法
getConstructor():getConstructor(Class<?>… parameterTypes):Constructor对象:获得权限为public的指定构造方法
getDeclaredConstructors():Constructor型数组:获得所有构造方法,按声明顺序返回
getDeclaredConstructor(Class<?>… parameterTypes)():Constructor对象:获得指定构造方法
如果是访问指定的构造方法,需要根据该构造方法的入口参数的类型来访问。例如,访问一个入口参数类型依次为String和int型构造方法,通过下面两种方式均可以实现。
objectClass.getDeclaredConstructor(String.class,int.class);
objectClass.getDeclaredConstructor(new Class[]{String.class,int.class});
Constructor类中提供的常用方法如下 (结构:方法+说明) :
isVarArgs():查看该构造方法是否允许带有可变数量的参数,如果允许则返回true,否则返回false
getParameterTypes():按照声明顺序以Class数组的形式获得该构造方法的各个参数的类型
getExceptionTypes():以Class数组的形式获得该构造方法可能抛出的异常类型
newInstance(Object… initargs):通过该构造方法利用指定参数构建一个该类的对象,如果未设置参数则表示采用默认无参数的构造方法
setAccessible(boolean flag):如果该构造方法的权限为private,默认为不允许通过反射利用newInstance(Object… initargs)方法创建对象。如果先执行该方法,并将入口参数设为true,则允许创建
getModifiers():获得可以解析出该构造方法所采用修饰符的整数
通过java.lang.reflect.Modifier类可以解析出getModifiers()方法的返回值所表示的修饰符信息,在该类中提供了一系列用来解析的静态方法,既可以查看是否被指定的修饰符修饰,还可以以字符串的形式获得所有修饰符。该类常用静态方法如下 (结构:静态方法+说明):
isPublic(int mod):查看是否被public修饰符修饰,如果是则返回true,否则返回false
isProtected(int mod):查看是否被protected修饰符修饰,如果是则返回true,否则返回false
isPrivate(int mod):查看是否被private修饰符修饰,如果是则返回true,否则返回false
isStatic(int mod):查看是否被static修饰符修饰,如果是则返回true,否则返回false
isFinal(int mod):查看是否被final修饰符修饰,如果是则返回true,否则返回false
toString(int mod):以字符串的形式返回所有修饰符
例如,判断对象constructor所代表的构造方法是否被private修饰,以及以字符串形式获得该构造方法的所有修饰符的典型代码如下:
int modifiers=constructor.getModifiers();
boolean isEmbellishByPrivate=Modifier.isPrivate(modifiers);
String embellishment=Modifier.toString(modifiers);
例子:访问构造方法
package com.base2;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Modifier;
import java.util.Arrays;
public class Construc {
String s;
int i1,i2,i3;
private Construc(){}
protected Construc(String s,int i1){
this.s=s;
this.i1=i1;
}
public Construc(String... strs)throws NumberFormatException{
if(0<strs.length)
i1=Integer.parseInt(strs[0]);
if(1< strs.length)
i2=Integer.parseInt(strs[1]);
if(2< strs.length)
i3=Integer.parseInt(strs[2]);
}
public void print(){
System.out.println("s="+s);
System.out.println("i1="+i1);
System.out.println("i2="+i2);
System.out.println("i3="+i3);
}
public static void main(String[] args) {
Construc c=new Construc("10","20","30");
Class<? extends Construc> e=c.getClass();
//获得所有构造方法
Constructor<?>[] c1=e.getDeclaredConstructors();
for (Constructor<?> constructor : c1) {
System.out.println("查看是否允许带有可变数量的参数:"+constructor.isVarArgs());
System.out.println("该构造方法的入口参数类型依次为:");
Class<?>[] parameterTypes=constructor.getParameterTypes();
//注意:String...的方法参数形式,既可以传入多个String参数,也可以传入String[] 数组
System.out.println(Arrays.asList(parameterTypes));
System.out.println("该构造方法可能抛出的异常类型为:");
Class<?>[] exceptionTypes=constructor.getExceptionTypes();
System.out.println(Arrays.toString(exceptionTypes));
System.out.println("该方法的权限修饰:");
System.out.println(Modifier.isPrivate(constructor.getModifiers()));
System.out.println(Modifier.isProtected(constructor.getModifiers()));
System.out.println(Modifier.isPublic(constructor.getModifiers()));
//
Construc cc=null;
while(cc==null){
//通过执行具有可变数量参数的构造方法创建对象
try {
if(Modifier.isPublic(constructor.getModifiers())){
System.out.println("开始public:");
Object[] parameters=new Object[]{new String[]{"100","200","300"}};
cc= (Construc) constructor.newInstance(parameters);
}else if(Modifier.isProtected(constructor.getModifiers())){
System.out.println("开始protected:");
//通过执行具有两个参数的构造方法创建对象
cc=(Construc) constructor.newInstance("88",10);
}else{
System.out.println("开始private:");
//通过执行默认没有参数的构造方法创建对象
cc=(Construc) constructor.newInstance();
}
} catch (InstantiationException ex) {
ex.printStackTrace();
} catch (IllegalAccessException ex) {
ex.printStackTrace();
} catch (InvocationTargetException ex) {
ex.printStackTrace();
}
}
if(cc!=null){
cc.print();
System.out.println();
}
System.out.println("------------------------");
}
}
}
查看是否允许带有可变数量的参数:true
该构造方法的入口参数类型依次为:
[class [Ljava.lang.String;]
该构造方法可能抛出的异常类型为:
[class java.lang.NumberFormatException]
该方法的权限修饰:
false
false
true
开始public:
s=null
i1=100
i2=200
i3=300
------------------------
查看是否允许带有可变数量的参数:false
该构造方法的入口参数类型依次为:
[class java.lang.String, int]
该构造方法可能抛出的异常类型为:
[]
该方法的权限修饰:
false
true
false
开始protected:
s=88
i1=10
i2=0
i3=0
------------------------
查看是否允许带有可变数量的参数:false
该构造方法的入口参数类型依次为:
[]
该构造方法可能抛出的异常类型为:
[]
该方法的权限修饰:
true
false
false
开始private:
s=null
i1=0
i2=0
i3=0
------------------------
Process finished with exit code 0
4 访问成员变量
在通过下列一组方法访问成员变量时,将返回Field类型的对象或数组。每个Field对象代表一个成员变量,利用Field对象可以操纵相应的成员变量。
getFields()
getField(String name)
getDeclaredFields()
getDeclaredField(String name)
如果是访问指定的成员变量,可以通过该成员变量的名称来访问。例如,访问一个名称为birthday的成员变量,访问方法如下:
object.getDeclaredField("birthday");
Field类中提供的常用方法如下(结构:方法+说明):
getName():获得该成员变量的名称
getType():获得表示该成员变量类型的Class对象
get(Object obj):获得指定对象obj中成员变量的值,返回值为Object型
set(Object obj,Object value):将指定对象obj中成员变量的值设置为value
getInt(Object obj):获得指定对象obj中类型为int的成员变量的值
setInt(Object obj,int i):将指定对象obj中类型为int的成员变量的值设置为i
getFloat(Object obj):获得指定对象obj中类型为float的成员变量的值
setFloat(Object obj,float f):将指定对象obj中类型为float的成员变量的值设置为f
getBoolean(Object obj):获得指定对象obj中类型为boolean的成员变量的值
setBoolean(Object obj,boolean z):将指定对象obj中类型为boolean的成员变量的值设置为z
setAccessible(boolean flag):此方法可以设置是否忽略权限限制直接访问private等私有权限的成员变量
getModifiers():获得可以解析出该成员变量所采用修饰符的整数
package com.base2;
import java.lang.reflect.Field;
public class Metho {
int i;
public float f;
protected boolean b;
private String s;
public static void main(String[] args) throws IllegalAccessException {
Metho m=new Metho();
Class<? extends Metho> c=m.getClass();
//获得所有成员变量
Field[] fs=c.getDeclaredFields();
for (Field f : fs) {
System.out.println(f);
System.out.println("名称为:"+f.getName());
System.out.println("类型为:"+f.getType());
boolean isFlag=true;
while(isFlag){
//如果该成员变量的访问权限
isFlag=false;
//获得成员变量值
//获得修改前的值,需要抛出IllegalAccessException异常
System.out.println("修改前的值为:"+f.get(m));
if(f.getType().equals(int.class)){
//判断成员变量的类型是否为int型
System.out.println("利用方法setInt()修改成员变量的值");
f.setInt(m,27);
}else if(f.getType().equals(float.class)){
System.out.println("利用方法setFloat()修改成员变量的值");
f.setFloat(m,9.99F);
}else if(f.getType().equals(boolean.class)){
System.out.println("利用方法setBoolean()修改成员变量的值");
f.setBoolean(m,true);
}else{
System.out.println("利用方法set()修改成员变量的值");
f.set(m,"XiaoXu");
}
//获得成员变量值
System.out.println("修改后的值为:"+f.get(m));
}
System.out.println("-----------------");
}
}
}
int com.base2.Metho.i
名称为:i
类型为:int
修改前的值为:0
利用方法setInt()修改成员变量的值
修改后的值为:27
-----------------
public float com.base2.Metho.f
名称为:f
类型为:float
修改前的值为:0.0
利用方法setFloat()修改成员变量的值
修改后的值为:9.99
-----------------
protected boolean com.base2.Metho.b
名称为:b
类型为:boolean
修改前的值为:false
利用方法setBoolean()修改成员变量的值
修改后的值为:true
-----------------
private java.lang.String com.base2.Metho.s
名称为:s
类型为:class java.lang.String
修改前的值为:null
利用方法set()修改成员变量的值
修改后的值为:XiaoXu
-----------------
Process finished with exit code 0
5 访问方法
通过下列一组方法访问方法时,将返回Method类型的对象或数组。每个Method对象代表一个方法,利用Method对象可以操作相应的方法。
getMethods():Method型数组:获得所有权限为public的方法
getMethod(String name, Class<?>… parameterTypes)():Method对象:获得权限为public的指定方法
getDeclaredMethods():Method型数组:获得所有方法,按声明顺序返回
getDeclaredMethod(String name, Class<?>… parameterTypes)():Method对象:获得指定方法
如果是访问指定的方法,需要根据该方法的名称和入口参数的类型来访问。例如,访问一个名称为print、入口参数依次为String和int型的方法,以下两种方式均可以:
objectClass.getDeclaredMethod("print",String.class,int.class)
objectClass.getDeclaredMethod("print",new Class[]{String.class,int.class})
Method类中提供的常用方法如下(结构:方法+说明):
getName():获得该方法的名称
getParameterTypes():按照声明顺序以Class数组的形式获得该方法的各个参数的类型
getReturnType():以Class对象的形式获得该方法的返回值类型
getExceptionTypes():以Class数组的形式获得该方法可能抛出的异常类型
invoke(Object obj,Object… args):利用指定参数args执行指定对象obj中的该方法,返回值为Object型
getModifiers():获得可以解析出该方法所采用的修饰符的整数
package com.base2;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.Arrays;
public class Met {
static void staticMethod(){
System.out.println("执行staticMethod()方法");
}
public int publicMethod(int i){
System.out.println("执行publicMethod()方法");
return i*100;
}
protected int protectedMethod(String s,int i)throws NumberFormatException{
System.out.println("执行protectedMethod()方法");
return Integer.valueOf(s)+i;
}
private String privateMethod(String... strs){
System.out.println("执行privateMethod()方法");
StringBuffer sb=new StringBuffer();
for (String str : strs) {
sb.append(str);
}
return sb.toString();
}
public static void main(String[] args) throws InvocationTargetException, IllegalAccessException {
Met k=new Met();
Class<? extends Met> h=k.getClass();
Method[] ms=h.getDeclaredMethods();
for (Method m : ms) {
System.out.println("名称为:"+m.getName());
System.out.println("是否允许带有可变数量的参数:"+m.isVarArgs());
System.out.println("入口参数类型依次为:");
Class<?>[] parameterTypes=m.getParameterTypes();
for (Class<?> parameterType : parameterTypes) {
System.out.print(" "+parameterType);
}
//获得方法返回值类型
System.out.println("返回值类型为:"+m.getReturnType());
System.out.println("可能抛出的异常类型有:"+ Arrays.toString(m.getExceptionTypes()));
boolean isTrue=true;
while(isTrue){
isTrue=false;
if("staticMethod".equals(m.getName())){
m.invoke(k);
}else if("publicMethod".equals(m.getName())){
System.out.println("返回值为:"+m.invoke(k,189));
}else if("protectedMethod".equals(m.getName())){
System.out.println("返回值为:"+m.invoke(k,"9",2));
}else if("privateMethod".equals(m.getName())){
Object[] p=new Object[]{
new String[]{
"X","I"
}
};
System.out.println("返回值为:"+m.invoke(k,p));
}
}
System.out.println("------------------------");
}
}
}
名称为:main
是否允许带有可变数量的参数:false
入口参数类型依次为:
class [Ljava.lang.String;返回值类型为:void
可能抛出的异常类型有:[class java.lang.reflect.InvocationTargetException, class java.lang.IllegalAccessException]
------------------------
名称为:staticMethod
是否允许带有可变数量的参数:false
入口参数类型依次为:
返回值类型为:void
可能抛出的异常类型有:[]
执行staticMethod()方法
------------------------
名称为:privateMethod
是否允许带有可变数量的参数:true
入口参数类型依次为:
class [Ljava.lang.String;返回值类型为:class java.lang.String
可能抛出的异常类型有:[]
执行privateMethod()方法
返回值为:XI
------------------------
名称为:publicMethod
是否允许带有可变数量的参数:false
入口参数类型依次为:
int返回值类型为:int
可能抛出的异常类型有:[]
执行publicMethod()方法
返回值为:18900
------------------------
名称为:protectedMethod
是否允许带有可变数量的参数:false
入口参数类型依次为:
class java.lang.String int返回值类型为:int
可能抛出的异常类型有:[class java.lang.NumberFormatException]
执行protectedMethod()方法
返回值为:11
------------------------
注意:在反射中执行具有可变数量的参数的构造方法时,需要将入口参数定义成二维数组。