Deep understanding of java reflection mechanism

Today, I will systematically learn the reflection mechanism of java from the following four aspects:

  • What is reflection in java

  • Java reflection (Reflection) underlying implementation principle

  • Simple demo of java reflection

  • Application scenarios of java reflection

 

1. What is java reflection

 

First of all, you should understand two concepts, compile time and run time . The compile time is when the compiler helps you translate the source code into code that the machine can recognize. For example, the compiler compiles the java code into a bytecode file recognized by the jvm, and Runtime refers to handing the executable file to the operating system for execution. The JAVA reflection mechanism is that in the running state , for any class, all attributes and methods of the class can be known; for any object, it can be called. Arbitrary methods and properties of ; this function of dynamically obtaining information and calling object methods dynamically is called the reflection mechanism of java language

 

2. The underlying implementation principle of java reflection (Reflection)

 

As we all know, Java has an Object class , which is the inheritance root of all Java classes. It declares several methods that should be rewritten in all Java classes: hashCode(), equals(), clone(), toString(), getClass( )Wait. where getClass() returns a Class object

 

And this Class class is very special. It inherits from Object like a general class. When a class is loaded, or when the defineClass() of the loader (class loader) is called by the JVM, the JVM automatically generates a Class object.

The Class object is the origin of the java reflection story. The Class class provides a large number of instance methods to obtain the detailed information corresponding to the Class object. We just make a brief introduction. For details, please refer to the JDK documentation. An online Chinese document is provided here for you as follows:

 

http://tool.oschina.net/apidocs/apidoc?api=jdk-zh

这边列了下Class类其中的很少yibufen方法,

获取公共构造器 getConstructors()
获取所有构造器 getDeclaredConstructors
获取包含的方法 getMethod()
获取包含的属性 getField(String name)
获取内部类 getDeclaredClasses()
获取外部类 getDeclaringClass()
获取所实现的接口 getInterfaces()
获取修饰符 getModifiers()
获取所在包 getPackage()
获取类名包含包路径  getName()
类名不包含包路径  getSimpleName()

 

3,java反射的简单演示

 

上面介绍了下java反射的实现机制,接下来我主要来演示一下反射的使用

首先定义一个user对象类如下:

 

 

/**
* 定义一个用户对象
*
* @author zhangqh
* @date 2018年4月24日
*/

public class User implements Serializable {
   /**
    *
    */

   private static final long serialVersionUID = 1L;
   /**
    * 用户id
    */

   private Integer userId;
   /**
    * 用户名称
    */

   private String userName;

   /**
    * 公共元素
    */

   public String age;

   private User(Integer userId){}

   public User(){}
   public User(Integer userId, String userName) {
       super();
       this.userId = userId;
       this.userName = userName;
   }
   /**
    * @return the userId
    */

   public Integer getUserId() {
       return userId;
   }
   /**
    * @param userId the userId to set
    */

   public void setUserId(Integer userId) {
       this.userId = userId;
   }
   /**
    * @return the userName
    */

   public String getUserName() {
       return userName;
   }
   /**
    * @param userName the userName to set
    */

   public void setUserName(String userName) {
       this.userName = userName;
   }

}

 

测试反射类:

 

/**
* 测试反射类
*
* @author zhangqh
* @date 2018年4月25日
*/

public class Test {
   public static void main(String[] args) throws ClassNotFoundException {
       // 第一种方法 直接通过类名获取class (一般不会这么用,因为实例都获取到了没必要多此一举)
       User user = new User();
       Class class1 = user.getClass();
       System.out.println("我是方法1反射处理的类 = "+class1);
       System.out.println("我是方法1反射处理的类的父类 = "+class1.getSuperclass());
       System.out.println("----------------------------------------------------");
       // 第二种办法通过类名的方法获取class 需要增加对应的类引用
       Class class2 = User.class;
       System.out.println("我是方法2反射处理的类 = "+class2);
       System.out.println("我是方法2反射处理的类的父类 = "+class2.getSuperclass());
       System.out.println("----------------------------------------------------");
       // 第三种办法通过全类名获取,用的比较多,也推荐使用这种方式
       Class class3 = Class.forName ("com.zhang.reflection.User");
       System.out.println("我是方法3反射处理的类 = "+class3);
       System.out.println("我是方法3反射处理的类的父类 = "+class3.getSuperclass());
       System.out.println("----------------------------------------------------");
       // 反射获取User对象的公共构造器
       Constructor<User>[] constructors = class3.getConstructors();
       for(int i=0;i<constructors.length;i++){
           System.out.println("我是公共构造器"+(i+1)+" = "+constructors[i]);
       }
       System.out.println("----------------------------------------------------");
       //反射获取User对象的所有构造器
       Constructor<User>[] dconstructors = class3.getDeclaredConstructors();
       for(int i=0;i<dconstructors.length;i++){
           System.out.println("我是所有构造器"+(i+1)+" = "+dconstructors[i]);
       }
       System.out.println("----------------------------------------------------");
       // 反射获取User对象的 Method 对象的数组,这些对象反映此 Class 对象所表示的类或接口(包括那些由该类或接口声明的以及从超类和超接口继承的那些的类或接口)的公共 member 方法
       Method[]  methods = class3.getMethods();
       for(int i=0;i<methods.length;i++){
           System.out.println("我是公共方法"+(i+1)+" = "+methods[i]);
       }
       System.out.println("----------------------------------------------------");
       // 反射获取User对象的 Method 对象的一个数组,这些对象反映此 Class 对象表示的类或接口声明的所有方法,包括公共、保护、默认(包)访问和私有方法,但不包括继承的方法
       Method[]  dmethods = class3.getDeclaredMethods();
       for(int i=0;i<dmethods.length;i++){
           System.out.println("我是所有的方法"+(i+1)+" = "+dmethods[i]);
       }
       System.out.println("----------------------------------------------------");
       // 获取包含某些 Field 对象的数组,这些对象反映此 Class 对象所表示的类或接口的所有可访问公共字段
       Field[] fields = class3.getFields();
       for(int i=0;i<fields.length;i++){
           System.out.println("我是公共的field"+(i+1)+" = "+fields[i]);
       }
       System.out.println("----------------------------------------------------");
       Field[] dfields = class3.getDeclaredFields();
       for(int i=0;i<dfields.length;i++){
           System.out.println("我是所有的field"+(i+1)+" = "+dfields[i]);
       }
       System.out.println("----------------------------------------------------");
       String sname = class3.getSimpleName();
       System.out.println("我是类名不包含包路径 = "+sname);
       System.out.println("----------------------------------------------------");
       String name = class3.getName();
       System.out.println("我是类名包含包路径 = "+name);
       System.out.println("----------------------------------------------------");
       Package packA=class3.getPackage();
       System.out.println("我是类的包路径 = "+packA.getName());
       System.out.println("----------------------------------------------------");
       Class<?>[] interfaces=class3.getInterfaces();
       for(int i=0;i<interfaces.length;i++){
           System.out.println("我是实现的接口"+(i+1)+" = "+interfaces[i]);
       }
       System.out.println("----------------------------------------------------");
       // 返回此类或接口以整数编码的 Java 语言修饰符。修饰符由 Java 虚拟机的 public、 protected、 private、 final、 static、 abstract 和 interface 对应的常量组成;
       // 它们应当使用 Modifier 类的方法来解码
       Integer modefiers = class3.getModifiers();
       System.out.println("我是类的modefiers = "+modefiers);
   }
}

 

以上代码中有详细的代码注释,这边就不过多的解释了

 

4,java反射的应用场景

 

a,注解的使用

 

不知道大家是否有看过之前写的深入理解java注解的实现原理它的底层实现就是java反射,主要有如下方法:

 

getAnnotations()
getAnnotation(Class annotationClass) 
getDeclaredAnnotations() 
isAnnotation() 
isAnnotationPresent(Class annotationClass)

 

b,编写基础框架

 

有一句话这么说来着:反射机制是很多Java框架的基石,经典的就是在xml文件或者properties里面写好了配置,然后在Java类里面解析xml或properties里面的内容,得到一个字符串,然后用反射机制,根据这个字符串获得某个类的Class实例,这样就可以动态配置一些东西,spring,Hibernate底层都有类似的实现

 

c,其他在编码阶段不知道那个类名,要在运行期从配置文件读取类名配置

 

如下:这段代码想必大家肯定都有写过,这个数据库的连接驱动类就是编译的时候不知道你到底是用的mysql,oracle还是其他数据库,而是由运行期动态加载的

 

 

// 1.加载驱动程序
       Class.forName("com.mysql.jdbc.Driver");
       // 2.获得数据库的连接
       Connection conn = DriverManager.getConnection(URL, NAME, PASSWORD);
       // 3.通过数据库的连接操作数据库,实现增删改查
       Statement stmt = conn.createStatement();
       ResultSet rs = stmt
               .executeQuery("select user_name,age from user");
       while (rs.next()) {// 如果对象中有数据,就会循环打印出来
           System.out.println(rs.getString("user_name") + ","
                   + rs.getInt("age"));
       }

 

注:以上介绍了反射的应用场景,程序猿开发业务代码中应尽量少用反射,一个是代码可读性不是特别好,第二是反射需要运行期jvm去重新解析性能上也没有直接使用好,唯一比较合理的地方是业务中需要用到AOP可以大大简化业务代码建议使用

 

以上是今天文章的所有内容,欢迎大家吐槽

 

如果觉得文章对你有帮助,欢迎转发或关注如下公众号阅读更多优质文章

Guess you like

Origin http://43.154.161.224:23101/article/api/json?id=326109138&siteId=291194637
Recommended