java反射批量处理字段值_Java反射篇学习笔记

本文是一篇关于Java反射的学习笔记,详细介绍了如何通过反射获取和操作类的构造函数、成员变量和方法。通过实例展示了如何批量处理字段值,包括获取Class对象、构造函数、成员变量和方法的调用。最后讨论了反射在框架和实际工作中的应用,加深了对面向对象的理解。
摘要由CSDN通过智能技术生成

今天重新学习了java中的反射,写一篇学习笔记总结一下。代码基本都是照着两篇博客敲的:

其中,第一篇比较详细点。作为初学者,我觉得不能根据晦涩的概念强行去理解一个知识点,而应该结合具体的应用实例。

先初步理解一下反射的作用:

(1)反编译,将 .class文件转化为 .java文件

(2)通过class对象来访问其对应类的对象的属性、方法、构造方法。

1、Class类

先来理解一下Class这个特殊的的类,在平时敲代码的时候,偶尔会写到,this.getClass( )这样的方法,但是却不知道是什么意思。查一下API可知,Class类也同样继承了Object类,Class类的实例用来表示正在运行的java应用程序中的类和接口,也就是说jvm中已经存在对象的类、已经被加载进去的类,都会有对应的Class实例(这也包括基本的数据结构),详细图解见第一篇推荐博客。

注意点:

(1)Class类保存的是对应类的信息,比如现在有一个Student类,现在通过new 方法 产生了一个stu1的实例,那么jvm会把Stduent类加载进内存,通过类加载器中等defineClass方法构造 一个对应的Class对象,来保存Student的一些信息,包括其中的一些方法、属性、构造方法等。

(2)同一种类型的对象或者数据类型,共享一个class实例。比如说,Student方法继续产生stu2、stu3.。。。等等的对象,即使再多,也只有一个对应的Class实例来保存他们的信息。

(3)通过Class实例,可以反向地获取对应类的信息,如果指定对象(例如 stu1), 可以反向获得他的属性、方法等信息。

2、反射的使用

下面举的例子都是来自上面推荐的第一篇博客,我自己也敲了一遍,学习一下。

(1)获取Class对象的方法

1 packagefanshe;2 /**

3 *4 * 获取class对象的三种方式5 * 1、object ——> getClass();6 * 2、任何数据类型(包括基本数据类型)都有一个静态的class属性。7 * 3、通过class类的静态方法:forName(String className)(常用)8 *9 */

10 public classDemo_1 {11

12 public static voidmain(String[] args) {13 //第一种获得class对象的方法

14 Student stu1 = new Student();//这一个new产生一个Student对象,一个Class对象

15 Class stuClass = stu1.getClass();//获取class对象

16 System.out.println(stuClass.getName());17

18 //第二种方式获取class对象

19 Class stuClass2 = Student.class;20 System.out.println(stuClass ==stuClass2);21

22 //第三种方式获取class对象

23 try{24 Class stuClass3 = Class.forName("fanshe.Student");//带包名

25 System.out.println(stuClass3 ==stuClass2);26 } catch(ClassNotFoundException e) {27 //TODO Auto-generated catch block

28 e.printStackTrace();29 }30

31 }32 }

Student:

classStudent{

Student(){}

}

结果:

fanshe.Studenttrue

true

总结:第三种方法比较常见,不用导包,也不用知道对象。上面的测试也说明了,同一个对象共享一个Class实例,一个类只产生一个class实例。

(2)通过反射获取构造函数

Student类:

packagefanshe;public classStudent {//默认构造方法

Student(String str){

System.out.println("(默认)的默认构造方法 s = " +str);

}//无参构造方法

publicStudent() {

System.out.println("调用了共有的、无参构造方法执行");

}//有一个参数的构造方法

public Student(charname) {

System.out.println("姓名: " +name);

}//有多个参数的构造方法

public Student(String name, intage) {

System.out.println("姓名: " + name+ "年龄:" +age);//这的执行效率有问题

}//受保护的构造方法

protected Student(booleann) {

System.out.println("受保护的构造方法 n= " +n);

}//私有构造方法

private Student(intage) {

System.out.println("私有构造方法 年龄:" +age);

}

}

测试类:

1 packagefanshe;2 importjava.lang.reflect.Constructor;3 /**

4 *5 * 通过Class对象可以获取某个类中的构造方法、成员变量、成员方法:并访问成员;6 * 1、获取构造方法:7 * (1)批量的方法8 * public Constructor[] getConstructor(); 所有“公有的”构造方法9 * public Constructor[] getDeclaredConstructors(); 获取所有的构造方法10 *11 * (2)获取单个的方法,并调用:12 * public Constructor getConstructor(Class parameterTypes):获取单个公有的构造方法13 * public Constructor getDeclaredConstructor(Class parameterTypes);获取某个构造方法可以是私有的,或者是受保护的14 * 、默认的。公有的:15 * 调用构造方法16 * Construtor -->newInstance(Object、、、initargs)17 *18 *19 */

20 public classTest_1 {21

22 public static void main(String[] args)throwsException{23 //1、加载class对象

24 Class clazz = Class.forName("fanshe.Student");25

26 //2、获取所有公有构造方法

27 System.out.println("*****************************所有公有构造方法*************");28 Constructor[] conArray =clazz.getConstructors();29 for(Constructor c : conArray) {30 System.out.println(c);31 }32

33 System.out.println("********所有的构造方法(包括私有、受保护、默认、公有)********");34 conArray =clazz.getDeclaredConstructors();35 for(Constructor c : conArray) {36 System.out.println(c);37 }38

39 System.out.println("********获取公有的 、无参的构造方法");40 Constructor con = clazz.getConstructor(null);41 //1>、因为是无参的构造方法所以类型是一个null,不写也可以:这里需要的是一个参数的类型,切记是类型42 //2>、返回的是描述这个无参构造函数的类对象。

43

44 System.out.println("con = "+con);45

46 //调用构造方法

47 Object obj =con.newInstance();48

49

50 System.out.println("******************获取私有构造方法,并调用*******************************");51 con = clazz.getDeclaredConstructor(char.class);52 System.out.println(con);53

54 //调用构造函数

55 con.setAccessible(true);//暴力访问(忽略掉访问修饰符)

56 obj = con.newInstance('男');57 }58 }

结果:

*****************************所有公有构造方法*************

public fanshe.Student(java.lang.String,int)public fanshe.Student(char)publicfanshe.Student()********所有的构造方法(包括私有、受保护、默认、公有)********

private fanshe.Student(int)protected fanshe.Student(boolean)public fanshe.Student(java.lang.String,int)public fanshe.Student(char)publicfanshe.Student()

fanshe.Student(java.lang.String)********获取公有的 、无参的构造方法

con= publicfanshe.Student()

调用了共有的、无参构造方法执行******************获取私有构造方法,并调用*******************************

public fanshe.Student(char)

姓名: 男

(3)获取成员变量并调用

Stduent类:

packagefanshe;public classStudent_1 {publicStudent_1() {

}//******字段******// publicString name;protected intage;charsex;privateString phoneNum;publicString toString() {return "Student [name="+name+",age="+age+",sex="+sex+", phoneNum="+phoneNum+"]";

}

}

测试类:

1 /**

2 *3 * 获取成员变量并调用:4 *5 * 1.批量的6 * 1).Field[] getFields():获取所有的"公有字段"7 * 2).Field[] getDeclaredFields():获取所有字段,包括:私有、受保护、默认、公有;8 * 2.获取单个的:9 * 1).public Field getField(String fieldName):获取某个"公有的"字段;10 * 2).public Field getDeclaredField(String fieldName):获取某个字段(可以是私有的)11 *12 * 设置字段的值:13 * Field --> public void set(Object obj,Object value):14 * 参数说明:15 * 1.obj:要设置的字段所在的对象;16 * 2.value:要为字段设置的值;17 */

18 public classTest_2 {19

20 public static void main(String[] args) throwsException {21 //1.获取Class对象

22 Class stuClass = Class.forName("fanshe.Student_1");23 //2.获取字段

24 System.out.println("************获取所有公有的字段********************");25 Field[] fieldArray =stuClass.getFields();26 for(Field f : fieldArray){27 System.out.println(f);28 }29 System.out.println("************获取所有的字段(包括私有、受保护、默认的)********************");30 fieldArray =stuClass.getDeclaredFields();31 for(Field f : fieldArray){32 System.out.println(f);33 }34 System.out.println("*************获取公有字段**并调用***********************************");35 Field f = stuClass.getField("name");36 System.out.println(f);37 //获取一个对象

38 Object obj = stuClass.getConstructor().newInstance();//产生Student对象--》Student stu = new Student();39 //为字段设置值

40 f.set(obj, "刘德华");//为Student对象中的name属性赋值--》stu.name = "刘德华"41 //验证

42 Student_1 stu =(Student_1)obj;43 System.out.println("验证姓名:" +stu.name);44

45

46 System.out.println("**************获取私有字段****并调用********************************");47 f = stuClass.getDeclaredField("phoneNum");48 System.out.println(f);49 f.setAccessible(true);//暴力反射,解除私有限定

50 f.set(obj, "18888889999");51 System.out.println("验证电话:" +stu);52 }53 }

结果:

************获取所有公有的字段********************

publicjava.lang.String fanshe.Student_1.name************获取所有的字段(包括私有、受保护、默认的)********************

publicjava.lang.String fanshe.Student_1.nameprotected intfanshe.Student_1.agecharfanshe.Student_1.sexprivatejava.lang.String fanshe.Student_1.phoneNum*************获取公有字段**并调用***********************************

publicjava.lang.String fanshe.Student_1.name

验证姓名:刘德华**************获取私有字段****并调用********************************

privatejava.lang.String fanshe.Student_1.phoneNum

验证电话:Student [name=刘德华,age=0,sex=

(4)获取成员方法并调用

Stduent类

1 packagefanshe;2

3 public classStudent_3 {4

5 //**************成员方法***************//

6 public voidshow1(String s){7 System.out.println("调用了:公有的,String参数的show1(): s = " +s);8 }9 protected voidshow2(){10 System.out.println("调用了:受保护的,无参的show2()");11 }12 voidshow3(){13 System.out.println("调用了:默认的,无参的show3()");14 }15 private String show4(intage){16 System.out.println("调用了,私有的,并且有返回值的,int参数的show4(): age = " +age);17 return "abcd";18 }19 }

测试类:

1 packagefanshe;2 importjava.lang.reflect.Method;3

4 /**

5 * 获取成员方法并调用:6 *7 * 1.批量的:8 * public Method[] getMethods():获取所有"公有方法";(包含了父类的方法也包含Object类)9 * public Method[] getDeclaredMethods():获取所有的成员方法,包括私有的(不包括继承的)10 * 2.获取单个的:11 * public Method getMethod(String name,Class>... parameterTypes):12 * 参数:13 * name : 方法名;14 * Class ... : 形参的Class类型对象15 * public Method getDeclaredMethod(String name,Class>... parameterTypes)16 *17 * 调用方法:18 * Method --> public Object invoke(Object obj,Object... args):19 * 参数说明:20 * obj : 要调用方法的对象;21 * args:调用方式时所传递的实参;22 *23 */

24

25 public classTest_3 {26

27 public static void main(String[]args) throwsException{28 //1.获取Class对象

29 Class stuClass = Class.forName("fanshe.Student_3");30 //2.获取所有公有方法

31 System.out.println("***************获取所有的”公有“方法*******************");32 stuClass.getMethods();33 Method[] methodArray =stuClass.getMethods();34 for(Method m : methodArray){35 System.out.println(m);36 }37 System.out.println("***************获取所有的方法,包括私有的*******************");38 methodArray =stuClass.getDeclaredMethods();39 for(Method m : methodArray){40 System.out.println(m);41 }42 System.out.println("***************获取公有的show1()方法*******************");43 Method m = stuClass.getMethod("show1", String.class);44 System.out.println(m);45 //实例化一个Student对象

46 Object obj =stuClass.getConstructor().newInstance();47 m.invoke(obj, "刘德华");48

49 System.out.println("***************获取私有的show4()方法******************");50 m = stuClass.getDeclaredMethod("show4", int.class);51 System.out.println(m);52 m.setAccessible(true);//解除私有限定

53 Object result = m.invoke(obj, 20);//需要两个参数,一个是要调用的对象(获取有反射),一个是实参

54 System.out.println("返回值:" +result);55 }56 }

结果:

***************获取所有的”公有“方法*******************

public voidfanshe.Student_3.show1(java.lang.String)public final void java.lang.Object.wait() throwsjava.lang.InterruptedExceptionpublic final void java.lang.Object.wait(long,int) throwsjava.lang.InterruptedExceptionpublic final native void java.lang.Object.wait(long) throwsjava.lang.InterruptedExceptionpublic booleanjava.lang.Object.equals(java.lang.Object)publicjava.lang.String java.lang.Object.toString()public native intjava.lang.Object.hashCode()public final nativejava.lang.Class java.lang.Object.getClass()public final native voidjava.lang.Object.notify()public final native voidjava.lang.Object.notifyAll()***************获取所有的方法,包括私有的*******************

protected voidfanshe.Student_3.show2()private java.lang.String fanshe.Student_3.show4(int)voidfanshe.Student_3.show3()public voidfanshe.Student_3.show1(java.lang.String)***************获取公有的show1()方法*******************

public voidfanshe.Student_3.show1(java.lang.String)

调用了:公有的,String参数的show1(): s=刘德华***************获取私有的show4()方法******************

private java.lang.String fanshe.Student_3.show4(int)

调用了,私有的,并且有返回值的,int参数的show4(): age= 20返回值:abcd

(5)反射main方法

student类:

packagefanshe;public classStudent_4 {public static voidmain(String[]args) {

System.out.println("main 方法执行了。。。");

}

}

测试类:

1 packagefanshe;2 importjava.lang.reflect.Method;3 /**

4 * 获取Student类的main方法、不要与当前的main方法搞混了5 */

6 public classTest_4 {7

8 public static voidmain(String[]args) {9 try{10 //1、获取Student对象的字节码

11 Class clazz = Class.forName("fanshe.Student_4");12

13 //2、获取main方法

14 Method methodMain = clazz.getMethod("main", String[].class);//第一个参数:方法名称,第二个参数:方法形参的类型,15 //3、调用main方法16 //methodMain.invoke(null, new String[]{"a","b","c"});17 //第一个参数,对象类型,因为方法是static静态的,所以为null可以,第二个参数是String数组,这里要注意在jdk1.4时是数组,jdk1.5之后是可变参数18 //这里拆的时候将 new String[]{"a","b","c"} 拆成3个对象。。。所以需要将它强转。

19 methodMain.invoke(null, (Object)new String[]{"a","b","c"});//方式一20 //methodMain.invoke(null, new Object[]{new String[]{"a","b","c"}});//方式二

21

22 } catch(Exception e) {23 e.printStackTrace();24 }25 }26 }

结果:

main 方法执行了。。。

(6)通过反射运行配置文件

student类:

1 public classStudent {2 public voidshow(){3 System.out.println("is show()");4 }5 }

配置文件,以txt为例(pro.txt)

1 className =cn.fanshe.Student2 methodName = show

测试类:

importjava.io.FileNotFoundException;importjava.io.FileReader;importjava.io.IOException;importjava.lang.reflect.Method;importjava.util.Properties;/** 我们利用反射和配置文件,可以使:应用程序更新时,对源码无需进行任何修改

* 我们只需要将新类发送给客户端,并修改配置文件即可*/

public classDemo {public static void main(String[] args) throwsException {//通过反射获取Class对象

Class stuClass = Class.forName(getValue("className"));//"cn.fanshe.Student"//2获取show()方法

Method m = stuClass.getMethod(getValue("methodName"));//show//3.调用show()方法

m.invoke(stuClass.getConstructor().newInstance());

}//此方法接收一个key,在配置文件中获取相应的value

public static String getValue(String key) throwsIOException{

Properties pro= new Properties();//获取配置文件的对象

FileReader in = new FileReader("pro.txt");//获取输入流

pro.load(in);//将流加载到配置文件对象中

in.close();return pro.getProperty(key);//返回根据key获取的value值

}

}

结果:

is show()

需求:更新系统时,只要再写一个Student2类,更改一下配置文件,而不需要动原来的类。

Student2类:

1 public classStudent2 {2 public voidshow2(){3 System.out.println("is show2()");4 }5 }

配置文件:

className =cn.fanshe.Student2

methodName= show2

(7)通过反射越过泛型检查

测试类:

1 importjava.lang.reflect.Method;2 importjava.util.ArrayList;3

4 /*

5 * 通过反射越过泛型检查6 *7 * 例如:有一个String泛型的集合,怎样能向这个集合中添加一个Integer类型的值?8 */

9 public classDemo {10 public static void main(String[] args) throwsException{11 ArrayList strList = new ArrayList<>();12 strList.add("aaa");13 strList.add("bbb");14

15 //strList.add(100);16 //获取ArrayList的Class对象,反向的调用add()方法,添加数据

17 Class listClass = strList.getClass(); //得到 strList 对象的字节码 对象18 //获取add()方法

19 Method m = listClass.getMethod("add", Object.class);20 //调用add()方法

21 m.invoke(strList, 100);22

23 //遍历集合

24 for(Object obj : strList){25 System.out.println(obj);26 }27 }28 }

输出:

aaa

bbb100

其清晰的表述,具体的案例,让我进一步了解了反射机制的一些应用,等以后学习框架或者工作的时候,再根据具体情况深入地学习反射的原理。通过反射机制的初步学习,对面向对象这个概念也有了更进一步的体会,原来一个类中的方法,属性,构造方法,也可以抽象并封装为一个类(Field,Method,Constructor),果然面向对象,一切皆对象。

如有错误,欢迎批评指正。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值