今天将从以下4方面来系统的学习一下java的反射机制:

  • java反射是什么

  • java反射(Reflection)底层实现原理

  • java反射的简单演示

  • java反射的应用场景

1,java反射是什么

首先大家应该先了解两个概念,编译期运行期,编译期就是编译器帮你把源代码翻译成机器能识别的代码,比如编译器把java代码编译成jvm识别的字节码文件,而运行期指的是将可执行文件交给操作系统去执行,JAVA反射机制是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法;对于任意一个对象,都能够调用它的任意方法和属性;这种动态获取信息以及动态调用对象方法的功能称为java语言的反射机制

2,java反射(Reflection)的底层实现原理

众所周知Java有个Object 类,是所有Java 类的继承根源,其内声明了数个应该在所有Java 类中被改写的方法:hashCode()、equals()、clone()、toString()、getClass()等。其中getClass()返回一个Class 对象

而这个Class 类十分特殊。它和一般类一样继承自Object,当一个class被加载,或当加载器(class loader)的defineClass()被JVM调用,JVM 便自动产生一个Class 对象。

而Class对象是java反射故事起源。Class类提供了大量的实例方法来获取该Class对象所对应的详细信息,我们只是做简单的介绍,详细请参考JDK文档,这边提供一个在线的中文文档给大家如下:

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
[] constructors = class3.getConstructors();        for(int i=0;i
[] dconstructors = class3.getDeclaredConstructors();        for(int i=0;i
[] interfaces=class3.getInterfaces();        for(int i=0;i

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

4,java反射的应用场景

a,注解的使用

不知道大家是否有看过之前写的它的底层实现就是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可以大大简化业务代码建议使用

以上是今天文章的所有内容,欢迎大家吐槽smiley_29.png?wx_lazy=1

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

640?wx_fmt=png&tp=webp&wxfrom=5&wx_lazy=1