Java 反射简介
本文部分内容参考博客。点击链接可以查看原文。
1. 反射的概念
反射是指在运行时将类的属性、构造函数和方法等元素动态地映射成一个个对象。通过这些对象我们可以动态地生成对象实例,调用类的方法和更改类的属性值。
2. 使用场景
什么情况下运用JAVA反射呢?如果编译时根本无法预知对象和类可能属于哪些类,程序只依靠运行时信息来发现该对象和类的真实信息,此时就必须使用反射。
使用反射可以实现下面的功能:
- 在运行时判断任意一个对象所属的类
 - 在运行时构造任意一个类的对象
 - 在运行时判断任意一个类所具有的方法和属性
 - 在运行时调用任意一个对象的方法
 - 生成动态代理
 
3. 获得Class对象的几种方式
前面已经介绍过了,每个类被加载之后,系统就会为该类生成一个对应的Class对象,通过该Class对象就可以访问到JVM中的这个类。在Java程序中获得Class对象通常有如下3种方式。
- 使用Class类的forName(String clazzName)静态方法。该方法需要传入字符串参数,该字符串参数的值是某个类的全限定类名(必须添加完整包名)。
 - 调用某个类的class属性来获取该类对应的Class对象。例如,Person.class将会返回Person类对应的Class对象。
 - 调用某个对象的getClass()方法。该方法是java.lang.Object类中的一个方法,所以所有的Java对象都可以调用该方法,该方法将会返回该对象所属类对应的Class对象。
 
对于第一种方式和第二种方式都是直接根据类来取得该类的Class对象,相比之下,第二种方式有如下两种优势。
- 代码更安全。程序在编译阶段就可以检查需要访问的Class对象是否存在。
 - 程序性能更好。因为这种方式无须调用方法,所以性能更好。
 
也就是说,大部分时候我们都应该使用第二种方式来获取指定类的Class对象。但如果我们只有一个字符串,例如“java.lang.String”,若需要获取该字符串对应的Class对象,则只能使用第一种方式,使用Class的forName(String clazzName)方法获取Class对象时,该方法可能抛出一个ClassNotFoundException异常。一旦获得了某个类所对应的Class对象之后,程序就可以调用Class对象的方法来获得该对象和该类的真实信息了。
4. Class类 API介绍
通过class类我们能够获取大量的信息:
- 获取构造函数
 
- Connstructor getConstructor(Class<?>... parameterTypes):返回此Class对象对应类的指定public构造器。
 - Constructor<?>[] getConstructors():返回此Class对象对应类的所有public构造器。
 - Constructor getDeclaredConstructor(Class<?>... parameterTypes):返回此Class对象对应类的指定构造器,与构造器的访问权限无关。
 - Constructor<?>[] getDeclaredConstructors():返回此Class对象对应类的所有构造器,与构造器的访问权限无关。
 
- 获取方法
 
- Method getDeclaredMethod(String name, Class<?>... parameterTypes):返回此Class对象对应类的指定方法,与方法的访问权限无关。
 - Method[] getDeclaredMethods():返回此Class对象对应类的全部方法,与方法的访问权限无关。
 
- 获取属性
 
- Field getField(String name):返回此Class对象对应类的指定public Field。
 - Field[] getFields():返回此Class对象对应类的所有public Field。
 - Field getDeclaredField(String name):返回此Class对象对应类的指定Field,与Field的访问权限无关。
 - Field[] getDeclaredFields():返回此Class对象对应类的全部Field,与Field的访问权限无关。
 
- 获取Class对应类上所包含的Annotation。
 
- A getAnnotation(ClassannotationClass):试图获取该Class对象对应类上指定类型的Annotation;如果该类型的注释不存在,则返回null。
 - Annotation[] getAnnotations():返回该Class对象对应类上的所有Annotation。
 - Annotation[] getDeclaredAnnotations():返回直接修饰该Class对应类的所有Annotation。
 
- 获取Class对象对应类包含的内部类。
 
- Class<?>[] getDeclaredClasses():返回该Class对象对应类里包含的全部内部类。
如下方法用于访问该Class对象对应类所在的外部类。 - Class<?> getDeclaringClass():返回该Class对象对应类所在的外部类。
如下方法用于访问该Class对象对应类所继承的父类、所实现的接口等。 - Class<?>[] getInterfaces():返回该Class对象对应类所实现的全部接口。
 
- 获取Class对象对应类所继承的父类
 
- Class<? super T> getSuperclass():返回该Class对象对应类的超类的Class对象。
 
- 获取Class对象对应类的修饰符、所在包、类名等基本信息。
 
- int getModifiers():返回此类或接口的所有修饰符。修饰符由public、protected、private、final、static、abstract等对应的常量组成,返回的整数应使用Modifier工具类的方法来解码,才可以获取真实的修饰符。
 - Package getPackage():获取此类的包。
 - String getName():以字符串形式返回此Class对象所表示的类的名称。
 - String getSimpleName():以字符串形式返回此Class对象所表示的类的简称。
 
- 判断该类是否为接口、枚举、注释类型等
 
- boolean isAnnotation():返回此Class对象是否表示一个注释类型(由@interface定义)。
 - boolean isAnnotationPresent(Class<? extends Annotation> annotationClass):判断此Class对象是否使用了Annotation注释修饰。
 - boolean isAnonymousClass():返回此Class对象是否是一个匿名类。
 - boolean isArray():返回此Class对象是否表示一个数组类。
 - boolean isEnum():返回此Class对象是否表示一个枚举(由enum关键字定义)。
 - boolean isInterface():返回此Class对象是否表示一个接口(使用interface定义)。
 - boolean isInstance(Object obj):判断obj是否是此Class对象的实例,该方法可以完全代替instanceof操作符。
 
上面的多个getMethod()方法和getConstructor()方法中,都需要传入多个类型为Class<?>的参数,用于获取指定的方法或指定的构造器。关于这个参数的作用,假设某个类内包含如下3个info方法签名:
- public void info()
 - public void info(String str)
 - public void info(String str , Integer num)
 
这3个同名方法属于重载,它们的方法名相同,但参数列表不同。在Java语言中要确定一个方法光有方法名是不行的,例如,我们指定info方法——实际上可以是上面3个方法中的任意一个!如果需要确定一个方法,则应该由方法名和形参列表来确定,但形参名没有任何实际意义,所以只能由形参类型来确定。例如,我们想要确定第二个info方法,则必须指定方法名为info,形参列表为String.class——因此在程序中获取该方法使用如下代码:
clazz.getMethod("info",String.class);
使用反射生成对象
- 利用构造函数生成对象
 
- 使用Class对象的newInstance()方法来创建该Class对象对应类的实例,这种方式要求该Class对象的对应类有默认构造器,而执行newInstance()方法时实际上是利用默认构造器来创建该类的实例。
 - 先使用Class对象获取指定的Constructor对象,再调用Constructor对象的newInstance()方法来创建该Class对象对应类的实例。通过这种方式可以选择使用指定的构造器来创建实例。
 
Constructor c = clazz.getConstructor(String.class);
c.newInstance("xx");
调用方法
Method setProName = aClass.getDeclaredMethod("setProName",String.class);
setProName.setAccessible(true);
etProName.invoke(product,"我是一个产品");
操作属性
Field[] declaredFields = aClass.getDeclaredFields();
        for (Field declaredField : declaredFields) {
            System.out.println("fieldName:"+declaredField.getName()+" filedType:"+declaredField.getType());
        }
        Field proName = aClass.getDeclaredField("proName");
        proName.setAccessible(true);
        proName.set(product,"我是一个产品");
        System.out.println("修稿属性:"+product);
操作数组
//使用反射动态地创建数组
//创建一个元素类型为String,长度为3的数组
Object arr = Array.newInstance(String.class, 3);
//依次为arr数组中index为0,1,2的元素赋值
Array.set(arr, 0, "荣耀盒子");
Array.set(arr, 1, "荣耀8手机");
Array.set(arr, 2, "华为mate9保时捷版");
Object o1= Array.get(arr, 0);
Object o2= Array.get(arr, 1);
Object o3= Array.get(arr, 2);
System.out.println(o1);
System.out.println(o2);
System.out.println(o3);
5. 使用Demo
public class ReflectDemo {
    public static void main(String[] args) throws Exception {
        Class<Product> aClass = Product.class;
        Constructor<?>[] declaredConstructors = aClass.getDeclaredConstructors();
        for (Constructor<?> declaredConstructor : declaredConstructors) {
            System.out.println(declaredConstructor.getName());
        }
        Constructor<Product> constructor = aClass.getConstructor(int.class, String.class);
        Product product = constructor.newInstance(10, "ds");
        System.out.println("创建对象:"+product);
        //获取方法并调用
        Method setProName = aClass.getDeclaredMethod("setProName", String.class);
        setProName.setAccessible(true);
        setProName.invoke(product,"我是一个产品");
        System.out.println("调用方法:"+product);
        //获取属性,并设置属性的值
        Field[] declaredFields = aClass.getDeclaredFields();
        for (Field declaredField : declaredFields) {
            System.out.println("fieldName:"+declaredField.getName()+" filedType:"+declaredField.getType());
        }
        Field proName = aClass.getDeclaredField("proName");
        proName.setAccessible(true);
        proName.set(product,"我是一个产品");
        System.out.println("修稿属性:"+product);
        //使用反射动态地创建数组
        //创建一个元素类型为String,长度为3的数组
        Object arr = Array.newInstance(String.class, 3);
        //依次为arr数组中index为0,1,2的元素赋值
        Array.set(arr, 0, "荣耀盒子");
        Array.set(arr, 1, "荣耀8手机");
        Array.set(arr, 2, "华为mate9保时捷版");
        Object o1= Array.get(arr, 0);
        Object o2= Array.get(arr, 1);
        Object o3= Array.get(arr, 2);
        System.out.println(o1);
        System.out.println(o2);
        System.out.println(o3);
        System.out.println("end...");
    }
}
												
											Java 反射简介的更多相关文章
- Java反射简介
		
Java反射简介 1.Class类 1) 在面向对象的世界里,万事万物皆对象.(java语言中,静态的成员.普通数据类型除外) 类是不是对象呢?类是(哪个类的对象呢?)谁的对象呢? 类是对象,类是ja ...
 - Java 反射简介(转载)
		
反射机制是什么 反射机制是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法:对于任意一个对象,都能够调用它的任意一个方法和属性:这种动态获取的信息以及动态调用对象的方法的功能称为java ...
 - 理解Java反射机制
		
理解Java反射机制 转载请注明出处,谢谢! 一.Java反射简介 什么是反射? Java的反射机制是Java特性之一,反射机制是构建框架技术的基础所在.灵活掌握Java反射机制,对学习框架技术有很大 ...
 - java反射机制梳理
		
java反射机制梳理 Java反射简介 反射简介 编译和运行 编译时刻加载类是静态加载类.运行时刻加载类是动态加载类 要让Java程序能够运行,那么就得让Java类要被Java虚拟机加载.Java类如 ...
 - Java 反射(一)反射简介、原理和应用场景
		
目录 一.动态语言和动态语言的比较 动态语言 静态语言 二.反射 简介 反射的常见使用 1. 代码编辑器 2. Spring等框架的IoC容器 3. 和注解的配合使用 原理 反射优缺点 调试查看 Cl ...
 - java反射机制简介
		
1.字节码.所谓的字节码就是当java虚拟机加载某个类的对象时,首先需要将硬盘中该类的源代码编译成class文件的二进制代码(字节码),然后将class文件的字节码加载到内存中,之后再创建该类的对象 ...
 - 11.Java反射机制 哦对了,前面的序号来自随笔关于编程之路的思索第一篇
		
基本概念 在Java运行时环境中,对于任意一个类,能否知道这个类有哪些属性和方法?对于任意一个对象,能否调用它的任意一个方法? 答案是肯定的. 这种动态获取类的信息以及动态调用对象的方法的功能来自于J ...
 - 转!!java反射机制
		
Java 反射机制 基本概念 在Java运行时环境中,对于任意一个类,能否知道这个类有哪些属性和方法?对于任意一个对象,能否调用它的任意一个方法? 答案是肯定的. 这种动态获取类的信息以及动态调用对象 ...
 - Java 反射 设计模式 动态代理机制详解 [ 转载 ]
		
Java 反射 设计模式 动态代理机制详解 [ 转载 ] @author 亦山 原文链接:http://blog.csdn.net/luanlouis/article/details/24589193 ...
 
随机推荐
- Rocket - devices - TLError
			
https://mp.weixin.qq.com/s/s_6qPkT2zwdqYLw5iK7_8g 简单介绍TLError的实现. 1. 继承自DevNullDevice TLError继承自DevN ...
 - Rocket - diplomacy - wirePrefix
			
https://mp.weixin.qq.com/s/DVcA2UixnB_6vgI3SjZGyQ 调试wirePrefix方法. 1. 实现 wirePrefix用于调整名称格式,其实现 ...
 - 万字超强图文讲解AQS以及ReentrantLock应用(建议收藏)
			
| 好看请赞,养成习惯 你有一个思想,我有一个思想,我们交换后,一个人就有两个思想 If you can NOT explain it simply, you do NOT understand it ...
 - (Java实现) 洛谷 P1028 数的计算
			
题目描述 我们要求找出具有下列性质数的个数(包含输入的自然数nn): 先输入一个自然数n(n≤1000),然后对此自然数按照如下方法进行处理: 不作任何处理; 在它的左边加上一个自然数,但该自然数不能 ...
 - Java实现复数运算
			
1 问题描述 编程实现两个复数的运算.设有两个复数 和 ,则他们的运算公式为: 要求:(1)定义一个结构体类型来描述复数. (2)复数之间的加法.减法.乘法和除法分别用不用的函数来实现. (3)必须使 ...
 - 自己动手写SQL执行引擎
			
自己动手写SQL执行引擎 前言 在阅读了大量关于数据库的资料后,笔者情不自禁产生了一个造数据库轮子的想法.来验证一下自己对于数据库底层原理的掌握是否牢靠.在笔者的github中给这个database起 ...
 - Jmeter用beanshell将相应中的参数写入到本地文件中
			
实现效果: 将每次请求的指定参数写入到本地csv文件中. 实际场景:将登录请求中,服务器返回的token值获取并写入到本地csv文件中,供其他接口调用.这样在压测单接口时,不需要再进行登录,避免压测单 ...
 - struts用action的属性接收参数
			
新建一个javaweb项目 在项目中加入Struts.xml( 选中项目右键MyEclipse-->project facets-->Struts2-->finish) 在src项目 ...
 - Pipeline 脚本调用 mvn 命令失败
			
问题描述 jenkins构建job时 提示mvn 未找到命令 + export JAVA_HOME=/home/tools/jdk1.8.0_221 + JAVA_HOME=/home/tools/j ...
 - 1.vue的基础认识
			
vue 1.基于MvvM MVC--MVVM,是MVC的改进版 MVVM主要是将视图的状态和行为抽象化,把视图和业务逻辑分开 M:模型--存放状态的容器,是以数据为中心的 ...