【JAVA - 基础】之反射的原理与应用
一、反射简介
反射机制指的是程序在运行时能够获取自身的信息。在JAVA中,只要给定类的名字,那么就可以通过反射机制来获取类的所有信息。
1、反射的应用
- JDBC编程中的:Class.forName("com.mysql.jdbc.Driver.class");
 - 通过文件名找到项目中的文件;
 - Hibernate、Struts、Dagger2等框架中都用到了反射机制。
 
2、反射的特点
- 优点:使用反射机制可以实现动态的创建对象和编译,体现出了很大的灵活性;
 - 缺点:反射对性能有影响。
 
3、反射的原理
JAVA语言编译之后都会生成一个.class文件,而不是生成机器码。反射就是在程序编译之后,通过程序字节码文件找到某一个类、类中的方法以及属性等。
简单来说,反射是JAVA语言在运行的时候拥有的一项自观能力,其实现主要借助于以下四个类:
- Class:类的对象;
 - Constructor:类的构造方法;
 - Field:类中的属性对象;
 - Method:类中的方法对象。
 
通过这四个类就可以找到并处理JAVA中的几乎所有东西了。
二、常用方法
1、获取类对象
- 通过类名获取Class对象:Class<?> c = Class.forName(“ClassName”);(这里的ClassName是完全的路径,需要包括包路径)
 - 通过Class对象获得具体类对象:Object o = (Object) c.newInstance();
 
2、获取类中的构造方法
以下代码中的c是2.1中获得的Class<?>类型的变量
- 根据指定参数类型获取public构造方法:Constructor con = c.getConstructor(Class<?> … paramTypes);
 - 获得所有public构造方法:Constructor[] cons = c.getConstructors();
 - 根据指定参数类型获取任意访问权限的构造方法:Constructor con = c.getDeclaredConstructor(Class<?> … paramTypes);
 - 获得所有任意访问权限的构造方法:Constructor[] cons = c.getDeclaredConstructors();
 
3、获取类中的方法
以下代码中的c是2.1中获得的Class<?>类型的变量
- 根据方法名和指定参数类型获取public方法:Method m = c.getMethod(String mName, Class<?> … paramTypes);
 - 获得所有public方法:Method[] ms= c.getMethods();
 - 根据方法名和指定参数类型获得任意访问权限的方法:Method m = c.getDeclaredMethod(String mName, Class<?> …paramTypes);
 - 获得所有任意访问权限的方法:Method[] ms = c.getDeclaredMethods();
 
4、获取类中的变量
以下代码中的c是2.1中获得的Class<?>类型的变量
- 根据变量名获取public变量:Field f =c.getField(String name);
 - 获得所有public变量:Field[] fs= c.getFields();
 - 根据变量名获取所有任意访问权限的变量:Field f = c.getDeclaredField(String name);
 - 获得所有任意访问权限的变量:Field[] fs = c.getDeclaredFields();
 
5、获取其他数据
- 获取类实现的所有接口:Class<?>[] interfaces = c.getInterfaces();
 - 获取类继承的父类:Class<?> parent = c.getSuperclass();
 - 获取修饰符:String modifier = Modifier.toString(X.getModifiers()); //X是类、方法、属性、构造方法等
 - 获取方法的返回值类型:String returnType = m.getReturnType().getSimpleName();
 - 获取属性的类型:String type = f.getType().getSimpleName();
 - 获取名称:String name = X.getName(); //X是类、方法、属性、构造方法等
 - 调用方法:m.invoke(clazz, Class<?> … paramTypes); //clazz是类对象
 - 获取属性值:Object o = f.get(clazz); //clazz是类对象
 
三、代码演示
以下代码是目标类,我们的测试类会从这个类中取出各种数据做测试:
public class DemoClass {
    // public修饰的int类型的变量
    public Integer publicInteger;
    // public修饰的String类型的变量
    public String publicString;
    // private修饰的int类型的变量
    protected Integer privateInteger;
    // private修饰的String类型的变量
    protected String privateString;
    // public修饰的无参构造方法
    public DemoClass() {
        this.publicInteger = 10;
        this.privateInteger = 20;
        this.publicString = "Public String";
        this.privateString = "Private String";
    }
    // public修饰的四个参数的构造方法,参数类型:int,String,int,String
    public DemoClass(Integer publicInteger, String publicString, Integer privateInteger, String privateString) {
        this.publicInteger = publicInteger;
        this.publicString = publicString;
        this.privateInteger = privateInteger;
        this.privateString = privateString;
    }
    // private修饰的两个参数的构造方法,参数类型:int,int
    protected DemoClass(Integer publicInteger, Integer privateInteger) {
        this.publicInteger = publicInteger;
        this.privateInteger = privateInteger;
    }
    // public修饰的无参的方法,返回int变量
    public int getPublicInteger() {
        return publicInteger;
    }
    // public修饰的四个参数的方法,参数类型:int,int,String,String,无返回值
    public void setParameters(Integer publicInteger, Integer privateInteger, String publicString,
            String privateString) {
        this.publicInteger = publicInteger;
        this.privateInteger = privateInteger;
        this.publicString = publicString;
        this.privateString = privateString;
    }
    // private修饰的两个参数的方法,参数类型:int,int,返回boolean类型的变量
    protected boolean setSomeParams(Integer publicInteger, Integer privateInteger) {
        this.publicInteger = publicInteger;
        this.privateInteger = privateInteger;
        return true;
    }
    @Override
    public String toString() {
        return "DemoClass [publicInteger=" + publicInteger + ", publicString=" + publicString + ", privateInteger="
                + privateInteger + ", privateString=" + privateString + "]";
    }
} 
编写这个类需要注意的有以下几点:
- 变量和参数的类型、方法的返回值类型不能是int、float、double,必须是封装类Integer、Float、Double;
 - 用private修饰的变量、方法和构造方法是不能通过反射获取的,使用其他修饰符都能获取到。
 
以下是测试类中的代码:
public class Test {
    public static void main(String[] args) {
        try {
            /**
             * 获取和类有关的数据
             */
            // 通过类名得到Class<?>对象
            Class<?> clazz = Class.forName("com.itgungnir.testreflect.democlass.DemoClass");
            System.out.println("Class Created");
            // 获取这个类实现的接口
            System.out.println("----------------------------------------------------------------------------");
            Class<?>[] interfaces = clazz.getInterfaces();
            if (interfaces.length == 0) {
                System.out.println("No Interfaces Implemented");
            }
            // 获取这个类的父类
            System.out.println("----------------------------------------------------------------------------");
            Class<?> parent = clazz.getSuperclass();
            System.out.println("Parent -----> " + parent.getName());
            /**
             * 获取和构造方法有关的数据
             */
            // 通过Class<?>对象获取DemoClass类的对象
            // newInstance()方法调用的是无参的构造方法,如果没有无参的构造方法,则会报错
            System.out.println("----------------------------------------------------------------------------");
            DemoClass c = (DemoClass) clazz.newInstance();
            System.out.println(c.toString());
            // 获取DemoClass对象中public修饰的无参构造方法
            System.out.println("----------------------------------------------------------------------------");
            Constructor<?> con1 = clazz.getConstructor();
            c = (DemoClass) con1.newInstance();
            System.out.println(c.toString());
            // 获取DemoClass对象中public修饰的四个参数的构造方法,参数类型:Integer,String,Integer,String
            System.out.println("----------------------------------------------------------------------------");
            Constructor<?> con2 = clazz.getConstructor(Integer.class, String.class, Integer.class, String.class);
            c = (DemoClass) con2.newInstance(100, "", 100, "aaa");
            System.out.println(c.toString());
            // 获取DemoClass对象中protected修饰的两个参数的构造方法,参数类型:Integer,Integer
            System.out.println("----------------------------------------------------------------------------");
            Constructor<?> con3 = clazz.getDeclaredConstructor(Integer.class, Integer.class);
            c = (DemoClass) con3.newInstance(55, 66);
            System.out.println(c.toString());
            // 获取DemoClass对象中所有public修饰的构造方法
            System.out.println("----------------------------------------------------------------------------");
            Constructor<?>[] cons1 = clazz.getConstructors();
            c = (DemoClass) cons1[0].newInstance(0, "Hello", 111111, "World");
            System.out.println(c.toString());
            c = (DemoClass) cons1[1].newInstance();
            System.out.println(c.toString());
            // 获取DemoClass对象中所有任意访问权限的构造方法
            System.out.println("----------------------------------------------------------------------------");
            Constructor<?>[] cons2 = clazz.getDeclaredConstructors();
            c = (DemoClass) cons2[0].newInstance(-1, -2);
            System.out.println(c.toString());
            c = (DemoClass) cons2[1].newInstance(0, "Hello", 111111, "World");
            System.out.println(c.toString());
            c = (DemoClass) cons2[2].newInstance();
            System.out.println(c.toString());
            /**
             * 获取和变量有关的数据
             */
            // 获取DemoClass对象中public修饰的Integer类型的变量publicInteger
            // 获取属性值时传入的Object类型的参数是DemoClass类的对象
            System.out.println("----------------------------------------------------------------------------");
            Field f1 = clazz.getField("publicInteger");
            System.out.println(f1.get(c));
            // 获取DemoClass对象中public修饰的String类型的变量privateInteger
            System.out.println("----------------------------------------------------------------------------");
            Field f2 = clazz.getDeclaredField("privateInteger");
            System.out.println(f2.get(c));
            // 获取DemoClass对象中public修饰的Integer类型的变量publicString
            System.out.println("----------------------------------------------------------------------------");
            Field f3 = clazz.getField("publicString");
            System.out.println(f3.get(c));
            // 获取DemoClass对象中protected修饰的String类型的变量privateString
            System.out.println("----------------------------------------------------------------------------");
            Field f4 = clazz.getDeclaredField("privateString");
            System.out.println(f4.get(c));
            // 获取DemoClass对象中所有public修饰的变量
            System.out.println("----------------------------------------------------------------------------");
            Field[] fs1 = clazz.getFields();
            for (Field f : fs1) {
                System.out.println(Modifier.toString(f.getModifiers()) + " " + f.getType().getSimpleName() + " "
                        + f.getName() + " = " + f.get(c) + ";");
            }
            // 获取DemoClass对象中所有任意访问权限的变量
            System.out.println("----------------------------------------------------------------------------");
            Field[] fs2 = clazz.getDeclaredFields();
            for (Field f : fs2) {
                System.out.println(Modifier.toString(f.getModifiers()) + " " + f.getType().getSimpleName() + " "
                        + f.getName() + " = " + f.get(c) + ";");
            }
            /**
             * 获取和方法有关的数据
             */
            // 获取DemoClass对象中public修饰的无参方法getPublicInteger,返回Integer类型变量
            System.out.println("----------------------------------------------------------------------------");
            Method m1 = clazz.getMethod("getPublicInteger");
            System.out.println(m1.invoke(c));
            // 获取DemoClass对象中public修饰的四个参数的方法setParameters,参数类型:Integer,Integer,String,String,无返回值
            System.out.println("----------------------------------------------------------------------------");
            Method m2 = clazz.getMethod("setParameters", Integer.class, Integer.class, String.class, String.class);
            m2.invoke(c, 111, 1111, "abc", "abcdef");
            System.out.println(c.toString());
            // 获取DemoClass对象中protected修饰的两个参数的方法setSomeParams,参数类型:Integer,Integer,返回boolean类型变量
            System.out.println("----------------------------------------------------------------------------");
            Method m3 = clazz.getDeclaredMethod("setSomeParams", Integer.class, Integer.class);
            System.out.println(m3.invoke(c, 0, 0));
            // 获取DemoClass对象中所有public修饰的方法(包括Object类中的public方法)
            System.out.println("----------------------------------------------------------------------------");
            Method[] ms1 = clazz.getMethods();
            for (Method m : ms1) {
                System.out.println(Modifier.toString(m.getModifiers()) + " " + m.getReturnType().getSimpleName() + " "
                        + m.getName() + "(){...}");
            }
            // 获取DemoClass对象中所有任意访问权限的方法(所有自定义的方法)
            System.out.println("----------------------------------------------------------------------------");
            Method[] ms2 = clazz.getDeclaredMethods();
            for (Method m : ms2) {
                System.out.println(Modifier.toString(m.getModifiers()) + " " + m.getReturnType().getSimpleName() + " "
                        + m.getName() + "(){...}");
            }
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        } catch (InstantiationException e) {
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        } catch (NoSuchMethodException e) {
            e.printStackTrace();
        } catch (SecurityException e) {
            e.printStackTrace();
        } catch (IllegalArgumentException e) {
            e.printStackTrace();
        } catch (InvocationTargetException e) {
            e.printStackTrace();
        } catch (NoSuchFieldException e) {
            e.printStackTrace();
        }
    }
} 
要想得到不同的数据,只需要参照上面的代码进行编写即可。
唯一值得注意的是,当调用getFields()、getDeclaredFields()、getMethods()、getDeclaredMethods()、getConstructors()、getDeclaredConstructors()等能获取数组类型的结果的方法时,返回的数组中的方法、变量或构造方法的顺序和类中定义的顺序是反过来的!
以上就是对Java中反射的一些总结,希望对大家有帮助!
【JAVA - 基础】之反射的原理与应用的更多相关文章
- 黑马程序员:Java基础总结----反射
		
黑马程序员:Java基础总结 反射 ASP.Net+Android+IO开发 . .Net培训 .期待与您交流! 反射 反射的基石:Class类 Class类代表Java类,它的各个实例对象又分别 ...
 - Java基础之一反射
		
反射是框架设计的灵魂 (使用的前提条件:必须先得到代表的字节码的Class,Class类用于表示.class文件(字节码)) 一.反射的概述 JAVA反射机制是在运行状态中,对于任意一个类,都能够 ...
 - Java基础之—反射
		
反射是框架设计的灵魂 (使用的前提条件:必须先得到代表的字节码的Class,Class类用于表示.class文件(字节码)) 一.反射的概述 JAVA反射机制是在运行状态中,对于任意一个类,都能够 ...
 - java基础之反射---重要
		
java反射: 反射是框架设计的灵魂 (使用的前提条件:必须先得到代表的字节码的Class,Class类用于表示.class文件(字节码)): 1:获取Class字节码文件对象的三种方式: /** ...
 - 【Java基础】反射和注解
		
前言 在Java中,反射机制和注解机制一直是一个很重要的概念,那么他们其中的原理是怎么样呢,我们不仅仅需要会使用,更要知其然而之所以然. 目录 反射机制 反射如何使用 注解定义 注解机制原理 注解如何 ...
 - JAVA基础知识|反射
		
一.理解反射 1.1.基础概念 反射:在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法:对于任意一个对象,都能够调用它的任意方法和属性:这种动态获取信息以及动态调用对象方法的功能称为ja ...
 - java基础之反射机制
		
一.概念 JAVA反射机制是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法:对于任意一个对象,都能够调用它的任意一个方法和属性:这种动态获取的信息以及动态调用对象的方法的功能称为jav ...
 - java基础(十一 )-----反射——Java高级开发必须懂的
		
本文我们通过一个实际的例子来演示反射在编程中的应用,可能之前大家对反射的学习,仅仅是停留在概念层面,不知道反射究竟应用在哪,所以是一头雾水.相信通过这篇教程,会让你对反射有一个更深层次的认知. 概念 ...
 - java基础篇---反射机制
		
一.JAVA是动态语言吗? 一般而言,说到动态言,都是指在程序运行时允许改变程序结构或者变量类型,从这个观点看,JAVA和C++一样,都不是动态语言. 但JAVA它却有着一个非常突出的动态相关机制:反 ...
 - Java 基础总结--反射的基本操作
		
一.反射的概念 JAVA反射机制是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法:对于任意一个对象,都能够调用它的任意一个方法和属性:这种动态获取的信息以及动态调用对象的方法的功能称为 ...
 
随机推荐
- asp.net treeview控件无刷新选择和删除节点的ajax方法
			
转载 http://blog.csdn.net/luq885/article/details/1621681 如果节点被选择的话,节点所在的td的class属性就会被设置为TreeView1_1. ...
 - 从网页psd到html的开发
			
从网上下载了一张psd的网页设计稿,初学html+css,所以记录一下我的学习过程.原图是这个样子: 原图 ...
 - ubuntu下mysql安装与测试
			
原文地址: http://www.cnblogs.com/zhuyp1015/p/3561470.html 注意:原文地址中,最后g++ 编译源代码时少了个字母.添上即可. ubuntu上安装mysq ...
 - 了解SOA是什么!
			
面向服务架构 面向服务的体系结构(service-oriented architecture,SOA)是一个组件模型,它将应用程序的不同功能单元(称为服务)通过这些服务之间定义良好的接口和契约联系起来 ...
 - 2016多校联合训练contest4 1012Bubble Sort
			
Bubble Sort Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 65536/65536 K (Java/Others) Tota ...
 - 阿里云ECS服务器配置ubuntu安装openfire服务器
			
最近搞了一台阿里云的ECS服务器,因为搞活动半年免费,所以就申请了一台,过两天就批准下来,顺便多花了1百多RMB买了固定IP.总体说来还是挺值的,觉得一个人用挺浪费,分享出来跟大家一起玩玩. 搞台服务 ...
 - windows server 2012服务器IIS基本配置
 - dubbo 负载均衡中策略决策
			
在dubbo中的服务端负载均衡配置,如果像以下情况,将需要决策最终的负载策略问题: <dubbo:application name="hello-world-server" ...
 - webkit.net使用方法日记
			
1.首先貌似只有36位的库,所以项目也要修改为X86平台 2.里面的所有dll库文件都要拷贝到项目中去,包括WebKitBrowser.dll.manifest 此文件一定要拷贝过去. 3.然后引用 ...
 - Web Adaptor重装配置时 提示已经配置成功的问题
			
环境 ArcGIS 10.1/10.2/10.3 Windwos 8.1 Tomcat 7.0.5 问题描述 较早之前在本机上安装配置过一个10.2.1版本的ArcGIS产品,包括桌面.Server和 ...