反射除了可以取得一个类的完整结构外,还可以调用类中的指定方法或指定属性,并且可以通过反射完成对数组的操作
一、通过反射调用类中的方法
如果要使用反射调用类中的方法可以通过 Method 类完成:
(1)通过 Class 类的 getMethod(String name,Class...parameterTypes)
方法取得一个 Method 的对象,并设置此方法操作时所需要的参数类型
(2)之后可以使用 invoke 进行调用,并向方法中传递要设置的参数
- 调用 Person 类中的
sayChina()
方法:
import java.lang.reflect.Method;
public class Test{
public static void main(String[] args) {
Class<?> c1 = null;
try {
c1 = Class.forName("Person");
}catch (ClassNotFoundException e){
e.printStackTrace();
}
try{
Method met = c1.getMethod("sayChina");//此方法没有参数
met.invoke(c1.newInstance());//调用方法,必须传递对象实例
}catch (Exception e){
e.printStackTrace();
}
}
}
- 调用Person 类中的
sayHello()
方法
程序中通过 Class 类的 getMethod()
方法根据一个类中的方法取得 Method 对象,并通过 invoke 调用指定的方法。但是在使用 invoke()
方法时必须传入一个类的实例化对象,因为在 sayChina()
方法上没有任何的参数,所以此处没有设置参数类型和参数内容,程序操作如下:
import java.lang.reflect.Method;
public class Test{
public static void main(String[] args) {
Class<?> c1 = null;
try {
c1 = Class.forName("Person");
}catch (ClassNotFoundException e){
e.printStackTrace();
}
try{
Method met = c1.getMethod("sayHello",
String.class,int.class);//此方法需要两个参数
String rv = null;//接收方法的返回值
rv = (String)met.invoke(c1.newInstance(),"Java",20);
System.out.println(rv);
}catch (Exception e){
e.printStackTrace();
}
}
}
- 19
- 20
- 21
程序中在使用 getMethod()
方法调用时除了要指定调用的方法名称,也同样指定了参数的类型,因为 sayHello()
方法调用完后存在返回值,所以用来一个字符串接收返回的内容。
二、调用 setter 及 getter 方法
面向对象部分已经知道,类中的属性必须封装,封装之后的属性要通过 setter 及 getter 方法设置和取得,同样在使用反射的调用方法操作中,最重要的也是调用类中的 setter 及 getter 方法。
import java.lang.reflect.Method;
public class Test{
public static void main(String[] args) {
Class<?> c1 = null;//声明 Class 对象
Object obj = null;//声明一个对象
try {
c1 = Class.forName("Person");
}catch (ClassNotFoundException e){
e.printStackTrace();
}
try{
obj = c1.newInstance();//实例化操作对象
}catch (InstantiationException e){
e.printStackTrace();
}catch (IllegalAccessException e){
e.printStackTrace();
}
setter(obj,"name","Java",String.class);
setter(obj,"age",30,int.class);
System.out.print("姓名:");
getter(obj,"name");
System.out.print("年龄:");
getter(obj,"age");
}
/*
@param obj 操作的对象
@param att 操作的属性
@param obj value 设置的值
@param obj type 参数的类型
*/
public static void setter(Object obj,String att,Object value, Class<?> type){
try{
Method met = obj.getClass().getMethod(
"set" + initStr(att),type);//设置方法参数类型
met.invoke(obj,value);//调用方法
}catch(Exception e){
e.printStackTrace();
}
}
public static void getter(Object obj,String att){//调用 getter 方法
try{
Method met = obj.getClass().getMethod(
"get" + initStr(att));//此方法不需要参数
System.out.println(met.invoke(obj));//接收方法的返回值
}catch(Exception e){
e.printStackTrace();
}
}
public static String initStr(String old){//单词首字母大写
String str = old.substring(0,1).toUpperCase() + old.substring(1);
return str;
}
}
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
- 46
- 47
- 48
- 49
- 50
- 51
- 52
- 53
- 54
三、通过反射操作属性
反射操作中虽然可以使用 Method 调用类中的 setter 及 getter 方法设置和取得属性,但是这样操作很麻烦,所以在反射机制中也可以直接通过 Field 类操作类中的属性,通过 Field 类提供的 set()
和 get()
方法就可以完成设置和取得属性内容的操作。
但是操作之前,类中的属性已经都设置成私有的访问权限,所以在使用 set() 或 get() 方法时首先要使用 Field 类中的 setAccessible(true)
方法将需要操作的属性设置成可以被外部访问
import java.lang.reflect.Field;
public class Test{
public static void main(String[] args)throws Exception {
Class<?> c1 = null;//声明 Class 对象
Object obj = null;//声明一个对象
c1 = Class.forName("Person");
obj = c1.newInstance();//实例化操作对象
Field nameField = null;//表示 name 属性
Field ageField = null;//表示 age 属性
nameField = c1.getDeclaredField("name");//取得name属性
ageField = c1.getDeclaredField("age");
nameField.setAccessible(true);//将 name 属性设置成可被外部访问
nameField.set(obj,"Java");//设置 name 属性内容
ageField.setAccessible(true);
ageField.set(obj,30);//设置 age 属性
System.out.println("姓名:" + nameField.get(obj));
System.out.println("年龄:" + ageField.get(obj));
}
}
- 19
- 20
使用反射操作属性时最好通过 setter 及 getter 方法
四、通过反射操作数组
反射机制不仅能用在类上,还可以用在任意的引用数据类型的数据上,当然这本身就包含了数组,既可以使用反射操作数组。可以通过 Class 类的以下方法取得一个数组的 Class 对象:
public Class<?> getComponentType()
- 1
在反射操作包 java.lang.reflect
中使用 Array 类表示一个数组,可以通过此类取得数组长度,取得数组内容的操作
- 取得数组信息并修改数组内容
import java.lang.reflect.Array;
public class Test{
public static void main(String[] args)throws Exception {
int temp[] = {1,2,3};
Class<?> c = temp.getClass().getComponentType();//取得数组的 Class 对象
System.out.println("类型:" + c.getName());//得到数组类型名称
System.out.println("长度:" + Array.getLength(temp));//得到数组长度
System.out.println("第一个内容:" + Array.get(temp,0));//得到第一个内容
Array.set(temp,0,6);//修改第一个内容
System.out.println("第一个内容:" + Array.get(temp,0));//得到第一个内容
}
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 修改数组的大小
import java.lang.reflect.Array;
public class Test{
public static void main(String[] args)throws Exception {
int temp[] = {1,2,3};
int newTemp[] = (int[])arrayInc(temp,5);//扩大数组长度
print(newTemp);
System.out.println("\n-------------------------");
String t[] = {"J1","J2","J3"};//声明一个字符串数组
String nt[] = (String[])arrayInc(t,8);//扩大数组长度
print(nt);
}
public static Object arrayInc(Object obj,int len){//修改数组大小
Class<?> c = obj.getClass();//通过数组得到 Class 对象
Class<?> arr = c.getComponentType();//得到数组的 Class 对象
Object newO = Array.newInstance(arr,len);//重新开辟新的数组大小
int co = Array.getLength(obj);//取得数组长度
System.arraycopy(obj,0,newO,0,co);//复制数组内容
return newO;
}
public static void print(Object obj){
Class<?> c = obj.getClass();//通过数组得到 Class 对象
if (!c.isArray()){//判断是否是数组,不是则返回
return;
}
Class<?> arr = c.getComponentType();//取得数组的 Class
System.out.println(arr.getName() +
"数组的长度是:" + Array.getLength(obj));
for (int i=0;i<Array.getLength(obj);i++){
System.out.print(Array.get(obj,i) + "、");
}
}
}
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
五、程序中用到的Person 类
interface China{
public static final String NATIONAL = "China";
public static final String AUTHOR = "Java";
public void sayChina();//定义无参的抽象方法
public String sayHello(String name,int age);//定义有参的抽象方法
}
class Person implements China{
private String name;
private int age;
public Person(){
}
public Person(String name){//声明有一个参数的构造方法
this.name = name;
}
public Person(String name,int age){
this(name);
this.setAge(age);
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public void setAge(int age) {
this.age = age;
}
public int getAge() {
return age;
}
@Override
public void sayChina() {
System.out.println("作者:" + AUTHOR + ",国籍:" + NATIONAL);
}
@Override
public String sayHello(String name, int age) {
return name + "你好!我今年" + age + "岁了!";
}
}
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45