• java web开发(反射)


    【 声明:版权所有,欢迎转载,请勿用于商业用途。 联系信箱:feixiaoxing @163.com】

            反射是java很重要的一个特点。也是它区别于c、c++、fortan等传统语言的一个重要的语言特征。通过反射可以做很多的事情,比如动态创建类,动态修改变量,动态调用类函数等等。spring等一些框架,也大量使用了java的反射特性。

            反射特性的基础是数据类型。java编译器默认为所有的class创建了一个数据类型,那就是Class。如果不好理解,可以看成是c++里面的typeinfo。下面,可以通过几个test case验证下。

    1、添加必要的引用文件

    1. import java.lang.*;
    2. import java.lang.reflect.*;

    2、准备测试类

    1. class Person {
    2. public String name;
    3. public String getName(){
    4. return "Person";
    5. }
    6. }
    7. class Student extends Person{
    8. public int score;
    9. private int grade;
    10. public Student(){
    11. return;
    12. }
    13. public Student(int s, int g){
    14. score = s;
    15. grade = g;
    16. }
    17. public int getScore() {
    18. return 10;
    19. }
    20. private int getGrade(){
    21. return 100;
    22. }
    23. }

    3、测试1,验证Class的存在

    1. public static void test1() {
    2. System.out.println(String.class);
    3. }

            这个例子比较简单,主要是验证一下是不是真的有Class存在。如代码所示,首先获取了String数据类型的Class,接着就是将这个Class打印出来。运行,不出意外,你就会看到这样的内容,

    class java.lang.String

    4、测试2,判断一个实例的数据类型是否正确

    1. public static void test2() {
    2. Class s1 = String.class;
    3. String s = "abc";
    4. Class s2 = s.getClass();
    5. if(s1 == s2){
    6. System.out.println("yes");
    7. }else{
    8. System.out.println("no");
    9. }
    10. }

            前面已经了解到数据类型确实是存在的。那么,接下来就可以判断,假设存在一个实例,可以检验下它是否真的属于某种数据类型。如上面所示,首先获取了String的数据类型s1,接着有一个实例s,同样可以获取它的数据类型s2,后面就可以判断s1和s2是否相等。相等,则输出yes;否则,输出no。不出意外的话,输出的结果肯定是yes。

    5、测试3,通过名称获取数据类型

    1. public static void test3() {
    2. try {
    3. Class cls = Class.forName("java.lang.String");
    4. String s = "abc";
    5. if (cls == s.getClass()) {
    6. System.out.println("yes");
    7. } else {
    8. System.out.println("no");
    9. }
    10. } catch (ClassNotFoundException e){
    11. return;
    12. }
    13. }

            测试3和测试2的代码非常相像。唯一的区别,这里获取初始数据类型的方法不再是String.class,而是通过Class.forName来获取。其实结果都是一样的。

    6、测试4,通过obj获取数据类型

    1. public static void test4(){
    2. Object obj = new String("abc");
    3. Class cls = obj.getClass();
    4. System.out.println(cls);
    5. }

            Object是所有类的父类。假设创建一个String对象,将它赋值给obj。再从obj获取Class,赋值给cls,那么这个时候如果打印cls的话,本质上和String.class的打印结果是一样的。

    7、测试5,通过class创建实例

    1. public static void test5(){
    2. Class cls = String.class;
    3. try {
    4. String s = (String) cls.newInstance();
    5. }catch(InstantiationException ins){
    6. return;
    7. }catch(IllegalAccessException ill){
    8. return;
    9. }
    10. }

            java语言的发明人设计发射这一特性,绝不仅仅用来实现打印这么简单。通过这个Class,是可以直接调用newInstance创建实例的。当然,创建的过程中需要处理一下InstantiationException和IlegalAccessException这两个异常。当然,这里创建实例的时候,没有带参数。后面会接着讨论,如果需要构造函数带参数,应该怎么来处理。

    8、测试6,访问类变量

    1. public static void test6() {
    2. Class cls = Student.class;
    3. try {
    4. System.out.println(cls.getField("score"));
    5. System.out.println(cls.getField("name"));
    6. System.out.println(cls.getDeclaredField("grade"));
    7. Field f = cls.getField("score");
    8. System.out.println(f.getName());
    9. System.out.println(f.getType());
    10. Student s = new Student();
    11. s.score = 10;
    12. try {
    13. Object o = f.get(s);
    14. System.out.println(o);
    15. f.set(s, 100);
    16. o = f.get(s);
    17. System.out.println(o);
    18. }catch(IllegalAccessException ill){
    19. return;
    20. }
    21. }catch(NoSuchFieldException no){
    22. return;
    23. }
    24. }

            有了数据类型Class,就可以获取类里面的变量信息,使用getField子函数就可以实现这一目的。不仅如此,拿到了field信息,就可以通过getName获取名称信息,通过getType获得数据信息。更进一步的话,可以通过get获取数据,通过set设置数据,这都是做得到的。

    9、测试7,访问类函数

    1. public static void test7(){
    2. Class cls = Student.class;
    3. try {
    4. System.out.println(cls.getMethod("getScore"));
    5. System.out.println(cls.getMethod("getName"));
    6. }catch (NoSuchMethodException no){
    7. return;
    8. }
    9. try {
    10. System.out.println(cls.getDeclaredMethod("getGrade"));
    11. }catch (NoSuchMethodException no){
    12. return;
    13. }
    14. Student s = new Student();
    15. try {
    16. Method m = Student.class.getMethod("getScore");
    17. try {
    18. System.out.println(m.invoke(s));
    19. }catch(IllegalAccessException ill){
    20. return;
    21. }catch(InvocationTargetException invo){
    22. return;
    23. }
    24. }catch(NoSuchMethodException no){
    25. return;
    26. }
    27. }

            既然类变量可以通过Class访问,那么类函数也不例外。类函数的获取方法是getMethod,返回值是Method。有了这个Method,接下来就可以调用invoke函数,直接获得数据结果了。是不是很神奇?当然,执行的过程中还要处理IllegalAccessException和InvocationTargetException两个异常/

    10、测试8,类构造

    1. public static void test8(){
    2. try {
    3. Constructor cons = Student.class.getConstructor(int.class, int.class);
    4. try {
    5. Student s = (Student) cons.newInstance(1, 2);
    6. System.out.println(s.score);
    7. }catch(InstantiationException ins){
    8. return;
    9. }catch(IllegalAccessException ill){
    10. return;
    11. }catch(InvocationTargetException invo){
    12. return;
    13. }
    14. }catch(NoSuchMethodException no){
    15. return;
    16. }
    17. }

            类构造是Class特征中的重中之重。有了这一点,类的构造不需要用户自己来显式完成了。如果设计好合适的框架,完全可以通过Class来完成,不需要用户的参与。类构造的完成,主要是通过Class的getConstructor来实现的。获取到Constructor之后,就可以调用它的newInstance来完成了。这和测试5有点类似,不过它当时没有带参数。

    11、测试9,查找继承关系

    1. public static void test9(){
    2. Class chd = Student.class;
    3. Class parent = chd.getSuperclass();
    4. Class grnd = parent.getSuperclass();
    5. System.out.println(chd);
    6. System.out.println(parent);
    7. System.out.println(grnd);
    8. }

            Class还有一个用的比较多的特征,就是查找继承关系。这在一些场景下也是非常有用的。比如说,如果我们想调用某个类的虚函数,那么就要先判断下,这个类是不是真的来自于某个父类,这样才好进行后面的操作。

            文章读到这里,基本上应该有点头昏眼花了。有兴趣的同学可以把这部分内容反复看看,还是很有意思的。反射和注解算是java比较有特色的两个特征,值得好好学学。当然后续的语言,比如c#,其实也包含了这两点,当然这都是后话了。

  • 相关阅读:
    2022暑期复习-Day6
    2. 两数相加
    使用conda install一直卡在solving environment的解决方法
    uniapp快速入门系列(2)- Vue基础知识
    【Linux】进度条和git命令行
    CSS3 动画
    如果集群状态是HEALTH_ERR 并且有pgs inconsistent,需要进行如下操作
    【一起玩蛇】Python 结构化数据分析工具 Pandas | Series 与 DataFrame | 读取CSV文件数据 |
    ElasticSearch学习篇10_Lucene数据存储之BKD动态磁盘树
    优惠劵秒杀优化-分布式锁
  • 原文地址:https://blog.csdn.net/feixiaoxing/article/details/127116740