网站菜单

JDK1.8(六) 反射

(一)什么是反射

除了基本类型外,所有的数据类型全部都是class
因此,每加载一个Class,就会创建一个实例对象,而一个Class实例中就记录了这个对象的所有信息。包括接口,所有方法,字段,父类等等等等。
这就意味着我们可以通过Class实例获取到这个class中的所有信息。
这种通过实例获取class信息的方法叫做反射。

(二)反射的使用

  • 1.我们可以通过一个Class对象来直接获取实例
    Class cls = String.class;
  • 2.如果知道一个class的完整类名,可以通过静态方法Class.forName()获取:
    Class cls = Class.forName("java.lang.String");
  • 3.如果我们有一个实例变量,可以通过该实例变量提供的getClass()方法获取:
    String s = "Hello"; Class cls = s.getClass();

用处:可以用来判断某个类是否是特定的对象类型

通常情况下,我们应该用instanceof判断数据类型,因为面向抽象编程的时候,我们不关心具体的子类型。只有在需要精确判断一个类型是不是某个class的时候,我们才使用==判断class实例。

    static void printClassInfo(Class cls) {
        System.out.println("Class name: " + cls.getName());
        System.out.println("Simple name: " + cls.getSimpleName());
        if (cls.getPackage() != null) {
            System.out.println("Package name: " + cls.getPackage().getName());
        }
        System.out.println("is interface: " + cls.isInterface());
        System.out.println("is enum: " + cls.isEnum());
        System.out.println("is array: " + cls.isArray());
        System.out.println("is primitive: " + cls.isPrimitive());//是否是基本类型
    }

以上代码通过反射来获取到类的信息。

注意:JVM有动态加载机制,一个类只有在首次运行的时候才会加载这个类

小结:

  • 获取一个class对应的Class实例后,就可以获取该class的所有信息;
  • 通过Class实例获取class信息的方法称为反射(Reflection);
Java的反射机制它知道类的基本结构,这种对Java类结构探知的能力,我们称为Java类的“自审”。大家都用过Jcreator和eclipse。当我们构建出一个对象的时候,去调用该对象的方法和属性的时候。一按点,编译工具就会自动的把该对象能够使用的所有的方法和属性全部都列出来,供用户进行选择。这就是利用了Java反射的原理,是对我们创建对象的探知、自审。

(三)简单实例

package com.utils;

import java.lang.reflect.Field;

public class CommonLogging {
    public static void main(String[] args) {
        Field field;
        Kingdee kingdee = new Kingdee();
        Class k = kingdee.getClass();
        try {
            field = k.getDeclaredField("object");
            try {
                System.out.println(field.get(kingdee));
            } catch (IllegalAccessException e) {
                e.printStackTrace();
            }
        } catch (NoSuchFieldException e) {
            e.printStackTrace();
        }
    }

}

class Kingdee{
    int x = 6;
    String str = "kingdee";
    Object object = 6;
    public void set(int y){
        this.x = y;
    }
}

上述代码先获取Class实例,再获取Field实例,然后,用Field.get(Object)获取指定实例的指定字段的值。

正常情况下,Main类无法访问Person类的private字段。要修复错误,可以将private改为public,或者,在调用Object value = f.get(p);前,先写一句:
field.setAccessible(true);
该代码的意思是,无论这个字段被什么限定词修饰,一律允许访问。

正常情况下,我们总是通过p.name来访问Person的name字段,编译器会根据public、protected和private决定是否允许访问字段,这样就达到了数据封装的目的。

而反射是一种非常规的用法,使用反射,首先代码非常繁琐,其次,它更多地是给工具或者底层框架来使用,目的是在不知道目标实例任何信息的情况下,获取特定字段的值。

同样,使用反射也可以用来修改部分字段的值。

package com.utils;

import java.lang.reflect.Field;

public class CommonLogging {
    public static void main(String[] args) {
        Field field;
        Kingdee kingdee = new Kingdee();
        Class k = kingdee.getClass();
        try {
            field = k.getDeclaredField("object");
            Field demo = k.getDeclaredField("demo");
            demo.setAccessible(true);
            try {
                System.out.println(field.get(kingdee));
                System.out.println(demo.get(kingdee));
                demo.set(kingdee,"after");
                System.out.println(demo.get(kingdee));
            } catch (IllegalAccessException e) {
                e.printStackTrace();
            }
        } catch (NoSuchFieldException e) {
            e.printStackTrace();
        }
    }

}

class Kingdee{
    int x = 6;
    String str = "kingdee";
    Object object = 6;
    private String demo = "before";
    public void set(int y){
        this.x = y;
    }
}

但是注意,反射会破坏java的封装性,使用反射来读写字段是一种非常规方法。

相关推荐

JDK1.8(五) 断言与日志

(一)断言 断言的作用: 断言(Assertion)是一种调试程序的方式。在Java中,使用assert关键字来实现断言。 断言可以用于开发和调试阶段: assert x >= 0 : &quo…

JAVA中常用的包的作用

包名 说明 java.lang 该包提供了Java编程的基础类,例如 Object、Math、String、StringBuffer、System、Thread等,不使用该包就很难编写Java代码了。…