Java 反射机制快速入门及常见方法全归纳。
目录
一、反射机制
1、基本介绍
2、原理示意图
3、反射基本代码实现
4、反射性能
二、Class 类
1、基本介绍
2、获取 Class类对象的方式
3、有 Class对象的类
三、类加载
1、基本介绍
2、连接阶段
四、常见方法取类的结构信息
1、常用类的方法
2、通过反射创建对象
一、反射机制
1、基本介绍
基本概念:在计算机科学领域,反射是指一类应用,它们能够自描述和自控制。也就是说,这类应用通过采用某种机制来实现对自己行为的描述(self-representation)和监测(examination),并能根据自身行为的状态和结果,调整或修改应用所描述行为的状态和相关的语义。
基于Java:Java中,反射是一种强大的工具。它使您能够创建灵活的代码,这些代码可以在运行时装配,无需在组件之间进行源代表链接。反射允许我们在编写与执行时,使我们的程序代码能够接入装载到JVM中的类的内部信息,而不是源代码中选定的类协作的代码。这使反射成为构建灵活的应用的主要工具。但需注意的是:如果使用不当,反射的成本很高。
注意:
1、反射机制允许程序在执行期借助于(Reflection API)取得任何类的内部信息(比如成员变量,构造器,成员方法等等), 并能操作对象的属性及方法。 反射在设计模式和框架底层都会用到。
2、加载完类之后,在堆中就产生了一个Class类型的对象(一个类只有一个Class对象),这个对象包含了类的完整结构信息。 通过这个对象得到类的结构。 这个Class对象就像一面镜子,透过这个镜子看到类的结构,所以,形象的称之为:反射。2、原理示意图
▶ 发射机制的应用
1、在运行时判断任意一个对象所属的类
2、在运行时构造任意一个类的对象
3、在运行时得到任意一个类所具有的成员变量和方法4、在运行时调用任意一个对象的成员变量和方法
5、生成动态代理
▶ 反射常用类
1、java.lang.Class : 代表一个类, Class对象表示某个类加载后在堆中的对象
2、java.lang.reflect. Method : 代表类的方法,Method对象表示某个类的方法
3、java.lang.refiect.Field : 代表类的成员变量,Field对象表示某个类的成员变量4、java.lang.reflect.Constructor : 代表类的构造方法,Constructor对象表示构造器
3、反射基本代码实现
//(1) 加载类, 返回 Class 类型的对象 clsClass cls = Class.forName(classfullpath);//(2) 通过 cls 得到你加载的类 Cat 的对象实例Object o = cls.newInstance();//(3) 通过 cls 得到你加载的类 Cat 的 methodName"hi" 的方法对象// 即:在反射中,可以把方法视为对象(万物皆对象)Method method1 = cls.getMethod(methodName);//(4) 通过 method1 调用方法: 即通过方法对象来实现调用方法method1.invoke(o); //传统方法:对象.方法() , 反射机制:方法.invoke(对象)
//java.lang.reflect.Field: 代表类的成员变量, Field 对象表示某个类的成员变量//注意:getField 不能得到私有的属性Field nameField = cls.getField("age");//得到 name 字段//传统写法:对象.成员变量 , 反射:成员变量对象.get(对象) System.out.println(nameField.get(o)); //java.lang.reflect.Constructor: 代表类的构造方法, Constructor 对象表示构造器 //()中可以指定构造器参数类型, 此处返回无参构造器 Constructor constructor = cls.getConstructor(); System.out.println(constructor); //Cat()//String.class 就是 String 类的 Class 对象,有参构造器 Constructor constructor2 = cls.getConstructor(String.class); System.out.println(constructor2); //Cat(String name)
4、反射性能
▶ 反射的优缺点
1、优点:可以动态的创建和使用对象(也是框架底层核心),使用灵活,没有反射机制, 框架技术就失去底层支撑。
2、缺点:使用反射基本是解释执行,对执行速度有影响。▶ 传统方式调用方法
public static void m1() {Cat cat = new Cat();long start = System.currentTimeMillis();for (int i = 0; i < 90; i++) {cat.hi();}long end = System.currentTimeMillis();System.out.println("m1() 耗时=" + (end - start)); }
▶ 反射方式调用方法
public static void m2() throws ClassNotFoundException, IllegalAccessException, InstantiationException, NoSuchMethodException, InvocationTargetException {Class cls = Class.forName("com.Cat");Object o = cls.newInstance();Method hi = cls.getMethod("hi");long start = System.currentTimeMillis();for (int i = 0; i < 900000000; i++) {hi.invoke(o);//反射调用方法}long end = System.currentTimeMillis();System.out.println("m2() 耗时=" + (end - start)) }
▶ 反射优化
▷ Method 和 Field,Constructor 对象都有 setAccessible()方法
▷ setAccessible 作用是启动和禁用访问安全检查的开关
▷ 参数值为true表示反射的对象在使用时取消访问检查,提高反射的效率。参数值为false则表示反射的对象执行访问检查public static void m3() throws ClassNotFoundException, IllegalAccessException, InstantiationException, NoSuchMethodException, InvocationTargetException {Class cls = Class.forName("com.hspedu.Cat");Object o = cls.newInstance();Method hi = cls.getMethod("hi");hi.setAccessible(true);//在反射调用方法时,取消访问检查long start = System.currentTimeMillis();for (int i = 0; i < 900000000; i++) {hi.invoke(o);//反射调用方法}long end = System.currentTimeMillis();System.out.println("m3() 耗时=" + (end - start)); }
二、Class 类
1、基本介绍
▶ Class也是类,因此也继承Object类
▶ Class类对象不是new出来的, 而是系统创建的
▶ 对于某个类的Class类对象, 在内存中只有一份。 因为类只加载一次
▶ 每个类的实例都会记得自己是由哪个Class实例所生成
▶ 通过Class对象可以完整地得到一个类的完整结构,通过一系列API
▶ Class对象是存放在堆的
▶ 类的字节码二进制数据, 是放在方法区的, 有的地方称为类的元数据(包括方法代码,变量名,方法名,访问权限等等)▶ 常见方法
▶ 代码示例
String classAllPath = "com.Car"; //获取到 Car 类 对应的 Class 对象 。 <?> 表示不确定的 Java 类型Class<?> cls = Class.forName(classAllPath);//输出 cls System.out.println(cls); //显示 cls 对象, 是哪个类的 Class 对象 com.CarSystem.out.println(cls.getClass());//输出 cls 运行类型 java.lang.Class
//得到包名 System.out.println( cls.getPackage().getName() );//包名
//得到全类名 System.out.println( cls.getName() );
//5. 通过 cls 创建对象实例 Car car = (Car) cls.newInstance();
//6. 通过反射获取属性 brand Field brand = cls.getField("brand");System.out.println( brand.get(car) );//输出方式
//7. 通过反射给属性赋值 brand.set(car, "奔驰");System.out.println( brand.get(car) );
//8 可以得到所有的属性(字段) Field[] fields = cls.getFields();for (Field f : fields) {System.out.println(f.getName());//名称}
2、获取 Class类对象的方式
▶(1)第一种方式
▷ 前提 : 已知一个类的全类名,且该类在类路径下, 可通过Class类的静态方法forName()获取,可能抛出ClassNotFoundException。
▷ 实例 :
Class cls1 = Class.forName("java.lang.Cat")
▷ 应用场景 : 多用于配置文件,读取类全路径,加载类。
▶(2)第二种方式
▷ 前提 : 若已知具体的类,通过类的class 获取,该方式 最为安全可靠,程序性能
▷ 实例:Class cls2 = Cat.class
▷ 应用场景 : 多用于参数传递,比如通过反射得到对应构造器对象
▶(3)第三种方式
▷前提 : 已知某个类的实例, 调用该实例的getClass0方法获取Class对象,
▷实例:
Class class = 对象.getClass(); //运行类型
▷应用场景 : 通过创建好的对象,获取Class对象.其他方式
►(4)其他方式ClassLoader cl = 对象.getClass().getClassLoader();Class clazz4 = cl.loadClass(“类的全类名”);
▶ (5)基本数据(int, charboolean, float,double, byte,long,short) 按如下方式得到Class类对象
Class cls = 基本数据类型.class
▶ (6)基本数据类型对应的包装类,可以通过.TYPE 得到Class类对象
Class cls = 包装类.TYPE
3、有 Class对象的类
▷ 外部类,成员内部类,静态内部类,局部内部类, 匿名内部类
▷ interface : 接口
▷ 数组
▷ enum : 枚举
▷ annotation : 注解基本数据类型
▷ voidClass<String> cls1 = String.class;//外部类Class<Serializable> cls2 = Serializable.class;//接口Class<Integer[]> cls3 = Integer[].class;//数组Class<float[][]> cls4 = float[][].class;//二维数组Class<Deprecated> cls5 = Deprecated.class;//注解Class<Thread.State> cls6 = Thread.State.class;//枚举Class<Long> cls7 = long.class;//基本数据类型Class<Void> cls8 = void.class;//void 数据类型Class<Class> cls9 = Class.class;
三、类加载
1、基本介绍
▶ 基本概念
反射机制是java实现动态语言的关键,也就是通过反射实现类动态加载。①静态加载 : 编译时加载相关的类, 如果没有则报错, 依赖性太强。②动态加载 : 运行时加载需要的类,如果运行时不用该类, 即使存在该类,则也不会报错,降低了依赖性。
▶ 什么时候加载类▷ 当创建对象时(new)。 //静态加载
▷ 当子类被加载时,父类也加载。 //静态加载
▷ 调用类中的静态成员时。 //静态加载
▷ 通过反射。 //动态加载,Class.forName("com.Cat");
▶ 类加载过程图
▶ 类加载各阶段图
▶ 加载阶段
2、连接阶段
▶验证阶段
▷目的是为了确保Class文件的字节流中包含的信息符合当前虚拟机的要求,并且不会危害虚拟机自身的安全。
▷验证包括 : 文件格式验证(是否以魔数 oxcafebabe开头)、元数据验证、字节码验证和符号引用验证
▷可以考虑使用-Xverify : none 参数来关闭大部分的类验证措施, 缩短虚拟机类加载的时间。▶准备阶段
▷ JVM 会在该阶段对静态变量,分配内存井默认初始化(对应数据类型的默认初始值,如 0、OL、 null, false 等),这些变量所使用的内存都将在方法区中进行分配。
//1. n1 是实例属性, 不是静态变量,因此在准备阶段,是不会分配内存public int n1 = 10;
//2. n2 是静态变量,分配内存 n2 是默认初始化 0 ,而不是 20public static int n2 = 20;
//3. n3 是 static final 是常量, 他和静态变量不一样, 因为一旦赋值就不变 n3 = 30public static final int n3 = 30;
▶ 解析阶段
虚拟机将常量池里面的符号引用替换为直接引用的的过程。
▶ 初始化
▷ 到初始化阶段, 才真正开始执行类中定义的Java程序代码,此阶段是执行<clinit>() 方法的过程。
▷ <clinit>()方法是由编译器按语句在源文件中出现的顺序,依次自动收集类中的所有静态变量的赋值动作和静态代码块中的语句,并进行合并。
▷ 虚拟机会保证一个类的<clinit>()方法在多线程环境中被正确地加锁、同步,如果多个线程同时去初始化一个类,那么只会有一个线程去执行这个类的<clinit>()方法,其他线程都需要阻塞等待,直到活动线程执行<clinit>() 方法完毕。
四、常见方法取类的结构信息
1、常用类的方法
▶ java.lang.Class 类
方法名 功能 getName 获取全类名 getSimpleName 获取简单类名 getFields 获取所有public修饰的属性,包含本类以及父类的 getDeclaredFields 获取本类中所有属性 getMethods 获取所有public修饰的方法,包含本类以及父类的 getDeclaredMethods 获取本类中所有方法 getConstructors 获取本类所有public修饰的构造器 getDeclaredConstructors 获取本类中所有构造器 getPackage 以Package形式返回包信息 getSuperClass 以Class形式返回父类信息 getinterfaces 以Class[ ]形式返回接口信息 getAnnotations 以Annotation[ ] 形式返回注解信息 ▶ java.lang.reflect. Method 类
方法名 功能 getModifiers 以int形式返回修饰符。[说明:默认修饰符是0 ,public 是1,private是2 ,protected 是4 ,static是8, final 是 16] getReturnType 以Class形式获取 返回类型 getName 返回方法名 getParameterTypes 以Class返回参数类型数组 ▶ java.lang.refiect.Field 类
方法名 功能 getModifiers 以int形式返回修饰符。[说明:默认修饰符是0 ,public 是1,private是2 ,protected 是4 ,static是8, final 是 16] getType 以Class形式返回类型 getName 返回属性名 ▶ java.lang.reflect.Constructor 类
方法名 功能 getModifiers 以int形式返回修饰符 getName 返回构造器名(全类名) getParameterTypes 以Class[ ]返回参数类型数组 2、通过反射创建对象
▶ 方式一 : 调用类中的public修饰的无参构造器
▶ 方式二 : 调用类中的指定构造器
▶ Class类相关方法:
▷ newlnstance : 调用类中的无参构造器, 获取对应类的对象▷ getConstructor(Class..clazz) : 根据参数列表,获取对应的public构造器对象
▷ getDecalaredConstructor(Class..clazz) : 根据参数列表,获取对应的所有构造器对象
▶ Constructor类相关方法:▷ setAccessible : 暴破
▷ newlnstance(Object..obj) : 调用构造器▶ 代码实现
//1. 先获取到 User 类的 Class 对象 Class<?> userClass = Class.forName("com.reflection.User");
//2. 通过 public 的无参构造器创建实例 Object o = userClass.newInstance();
//3. 通过 public 的有参构造器创建实例,先得到对应构造器 Constructor<?> constructor = userClass.getConstructor(String.class); //创建实例,并传入实参 Object h = constructor.newInstance("hi");
//4. 通过非 public 的有参构造器创建实例,得到 private 的构造器对象 Constructor<?> constructor1 = userClass.getDeclaredConstructor(int.class, String.class);//创建实例,暴破【暴力破解】 , 使用反射可以访问 private 构造器/方法/属性 constructor1.setAccessible(true); Object user2 = constructor1.newInstance(传入对应参数...);
Java 反射机制快速入门及常见方法全归纳。相关推荐
- Java反射机制涉及的类常见方法使用总结
1 import java.lang.reflect.Constructor; 2 import java.lang.reflect.*; 3 4 /*Class:代表一个字节码文件的对象,每当有类被 ...
- 利用Java反射机制调用类的私有方法
利用Java反射机制调用类的私有方法 引言 来吧·展示 参考链接 引言 如何调用其他类的私有方法呢? 可以利用Java的反射机制,去调用其他类的私有方法 来吧·展示 package cn.learn. ...
- java反射机制调用带参数的方法_Java反射机制:跟着代码学反射
1. 前言 在OOP的世界里,万物皆对象.也就是说,我们可以将任何东西抽象成一个对象. 比如人,可以抽象成一个Person类,通过new Person()来实例化一个对象:再比如鸭子,可以抽象成一个D ...
- Java 反射机制详解:私有方法调用头大?如何通过反射调用类中的私有方法?
文章目录 前言 一.私有方法在本类中直接调用 1.1.在本类中实例化,调用私有方法 1.2.尝试在其他类直接调用私有方法(错误示范) 二.使用反射实例化类强制调用私有方法 2.1.使用类加载器加载被调 ...
- Java反射机制--笔记
1.认识Class类 任何一个类都是Class类的实例对象,这个实例对象有三种表示方式. 1 /*java 反射机制*/ 2 // 获取类的方法 3 UserDao userDao = new Use ...
- java 反射 Gc_深入浅析Java反射机制
Java反射机制是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法:对于任意一个对象,都能够调用它的任意一个方法和属性:这种动态获取的信息以及动态调用对象的方法的功能称为Java语言的反 ...
- [转]Java反射机制详解
目录 1反射机制是什么 2反射机制能做什么 3反射机制的相关API ·通过一个对象获得完整的包名和类名 ·实例化Class类对象 ·获取一个对象的父类与实现的接口 ·获取某个类中的全部构造函数 - 详 ...
- 【Java】Java 反射机制浅析
1.概述 转载:https://www.cnblogs.com/gulvzhe/archive/2012/01/27/2330001.html Java反射机制是在运行状态中,对于任意一个类,都能够知 ...
- 详解Java反射机制------入门篇
一.什么叫Java反射机制? Java中的反射机制是指在运行状态中,对于任意一个类,能够动态获取这个类中的属性和方法:对于任意一个对象,都能够任意调用它的属性和方法.这种动态获取类的信息以及动态调用对 ...
最新文章
- apache常用的配置指令:ServerRoot
- 存clob为空的值_给Oracle数据库中CLOB字段插入空值
- Go聊天室的思路:一个拨号 一个监听
- SAP 电商云 Spartacus UI 产品搜索结果的设计明细
- 通过点击事件监听 setOnClickListener 彻底理解回调-Android
- Mysql编码教程_mysql编码设置教程 mysql编码要怎么设置呢
- fn:replace()函数
- ffmpeg抓取rtsp流并保存_详细解析RTSP框架和数据包分析(1)
- 求一个3*3矩阵两条对角线上元素之和(每个元素只加一次) C语言
- 用自然语言教育人工智能:百度新算法发展出zero-shot学习能力
- linux像win7,如何使Ubuntu看起来像Windows 7
- 如何用计算机函数来求加权总分,Excel计算加权总分,函数公式还是超级表厉害,一起看看!-excel乘法函数...
- 留人间多少爱,迎浮世千重变;和有情人,做快乐事, 别问是劫是缘
- linux mplayer rpm,mplayer - movie player for linux
- XILINX FPGA OV5640 摄像头驱动(一)
- 【已解决】iphone和mac的备忘录、提醒事项、日历等无法同步。MacBook点击“更新Apple ID 设置”无反应。
- 【SQL开发实战技巧】系列(六):从执行计划看NOT IN、NOT EXISTS 和 LEFT JOIN效率,记住内外关联条件不要乱放
- Virtualbox的centos7 Nat和桥接网络配置
- python 多进程并发 阻塞_python并发编程多进程(一)
- Xlinx的 FIFO IP核