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反射的更多相关文章

  1. 代替Reflection(反射)的一些方法

    Reflection(反射)是深入学习.Net必须掌握的技能之一.最初学Reflection的时候,的确是被惊住了,原来还可以这样.只要给你一个Assembly, 你就能获取到其中所有的类型,根据类型 ...

  2. 代替Reflection(反射)的一些方法(转)

    作者:JustRun 林肯: http://www.cnblogs.com/JustRun1983/p/3830764.html 代替Reflection(反射)的一些方法(转) 2014-07-08 ...

  3. Java进阶之reflection(反射机制)——反射概念与基础

    反射机制是Java动态性之一,而说到动态性首先得了解动态语言.那么何为动态语言? 一.动态语言 动态语言,是指程序在运行时可以改变其结构:新的函数可以引进,已有的函数可以被删除等结构上的变化.比如常见 ...

  4. Java Reflection 反射基础

    反射基础: package reflection; /** * Created by : Infaraway * DATE : 2017/3/2 * Time : 23:06 * Funtion : ...

  5. List GroupBy真实用法,Reflection(反射)用法,Enum用法,正则,搜索下拉布局

    1.List  GroupBy 用法 var _roomProducts = homesingProducts.GroupBy(t => t.RoomName); RoomedProducts ...

  6. java学习--Reflection反射机制

    JAVA反射机制是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法:对于任意一个对象,都能够调用它的任意方法和属性:这种动态获取信息以及动态调用对象方法的功能称为java语言的反射机制. ...

  7. PHP的Reflection反射机制

    更多内容推荐微信公众号,欢迎关注: 原文地址: http://www.nowamagic.net/php/php_Reflection.php PHP5添加了一项新的功能:Reflection.这个功 ...

  8. C# 反射Reflection——反射反射程序员的快乐

    一.什么是反射 反射Reflection:System.Reflection,是.Net Framework提供的一个帮助类库,可以读取并使用metadata. 反射是无处不在的,MVC-Asp.Ne ...

  9. Java之reflection(反射机制)——通过反射操作泛型,注解

    一.反射操作泛型(Generic) Java采用泛型擦除机制来引入泛型.Java中的泛型仅仅是给编译器Javac使用的,确保数据的安全性和免去强制类型转换的麻烦.但是编译一旦完成,所有和泛型有关的类型 ...

  10. C# Reflection反射机制

    一.反射 什么是反射 .Net的应用程序由几个部分:'程序集(Assembly)'.'模块(Module)'.'类型(class)'组成: 反射提供一种编程的方式,让程序员可以在程序运行期获得这几个组 ...

随机推荐

  1. flink 版本

    从1.10.0开始,flink版本是一个分界线,所以如果用>1.10版本的特性,一些flink引用可以从1.10官网文档中查 后面版本中没有这些说明了. flink代码文档地址:https:// ...

  2. Fiddler 教程【转】

    作者: 小坦克  来源: 博客园  发布时间: 2012-07-07 14:20  阅读: 71973 次  推荐: 45   原文链接   [收藏]  阅读目录 Fiddler的基本介绍 Fiddl ...

  3. 面试之CAS

    1.CAS(Compare And Swap)比较并替换,是线程并发运行时用到的一种技术或者算法,CAS与之对应的是一些锁技术,,例如synconozied,同事这种比较替换的思想也可以运用到数据库上 ...

  4. pgsql的round函数

    不知道是我菜还是咋地,感觉pg里面用round不是很爽啊,明明在其他库能运行的,字段类型卡得太死了吧 照说float8类型还是数值,怎么就报错呢,如下 错误:  函数 round(double pre ...

  5. 把userId:12323 直接拿到12323

    JSONObject jsonObject1 = JSONObject.parseObject(mqttMessage); MessageVo messageVo =  JSONObject.toJa ...

  6. JAVA课程设计(附源码)

    Java课程设计选题 Java课程设计说明 本次课程设计的目的是通过课程设计的各个项目的综合训练,培养学生实际分析问题.编程和动手能力,提高学生的综合素质.本课程设计尝试使用一些较生动的设计项目,激发 ...

  7. exe可执行文件反编译成py文件

    记录一下exe文件反编译的问题 准备工作 1. 安装第三方包 uncompyle6 (pip install uncompyle6==3.7.4) 2. 下载pyinstxtractor.py文件 3 ...

  8. input点击焦点后阴影

    input[type=text]:focus { outline: none; border-color: rgba(82, 168, 236, 0.8); box-shadow:inset 0 1p ...

  9. Vue后台管理项目中解决需要配置多个端口号问题

    背景 登录接口:http://39.98.123.211:8170/ 商品接口:http://39.98.123.211:8510/ 可见前面是地址是一致的,但是端口号不一样. 这就会导致,登录进得去 ...

  10. loj6851

    (CF1761D Tester Solution in Chinese) 定义 \(L(v)=\log_2\operatorname{lowbit}(v+1)\):也就是说,\(L(v)\) 是 \( ...