`
weitao1026
  • 浏览: 1048233 次
  • 性别: Icon_minigender_1
  • 来自: 上海
社区版块
存档分类
最新评论

java的反射

阅读更多
JAVA 反射的应用还是比较多,这里会对反射的一些原理进行介绍,然后我们才知道如何使用和优化。至于反射的使用介绍,这里就不在过多叙述了,API 上都介绍得有。

   要了解JAVA 反射的原理,我们还得对类在虚拟机中的一些知识做简要介绍...

一、类文件的结构:

   1.1 虚拟机加载Class文件过程:

       在JVM 类加载机制的博客里面我介绍过整体流程,这里仅仅介绍加载时相关部分。

       在我们启动一个类,或者其他方式加载一个类的时候,会通过类的全限定名获取该类的二进制流,然后将字节流所代表的的静态存储结构转化成方法区的运行时数据结构,然后会生成一个代表该类的java.lang.Class 对象,作为在方法区这个类的访问入口。也就是说只要完成了这一步骤,那么通过这个入
口我们就可以访问里面的存储好的数据结构信息了。而且动态加载的时候,会先进行查找,该类是否存在,

存在了就不会再加载了,保持一份。

    class 文件是一组以8位字节为基础单位的二进制流,各个数据项目按严格的顺序紧凑的排列在Class文

件中,里面的信息主要描述以下信息:

    1.版本号:主版本号和次版本号

    2.常量池:主要存放字面量(Literal)和符号引用(references)

      2.1 字面量:文本字符串、final 类型的常量值 等

      2.2 符号引用:

          a.类和接口的全限定名字

          b.字段描述和描述符

          c.方法的名称和描述

    3.访问标志:

      a.是类还是接口

      b.是否是public 等类型

      c.是否是abstract ,是否被声明为final 等标志

    4.类索引、父类索引和接口索引集合

      a.类索引:确定这个类的全限定名

      b.父类索引:确定父类的全限定名

      c.接口索引集合:作为入口,作为一个计数器


    5.字段表集合:

      包括信息有字段作用域(public,private等修饰符)、是实例变量还是类变量(static)、可变性 (final)、并发可见性(volatile)、可否被序列化(transient)等信息

   
    6.方法集合:

      包括访问标志、名称索引、描述符索引、属性表集合。


    7.其他:包括属性表集合、Code 属性(指令) 等其他这里暂时不过多介绍,详细请看虚拟机的书籍。

二、反射概念:

    通过上面简单的介绍,相信大家了解了我们的Class 文件在加载到JVM 里面之后,实际存放的信息有很

多,而且上面介绍的都是大家有一定了解的,比如 方法 、属性 等等,那么反射是什么呢?

    所谓反射是JAVA 语言允许在 运行时拥有一种自审的能力,也就是说JVM 允许代码在运行期间可以获得

类的内部信息,简单的说我们可以在程序运行期间获得刚才我们介绍的类里面的信息。

    2.1 反射的常用方法:

        a.forName(String className) :

          返回与带有给定字符串名的类或接口相关联的 Class 对象。

        b.forName(String name, boolean initialize, ClassLoader loader) :

          使用给定的类加载器,返回与带有给定字符串名的类或接口相关联的 Class 对象。
        c.getAnnotation(Class<A> annotationClass)

          如果存在该元素的指定类型的注释,则返回这些注释,否则返回 null。

        d.getAnnotations()

          返回此元素上存在的所有注释。
        e.getConstructor(Class<?>... parameterTypes)

          返回一个 Constructor 对象,它反映此 Class 对象所表示的类的指定公共构造方法。

        f.getDeclaredField(String name)

          返回一个 Field 对象,该对象反映此 Class 对象所表示的类或接口的指定已声明字段。
  g.getDeclaredMethod(String name, Class<?>... parameterTypes)

          返回一个 Method 对象,该对象反映此 Class 对象所表示的类或接口的指定已声明方法。

这里我就不累赘了,仅仅引入性的介绍几个,更多的可以去看看API

三、反射的基本使用:这里我们写一个简单类,模拟常见的功能。




Java代码 复制代码 收藏代码
1. public class Test {   
2.// 构造方法   
3.public Test() {   
4.System.out.println("无参数构造");   
5.}   
6.public Test(String str) {   
7.System.out.println("有参构造:"+str);   
8.}   
9.public  void test(){   
10.System.out.println("普通测试方法:");   
11.}   
12.public static void staticTest(){   
13.System.out.println("静态测试方法");   
14.}   
15.// 基本属性   
16.private Integer number;   
17.public String name = "张三";   
18.    }   



1.类加载:



Java代码 复制代码 收藏代码
1.   public static void main(String[] args) throws Exception {   
2.Class<?> c = Class.forName("com.Test");   
3.// 这里加载类,会调toString 方法, 打印类型,和getName 方法   
4.// 同时发现类已经存在,说明加载成功   
5.// 这里常常我们用来动态加载一个类,比如再获得JDBC 连接的时候,   
6.// 我们可以动态的获得不通厂商的连接:Class.forName("xxx.oracle/mysql")   
7.System.out.println("类信息:"+c);   
8.// 同时这里可以直接这只加载器实现:Class.forName(name, initialize, loader)    
9.}   


2 获得方法并且调用:



Java代码 复制代码 收藏代码
1.  public static void main(String[] args) throws Exception {   
2.Class<?> c = Class.forName("com.Test");   
3.// 这个是获得指定方法,我们先获得普通方法   
4.Method m = c.getMethod("test");   
5.// 这里执行会失败了,因为我们们的类没进行实例化   
6.// m.invoke(c);   
7.// 这样就不会,这里使用了默认的构造   
8.m.invoke(c.newInstance());   
9.// 但是静态方法不用实例化就可以   
10.Method m2 = c.getMethod("staticTest");   
11.m2.invoke(c);   
12.// 当然我们还能获得所有的方法信息   
13.// 获得该类所有方法   
14.c.getDeclaredMethods();   
15.// 获得包括继承的类的所有方法   
16.c.getMethods();   
17.}   


3.获得字段信息:



Java代码 复制代码 收藏代码
1.public static void main(String[] args) throws Exception {   
2.Class<?> c = Class.forName("com.Test");   
3.// 私有字段是无法通过公有方式访问   
4.// Field f1 = c.getField("number");   
5.// public 字段是可以直接访问   
6.Field f = c.getField("name");   
7.System.out.println(f);   
8.   
9.   
10.// 这是赋值,必须先获得对象实例,可以为字段赋值   
11.Object o = c.newInstance();   
12.f.set(o, "2");   
13.System.out.println(f.get(o));   
14.// 其他方法,和获取method 差不多   
15.}   


关于构造器,权限等这些就可以看API,这里仅仅介绍。

    

      4.其他应用:

        反射运用得很多,比如我们熟悉的hibernate、spring、以及其他的orm 框架都需要用到。

        这里我们模拟hibernate 的实现,来完成对象的保存操作。

        // 这是我们模拟的实体bean



Java代码 复制代码 收藏代码
1.// 这是我们模拟的实体bean   
2.public class Bean {   
3.    private Integer id;   
4.    private String name;   
5.    private String password;   
6.    public Integer getId() {   
7.        return id;   
8.    }   
9.    public void setId(Integer id) {   
10.        this.id = id;   
11.    }   
12.    public String getName() {   
13.        return name;   
14.    }   
15.    public void setName(String name) {   
16.        this.name = name;   
17.    }   
18.    public String getPassword() {   
19.        return password;   
20.    }   
21.    public void setPassword(String password) {   
22.        this.password = password;   
23.    }   
24.}   






Java代码 复制代码 收藏代码
1.import java.lang.reflect.Field;   
2.import java.lang.reflect.Method;   
3.   
4.// 这是我们的测试   
5.public class Test {   
6.    public static void main(String[] args) {   
7.        // 1. 首先我们创建一个bean,模拟从前端获取的数据   
8.        Test t = new Test();   
9.        Bean bean = t.getBean();   
10.        // 2.生成我们需要的SQL 并设值   
11.        t.save(bean);   
12.    }   
13.       
14.    private Bean getBean(){   
15.        // 模拟用反射实现   
16.        Bean bean = null;   
17.        try {   
18.            Class c = Class.forName("Bean");   
19.            bean = (Bean) c.newInstance();   
20.            // 私有字段无法访问,我们通过方法赋值   
21.            Method m1 = c.getDeclaredMethod("setId",Integer.class);   
22.            Method m2 = c.getDeclaredMethod("setName",String.class);   
23.            Method m3 = c.getDeclaredMethod("setPassword",String.class);   
24.            m1.invoke(bean, 1);   
25.            m2.invoke(bean, "admin");   
26.            m3.invoke(bean, "123456");   
27.        } catch (Exception e) {   
28.            e.printStackTrace();   
29.        }   
30.        return bean;   
31.    }   
32.       
33.    // 假设我们的表  就是 BEAN   
34.    private void save(Bean bean){   
35.        Field[] fields = Bean.class.getDeclaredFields();   
36.        StringBuffer sb = new StringBuffer("INSERT INTO BEAN VALUES");   
37.        sb.append(getInsertStr(fields.length));   
38.        // 这里我们可以看到SQL 已经生成   
39.        System.out.println(sb);   
40.        // 这里就是我们的JDBC 根据字段名字赋值 的操作了。   
41.        // 当然hibernate 写得肯定会复杂很多,但是基本原理不变   
42.           
43.    }   
44.       
45.    private String getInsertStr(int fields){   
46.        StringBuffer sb = new StringBuffer("(");   
47.        for(int i = 0;i<fields;i++){   
48.            sb.append("?,");   
49.        }   
50.        sb.delete(sb.length()-1,sb.length());   
51.        sb.append(")");   
52.        return sb.toString();   
53.    }   
54.}   



在spring 里面,在介绍过生成代理类,也就是AOP 的地方也用过,这里也就不多说了。



小结:

     1.这里介绍了反射的基本运用,以及一些相关原理的东西,还没真正深入

     2.反射给了我们很大的灵活,但是同时很多错误只能到运行期间才能发现,使用要多注意。

     3.反射提供灵活的同时,也牺牲了性能,在JDK1.6+ 版本,反射的一般调用,比直接调用慢2倍左右。

       性能这一块后面再研究,再招优化的方案。



实例应用:BeanUtils.copyProperties(
分享到:
评论

相关推荐

    java反射 java反射 java反射java反射

    Java反射是Java编程语言中的一个重要特性,它允许程序在运行时动态地获取类的信息并操作类的对象。在Java中,反射机制提供了强大的能力,包括在运行时检查类的结构、创建对象实例、调用方法以及访问和修改字段值。...

    JAVA反射机制的入门代码

    Java反射机制是Java编程语言中的一个强大特性,它允许运行中的Java程序对自身进行检查并且可以直接操作程序的内部属性。这个特性使得Java具有了高度的灵活性和动态性,尤其是在处理元数据、创建对象、调用私有方法...

    java反射,获取所有属性、方法以及List集合类

    Java反射是Java编程语言中的一个强大工具,它允许运行中的Java程序对自身进行检查并且可以直接操作程序的内部属性。在Java中,反射主要用于在运行时分析类和对象,包括访问私有成员、调用私有方法、创建对象、获取类...

    JAVA 反射机制应用

    Java反射机制是Java语言提供的一种强大功能,它允许运行中的Java程序对自身进行检查并且可以直接操作程序的内部属性。在Java中,反射机制的核心类是java.lang.Class,它代表了运行时的类信息。通过Class对象,我们...

    java 反射得到某个方法

    在本文中,我们将深入探讨如何使用Java反射来获取并执行某个特定的方法。 首先,我们需要了解Java反射的基本概念。`java.lang.Class`类是反射的核心,它代表了Java中的每一个类。我们可以通过以下方式获取到一个...

    Java反射性能测试分析

    ### Java反射性能测试分析 #### 引言 Java反射机制是Java编程语言中一个强大的特性,它允许程序在运行时动态地访问、检测和修改类、接口、字段和方法等对象。然而,反射操作通常会引入额外的开销,这在性能敏感的...

    Java反射机制总结

    ### Java反射机制总结 #### 反射的概念与起源 反射的概念最早由Smith于1982年提出,指的是程序能够访问、检测并修改其自身状态或行为的能力。这一概念的提出迅速引起了计算机科学领域的广泛关注,并在之后的研究中...

    Java反射经典实例

    Java反射是Java编程语言中的一个强大特性,它允许运行时的程序访问并操作类、接口、字段和方法等信息,即使这些信息在编译时并未明确知晓。在Java中,反射通常通过`java.lang.Class`类和相关的API来实现。本实例将...

    java反射-英文版反射规范

    ### Java反射机制详解 #### 一、概述 Java反射机制是一种强大的编程技术,它允许运行时检查类的信息并操作对象的内部结构。本篇将基于Sun公司的官方文档《Java™ Core Reflection API and Specification》(1997年...

    反射实例-JAVA反射机制

    ### 反射实例—JAVA反射机制 #### 一、反射概念及原理 反射在计算机科学领域,特别是程序设计中,是指程序有能力访问、检测和修改其自身的结构和行为。这一概念最早由Smith于1982年提出,并迅速应用于各种编程语言...

    java反射.pdf

    ### Java反射机制详解 #### 一、什么是Java反射? Java反射是Java编程语言的一个特性,它允许运行时检查和操作程序结构(类、字段、方法等)。反射的主要用途包括但不限于:动态实例化对象、访问私有成员、调用...

    java 反射 调用私有方法(有参数私有方法)获取私有属性值

    Java反射是Java语言提供的一种强大的动态类型特性,它允许程序在运行时检查类、接口、字段和方法的信息,并且能够动态地创建对象和调用方法。这个能力使得开发者可以突破静态类型的束缚,实现一些在编译时期无法完成...

    java反射源代码

    Java反射是Java编程语言中的一个强大特性,它允许在运行时检查类、接口、字段和方法的信息,并且能够在运行时动态地创建对象和调用方法。这个特性使得Java具有高度的灵活性,尤其在处理框架、插件系统以及元数据驱动...

    java 反射机制例子

    ### Java反射机制详解 #### 一、反射的基本概念与历史背景 反射的概念最早由Smith在1982年提出,其核心思想是程序有能力访问、检测甚至修改自身的状态和行为。这种能力一经提出,迅速成为了计算机科学领域的研究...

    java 反射 报错 no such method exception

    ### Java反射机制与NoSuchMethodException详解 在Java编程中,反射是一种强大的机制,允许程序在运行时检查和修改自身结构和行为。然而,当开发者尝试使用反射调用一个不存在的方法时,便会遇到`java.lang....

    java反射获取所有属性,获取所有get方法,包括子类父类

    Java反射是Java编程语言中的一个强大工具,它允许运行中的Java程序对自身进行检查并且可以直接操作程序的内部属性。在Java中,反射主要用于在运行时分析类和对象,包括访问私有成员、调用私有方法、创建动态代理等。...

    利用java反射将json字符串转成对象.zip

    Java反射是Java编程语言中的一个强大工具,它允许运行中的Java程序对自身进行检查并且可以直接操作程序的内部属性。在给定的“利用java反射将json字符串转成对象”的主题中,我们将深入探讨如何借助反射机制将JSON...

    Java反射机制Demo

    ### Java反射机制详解 #### 一、什么是Java反射机制? Java反射机制是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法;对于任意一个对象,都能够调用它的任意一个方法和属性;这种动态获取的...

    北大青鸟java反射机制

    Java反射机制是Java编程语言中的一个强大工具,它允许程序在运行时检查并操作类、接口、字段和方法等对象。在"北大青鸟java反射机制"的学习资料中,我们将会深入探讨这一核心特性。 首先,我们要理解反射的核心概念...

    java反射

    ### Java反射机制详解 #### 一、引言 在Java编程语言中,反射(Reflection)是一种强大的工具,它允许程序在运行时访问类的信息,并能够动态地创建对象、调用方法以及获取字段值等。这种能力对于框架设计、代码...

Global site tag (gtag.js) - Google Analytics