Java反射:Class类的使用
通过Java反射机制,可以在程序中访问已经转载到JVM中的Java对象的描述,实现访问、检测和修改描述Java对象本身信息的功能。Java反射机制的功能十分强大,在java.lang.reflect包中提供了对该功能的支持。
所有Java类均继承了Object类,在Object类中定义了一个getClass()方法,该方法返回一个类型为Class的对象。
JTextField textField = new JTextField(); // 创建JTextField对象
Class textFieldC = textField.getClass(); // 获取Class对象
利用Class类的对象textFieldC,可以访问用来返回该对象的textField对象的描述信息。
获取Class对象的三种方式:
(1)通过Object类继承来的getClass()方法。
(2)通过类的“静态”的class属性。
(3)通过Class类的静态方法:Class.forName(String className)方法。
示例:使用三种方式获取Class对象。
import javax.swing.JTextField;
/**
* 使用三种方式获取Class对象。
*
* @author pan_junbiao
*
*/
public class Test
{
public static void main(String[] args) throws NoSuchMethodException, SecurityException
{
// 第一种方式获取Class对象
JTextField textField = new JTextField(); // 创建JTextField对象
Class myClass1 = textField.getClass(); // 获取Class对象
// 第二种方式获取Class对象
Class myClass2 = JTextField.class;
// 第三种方式获取Class对象
try
{
// 注意此字符串必须是真实路径,就是带包名的类路径,包名.类名
Class myClass3 = Class.forName("javax.swing.JTextField");
} catch (ClassNotFoundException e)
{
e.printStackTrace();
}
}
}
通过反射可访问的主要描述信息:
组成部分 | 访问方法 | 返回值类型 | 说明 |
---|---|---|---|
包路径 | getPackage() | Package对象 | 获取该类的存放路径 |
类名称 | getName() | String对象 | 获取该类的名称 |
继承类 | getSuperclass() | Class对象 | 获取该类继承的类 |
实现接口 | getInterfaces() | Class型数组 | 获取该类实现的所有接口 |
构造方法 | getConstructors() | Constructor型数组 | 获取所有权限为public的构造方法 |
getConstructor(Class<?>… parameterTypes) | Constructor对象 | 获取权限为public的指定构造方法 | |
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()只是获得在本类中定义的所有成员变量和方法。
1、访问构造方法
在通过下列一组方法访问构造方法时,将返回Constructor类型的对象或数组。每个Constructor对象代表一个构造方法,利用Constructor对象可以操纵相应的构造方法。
方法 | 说明 |
---|---|
getConstructors() | 获取所有权限为public的构造方法。 |
getConstructor(Class<?>… parameterTypes) | 获取权限为public的指定构造方法。 |
getDeclaredConstructors() | 获取所有构造方法,按照声明顺序返回。 |
getDeclaredConstructor(Class<?>… parameterTypes) | 获取指定构造方法。 |
如果是访问指定的构造方法,需要根据该构造方法的入口参数的类型来访问。例如,访问一个入口参数类型依次为String和int型的构造方法,通过下面两种方式均可实现。
Constructor cons1 = objectClass.getDeclaredConstructor(String.class, int.class);
Constructor cons2 = 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()方法的返回值所表示的修饰符信息,在该类中提供了一系列用来解析的静态方法,即可以查看是否被指定的修饰符修饰,还可以以字符串的形式获得所有修饰符。
Modifier类中的常用解析方法:
静态方法 | 说明 |
---|---|
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);
示例:访问构造方法。
首先创建一个Example_01类,在该类中声明一个String类型成员变量和3个int类型成员变量,并提供3个构造方法。
/**
* Example_01类
*
* @author pan_junbiao
*
*/
public class Example_01
{
String s;
int i, i2, i3;
private Example_01()
{
}
protected Example_01(String s, int i)
{
this.s = s;
this.i = i;
}
public Example_01(String... strings) throws NumberFormatException
{
if (0 < strings.length)
i = Integer.valueOf(strings[0]);
if (1 < strings.length)
i2 = Integer.valueOf(strings[1]);
if (2 < strings.length)
i3 = Integer.valueOf(strings[2]);
}
public void print()
{
System.out.println("s=" + s);
System.out.println("i=" + i);
System.out.println("i2=" + i2);
System.out.println("i3=" + i3);
}
}
然后编写测试类Main_01,在该类中通过反射访问Example_01类中的所有构造方法,并将该构造方法是否允许带有可变参数的参数、入口参数类型和可能抛出的异常类型信息输出到控制台。
import java.lang.reflect.Constructor;
/**
* 通过反射访问Example_01类中的所有构造方法 <br/>
* 并将该构造方法是否允许带有可变参数的参数 <br/>
* 入口参数类型和可能抛出的异常类型信息输出到控制台
*
* @author pan_junbiao
*
*/
public class Main_01
{
public static void main(String[] args)
{
Example_01 example = new Example_01("10", "20", "30");
Class<? extends Example_01> exampleC = example.getClass();
Constructor[] declaredConstructors = exampleC.getDeclaredConstructors();
for (int i = 0; i < declaredConstructors.length; i++)
{
Constructor<?> constructor = declaredConstructors[i];
System.out.println("查看是否允许带有可变数量的参数:" + constructor.isVarArgs());
System.out.println("该构造方法的入口参数类型依次为:");
Class[] parameterTypes = constructor.getParameterTypes();
for (int j = 0; j < parameterTypes.length; j++)
{
System.out.println(" " + parameterTypes[j]);
}
System.out.println("该构造方法可能抛出的异常类型为:");
Class[] exceptionTypes = constructor.getExceptionTypes();
for (int j = 0; j < exceptionTypes.length; j++)
{
System.out.println(" " + exceptionTypes[j]);
}
Example_01 example2 = null;
while (example2 == null)
{
try
{
if (i == 2)
example2 = (Example_01) constructor.newInstance();
else if (i == 1)
example2 = (Example_01) constructor.newInstance("pan_junbiao的博客", 5);
else
{
Object[] parameters = new Object[] { new String[] { "100", "200", "300" } };
example2 = (Example_01) constructor.newInstance(parameters);
}
} catch (Exception e)
{
System.out.println("在创建对象时抛出异常,下面执行setAccessible()方法");
constructor.setAccessible(true);
}
}
if (example2 != null)
{
example2.print();
System.out.println();
}
}
}
}
执行结果:
2、访问成员变量
在通过下列一组方法访问成员变量时,将返回Field类型的对象或数组。每个Field对象代表一个成员变量,利用Field对象可以操纵相应的成员变量。
方法 | 说明 |
---|---|
getFields() | 获取所有权限为public的成员变量。 |
getField(String name) | 获取权限为public的指定成员变量。 |
getDeclaredFields() | 获取所有成员变量,按照声明顺序返回。 |
getDeclaredField(String name) | 获取指定成员变量。 |
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() | 获取可以解析出该成员变量所采用修饰符的整数 |
示例:访问成员变量
首先创建一个Example_02类,在该类中声明int、float、boolean和String型的成员变量,并将它们设置为不同的访问权限。
/**
* Example_02类
*
* @author pan_junbiao
*
*/
public class Example_02
{
int i1;
int i2;
public float f;
protected boolean b;
private String s;
}
然后通过反射访问Example_02类中的所有成员变量,将成员变量的名称和类型信息输出到控制台,并分别将各个成员变量在修改前后的值输出到控制台。
import java.lang.reflect.Field;
/**
* 通过反射访问Example_02类中的所有成员变量 <br/>
* 将成员变量的名称和类型信息输出到控制台 <br/>
* 并分别将各个成员变量在修改前后的值输出到控制台
*
* @author pan_junbiao
*
*/
public class Main_02
{
public static void main(String[] args)
{
Example_02 example = new Example_02();
Class exampleC = example.getClass();
// 获得所有成员变量
Field[] declaredFields = exampleC.getDeclaredFields();
for (int i = 0; i < declaredFields.length; i++)
{
Field field = declaredFields[i]; // 遍历成员变量
// 获得成员变量名称
System.out.println("名称为:" + field.getName());
Class fieldType = field.getType(); // 获得成员变量类型
System.out.println("类型为:" + fieldType);
boolean isTurn = true;
while (isTurn)
{
// 如果该成员变量的访问权限为private,则抛出异常,即不允许访问
try
{
isTurn = false;
// 获得成员变量值
System.out.println("修改前的值为:" + field.get(example));
// 判断成员变量的类型是否为int型
if (fieldType.equals(int.class))
{
System.out.println("利用方法setInt()修改成员变量的值");
field.setInt(example, 168); // 为int型成员变量赋值
// 判断成员变量的类型是否为float型
} else if (fieldType.equals(float.class))
{
System.out.println("利用方法setFloat()修改成员变量的值");
// 为float型成员变量赋值
field.setFloat(example, 99.9F);
// 判断成员变量的类型是否为boolean型
} else if (fieldType.equals(boolean.class))
{
System.out.println("利用方法setBoolean()修改成员变量的值");
// 为boolean型成员变量赋值
field.setBoolean(example, true);
} else
{
System.out.println("利用方法set()修改成员变量的值");
// 可以为各种类型的成员变量赋值
field.set(example, "欢迎访问 pan_junbiao的博客");
}
// 获得成员变量值
System.out.println("修改后的值为:" + field.get(example));
} catch (Exception e)
{
System.out.println("在设置成员变量值时抛出异常," + "下面执行setAccessible()方法!");
field.setAccessible(true); // 设置为允许访问
isTurn = true;
}
}
System.out.println();
}
}
}
执行结果:
3、访问方法
在通过下列一组方法访问方法时,将返回Method类型的对象或数组。每个Method对象代表一个方法,利用Method对象可以操纵相应的方法。
方法 | 说明 |
---|---|
getMethods() | 获取所有权限为public的方法。 |
getMethod(String name, Class<?>… parameterTypes) | 获取权限为public的指定方法。 |
getDeclaredMethods() | 获取所以方法,按照声明顺序返回。 |
getDeclaredMethod(String name, Class<?>… parameterTypes) | 获取指定方法。 |
如果是访问指定的方法,需要根据该方法的名称和入口参数的类型来访问。例如,访问一个名称为print、入口参数类型依次为String和int型的方法,通过下面两种方法均可实现:
Method m1 = objectClass.getDeclaredMethod("print", String.class, int.class);
Method m2 = 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型 |
isVarArgs() | 查看该构造方法是否允许带有可变数量的参数,如果允许则返回true,否则返回false |
getModifiers() | 获取可以解析出该方法所采用修饰符的整型 |
示例:访问方法。
首先创建一个Example_03类,并编写4个典型的方法。
/**
* Example_03类
*
* @author pan_junbiao
*
*/
public class Example_03
{
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... strings)
{
System.out.println("执行privateMethod()方法");
StringBuffer stringBuffer = new StringBuffer();
for (int i = 0; i < strings.length; i++)
{
stringBuffer.append(strings[i]);
}
return stringBuffer.toString();
}
}
然后通过反射访问Example_03类中的所有方法,将各个方法的名称、入口参数类型、返回值类型等信息输出到控制台,并执行部分方法。
import java.lang.reflect.Method;
/**
* 通过反射访问Example_03类中的所有方法 <br/>
* 将各个方法的名称、入口参数类型、返回值类型等信息输出到控制台 <br/>
* 并执行部分方法
*
* @author pan_junbiao
*
*/
public class Main_03
{
public static void main(String[] args)
{
Example_03 example = new Example_03();
Class exampleC = example.getClass();
// 获得所有方法
Method[] declaredMethods = exampleC.getDeclaredMethods();
for (int i = 0; i < declaredMethods.length; i++)
{
Method method = declaredMethods[i]; // 遍历方法
System.out.println("名称为:" + method.getName()); // 获得方法名称
System.out.println("是否允许带有可变数量的参数:" + method.isVarArgs());
System.out.println("入口参数类型依次为:");
// 获得所有参数类型
Class[] parameterTypes = method.getParameterTypes();
for (int j = 0; j < parameterTypes.length; j++)
{
System.out.println(" " + parameterTypes[j]);
}
// 获得方法返回值类型
System.out.println("返回值类型为:" + method.getReturnType());
System.out.println("可能抛出的异常类型有:");
// 获得方法可能抛出的所有异常类型
Class[] exceptionTypes = method.getExceptionTypes();
for (int j = 0; j < exceptionTypes.length; j++)
{
System.out.println(" " + exceptionTypes[j]);
}
boolean isTurn = true;
while (isTurn)
{
// 如果该方法的访问权限为private,则抛出异常,即不允许访问
try
{
isTurn = false;
if ("staticMethod".equals(method.getName()))
method.invoke(example); // 执行没有入口参数的方法
else if ("publicMethod".equals(method.getName()))
System.out.println("返回值为:" + method.invoke(example, 168)); // 执行方法
else if ("protectedMethod".equals(method.getName()))
System.out.println("返回值为:" + method.invoke(example, "7", 5)); // 执行方法
else if ("privateMethod".equals(method.getName()))
{
Object[] parameters = new Object[] { new String[] { "您好!", "欢迎访问 ", "pan_junbiao的博客" } }; // 定义二维数组
System.out.println("返回值为:" + method.invoke(example, parameters));
}
} catch (Exception e)
{
System.out.println("在执行方法时抛出异常," + "下面执行setAccessible()方法!");
method.setAccessible(true); // 设置为允许访问
isTurn = true;
}
}
System.out.println();
}
}
}
执行结果:
还没有评论,来说两句吧...