Java 利用反射类操作其他类
反射的概念:
JAVA反射机制是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法;对于任意一个对象,都能够调用它的任意一个方法和属性;这种动态获取的信息以及动态调用对象的方法的功能称为java语言的反射机制。
要想解剖一个类,必须先要获取到该类的字节码文件对象。而解剖使用的就是Class类中的方法.所以先要获取到每一个字节码文件对应的Class类型的对象.
反射就是把java类中的各种成分映射成一个个的Java对象
例如:一个类有:成员变量、方法、构造方法、包等等信息,利用反射技术可以对一个类进行解剖,把个个组成部分映射成一个个对象。(其实:一个类中这些成员方法、构造方法、在加入类中都有一个类来描述)
Class反射类一直是Java中较为重要的一部分,说深入了解不敢说,基础的操作其他类的公有属性/方法,私有的属性/方法做个操作,什么是反射类,请参考其他更为详细的文章。
首先创建一个类,Student类:
public class Student {
private String name;
private String sex;
private int age;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getSex() {
return sex;
}
public void setSex(String sex) {
this.sex = sex;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public void run(){
System.out.println("奔跑");
}
private String say(String str){
return "他说"+str;
}
@Override
public String toString() {
return "Student{" +
"name='" + name + '\'' +
", sex='" + sex + '\'' +
", age=" + age +
'}';
}
}
在这个类中,有三个私有的属性,一个无返回值无参的方法,一个有返回值有参的方法,现在要利用Class反射类要做一个操作,获取这个Student类中的属性并赋值,调用这个类的方法
介绍一下获取Class对象的三种方式:
1、 Object ——> getClass();(封装时常用)
2、 任何数据类型(包括基本数据类型)都有一个“静态”的class属性
3、 通过Class类的静态方法:forName(String className)(常用)
第一种:
Student student = new Student();//这一new 产生一个Student对象,一个Class对象。
Class cls = student.getClass();//获取Class对象
第二种:
Class sls = Student.class;
第三种:
Class sls = Class.forName("com.uhope.uip.item.constants.Student");
第三种就是类所在包的完整路径
三种写法,看自己的需求来写,我这里要介绍的是第一种,因为我对这个反射类进行了一次的封装,封装成工具类方便调用。
创建好了Student类以后,创建一个测试类来进行测试一下看看效果:
在不知道类名的情况下,不把代码写死,想要写的灵活点,那就让使用这个工具类的人自己传一个类进来,那方法中的参数就放一个Object,Object是所有类的父类,所以都是没问题的:
public static void ClassUtil(Object obj){
Class cls = obj.getClass();
}
这样就获取到了别人传入的类
接着要操作类的方法,使用Method:
public static void ClassUtil(Object obj){
try {
Class cls = obj.getClass();
Method method = cls.getMethod("setName",String.class);
method.invoke(obj,"测试名称");
System.out.println(obj);
} catch (NoSuchMethodException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
e.printStackTrace();
}
}
这是操作公有方法的写法,接下来是操作私有方法的写法:
public static void ClassUtil(Object obj){
try {
Class cls = obj.getClass();
Method method = cls.getDeclaredMethod("say",String.class);
method.setAccessible(true);
method.invoke(obj, "哈喽");
} catch (NoSuchMethodException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
e.printStackTrace();
}
}
say是private封装的方法,setName是公有方法,操作私有的,需要 setAccessible(true) 来解除私有状态,还有一个不一样的是需要getDeclaredMethod而不是getMethod方法了,getDeclaredMethod是为了私有方法准备的,由于say是有返回值的方法,这里就不需要System.out.println了,在打印中就会展示出来
接下来是操作Student类中的run方法,run是一个无返回值无参的方法,但是里面写好了内容,这样的话只需要如下代码:
public static void ClassUtil(Object obj){
try {
Class cls = obj.getClass();
Method method = cls.getMethod("run");
method.invoke(obj);
} catch (NoSuchMethodException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
e.printStackTrace();
}
}
三种操作方法的演示好了,需要注意的就是 getDeclaredMethod和getMethod方法的使用区别,以及有无参数的区别,有参数的话要多写两个地方,一个是Method的第二个参数类型,一个是invoke的第二个指定的值。
接下来看调用私有的属性(一般项目中都是私有封装的,所以就讲解一下私有操作),调用方法是Method,调用属性是用Field:
public static void ClassUtil(Object obj){
try {
Class cls = obj.getClass();
Field field = cls.getDeclaredField("name");
field.setAccessible(true);
field.set(obj,"测试名称");
System.out.println(field.get(obj));
}catch (IllegalAccessException e) {
e.printStackTrace();
}catch (NoSuchFieldException e) {
e.printStackTrace();
}
}
和获取私有方法相同,都有一个getDeclared,也需要解除私有状态,通过Field中的set方法,将要给与的值赋进去,查看有没有赋值成功,就用Field的get方法即可,也可以通过Method获取setName方法,将参数写进去,再用Field获取值:
public static void ClassUtil(Object obj){
try {
Class cls = obj.getClass();
Method method = cls.getMethod("setName",String.class);
method.invoke(obj,"Method测试名称");
Field field = cls.getDeclaredField("name");
field.setAccessible(true);
System.out.println(field.get(obj));
} catch (NoSuchFieldException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (NoSuchMethodException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
e.printStackTrace();
}
}
还没有评论,来说两句吧...