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 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)'组成: 反射提供一种编程的方式,让程序员可以在程序运行期获得这几个组 ...
随机推荐
- 生态学建模:增强回归树(BRT)预测短鳍鳗生存分布和影响因素|附代码数据
全文下载链接: http://tecdat.cn/?p=22482 最近我们被客户要求撰写关于增强回归树(BRT)的研究报告,包括一些图形和统计输出. 在本文中,在R中拟合BRT(提升回归树)模型.我 ...
- 没解决的问题-git连接失败
[parallels@localhost ~]$ ssh-keygen -t rsa -C '1012144290@qq.com'Generating public/private rsa key p ...
- UltiSnips安装及设置
2022-10-05 10:56:50 星期三 安装了UltiSnips插件,然后开始学习 第一个命令 UltiSnipsEdit 不好使,创建了~/.vim/UltiSnips 还是 can not ...
- springBoot中对mongodb添加2dsphere位置索引
项目需求:最近有个需求,就是要根据坐标位置找出附近的车辆(车辆有对应的坐标).然后翻了翻百度,cv流一顿操作之后,大概整理出来了一段代码如下 //根据当前位置坐标,找出附近*米内的所有车辆BasicD ...
- 记一个好用的轮播图的FlexSlider
之前给自己公司的主页套用过一个js动态生成的轮播图,但是从载入的时机和载入后的效果都不太理想,又懒得去优化了,这次偶然遇到一个比较不错的轮播图的js插件,记录之. 首先它是给予jquery的,引进jq ...
- pytorch 独热编码报错的解决办法:one_hot is only applicable to index tensor
首先,报错原因,我认为是数据类型错误, 在文档中表示,第一个tensor参数的数据类型为LongTensor,也就是torch.int64类型的,如果你有报这个错:"one_hot is o ...
- Python学习笔记组织文件之将美国风格日期的文件改名为欧洲风格的日期
随笔记录方便自己和同路人查阅. #------------------------------------------------我是可耻的分割线--------------------------- ...
- GIT 上传文件出错:fatal: Could not read from remote repository. 解决方案
问题 git push -u origin master 执行后报错 fatal: Could not read from remote repository. 解决方案 1. git执行 git ...
- VUE学习-基础(基础语法 & 模板语法)
基础语法 引入vue <!-- 开发环境版本,包含了有帮助的命令行警告 --> <script src="https://cdn.jsdelivr.net/npm/vue/ ...
- alertmanger告警配置
钉钉告警: 需先安装 Ding talk 配置 webhook vim docker-compose.yaml webhook-dingtalk: image: timonwong/prometheu ...