java 反射详解
反射的概念和原理
类字节码文件是在硬盘上存储的,是一个个的.class文件。我们在new一个对象时,JVM会先把字节码文件的信息读出来放到内存中,第二次用时,就不用在加载了,而是直接使用之前缓存的这个字节码信息。 字节码的信息包括:类名、声明的方法、声明的字段等信息。在Java中“万物皆对象”,这些信息当然也需要封装一个对象,这就是Class类、Method类、Field类。 通过Class类、Method类、Field类等等类 可以得到 这个类字节码的全部信息,甚至可以不用new关键字就创建一个实例,可以执行一个对象中的方法,设置或获取字段的值,这就是反射技术。 注意:在反射技术中一个类的任何成员都有对应 的类进行描述。 比如: 成员变量(Field) 方法----> Method类 |
Class类
Class类解释说明:
Java中有一个Class类用于代表某一个类的字节码。通过获取这个class类的对象,就可以得到字节码的一些信息 |
得到class对象的三种方法
Java提供了三种方式获取类的字节码 forName():forName方法用于加载某个类的字节码到内存中,并使用class对象进行封装(推荐使用这个,一般配合配置文件读取类的全名 创建对象) 类名.class 对象.getClass() |
例子:
Person类,用于被测试的类
package cn.itcast.reflect; public class Person { private int id; String name; public Person(int id,String name){ this.id = id; this.name = name; } public Person(){} private Person(int id){ this.id = id; } public void eat(int num){ System.out.println(name+"吃很"+num+"斤饭"); } private static void sleep(int num){ System.out.println("明天睡上"+num+"小时"); } public static void sum(int[] arr){ System.out.println("长度是:"+ arr.length); } @Override public String toString() { return " 编号:"+ this.id +" 姓名:"+ this.name; } } |
获取class对象的代码:
public static void main(String[] args) throws ClassNotFoundException { //推荐使用: 获取Class对象的方式一 Class clazz1 = Class.forName("cn.itcast.reflect.Person"); System.out.println("clazz1:"+ clazz1); //获取Class对象的方式二: 通过类名获取 Class clazz2 = Person.class; System.out.println("clazz1==clazz2?"+ (clazz1==clazz2)); //获取Class对象的方式三 :通过对象获取 Class clazz3 = new Person(110,"狗娃").getClass(); System.out.println("clazz2==clazz3?"+ (clazz2==clazz3)); } |
打印结果:
clazz1:class cn.itcast.reflect.Person clazz1==clazz2?true clazz2==clazz3?true |
通过class对象获取一些信息
获取类的全名(包名+类名),类的简单名称(不带包名,只有类名),类的修饰符
API解释说明:
1. getName()类的名称(全名,全限定名) 2 getSimpleName()类的的简单名称(不带包名) 3. getModifiers(); 类的的修饰符 |
例子:
import java.lang.reflect.Constructor; import java.lang.reflect.Modifier; //获取到对应的Class对象 Class clazz = Class.forName("cn.itcast.reflect.Person"); System.out.println("-----------获取类的全名------------"); //通过Class对象获取类的全名(包含 包名) String fullName = clazz.getName(); System.out.println(fullName); //通过class对象获取类名(不包含包名) String simpleName = clazz.getSimpleName(); System.out.println(simpleName); //通过class对象获取类的修饰符 int modifyName = clazz.getModifiers(); String retval = Modifier.toString(modifyName); System.out.println("Class Modifier = " + retval); |
打印结果:
-----------获取类的全名------------ cn.itcast.reflect.Person Person Class Modifier = public |
获取类的全部构造函数,私有的,公有的
API:
getConstructors()获取一个类的所有公共的构造方法 getDeclaredConstructors(); //获取到一个类的所有构造方法,包括私有的在内 。 |
代码:
//通过Class对象获取对应的构造方法 Constructor[] constructors = clazz.getConstructors(); // getConstructors()获取一个类的所有公共的构造方法 for(Constructor constructor : constructors){ System.out.println(constructor); } System.out.println("\n-------------获取所有的构造方法,包括私有的-------------"); Constructor[] constructors2 = clazz.getDeclaredConstructors(); //获取到一个类的所有构造方法,包括私有的在内 。 for(Constructor constructor2 : constructors2){ System.out.println(constructor2); } |
打印的结果:
----------获取所有的公共构造方法-------------- public cn.itcast.reflect.Person() public cn.itcast.reflect.Person(int,java.lang.String) -------------获取所有的构造方法,包括私有的------------- private cn.itcast.reflect.Person(int) public cn.itcast.reflect.Person() public cn.itcast.reflect.Person(int,java.lang.String) |
获取指定的构造对象,然后new出一个对象(这个是不能new出private修饰的构造函数)
API:
newInstance方法构造对象,默认使用的是无参数的构造方法 举例:Object ins = clazz.newInstance(); getConstructor(参数类型的.class)获取单个指定的构造方法。 举例:clazz.getConstructor(int.class,String.class); 局限地方:不能获取private的构造函数 |
例子:
System.out.println("\n获取指定的构造方法,然后new出一个对象"); //newInstance方法构造对象,默认使用的是无参数的构造方法 Object ins = clazz.newInstance(); Person p = (Person) ins; System.out.println(p); //getConstructor 获取单个指定的构造方法。 clazz.getConstructor(int.class,String.class); Constructor constructor = clazz.getConstructor(int.class,String.class); // Person p2 = (Person) constructor.newInstance(999,"小城"); // newInstance()创建一个对象 System.out.println(p2); |
打印结果:
获取指定的构造方法,然后new出一个对象 编号:0 姓名:null 编号:999 姓名:小城 |
获取指定的私有构造函数
API:
getDeclaredConstructor 方法:获取指定的私有构造函数 |
例子:
System.out.println("\n获取指定的私有构造函数"); Constructor constructor1 = clazz.getDeclaredConstructor(int.class); System.out.println(constructor1); |
打印结果:
获取指定的私有构造函数 private cn.itcast.reflect.Person(int) |
暴力反射:
System.out.println("暴力反射"); Constructor constructor2 = clazz.getDeclaredConstructor(int.class); System.out.println(constructor2); constructor2.setAccessible(true);//设置为true表示可以进行暴力反射,强行用private 构造函数new对象 Person p3 =(Person) constructor2.newInstance(100); System.out.println(p3); |
打印结果:
暴力反射 private cn.itcast.reflect.Person(int) 编号:100 姓名:null |
获取构造函数的完整代码:
package cn.itcast.reflect; import java.lang.reflect.Constructor; import java.lang.reflect.Modifier; /* 如何通过Class对象获取构造方法。 */ public class Demo2 { public static void main(String[] args) throws Exception { //获取到对应的Class对象 Class clazz = Class.forName("cn.itcast.reflect.Person"); // System.out.println("-----------获取类的全名------------"); // //通过Class对象获取类的全名(包含 包名) // String fullName = clazz.getName(); // System.out.println(fullName); // // // //通过class对象获取类名(不包含包名) // String simpleName = clazz.getSimpleName(); // System.out.println(simpleName); // // //通过class对象获取类的修饰符 // int modifyName = clazz.getModifiers(); // String retval = Modifier.toString(modifyName); // System.out.println("Class Modifier = " + retval); // System.out.println("----------获取所有的公共构造方法--------------"); // // //通过Class对象获取对应的构造方法 // Constructor[] constructors = clazz.getConstructors(); // getConstructors()获取一个类的所有公共的构造方法 // for(Constructor constructor : constructors){ // System.out.println(constructor); // } // // System.out.println("\n-------------获取所有的构造方法,包括私有的-------------"); // Constructor[] constructors2 = clazz.getDeclaredConstructors(); //获取到一个类的所有构造方法,包括私有的在内 。 // for(Constructor constructor2 : constructors2){ // System.out.println(constructor2); // } // System.out.println("\n获取指定的构造方法,然后new出一个对象"); // // //newInstance方法构造对象,默认使用的是无参数的构造方法 // Object ins = clazz.newInstance(); // Person p = (Person) ins; // System.out.println(p); // // //getConstructor 获取单个指定的构造方法。 // clazz.getConstructor(int.class,String.class); // Constructor constructor = clazz.getConstructor(int.class,String.class); // // Person p2 = (Person) constructor.newInstance(999,"小城"); // newInstance()创建一个对象 // System.out.println(p2); // System.out.println("\n获取指定的私有构造函数"); // Constructor constructor1 = clazz.getDeclaredConstructor(int.class); // System.out.println(constructor1); // // System.out.println("暴力反射"); Constructor constructor2 = clazz.getDeclaredConstructor(int.class); System.out.println(constructor2); constructor2.setAccessible(true);//设置为true表示可以进行暴力反射,强行用private 构造函数new对象 Person p3 =(Person) constructor2.newInstance(100); System.out.println(p3); } } |
通过class类获取 字节码中的方法信息
获取全部的方法部分
Api详解:
getMethods() 获取所有 的公共方法(不包括私有的)包括父类继承的。 getDeclaredMethods()//获取到所有的方法(私有的也有),但是不包含父类的方法。 |
例子:
//获取到对应的Class对象 Class clazz = Class.forName("cn.itcast.reflect.Person"); //获取到所有公共的方法 Method[] methods = clazz.getMethods(); // getMethods() 获取所有 的公共方法(不包括私有的)包括父类继承的。 //Method[] methods = clazz.getDeclaredMethods(); //获取到所有的方法(私有的也有),但是不包含父类的方法。 for(Method method : methods){ System.out.println(method); } |
获取指定的方法,并执行它
API:
getMethod("eat", int.class);//获取指定的方法,但是不能获取私有的方法 getDeclaredMethod("sleep",int.class);////执行私有的方法 setAccessible(true);//设置访问权限允许访问 invoke(p, 6);//invoke 执行一个方法。 第一个参数:方法的调用对象。 第二参数: 方法所需要的参数。 |
用法:
Person p = new Person(110,"狗娃"); //获取指定的方法,但是不能获取私有的方法 Method m = clazz.getMethod("eat", int.class); //invoke 执行一个方法。 第一个参数:方法的调用对象。 第二参数: 方法所需要的参数。 m.invoke(p, 3); //执行私有的方法 Method m2 =clazz.getDeclaredMethod("sleep",int.class); //设置访问权限允许访问 m2.setAccessible(true); //静态的方法第一个参数写null,表示没有对象调用,类本身会调用 m2.invoke(p, 6); |
暴力反射:
//暴力反射,获取私有的方法,并执行它 Method m = clazz.getDeclaredMethod("sleep", int.class); System.out.println(m); m.setAccessible(true); m.invoke(p, 8); |
获取方法部分完整代码:
package cn.itcast.reflect; import java.lang.reflect.Method; /* 通过Class对象获取到对应的方法。 在反射技术中使用了Method类描述了方法的。 */ public class Demo3 { public static void main(String[] args) throws Exception { //获取到对应的Class对象 Class<?> clazz = Class.forName("cn.itcast.reflect.Person"); // //获取到所有公共的方法 // Method[] methods = clazz.getMethods(); // getMethods() 获取所有 的公共方法(不包括私有的)包括父类继承的。 //// Method[] methods = clazz.getDeclaredMethods(); //获取到所有的方法(私有的也有),但是不包含父类的方法。 // for(Method method : methods){ // System.out.println(method); // } Person p = new Person(110,"狗娃"); // // //获取指定的方法,但是不能获取私有的方法 // Method m = clazz.getMethod("eat", int.class); // //invoke 执行一个方法。 第一个参数:方法的调用对象。 第二参数: 方法所需要的参数。 // m.invoke(p, 3); // // // //执行私有的方法 // Method m2 =clazz.getDeclaredMethod("sleep",int.class); // //设置访问权限允许访问 // m2.setAccessible(true); // //静态的方法第一个参数写null,表示没有对象调用,类本身会调用 // m2.invoke(p, 6); // Method m = clazz.getMethod("sum", int[].class); // m.invoke(p,new int[]{12,5,9}); //暴力反射,获取私有的方法,并执行它 Method m = clazz.getDeclaredMethod("sleep", int.class); System.out.println(m); m.setAccessible(true); m.invoke(p, 8); } } |
通过class对象获取到字段信息
代码;
public static void main(String[] args) throws Exception { //获取到对应的Class对象 Class clazz = Class.forName("cn.itcast.reflect.Person"); //获取 到所有的成员变量(包含私有的) // Field[] fields = clazz.getDeclaredFields(); // for(Field field : fields){ // System.out.println(field); // } Person p = new Person(); Field field = clazz.getDeclaredField("id"); //设置访问权限可以访问 field.setAccessible(true); field.set(p, 110); //第一个参数: 设置该数据 的成员变量, 第二个参数:属性值。 System.out.println(p); } |
反射API总结:
Class类
1. getName()类的名称(全名,全限定名) 2 getSimpleName()类的的简单名称(不带包名)
|
4.getConstructors()获取一个类的所有公共的构造方法 5.getDeclaredConstructors(); //获取到一个类的所有构造方法,包括私有的在内 。 |
6.newInstance方法构造对象,默认使用的是无参数的构造方法 举例:Object ins = clazz.newInstance(); 7.getConstructor(参数类型的.class)获取单个指定的构造方法。 举例:clazz.getConstructor(int.class,String.class); 局限地方:不能获取private的构造函数 |
8.getDeclaredConstructor 方法:获取指定的私有构造函数 |
方法部分 |
getMethods() 获取所有 的公共方法(不包括私有的)包括父类继承的。 getDeclaredMethods()//获取到所有的方法(私有的也有),但是不包含父类的方法。 |
getMethod("eat", int.class);//获取指定的方法,但是不能获取私有的方法 |
clazz.getDeclaredMethod("sleep",int.class);//执行私有的方法 m2.invoke(p, 6); //表示m2这个方法被p这个对象执行了,后面的参数是m2这个方法需要的参数 |
字段部分 1.获取公共字段 Field[] getFields() 2.获取指定参数的公共字段 Field getField(String name) 3.获取所有的字段 Field[] getDeclaredFields() 4.获取指定参数的字段,包括私用 Field getDeclaredField(String name) |
一般用getDeclaredConstructor方法进行获取构造函数,一般不获取private修饰的构造函数
java 反射详解的更多相关文章
- Java基础13:反射详解
本节主要介绍Java反射的原理,使用方法以及相关的技术细节,并且介绍了关于Class类,注解等内容. 具体代码在我的GitHub中可以找到 https://github.com/h2pl/MyTech ...
- Java基础-面向接口编程-JDBC详解
Java基础-面向接口编程-JDBC详解 作者:尹正杰 版权声明:原创作品,谢绝转载!否则将追究法律责任. 一.JDBC概念和数据库驱动程序 JDBC(Java Data Base Connectiv ...
- java基础(3)--详解String
java基础(3)--详解String 其实与八大基本数据类型一样,String也是我们日常中使用非常频繁的对象,但知其然更要知其所以然,现在就去阅读源码深入了解一下String类对象,并解决一些我由 ...
- Linux基础知识之挂载详解(mount,umount及开机自动挂载)
Linux基础知识之挂载详解(mount,umount及开机自动挂载) 转载自:http://www.linuxidc.com/Linux/2016-08/134666.htm 挂载概念简述: 根文件 ...
- 学习Spring必学的Java基础知识(1)----反射(转)
引述要学习Spring框架的技术内幕,必须事先掌握一些基本的Java知识,正所谓"登高必自卑,涉远必自迩".以下几项Java知识和Spring框架息息相关,不可不学(我将通过一个系 ...
- 学习Spring必学的Java基础知识(1)----反射
引述要学习Spring框架的技术内幕,必须事先掌握一些基本的Java知识,正所谓"登高必自卑,涉远必自迩".以下几项Java知识和Spring框架息息相关,不可不学(我将通过一个系 ...
- JAVA基础知识|java虚拟机(JVM)
一.JVM简介 java语言是跨平台的,兼容各种操作系统.实现跨平台的基石就是虚拟机(JVM),虚拟机不是跨平台的,所以不同的操作系统需要安装不同的jdk版本(jre=jvm+类库:jdk=jre+开 ...
- [java基础知识]java安装步骤
jre: java运行环境. jre = java虚拟机 + 核心类库(辅助java虚拟机运行的文件).如果只是运行java程序,只需要安装jre. jdk: java开发工具集 jd ...
- java基础知识——Java的定义,特点和技术平台
(作者声明:对于Java编程语言,很多人只知道怎么用,却对其了解甚少.我也是其中一员.所以菜鸟的我,去查询了教科书以及大神的总结,主要参考了<Java核心技术>这本神作.现在分享给大家!) ...
- 计算机基础知识和tcp详解
计算机基础知识 作为应用软件开发程序员是写应用软件的,而应用软件必须应用在操作系统之上,调用操作系统接口,由操作系统控制硬件 比如客户端软件想要基于网络发送一条消息给服务端软件,流程是: 1.客户端软 ...
随机推荐
- ArrayList 和Vector ,HashTable和HashMap异同
相同点: 1.都实现了List接口(List接口继承自Collection接口) 2.有序集合,数据可重复,可按索引号取值(而HashSet无序,不可重复) 不同点: 1.Vector是线程安全的,而 ...
- 福科田led漫反射灯条生产工序
led漫反射灯条简称透镜灯条,它两个其实是一种产品.下面我来讲讲led漫反射灯条的生产工序.首先介绍的是led漫反射灯条的生产总流程. 一. led漫反射灯条的生产总流程: 1. ...
- HDU 6006 Engineer Assignment:状压dp
题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=6006 题意: 在Google中,有个n项目,m个专家.第i个项目涉及c[i]个领域,分别为a[i][0 ...
- 一步一步学多线程-ThreadLocal源码解析
上网查看了很多篇ThreadLocal的原理的博客,上来都是文字一大堆,费劲看了半天,大脑中也没有一个模型,想着要是能够有一张图明确表示出来ThreadLocal的设计该多好,所以就自己看了源码,画了 ...
- MATLAB实现聚类
%% Cluster x = data; % 传入数据 [h, w] = size(x); num_cluster = 12; % 聚类数 T = clusterdata(x, num_cluster ...
- 【二次开发jumpserver】——整合jumpserver与zabbix推送主机功能
jasset/forms.py "ip", "other_ip", "hostname", "port", " ...
- 利用Div+CSS(嵌套+盒模型)布局页面完整实例流程
Div+CSS(嵌套+盒模型)布局页面完整实例流程: <!DOCTYPE html><html> <head> <meta charset="UT ...
- MySQL视图了解
视图是什么 视图是一种虚拟存在的表,不会在数据库中实际存在.相比较普通的表,有如下优势 简单:使用视图的用户完全不需要关心后面对应的表的结构.关联条件和筛选条件,对用户来说已经是过滤好的复合条件的结果 ...
- Linux学习总结(六)—— CentOS软件包管理:源代码安装
源代码包安装方式相对RPM/YUM安装方式较为复杂,并且安装过程更长,一般只在源码研究的时候才会使用这种方式去编译. 源码安装分为解压缩包.配置信息.编译安装三个步骤,安装地址地址一般是/usr/lo ...
- javascript DOM 笔记
以下内容来自<javasript DOM 编程艺术>第二版 dom中三种重要的节点:元素节点.属性节点.文本节点. 几种节点的重要属性:nodeValue,nodeType(为数字1.2. ...