Java高级特性——反射机制(第一篇)
——何为动态语言,何为静态语言?(学习反射知识前,需要了解动态语言和静态语言)
动态语言
>是一类在运行时可以改变其结构的语言,例如新的函数、对象、甚至是代码可以被引进,已有的函数可以被删除或者是其他结构上的改变,通俗的说就是代码在运行时可以根据某些自身条件改变自身的结构。
>主要的动态语言有:Object-C、C#、JavaScript、Python等。
动态语言JavaScript举例:
function f(){ //此时的x为一个字符串类型
var x="var a=1;var b=2;alert(a+b)"; //通过eval函数,执行x语句,此时的x值为运算后的值
eval(x);
}
通过上面代码可以了解到,本身的x在没有运行的时候是一个字符串类型,通过eval函数运行后,改变其本身原有的结构,就变成了一个整型。所以JavaScript语言拥有动态性,能够在运行时改变其本身原有的结构。
静态语言
>与动态语言相对应,运行时结构不可该变的语言。如Java、C++、C等。
>尽管Java不属于动态语言,但是可以称之为“准动态语言”,即Java具有一定的动态性,我们可以通过Java的反射机制获得类似动态语言的特性。Java的动态性让编程更加的灵活。
了解了什么是静态语言,什么是动态语言,下面开始了解Java的反射机制。
——什么是反射(Reflection)?
>reflection(反射)是Java被视为动态语言的关键。反射机制允许在执行期间借助Reflection API获取任何类的内部信息,并且能操作任意对象的内部属性及其方法。
Tip:类的内部信息:类名、方法、字段、属性、构造器等。
Tip:反射的强大之处:用private修饰的方法也能够通过反射获取到。
>加载完类后,在堆内存的方法区中就产生一个Class类型的对象(一个类只有一个Class对象),这个对象就包含了完整的这个类的信息,我们可以通过这个类看到类的结构的信息。这个对象就像一面镜子,透过这个镜子我们可以看到类的结构,所以我们形象的称之为“ 反射(Reflection)”。
比如获取一个Class对象,通过这个对象,我们可以看到这个类所有的结构信息,这就是反射(下面是获取Class对象一种方法,先了解):
Class<?> c = Class.forName("java.lang.String");
正常方式和反射方式的流程图:
反射机制提供的功能:
>在运行时判断任何一个对象所属的类
>在运行时构造任意一个类的对象
>在运行时判断任意一个类所具有的成员变量和方法
>在运行时获取泛型信息
>在运行时调运任何一个类的方法以及属性等
>在运行时处理注解
>生成动态代理
>>>等等
反射的优缺点:
优点:可以实现动态创建对象和编译,体现出很大的灵活性
缺点:对性能有影响,使用放射基本上属于一种解释操作,我们可以告诉JVM,做什么并且它要满足我们什么要求,这类操作总是慢于直接执行相同的操作。
——如何获取反射对象?
获取反射对象,最主要的是了解反射主要的API:
>java.lang.Class:代表一个类
>java.lang.reflect.Method:代表类的方法
>java.lang.reflect.Filed:代表类的成员变量
>java.lang.reflect.Constructer:代表类的构造器
>>>等等
通过反射获取类的Class对象,例如:
package test; public class Test{
//什么叫反射
public static void main(String[] args) throws ClassNotFoundException {
//通过反射获取类的class对象
Class c = Class.forName("test.Test"); System.out.println(c);
} }
打印的结果为:class test.Test
我们前边说一个类在内存中只对应一个Class对象,下面案例测试(只修改上一个案例中的main方法):
//什么叫反射
public static void main(String[] args) throws ClassNotFoundException {
//通过反射获取类的Class对象
Class<?> c = Class.forName("test.Test");
Class<?> c1 = Class.forName("test.Test");
Class<?> c2 = Class.forName("test.Test"); //一个类在内存中只能有一个Class对象
//一个类被加载后,类的整个结构都会被封装在Class对象中 System.out.println(c.hashCode() == c1.hashCode());
System.out.println(c.hashCode() == c2.hashCode());
System.out.println(c1.hashCode() == c2.hashCode()); }
打印结果为:true true true ,可以看到获取到的Class对象均为堆内存方法区中的同一个Class对象。
Class类详解:
在Object类中定义了public final Class getClass()方法,此方法被所有的子类继承。这个方法的返回值是一个Class类型,此类(Class类)是Java反射的源头,实际上所谓的反射从程序的运行结果来看也很好理解, 即:可以通过对象反射求出类的名称。
>Class类本身也是一个类
>Class对象由系统建立对象
>一个加载的类在内存中只有一个Class对象
>一个Class对象对应的是一个加载到JVM的.class文件
>每个类的实例都会记得自己由那个Class实例生成
>通过Class可以完整的得到一个类中所有被加载的结构
>Class类是Reflection(反射)的根源,针对任何你想动态加载和运行的类,唯有先获得相应的Class对象
class对象常用的方法:
如何获取Class实例:
> 若已知具体的类,通过类的class属性获取,该方法最为安全可靠,程序的性能最高,例如:Class c = Test.class;
>若知某个类的实例,调用该实例的getClass()方法获取Class对象 例如:Class c = new Test().getClass();
>已知一个类的全类名,且该类在路径下, 可以通过Class的静态方法forName获取,可能抛出ClassNotFoundException
例如:Class c = Class.forName("test.Test");
>内置的基本数据类型可以直接用类名.Type 例如:String.Type
>还可以通过ClassLoader (后边介绍)
案例(修改上述案例的main方法):
//什么叫反射
public static void main(String[] args) throws ClassNotFoundException { //通过Class的forName方法获取
Class c1 = Class.forName("test.Test"); //通过类名.Class获取
Class c2 = Test.class; //通过对象.getClass获取
Class c3 = new Test().getClass(); System.out.println(c1+"\r\n"+c2+"\r\n"+c3); //获取内置基本数据类型的Class对象,通过类型.TYPE获取 System.out.println(Integer.TYPE); //获取父类Class对象,通过子类的Class对象.getSuperClass方法获取 System.out.println(c1.getSuperclass()); }
打印的结果为:(可以看到几种方式都能获取到Class对象)
哪些类可以有Class对象:
>Class:外部类,成员(成员内部类,静态内部类),局部内部类,匿名内部类
>interface:接口
>[]:数组
>enum:枚举类型
>annotation:注解
>primitive type:基本数据类型
>void:空
举例:
package test; import java.lang.annotation.ElementType; public class Test{ //所有类的Class对象
public static void main(String[] args) {
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.TYPE; //基本数据类型
Class c8 = Void.class; //void
Class c9 =Class.class; //class //打印
System.out.println(c1);
System.out.println(c2);
System.out.println(c3);
System.out.println(c4);
System.out.println(c5);
System.out.println(c6);
System.out.println(c7);
System.out.println(c8);
System.out.println(c9); //只要元素类型与维度一样,就是同一个Class
int[] a=new int[10];
int[] b=new int[20]; System.out.println(a.getClass().hashCode() == b.getClass().hashCode());
} }
打印结果为:
Tip:对于数组来说,只要元素的类型与维度一样,就是同一个Class对象。
未经允许,禁止转载,转载请联系QQ:493116703
Java高级特性——反射机制(第一篇)的更多相关文章
- Java高级特性——反射机制(第二篇)
在Java高级特性——反射机制(第一篇)中,写了很多反射的实例,可能对于Class的了解还是有点迷糊,那么我们试着从内存角度去分析一下. Java内存 从上图可以看出,Java将内存分为堆.栈.方法区 ...
- Java高级特性——反射机制(第三篇)
获取类运行时的结构 通过反射获取运行时类的完整结构 Field.Method.Constructor.Superclass.Interface.Annotation >实现的全部接口 >所 ...
- Java高级特性——反射机制(完结)——反射与注解
按照我们的学习进度,在前边我们讲过什么是注解以及注解如何定义,如果忘了,可以先回顾一下https://www.cnblogs.com/hgqin/p/13462051.html. 在学习反射和注解前, ...
- Java高级特性——反射
感谢原文作者:peter_RD_nj 原文链接:https://www.jianshu.com/p/9be58ee20dee 注意:同一个类在JVM中只存在一份字节码对象 概述 定义 JAVA反射机制 ...
- JAVA高级特性反射和注解
反射: 枚举反射泛型注解.html34.3 KB 反射, 主要是指通过类加载, 动态的访问, 检测和修改类本身状态或行为的一种能力, 并能根据自身行为的状态和结果, 调整或修改应用所描述行为的状态和相 ...
- Java高级特性—反射和动态代理
1).反射 通过反射的方式可以获取class对象中的属性.方法.构造函数等,一下是实例: 2).动态代理 使用场景: 在之前的代码调用阶段,我们用action调用service的方法实现业务即可. 由 ...
- Java高级特性 第5节 序列化和、反射机制
一.序列化 1.序列化概述 在实际开发中,经常需要将对象的信息保存到磁盘中便于检索,但通过前面输入输出流的方法逐一对对象的属性信息进行操作,很繁琐并容易出错,而序列化提供了轻松解决这个问题的快捷方法. ...
- 浅说Java中的反射机制(一)
在学习传智播客李勇老师的JDBC系列时,会出现反射的概念,由于又是第一次见,不免感到陌生.所以再次在博客园找到一篇文章,先记录如下: 引用自java中的反射机制,作者bingoideas.(()为我手 ...
- 浅说Java中的反射机制(二)
写过一篇Java中的反射机制,不算是写,应该是抄了,因为那是别人写的,这一篇也是别人写的,摘抄如下: 引自于Java基础--反射机制的知识点梳理,作者醉眼识朦胧.(()为我手记) 什么是反射? 正常编 ...
随机推荐
- PHP uniqid() 函数
实例 生成一个唯一的 ID: <?phpecho uniqid();?>高佣联盟 www.cgewang.com 定义和用法 uniqid() 函数基于以微秒计的当前时间,生成一个唯一的 ...
- bzoj 4305 数列的GCD
LINK:数列的GCD 题意: 给出一个长度为N的数列{a[n]},1<=a[i]<=M(1<=i<=N). 现在问题是,对于1到M的每个整数d,有多少个不同的数列b[1], ...
- webapp项目新建java class、webapp目录树结构
上一篇中我们介绍了IDEA.maven新建webapp项目的两种方式,分别是:在命令行中用模板创建.直接在IDEA中选择骨架创建. 但都存在一个问题:目录树不完整.有些人会不知道接下来该如何创建j ...
- 基于.NetCore3.1系列 —— 日志记录之日志配置揭秘
一.前言 在项目的开发维护阶段,有时候我们关注的问题不仅仅在于功能的实现,甚至需要关注系统发布上线后遇到的问题能否及时的查找并解决.所以我们需要有一个好的解决方案来及时的定位错误的根源并做出正确及时的 ...
- Redis分布式限流器
以下文章来源于微信公众号:程序员内点事 ,作者:程序员内点事 请大家关注原作者 1. 什么是限流?为什么要限流? 限流是保证系统高可用的重要手段!!!由于互联网公司的流量巨大,系统上线会做一个流量峰值 ...
- [转]35张图就是为了让你深入AQS
以下文章来源于程序员cxuan ,作者一枝花算不算浪漫 谈到并发,我们不得不说AQS(AbstractQueuedSynchronizer),所谓的AQS即是抽象的队列式的同步器,内部定义了很多锁相关 ...
- 吴太银:华为消费者云服务Cassandra使用场景与最佳实践
大家好,我是华为消费者云的吴太银. 我今天分享的主要是华为消费者云服务使用Cassandra的应用场景和最佳实践.我这个可能跟其他嘉宾分享的不太一样,因为前几个嘉宾讲的实际上对Cassandra原生的 ...
- Ubuntu定时执行任务(定时爬取数据)
cron是一个Linux下的后台进程,用来定期的执行一些任务.因为我用的是Ubuntu,所以这篇文章中的所有命令也只能保证在Ubuntu下有效. 1:编辑crontab文件,用来存放你要执行的命令 s ...
- Spring Boot 数据缓存 - EhCache
EhCache 集成 EhCache 是一个纯 Java 的进程内缓存框架,具有快速.精干等特点,是 Hibernate 中默认的 CacheProvider. 在 Spring Boot 中集成 E ...
- JS 移动端轮播图案例
body { margin:; } .hearder { width: 100%; height: 150px; position: relative; } ul { list-style: none ...