• linkedu视频
  • 平面设计
  • 电脑入门
  • 操作系统
  • 办公应用
  • 电脑硬件
  • 动画设计
  • 3D设计
  • 网页设计
  • CAD设计
  • 影音处理
  • 数据库
  • 程序设计
  • 认证考试
  • 信息管理
  • 信息安全
菜单
linkedu.com
  • 网页制作
  • 数据库
  • 程序设计
  • 操作系统
  • CMS教程
  • 游戏攻略
  • 脚本语言
  • 平面设计
  • 软件教程
  • 网络安全
  • 电脑知识
  • 服务器
  • 视频教程
  • JavaScript
  • ASP.NET
  • PHP
  • 正则表达式
  • AJAX
  • JSP
  • ASP
  • Flex
  • XML
  • 编程技巧
  • Android
  • swift
  • C#教程
  • vb
  • vb.net
  • C语言
  • Java
  • Delphi
  • 易语言
  • vc/mfc
  • 嵌入式开发
  • 游戏开发
  • ios
  • 编程问答
  • 汇编语言
  • 微信小程序
  • 数据结构
  • OpenGL
  • 架构设计
  • qt
  • 微信公众号
您的位置:首页 > 程序设计 >Java > Java进阶之反射

Java进阶之反射

作者:diuleilaomo的 字体:[增加 减小] 来源:互联网 时间:2017-10-21

diuleilaomo的通过本文主要向大家介绍了等相关知识,希望对您有所帮助,也希望大家支持linkedu.com www.linkedu.com

1 什么是反射

  反射(Reflection)是Java 程序开发语言的特征之一,它允许运行中的 Java 程序获取自身的信息,并且可以操作类或对象的内部属性。 
  一句话总结:反射就是把Java类中的各种成分通过java的反射API映射成相应的Java类,得到这些类以后就可以对其进行使用。比如方法,构造方法,成员变量,类型,包等。 
  反射的核心是JVM在运行时才动态加载类或调用方法/访问属性,它不需要事先(写代码的时候或编译期)知道运行对象是谁。重点:是运行时而不是编译时

2 反射的主要用途

  当我们在使用IDE(如Eclipse,IDEA)时,当我们输入一个对象或类并想调用它的属性或方法时,一按点号,编译器就会自动列出它的属性或方法,这里就会用到反射。 
  反射最重要的用途就是开发各种通用框架。 
  很多框架(比如Spring)都是配置化的(比如通过XML文件配置JavaBean,Action之类的),为了保证框架的通用性,它们可能需要根据配置文件加载不同的对象或类,调用不同的方法,这个时候就必须用到反射——运行时动态加载需要加载的对象。例如:

  • 框架提供配置文件,用户可以配置,例如类名
  • 读取用户的配置文件
//一定要用完整的路径,不是硬编码,而是运算出来的
InputStream is = new FileInputStream("文件目录");
Properties properties = new Properties();
properties.load(is);
String value = properties.getProperty("key");
  • 1
  • 2
  • 3
  • 4
  • 5
  • 通过反射加载对应的类,并且动态去使用

3 反射的基本运用

3.1 获得Class对象

(1)使用Class类的forName静态方法:

public static Class<?> forName(String className)
// 在JDBC开发中常用此方法加载数据库驱动
Class.forName(driver);
  • 1
  • 2
  • 3

(2)直接获取某一个对象的class,比如:

Class<?> klass = int.class;
Class<?> classInt = Integer.TYPE;
  • 1
  • 2

(3)调用某个对象的getClass()方法,比如:

StringBuilder str = new StringBuilder("123");
Class<?> klass = str.getClass();
  • 1
  • 2

(4)判断是否为某个类的实例 
一般地,我们用instanceof关键字来判断是否为某个类的实例。同时我们也可以借助反射中Class对象的isInstance()方法来判断是否为某个类的实例,它是一个Native方法:

public native boolean isInstance(Object obj);
  • 1

3.2 创建对象

(1)使用Class对象的newInstance()方法来创建Class对象对应类的实例。

Class<?> c = String.class;
Object str = c.newInstance();
// 或者:
UserBean where;
Object item = where.getClass().newInstance();
  • 1
  • 2
  • 3
  • 4
  • 5

(2)先通过Class对象获取指定的Constructor对象,再调用Constructor对象的newInstance()方法来创建实例。这种方法可以用指定的构造器构造类的实例。

//获取String所对应的Class对象
Class<?> c = String.class;
//获取String类带一个String参数的构造器
Constructor constructor = c.getConstructor(String.class);
//根据构造器创建实例,constructor.newInstance();
Object obj = constructor.newInstance("23333");
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

3.3 获取某个Class对象的方法集合

(1)getDeclaredMethods()方法返回类或接口声明的所有方法,包括公共、保护、默认(包)访问和私有方法,但不包括继承的方法。

Class<?> c = methodClass.class;
Object object = c.newInstance();

Method[] declaredMethods = c.getDeclaredMethods();
  • 1
  • 2
  • 3
  • 4

(2)getMethods()方法返回某个类的所有公用(public)方法,包括其继承类的公用方法。

Method[] methods = c.getMethods();
  • 1

(3)getMethod方法返回一个特定的方法,其中第一个参数为方法名称,后面的参数为方法的参数对应Class的对象。

//获取methodClass类的add方法
Method method = c.getMethod("add", int.class, int.class);
  • 1
  • 2

3.4 获取构造器Constructor

(1)得到所有的构造方法

Constructor<?>[] constructors = Class.forName("java.lang.String").getConstructors();
  • 1

(2)得到指定参数的某一个构造方法

Constructor<?> constructor = Class.forName("java.lang.String").getConstructor(StringBuffer.class);
  • 1

3.5 获取类的成员变量(字段)信息

(1)getFiled: 访问公有的成员变量; 
(2)getDeclaredField:所有已声明的成员变量。但不能得到其父类的成员变量; 
(3)getFileds和getDeclaredFields用法同上(参照Method)。

3.6 调用方法

  当我们从类中获取了一个方法后,我们就可以用invoke()方法来调用这个方法。invoke方法的原型为:

public Object invoke(Object obj, Object... args)
        throws IllegalAccessException, IllegalArgumentException,
           InvocationTargetException
  • 1
  • 2
  • 3
public class test {
    Class<?> klass = methodClass.class;
    //创建methodClass的实例
    Object obj = klass.newInstance();
    //获取methodClass类的add方法
    Method method = klass.getMethod("add",int.class,int.class);
    //调用method对应的方法 => add(1,4)
    Object result = method.invoke(obj,1,4);
    System.out.println(result);
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10

3.7 利用反射创建数组

  数组在Java里是比较特殊的一种类型,它可以赋值给一个Object Reference。 
  

public static void testArray() throws ClassNotFoundException {
        Class<?> cls = Class.forName("java.lang.String");
        Object array = Array.newInstance(cls,25);
        //往数组里添加内容
        Array.set(array,0,"hello");
        Array.set(array,1,"Java");
        Array.set(array,2,"fuck");
        Array.set(array,3,"Scala");
        Array.set(array,4,"Clojure");
        //获取某一项的内容
        System.out.println(Array.get(array,3));
    }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12

  其中的Array类为java.lang.reflect.Array类。我们通过Array.newInstance()创建数组对象,它的原型是:

public static Object newInstance(Class<?> componentType, int length)
        throws NegativeArraySizeException {
        return newArray(componentType, length);
    }
  • 1
  • 2
  • 3
  • 4

  而newArray()方法是一个Native方法,它在Hotspot JVM里的具体实现我们后边再研究:

private static native Object newArray(Class<?> componentType, int length)
        throws NegativeArraySizeException;
  • 1
  • 2

4 实践

(1)基本使用参考:Java进阶之注解

(2)反射方式赋值

 /**
  * 获取查询结果
  */
 private List<T> getQueryResult(Cursor cursor, T where) {
    ArrayList items = new ArrayList();
    // 查询的对象
    Object item;
    while (cursor.moveToNext()) {
        try {
            item = where.getClass().newInstance();
            // 遍历映射集合(relationMap)的key:数据库表列名(colmunName)
            for (Object object : relationMap.entrySet()) {
                Map.Entry entry = (Map.Entry) object;
                // 得到数据库表列名
                String colomunName = (String) entry.getKey();
                // 然后以列名拿到:列名在游标的位置
                Integer colmunIndex = cursor.getColumnIndex(colomunName);

                // 获取key对应的值:成员变量(Field对象)
                Field field = (Field) entry.getValue();
                Class type = field.getType();
                if (colmunIndex != -1) {
                    if (type == String.class) {
                        // 反射方式赋值(native方法),相当于item.setValue(cursor.getString(colmunIndex));
                        field.set(item, cursor.getString(colmunIndex));
                    } else if (type == Double.class) {
                        field.set(item, cursor.getDouble(colmunIndex));
                    } else if (type == Integer.class) {
                        field.set(item, cursor.getInt(colmunIndex));
                    } else if (type == Long.class) {
                        field.set(item, cursor.getLong(colmunIndex));
                    } else if (type == byte[].class) {
                        field.set(item, cursor.getBlob(colmunIndex));
                    } else {
                        continue;
                    }
                }
            }
      items.add(item);
      } catch (InstantiationException e) {
          e.printStackTrace();
      } catch (IllegalAccessException e) {
          e.printStackTrace();
      }
    }
    return items;
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47

5 注意使用

  由于反射会额外消耗一定的系统资源,因此如果不需要动态地创建一个对象,那么就不需要用反射。另外,反射调用方法时可以忽略权限检查,因此可能会破坏封装性而导致安全问题。

6 参考链接

深入解析Java反射(1) - 基础

深入解析Java反射(2) - invoke方法

JAVA面试-基础加强与巩固:反射、注解、泛型等

分享到:QQ空间新浪微博腾讯微博微信百度贴吧QQ好友复制网址打印

您可能想查找下面的文章:

相关文章

  • 2017-05-28java 中Thread.join()的使用方法
  • 2017-05-28Java语言实现简单FTP软件 FTP上传下载管理模块实现(11)
  • 2017-05-28Java数据结构之链表(动力节点之Java学院整理)
  • 2017-05-28Eclipse 开发java 出现Failed to create the Java Virtual Machine错误解决办法
  • 2017-05-28老生常谈Log4j和Log4j2的区别(推荐)
  • 2017-05-28探索Java中的equals()和hashCode()方法_动力节点Java学院整理
  • 2017-05-28Java IO流对象的序列化和反序列化实例详解
  • 2017-05-28Java 用反射设置对象的属性值实例详解
  • 2017-05-28JVM 方法调用之静态分派(详解)
  • 2017-05-28java利用url实现网页内容的抓取

文章分类

  • JavaScript
  • ASP.NET
  • PHP
  • 正则表达式
  • AJAX
  • JSP
  • ASP
  • Flex
  • XML
  • 编程技巧
  • Android
  • swift
  • C#教程
  • vb
  • vb.net
  • C语言
  • Java
  • Delphi
  • 易语言
  • vc/mfc
  • 嵌入式开发
  • 游戏开发
  • ios
  • 编程问答
  • 汇编语言
  • 微信小程序
  • 数据结构
  • OpenGL
  • 架构设计
  • qt
  • 微信公众号

最近更新的内容

    • Spring MVC 4.1.3 + MyBatis零基础搭建Web开发框架(注解模式)
    • 详解spring security 配置多个AuthenticationProvider
    • mybatis高级映射一对多查询实现代码
    • Java IO中字节流复制图片实现代码
    • Spring Boot如何解决Mysql断连问题
    • springmvc实现简单的拦截器
    • java web如何解决瞬间高并发
    • AsyncTask 源码分析
    • Java CountDownLatch完成异步回调实例详解
    • SpringBoot入门系列之JPA mysql

关于我们 - 联系我们 - 免责声明 - 网站地图

©2020-2025 All Rights Reserved. linkedu.com 版权所有