反射(Java Reflection)
Java反射机制概述
- Reflection(反射)是Java被视为动态语言的关键,反射机制允许程序在执行期借助于ReflectionAPI取得任何类的内部信息,并能直接操作任意对象的内部属性及方法.
Class c = Class.forName("java.lang.String"); - 加载完类之后,在堆内的方法区中就产生了一个Class类的对象(一个类只有一个Class对象),这个对象就包含了完的类的结构信息。我们可以通过这个对象看到类的结构。**这个对象就像一面镜子,通过这个镜子可以看到类的结构,所有,我们形象的称之为:反射 **

Java反射机制提供的功能
在运行时判断任意一个对象所属的类
在运行时构造任意一个类的对象
在运行时判断任意一个类所具有的成员变量和方法
在运行时获取泛型信息
在运行时调用任意一个对象的成员变量二和方法
在运行时处理注解
生成动态代理
发射相关的主要API
java.lang.Class:代表一个类
java.lang.reflect.Method:代表类的方法
java.lang.reflect.Field:代表类的成员
java.lang.reflect.Constructor:代表类的构造器
Class类
在Object类中定义了以下的方法,此方法将被所有子类继承
public final Class getClass()
- 以上的方法返回值的类型是一个Class类,此类是Java反射的源头,实际上所谓反射从程序的运行结果看也很好理解,即:可以通过对象发射求出类的名称
四种方式:
1.forName类
2.类.class
3.对象名.Class
4.包装类Type
Class类
对象照镜子可以得到的信息:某个类的属性、方法和构造器、某个类到底实现了哪些接口。
对于每个类而言,JRE都为其保留一个不变的Class类型的对象。一个Class对象包含了特定某个结构(class/interface/enum/annotation/primitive/type/void[])的有关信息
- Class本身也是一个类
- Class对象只能由系统建立对象
- 一个加载的类在JVM中只会有一个Class实例
- 一个Class对象对应的是一个加载到JVM中的一个.class文件
- 每一个类的实例都会记得自己是由哪个Class实例所生成
- 通过Class可以完整地得到一个类中的所有被加载的结构
- Class类是Reflection的根源,针对任何你想动态加载、运行的类,唯有先获得相应的Class对象
Class类的常用方法
| 方法名 | 功能说明 |
|---|---|
| static ClassforName(String name) | 返回指定类名name的Class对象 |
| Object newInstance() | 调用缺省构造函数,返回Class对象的一个实例 |
| getName() | 返回此Class对象所表示的实体(类,接口,数组类或void)的名称 |
| Class getSuperClass() | 返回当前Class对象的父类的Class对象 |
| Class[] getinterfaces() | 获取当前Class对象的接口 |
| ClassLoader getClassLoader | 返回该类的类加载器 |
| Constructor[] getConstructors | 返回一个包含某些Constructors对象的数组 |
| Method getMothed(String name,Class..T) | 返回一个个Method对象,此对象的形参类型为paramType |
| Filed[] getDeclaredFields() | 返回Filed对象的一个数组 |
获取Class类的实例
- 若已知具体的类,通过类的class属性获取,该方法最安全可靠,程序性能最高
Class clazz = Person.class; - 已知某个类的实例,调用该实例的getClass()方法获取Class对象
Class class = person.getClass(); - 已知一个类的全类名,且该类在类路径下,可通过Class类的静态方法forName()获取可能抛出ClassNotFoundException
** Class clazz = Class.forName("demo01.Student");** - 内置基本数据类型可以直接用类名.Type
- 还可以利用ClassLoader
例子
//测试Class类的创建方式有哪些
public class Test03 {
public static void main(String[] args) throws ClassNotFoundException {
Person person = new Student();
System.out.println("这个人是:"+person.name);
//方式一:通过对象获得
Class c1 = person.getClass();
System.out.println(c1.hashCode());
//方式二:forname获得
Class c2 = Class.forName("Student");
System.out.println(c2.hashCode());
//方式三:通过类名.class获得
Class c3 = Student.class;
System.out.println(c3.hashCode());
//方式四:基本内置类型的包装类都有一个Type属性
Class c4 = Integer.TYPE;
System.out.println(c4);
//获得父类类型
Class c5= c1.getSuperclass();
System.out.println(c5);
}
}
class Person{
public String name;
public Person() {
}
public Person(String name) {
this.name = name;
}
@Override
public String toString() {
return "Person{" +
"name='" + name + '\'' +
'}';
}
}
class Student extends Person{
public Student(){
this.name="学生";
}
}
class Teacher extends Person{
public Teacher(){
this.name = "老师";
}
}
哪些类型可以有Class对象?
- class:外部类,成员(成员内部类,静态内部类),局部内部类,匿名内部类
- interface:接口
- [] 数组
- enum:枚举
- annotation: 注解@interface
- primitive type:基本数据类型
- void
//方式一:调用运行时类得属性: .class
Class clazz1 = Person.class;
System.out.println(clazz1);
//方式二:通过运行时类的对象,调用getClass()
Person p1 = new Person();
Class clazz2 = p1.getClass();
System.out.println(clazz2);
//方式三:调用Class的静态方法:forName(String classPath)
Class clazz3 = Class.forName("com.llxy.bean.Person");
System.out.println(clazz3);
System.out.println(clazz1 ==clazz2);
System.out.println(clazz1 ==clazz3);
//方式四:使用类的加载器 ClassLoader
ClassLoader classLoader = Test.class.getClassLoader();
Class clazz4 = classLoader.loadClass("com.llxy.bean.Person");
System.out.println(clazz4);
/**Class实例可以时那些结构的说明
* object.class Comparable.class String[].class int[][].class ElementTye.class Override.class
* int.class void.class Class.class int[] a =new int[10] 只要数组的元素与 维度一样,就是同一个Class
*/
例子
import java.lang.annotation.ElementType;
public class Test04 {
public static void main(String[] args) {
//类
Class c1 = Object.class;
//接口
Class c2 = Comparable.class;
//一维数组
Class c3 = String[].class;
//二维数组
Class c4 = int[][].class;
//注解类型
Class c6 = ElementType.class;
//引用数据类型
Class c7 = Integer.class;
//空类型
Class c8 = void.class;
//类类型
Class c9 = Class.class;
System.out.println(c1);
System.out.println(c2 );
System.out.println(c3);
System.out.println(c4);
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[100];
System.out.println(a.getClass().hashCode());
System.out.println(b.getClass().hashCode());
}
}
类的加载过程
当程序主动使用某个类时,如果该类还未被加载到内存中,则系统会通过三个步骤来对该类进行初始化。

加载
将class文件字节码内容加载到内存中,并将这些静态数据转换为方法区的运行时数据结构,然后生成一个代表这个类的java.lang.Class对象,作为方法区中类数据的访问入口(即引用地址)。所有需要访问合使用类数据只能通过Class对象。这个加载的过程需要类加载器参与。
链接
将Java类的二进制代码合并到JVM的运行状态之中的过程。
- 验证:确保加载的类信息符合JVM规范,例如以0afe开头,没有安全方面的问题。
- 准备:正式为类变量(static)分配内存并设置类变量默认初始值的阶段,这些内存都将在方法区进行分配。
- 解析:虚拟机常量池内的符号引用(常量名)替换为直接引用(地址)的过程
初始化
- 执行类构造器()方法的过程。类构造器()方法是由编译期自动收集类中所有类变量的赋值动作和静态代码块中的语句合并产生的。(类构造器是构造类信息的,不是构造该类对象的构造器)
- 当初始化一个类的时候,如果发现其父类还没有进行初始化,则需要先触发其父类的初始化。
- 虚拟机会保证一个类的()方法在多线程环境中被正确加锁和同步。
类的加载与ClassLoader的理解

类加载器的作用:
- 将class文件字节码内容加载到内存中,并将将这些静态数据转换成方法区运行时数据结构,然后在堆中生成一个代表这个类的java.lang.Class对象,作为方法区中类数据的访问入口。
- 类缓存:标准的JavaSE类加载器可以按要求查找类,但一旦某个类被加载到类加载器中,它将维持加载(缓存)一段时间。不过JVM垃圾回收机制可以回收这些Class对象。
ClassLoader

public class Test {
public static void main(String[] args) throws ClassNotFoundException {
//对于自定义类,使用系统类加载器进行加载
ClassLoader classLoader = Test.class.getClassLoader();
System.out.println(classLoader);
//调用系统类加载器的getParent(); 获取扩展类加载器
ClassLoader classLoader1 = classLoader.getParent();
System.out.println(classLoader1);
//调用扩展类加载器的getParent():无法获取引导类加载器
//引导类加载器主要负责加载java的核心类库,无法加载自定义类的。
ClassLoader classLoader2 = classLoader1.getParent();
System.out.println(classLoader2);
ClassLoader classLoader3 = String.class.getClassLoader();
System.out.println(classLoader3);
}
}
ClassLoader加载配置文件
//方式一:ProPerties用来读取配置文件
Properties pros = new Properties();
//方式一:输入流
FileInputStream fis = new FileInputStream("jdbc.properties");
pros.load(fis);
//方式二: 使用类加载器 配置文件默认识别为:当前module的src下
ClassLoader classLoader = ClassLoader.class.getClassLoader();
InputStream resourceAsStream = classLoader.getResourceAsStream("src\\jdbc.properties");
pros.load(resourceAsStream);
String user = pros.getProperty("user");
String password =pros.getProperty("password");
通过反射创建对应的运行时类的对象
不同类的hashcode也是可能相同的啊,只有相同类的不同对象的hashcode不同
反射(Java Reflection)的更多相关文章
- Java - 反射机制(Reflection)
Java - 反射机制(Reflection) > Reflection 是被视为 动态语言的关键,反射机制允许程序在执行期借助于 Reflection API 取得任何类的 ...
- Java反射(Reflection)
基本概念 在Java运行时环境中,对于任意一个类,能否知道这个类有哪些属性和方法?对于任意一个对象,能否调用它的任意一个方法? 答案是肯定的. 这种动态获取类的信息以及动态调用对象的方法的功能来自于J ...
- java 反射(Reflection)
看了很多关于java 反射的文章,自己把所看到的总结一下.对自己,对他人或多或少有帮助吧. Java Reflection是什么? 首先来看看官方文档Oracle里面对Reflection的描述: R ...
- java反射机制--reflection
反射,reflection,听其名就像照镜子一样,可以看见自己也可以看见别人的每一部分.在java语言中这是一个很重要的特性.下面是来自sun公司官网关于反射的介绍: Reflection is ...
- 全方位解读Java反射(reflection)
JAVA提供了一种反射机制,反射也称为反省. java程序运行以后内存中就是一堆对象,除了对象什么都没有. 找对象 拉关系 瞎折腾 对象在运行过程中能否有一种机制查看自身的状态,属性和行为.这就是反射 ...
- Java基础(九)反射(reflection)
1.反射库(reflection library)提供了一个非常丰富且精心设计的工具集,以便编写能够动态操纵Java代码的程序. 能够分析类能力的程序称为反射(reflection).反射机制的功能极 ...
- java Reflection(反射)基础知识讲解
原文链接:小ben马的java Reflection(反射)基础知识讲解 1.获取Class对象的方式 1.1)使用 "Class#forName" public static C ...
- Swift - 反射(Reflection)的介绍与使用样例(附KVC介绍)
1,反射(Reflection) 对于C#.Java开发人员来说,肯定都对反射这个概念相当熟悉.所谓反射就是可以动态获取类型.成员信息,同时在运行时(而非编译时)可以动态调用任意方法.属性等行为的特性 ...
- 反射(Reflection)
Java学习笔记--反射(Reflection) 关于反射 能够分析类能力的程序称之为反射(Reflection) 反射机制可以用来: 在运行时分析类的能力 在运行时检查对象,例如:编写一个适合所有类 ...
- 浅析Java反射--Java
前言 上篇文章我们提到了可以使用反射机制破解单例模式.这篇文章我们就来谈一谈什么是反射,反射有什么用,怎么用,怎么实现反射. 概述 Java的反射(reflection)机制:是指在程序的运行状态中, ...
随机推荐
- LangChain vs Semantic Kernel
每当向他人介绍 Semantic Kernel, 会得到的第一个问题就是 Semantic Kernel 类似于LangChain吗,或者是c# 版本的LangChain吗? 为了全面而不想重复的回答 ...
- DevOps、SRE、平台工程的区别
DevOps.SRE和平台工程的概念在不同时期出现,并由不同的个人和组织开发. DevOps作为一个概念是由Patrick Debois和Andrew Shafer在2009年的敏捷会议上提出的.他们 ...
- 《C和指针》第一章
1 第一章 C标准库中几个常用的IO函数 int puts(void *str): 从str中提取字符直到遇到第一个'\0'为止,将这些字符串加上'\n'后发送给stdout. int main(vo ...
- ACID和CAP特性
文章目录 ACID和CAP理论 ACID CAP ACID和CAP理论 ACID **atomicity(原子性):**所有的事务要么都成功要么都失败, **consistency(一致性):**执行 ...
- Prism Sample 23-RegionMemberLifetime
在导航中跳转时,视图是缓存的.如果要求某视图在离开后就销毁,需要实现 public class ViewAViewModel : BindableBase, INavigationAware, IRe ...
- java线程池和多线程的使用详解
Java 多线程和线程池使用 java多线程实现的几种方法 1.继承Thread类 继承Thread类,重写run方法,创建线程类对象调用start方法启动线程. public class Threa ...
- < Python全景系列-4 > 史上最全文件类型读写库大盘点!什么?还包括音频、视频?
欢迎来到我们的系列博客<Python全景系列>!在这个系列中,我们将带领你从Python的基础知识开始,一步步深入到高级话题,帮助你掌握这门强大而灵活的编程语言! 本文系列第四篇,介绍史上 ...
- Midjourney|文心一格prompt教程[进阶篇]:Midjourney Prompt 高级参数、各版本差异、官方提供常见问题
Midjourney|文心一格prompt教程[进阶篇]:Midjourney Prompt 高级参数.各版本差异.官方提供常见问题 1.Midjourney Prompt 高级参数 Quality ...
- Serverless冷扩机器在压测中被击穿问题
一.现象回顾 在今天ForceBot全链路压测中,有位同事负责的服务做Serverless扩容(负载达到50%之后自动扩容并上线接入流量)中,发现新扩容的机器被击穿,监控如下(关注2:40-3:15时 ...
- flutter填坑之旅(有状态组件StatefulWidget)
今天我们来看看flutter的StatefulWidget(有状态组件),最常用就是app 主页的底部导航栏的应用 效果图 首页 关于 我的 statefull-widget-learn .dart ...