reflection反射
reflection反射
动态和静态语言
动态语言
动态语言就是一类在运行时可以改变其结构的语言,通俗点说就是在运行时代码可以根据某些条件改变自身结构
主要动态语言:object-C,C#,JavaScript,PHP,Python等.
静态语言
- 与动态语言相对应,运行时结构不可变的语言就是静态语言。如java,c,c++。
- java不是动态语言,但java可以被称为“准动态语言”。即java有一定的动态性,我们可以利用反射机制获得类似动态语言的特性,java动态性让编程时更加灵活
java反射机制概述
反射概述
- 反射是java被视为动态语言的关键
- 反射机制允许程序在运行期间借助于Reflection API取得任何类的内部信息,
- 反射能直接操作任意对象的内部属性以及方法
- 反射就是我们正常的方式反过来
- 反射可以通过对象反射出类的名称
- 一个类被加载后,类的整个结构都会被封装在Class对象中
狂神 反射 反射概述视频06:29
在堆内存的方法区中就产生了一个Class类型的对象(一个类只有一个Class对象),这个对象包含了类的完整结构信息,这个对象就想一面镜子,透过这面镜子看到类的结构,所以我们称之为:反射
狂神 反射 获得反射对象01:29
反射的优缺点
优点
- 可以实现动态创建对象和编译,体现出很大的灵活性
缺点
- 对性能有影响。使用反射基本上是一解释操作,我们可以告诉JVM,我们希望做什么并且它满足我们的要求。这类操作总是慢于直接相同操作。
Class类
Class的概述
狂神 反射 得到Class类的几种方式00:04
Class的常用方法
狂神 反射 得到Class类的几种方式01:47
哪些类型有Class对象
狂神 反射 所有类型的Class对象
![哪些类型有Class对象](C:\Users\lyj\Desktop\Learning summary\img\reflection反射\哪些类型有Class对象.png)
Class c1 = Object.class;//类
Class c2 = Comparable.class;//接口
Class c3=String[].class;//一维数组
Class c4=int[][].class;//二维数组
Class c5= Override.class;//注解
Class c6= ElementType.class;//枚举
Class c7=Integer.class;//基本类型
Class c8=void.class;//空
Class c9=Class.class;//Class
java内存分析
狂神类加载内存分析00:23
类的加载过程
狂神类加载内存分析00:39
类的加载和Class Loader的理解
加载
- 编译过后将class文件加载到内存当中,并且将这些静态数据转换成方法区的运行时数据结构,然后生成一个Class对象
链接
- 将java类的二进制代码合并到JVM的运行环境中
验证
- 确保加载的类信息符合JVM规范,没有安全方面的问题
准备
- 正式为类变量(static)分配内存并设置类变量默认初始值的阶段,这些内存都将在方法区中进行分配
解析
- 虚拟机常量池内的符号引用(常量名)替换为直接引用(地址)的过程
初始化
- 执行类构造器()方法的过程。类构造器()方法是由编译期自动收集类中所有类变量的赋值动作和静态代码块中的语句合并产生的。(类构造器是构造器信息的,不是构造该类对象的构造器)。
- 当初始化一个类的时候,如果发现其父类还没有进行初始化,则需要先触发其父类的初始化。
- 虚拟机会保证一个类的()方法在多线程环境中被正确加锁和同步。
public class Test04 {
public static void main(String[] args) {
A a = new A();
System.out.println(A.m);
}
}
class A{
static {
System.out.println("A类静态代码块初始化");
m=300;
}
static int m = 100;
public A() {
System.out.println("A类的无参构造初始化");
}
}
什么时候会发生类初始化
类主动引用(一定会发生类的初始化)
- 当虚拟机启动,先初始化main方法所在的类
- new一个类的对象
- 调用类的静态成员(除了final常量)和静态方法
- 使用java.lang.reflect包的方法对类进行反射调用
- 当初始化一个类,如果其父类没有被初始化,则先会初始化它的父类
类的被动引用(不会发生类的初始化)
- 当访问一个静态域时,只有真正声明这个域的类才会被初始化。如:当通过子类引用父类的静态常量,不会导致子类初始化
- 通过数组定义类引用,不会触发此类的初始化
- 引用常量不会触发此类的初始化(常量在链接阶段就存入调用类的常量池中了)
类加载器的作用
类加载的作用
- 将class文件字节码内容加载到内存中,并将这些静态数据转换成方法区的运行时数据结构,然后在堆中生成一个代表这个类的java.lang.Class对象,作为方法区中类数据的访问入口。
类缓存
- 标准的javaSE类加载器可以按照要求查找类,但一旦某个类被加载到加载器中,它将维持加载(缓存)一段时间。不过JVM垃圾回收机制可以回收这些Class对象。
JVM规范定义了如下类型的加载器
反射的方法
获取类名
System.out.println(c1.getName());//获得包名加类名(由于我直接在src下写的类所有没有包名)
System.out.println(c1.getSimpleName());//获得类名
获取属性
user类内全部属性都为private
//获得类的属性
System.out.println("==============");
Field[] fields = c1.getFields();//只能找到public属性
for (Field field : fields) {
System.out.println(field);
}
Field[] declaredFields = c1.getDeclaredFields();//找到全部的属性
for (Field field : declaredFields) {
System.out.println(field);
}
System.out.println("==================");
System.out.println(c1.getDeclaredField("name"));//获取指定属性不管修饰符是什么
System.out.println(c1.getField("name"));//只能指定获取public属性
因为name是private所有报异常
获得类的全部类
//获取全部类的方法
System.out.println("==================");
Method[] methods = c1.getMethods();//获得本类和父类全部的public方法
for (Method method : methods) {
System.out.println(method);
}
System.out.println("==================");
methods=c1.getDeclaredMethods();//获得本类的所有方法(包括private)
for (Method method : methods) {
System.out.println(method);
}
- 获得本类和父类全部的public方法
- 获得本类的所有方法(包括private)
获得指定类的方法
//获得类的指定方法
//为什么后面要参数,因为java里有重载
System.out.println("==================");
Method getName = c1.getMethod("getName",null);
Method setName = c1.getMethod("setName", String.class);
System.out.println(setName);
System.out.println(getName);
获得构造器
//获得构造器
System.out.println("==================");
Constructor[] constructors = c1.getConstructors();//获得public构造器
for (Constructor constructor : constructors) {
System.out.println(constructor);
}
System.out.println("==================");
constructors = c1.getDeclaredConstructors();//获取全部构造器(后面单列模式构造方法是private)
for (Constructor constructor : constructors) {
System.out.println(constructor);
}
获得指定构造器
//获得指定构造器
System.out.println("==================");
Constructor constructor = c1.getConstructor(String.class, int.class, int.class);//获得public构造器
System.out.println(constructor);
constructor=c1.getDeclaredConstructor(String.class, int.class, int.class);//获取构造器(后面单列模式构造方法是private)
System.out.println(constructor);
有了Class对象,能做什么?
public static void main(String[] args) throws Exception {
//获得CLass对象
Class c1 = Class.forName("User");
//构造一个对象
User user = (User) c1.newInstance();
System.out.println(user);
//通过构造器创建对象
Constructor constructor = c1.getDeclaredConstructor(String.class, int.class, int.class);
User user2 = (User) constructor.newInstance("青牛", 1, 18);
System.out.println(user2);*/
//通过反射调用普通方法
User user = (User) c1.newInstance();
//通过反射调用方法
Method setName = c1.getDeclaredMethod("setName", String.class);
setName.invoke(user,"青牛");
System.out.println(user.getName());
//通过反射操作属性
User user = (User) c1.newInstance();
Field name = c1.getDeclaredField("name");
//不能直接操作私有属性,我们需要关闭程序的安全检测
name.setAccessible(true);//这个就是关闭检测的,参数写true
name.set(user,"青牛");
System.out.println(user.getName());
}
setAccessible
性能测试
//普通方式调用
public static void test01(){
User user =new User();
long startTime = System.currentTimeMillis();
for (int i = 0; i < 2000000000; i++) {
user.getName();
}
long endTime = System.currentTimeMillis();
System.out.println("普通方式执行时间:"+(endTime-startTime)+"ms");
}
//通过反射调用
public static void test02() throws Exception {
User user =new User();
Class c1 = user.getClass();
Method getName = c1.getMethod("getName", null);
long startTime = System.currentTimeMillis();
for (int i = 0; i < 2000000000; i++) {
getName.invoke(user,null);
}
long endTime = System.currentTimeMillis();
System.out.println("反射方式执行时间:"+(endTime-startTime)+"ms");
}
//通过反射调用 关闭检测
public static void test03() throws Exception {
User user =new User();
Class c1 = user.getClass();
Method getName = c1.getMethod("getName", null);
getName.setAccessible(true);
long startTime = System.currentTimeMillis();
for (int i = 0; i < 2000000000; i++) {
getName.invoke(user,null);
}
long endTime = System.currentTimeMillis();
System.out.println("反射关闭检测方式执行时间:"+(endTime-startTime)+"ms");
}
public static void main(String[] args) throws Exception {
test01();
test02();
test03();
}
- 结果
reflection反射的更多相关文章
- 代替Reflection(反射)的一些方法
Reflection(反射)是深入学习.Net必须掌握的技能之一.最初学Reflection的时候,的确是被惊住了,原来还可以这样.只要给你一个Assembly, 你就能获取到其中所有的类型,根据类型 ...
- 代替Reflection(反射)的一些方法(转)
作者:JustRun 林肯: http://www.cnblogs.com/JustRun1983/p/3830764.html 代替Reflection(反射)的一些方法(转) 2014-07-08 ...
- Java进阶之reflection(反射机制)——反射概念与基础
反射机制是Java动态性之一,而说到动态性首先得了解动态语言.那么何为动态语言? 一.动态语言 动态语言,是指程序在运行时可以改变其结构:新的函数可以引进,已有的函数可以被删除等结构上的变化.比如常见 ...
- Java Reflection 反射基础
反射基础: package reflection; /** * Created by : Infaraway * DATE : 2017/3/2 * Time : 23:06 * Funtion : ...
- List GroupBy真实用法,Reflection(反射)用法,Enum用法,正则,搜索下拉布局
1.List GroupBy 用法 var _roomProducts = homesingProducts.GroupBy(t => t.RoomName); RoomedProducts ...
- java学习--Reflection反射机制
JAVA反射机制是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法:对于任意一个对象,都能够调用它的任意方法和属性:这种动态获取信息以及动态调用对象方法的功能称为java语言的反射机制. ...
- PHP的Reflection反射机制
更多内容推荐微信公众号,欢迎关注: 原文地址: http://www.nowamagic.net/php/php_Reflection.php PHP5添加了一项新的功能:Reflection.这个功 ...
- C# 反射Reflection——反射反射程序员的快乐
一.什么是反射 反射Reflection:System.Reflection,是.Net Framework提供的一个帮助类库,可以读取并使用metadata. 反射是无处不在的,MVC-Asp.Ne ...
- Java之reflection(反射机制)——通过反射操作泛型,注解
一.反射操作泛型(Generic) Java采用泛型擦除机制来引入泛型.Java中的泛型仅仅是给编译器Javac使用的,确保数据的安全性和免去强制类型转换的麻烦.但是编译一旦完成,所有和泛型有关的类型 ...
- C# Reflection反射机制
一.反射 什么是反射 .Net的应用程序由几个部分:'程序集(Assembly)'.'模块(Module)'.'类型(class)'组成: 反射提供一种编程的方式,让程序员可以在程序运行期获得这几个组 ...
随机推荐
- linux 复合页( Compound Page )的介绍
1.复合页的定义: 复合页(Compound Page)就是将物理上连续的两个或多个页看成一个独立的大页,它可以用来创建hugetlbfs中使用的大页(hugepage), 也可以用来创建透明大页( ...
- UE4常用快捷键
编辑器快捷键 按键 操作 W 选择"移动"工具 E 选择"旋转"工具 R 选择"缩放"工具 F 聚焦对象 End 落到地面 Alt + En ...
- 什么是cache
什么是cacheTo minimize the quantity of control information stored, the spatial locality property is use ...
- Python游戏开发常用库
PyWeek:编程挑战,主要是Python游戏开发方面的 PyGame:PyGame在优秀的SDL库之上添加了更多功能.允许使用python语言创建功能齐全的游戏和多媒体程序.具有高度的可移植性,几乎 ...
- Vulnhub 靶场 HMS?: 1
Vulnhub 靶场 HMS?: 1 前期准备: 靶机地址:https://www.vulnhub.com/entry/hms-1,728/ 攻击机ip:192.168.147.190 靶机ip:19 ...
- Hyperledger fabric 2.2.0 环境搭建
基础环境搭建 ### docker 安装 如果服务器上有旧版的docker,需要先执行卸载操作. $ sudo yum remove docker \ docker-common \ docker-s ...
- 看K线学炒股(8.9)
今天是食品饮料类题材大涨的一天,相应板块涨了6个多点,看着真是诱人.我以前关注的两只股票:海天味业和三全食品,今天都大涨.三全食品接近涨停.这种票容易选出来但也很难拿住.比如前些天买入了,结果8.5的 ...
- logrotate配置记录
对于一些比较频繁又没有太大意义的log,可以设定出更严格的切割策略 see https://blog.csdn.net/liuxiao723846/article/details/100120058 ...
- 如何基于ZK实现高可用架构
zookeeper设计步骤 设计path 节点的路径 选择znode类型 普通节点.临时节点等 设计znode数据 节点中的数据 设计watch 节点的监听事件以及对应的处理 ZK实现主备切换架构 ...
- python调用lua脚本
目录 lua代码 python代码 lua代码 入口函数是必须要填的 function test1(params) return 'test1:'..params end function test2 ...