Java基础00-反射35
1. 类加载器
1.1 类加载
类加载或类初始化的三个步骤:类的加载、类的连接、类的初始化

加载:类加载过程的一个阶段:通过一个类的完全限定查找此类字节码文件,并利用字节码文件创建一个Class对象
验证:目的在于确保Class文件的字节流中包含信息符合当前虚拟机要求,不会危害虚拟机自身安全。主要包括四种验证,文件格式验证,元数据验证,字节码验证,符号引用验证。
准备:为类变量(即static修饰的字段变量)分配内存并且设置该类变量的初始值即0(如static int i=5;这里只将i初始化为0,至于5的值将在初始化时赋值),这里不包含用final修饰的static,因为final在编译的时候就会分配了,注意这里不会为实例变量分配初始化,类变量会分配在方法区中,而实例变量是会随着对象一起分配到Java堆中。
解析:主要将常量池中的符号引用替换为直接引用的过程。符号引用就是一组符号来描述目标,可以是任何字面量,而直接引用就是直接指向目标的指针、相对偏移量或一个间接定位到目标的句柄。有类或接口的解析,字段解析,类方法解析,接口方法解析(这里涉及到字节码变量的引用,如需更详细了解,可参考《深入Java虚拟机》)。
初始化:类加载最后阶段,若该类具有超类,则对其进行初始化,执行静态初始化器和静态初始化成员变量(如前面只初始化了默认值的static变量将会在这个阶段赋值,成员变量也将被初始化)。


当一个类被载入了JVM,就不会被再次载入了,只载入一次。
1.2 类加载器


代码示例:
public class ClassLoaderDemo {
public static void main(String[] args) {
// static ClassLoader getSystemClassLoader (): 返回用于委派的系统类加载器
ClassLoader c = ClassLoader.getSystemClassLoader();
System.out.println(c); // AppClassLoader
// ClassLoader getParent (): 返回父类加载器进行委派
ClassLoader c2 = c.getParent();
System.out.println(c2); // ExtClassLoader
ClassLoader c3 = c2.getParent();
System.out.println(c3); // null
}
}
运行结果:
AppClassLoader:系统类加载器(System)
ExtClassLoader:平台类加载器(Platform)
null:内置类加载器(Bootstrap),所以它控制台输出为null

2. 反射
2.1 反射概述
深入理解反射机制
Student和Teacher,要想使用就要通过类加载器加载对象的.class文件到内存中去,而每一个.class文件中都应该包含,成员变量、构造方法、成员方法等,每个class文件都包含这些信息,而Class就是所有.class文件对应的类型,Class就可以使用,成员变量、构造方法、成员方法等,就不需要Student和Teacher了,这就叫反射。

2.2 获取Class类的对象

第一个方法比较简洁,
第三个方法比较的灵活,
一般使用推荐使用第三个方法。
代码示例:
获取Class类的对象就要有一个对象,所以要创建一个学生类
学生类:
public class Student {
// 成员变量,一个私有,一个默认,一个公共
private String name;
int age;
public String address;
// 构造方法,一个私有,一个默认,两个公共
public Student() {
super();
}
private Student(String name) {
super();
this.name = name;
}
Student(String name, int age) {
super();
this.name = name;
this.age = age;
}
public Student(String name, int age, String address) {
super();
this.name = name;
this.age = age;
this.address = address;
}
// 成员方法,一个私有,四个公共
private void function() {
System.out.println("function");
}
public void method1() {
System.out.println("method");
}
public void method2(String s) {
System.out.println("method:" + s);
}
public String method3(String s, int i) {
return s + "," + i;
}
@Override
public String toString() {
return "Student [name=" + name + ", age=" + age + ", address=" + address + "]";
}
}
测试类:
//三种方式获取Class对象
public class ReflectDemo {
public static void main(String[] args) throws ClassNotFoundException {
// 1:使用类的class属性来获取该类对应的Class对象。举例: Student. class将会返回Student类对应的Class对象
Class<Student> c1 = Student.class;
System.out.println(c1); Class<Student> c2 = Student.class;
System.out.println(c1 == c2); // 一个类在内存中只有一个字节码文件对象,所以输出为true System.out.println("---------------------"); // 2:调用对象的getClass()方法,返回该对象所属类对应的Class对象
// 该方法是Object类中的方法,所有的Java对象都可以调用该方法
Student s = new Student();
Class<? extends Student> c3 = s.getClass();
System.out.println(c1 == c3);// 如果是true就代表通过该方法也可以得到该类的字节码文件 System.out.println("---------------------"); // 3:使用Class类中的静态方法forName(String className), 该方法需要传入字符串参数,该字符串参数的值是某个类的全路径
Class<?> c4 = Class.forName("myRrflect01.Student");
System.out.println(c1 == c4);// 如果是true就代表通过该方法也可以得到该类的字节码文件 }
}
运行结果:

2.3 反射获取构造方法并使用

代码示例:
对象使用的是2.2中的Student学生类
首先通过forName()得到字节码文件Class对象,通过Class对象的getConstructor()得到单个的构造方法,然后通过构造方法的newInstance()方法得到它的构造方法来创建对象。这就是反射。
public class ReflectDemo01 {
public static void main(String[] args) throws Exception {
// 获取Class对象
Class<?> c = Class.forName("myRrflect01.Student");
// Constructor<?>[] getConstructors():返回所有公共构造方法对象的数组
Constructor<?>[] cons1 = c.getConstructors();
for (Constructor<?> con1 : cons1) {
System.out.println(con1);
}
System.out.println("------------------");
// Constructor<?>[] getDeclaredConstructors():返回所有构造方法对象的数组
Constructor<?>[] cons2 = c.getDeclaredConstructors();
for (Constructor<?> con2 : cons2) {
System.out.println(con2);
}
System.out.println("------------------");
// Constructor<T> getConstructor(Class<?> .. parameterTypes):返回单个公共构造方法对象
// Constructor<T> getDeclaredConstructor(Class<?... parameterTypes):返回单个构造方法对象
// 参数:你要获取的构造方法的参数的个数和数据类型对应的字节码文件对象
// 取一个无参构造方法
Constructor<?> con = c.getConstructor();// 因为是无参,所以不需要添加参数。
// Constructor提供了一个类的单个构造函数的信息和访问权限
// Constructor类中用于创建对象的方法
// T newlnstance(Object... initargs):根据指定的构造方法创建对象
Object obj = con.newInstance();
System.out.println(obj );
// 这是不适用反射的方法
// Student s = new Student();
// System.out.println(s);
}
}
运行结果:

2.4 反射获取构造方法并使用练习
2.4.1 练习1

代码示例:
对象使用的是2.2中的Student学生类
//通过反射实现如下的操作:
//Student s = new Student("林青霞”, 30, "西安");
//System. out. println(s); public class RefectDemo02 {
public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException, SecurityException,
InstantiationException, IllegalAccessException, IllegalArgumentException, InvocationTargetException {
// 获取Class对象
Class<?> c = Class.forName("myRrflect01.Student"); // 获取构造方法对象
// public Student(String name, int age, String address)
// Constructor<T> getConstructor (Class<?>... parameterTypes ),返回单个公共构造方法对象
// 基本数据类型也可以通过. class得到对应的Class类型
Constructor<?> con = c.getConstructor(String.class, int.class, String.class); // 利用构造方法得到对象
// T newInstance (object... initargs),根据指定的构造方法创建对象
Object obj = con.newInstance("林青霞", 30, "西安");
System.out.println(obj); }
}
2.4.2 练习2

代码示例:
对象使用的是2.2中的Student学生类
//通过反射实现如下的操作:
//Student s = new Student("林青霞");
//System. out. println(s);
public class RefectDemo03 {
public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException, SecurityException,
InstantiationException, IllegalAccessException, IllegalArgumentException, InvocationTargetException {
// 获取Class对象
Class<?> c = Class.forName("myRrflect01.Student"); // 获取构造方法对象
// private Student(String name)
// Constructor<T> getDeclaredConstructor (Class<?>... parameterTypes),返回单个构造方法对象
Constructor<?> con = c.getDeclaredConstructor(String.class); // 因为私有的构造方法是不能创建对象的,但是在反射里面是可以的,这就需要使用暴力反射
// public void setAccessible (boolean flag) :值为true,取消访问检查
con.setAccessible(true); // 利用构造方法得到对象
// T newInstance (object... initargs),根据指定的构造方法创建对象
Object boj = con.newInstance("林青霞");
System.out.println(boj);
}
}
运行结果:

2.5 反射获取成员变量并使用

代码示例:
首先获取Class对象,通过Class对象的getFields ()方法获取指定的成员变量,得到成员变量对象,通过成员变量对象调用set()方法,给对象的成员变量赋值。
对象使用的是2.2中的Student学生类
//反射获取成员变量并使用
public class ReflectDemo02 {
public static void main(String[] args)
throws ClassNotFoundException, NoSuchFieldException, SecurityException, NoSuchMethodException,
InstantiationException, IllegalAccessException, IllegalArgumentException, InvocationTargetException {
// 获取Class对象
Class<?> c = Class.forName("myRrflect01.Student"); // Field[] getFields ()返回一个包含Field对象的数组,Field对象反 映由该Class对象表示的类或接口的所有可访问的公共字段
Field[] fields = c.getFields();
for (Field field : fields) {
System.out.println(field);
} System.out.println("----------------"); // Field[] getDeclaredFields () 返回一个Field对象的数组,反映了由该Class对象 表示的类或接口声明的所有字段
Field[] fields2 = c.getDeclaredFields();
for (Field field2 : fields2) {
System.out.println(field2);
} System.out.println("----------------"); // Field getField (String name) 返回一个Field对象, 该对象反映由该Class对象表示的类或接口的指定公共成员字段
// Field getDeclaredField (String name)返回个Field对象, 该对象反映由该Class对象 表示的类或接口的指定声明字段
Field addressField = c.getField("address"); // 获取无参构造方法获取对象
Constructor<?> con = c.getConstructor();
Object obj = con.newInstance(); // Field提供有关类或接口的单个字段的信息和动态访问
// void set (object obj, object value) 将指定的对象参数中由此Field对象表示的字段设置为指定的新值
addressField.set(obj, "西安");// 给obj的成员变量addressField赋值为西安
System.out.println(obj); }
}
运行结果:

2.5.1 反射获取成员变量并使用练习

代码示例:
对象使用的是2.2中的Student学生类
public class ReflectDemo02 {
public static void main(String[] args)
throws ClassNotFoundException, NoSuchMethodException, SecurityException, InstantiationException,
IllegalAccessException, IllegalArgumentException, InvocationTargetException, NoSuchFieldException {
// 获取Class对象
Class<?> c = Class.forName("myRrflect01.Student");
// 获取无参构造方法创建对象
// Student s = new Student( );
Constructor<?> con = c.getConstructor();
Object obj = con.newInstance();
System.out.println(obj);
// s. name ="林青霞”;
// 因为name变量是私有的,所以使用getDeclaredField()方法获取,同时也要使用暴力反射setAccessible()方法为true
Field nameField = c.getDeclaredField("name");
nameField.setAccessible(true);
nameField.set(obj, "林青霞");
System.out.println(obj);
// 为了方便也可以每次使用getDeclaredField()获取变量和setAccessible(true);取消访问检查
// s.age = 30;
Field ageField = c.getDeclaredField("age");
ageField.setAccessible(true);
ageField.set(obj, 30);
System.out.println(obj);
// s. address = “西安”;
Field addressField = c.getDeclaredField("address");
addressField.setAccessible(true);
addressField.set(obj, "西安");
System.out.println(obj);
}
}
运行结果:

2.6 反射获取成员方法并使用

首先获取Class对象,然后通过getMethod()方法得到成员方法对象,最后通过成员方法对象调用invoke()方法传入对象,就是调用该对象的方法。
代码示例:
对象使用的是2.2中的Student学生类
//反射获取成员方法并使用
public class ReflectDemo03 {
public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException, SecurityException,
InstantiationException, IllegalAccessException, IllegalArgumentException, InvocationTargetException {
// 获取Class对象
Class<?> c = Class.forName("myRrflect02.Student"); // Method[] getMethods() 返回一个包含方法对象的数组
// 方法对象反射由此表示的类或接口的所有公共方法 类对象,包括那些由类或接口和那些从超类和超接口继承的声明。
Method[] methods1 = c.getMethods();
for (Method method1 : methods1) {
System.out.println(method1);
} System.out.println("---------------------"); // Method[] getDeclaredMethods() 返回一个包含方法对象的数组
// 方法对象反射的类或接口的所有声明的方法,通过此表示类对象,包括公共,保护,默认(包访问和私有方法,但不包括继承的方法。
Method[] methods2 = c.getDeclaredMethods();
for (Method method2 : methods2) {
System.out.println(method2);
} System.out.println("---------------------"); // Method getMethod(String name, 类<?>... parameterTypes)
// 返回一个 方法对象,它反映此表示的类或接口的指定公共成员方法 类对象。
// Method getDeclaredMethod(String name, 类<?>... parameterTypes)
// 返回一个 方法对象,它反映此表示的类或接口的指定声明的方法 类对象。 // 获取public void method1()
Method m = c.getMethod("method1"); // 获取无参构造方法创建对象
Constructor<?> con = c.getConstructor();
Object obj = con.newInstance(); // 在类或接口.上提供有关单一方法的信息和访问权限
// Object invoke (Object obj, Object... args) 在具有指定参数的指定对象.上调用此方法对象表示的基础方法
// Object:返回值类型
// obj:调用方法的对象
// args:方法需要的参数
m.invoke(obj); }
}
运行结果:
最后输出了Student类中method1()成员方法

2.6.1 反射获取成员方法并使用练习

代码示例:
对象使用的是2.2中的Student学生类
public class ReflectDemo04 {
public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException, SecurityException,
InstantiationException, IllegalAccessException, IllegalArgumentException, InvocationTargetException {
// 获取Class对象
Class<?> c = Class.forName("myRrflect02.Student");
// Student s = new Student();
Constructor<?> con = c.getConstructor();
Object obj = con.newInstance();
// s.method1();
Method m1 = c.getMethod("method1");
m1.invoke(obj);
// s.method2( "林青霞");
Method m2 = c.getMethod("method2", String.class);
m2.invoke(obj, "林青霞");
// String ss = s. method3("林青霞", 30);
// System.out.println(ss);
Method m3 = c.getMethod("method3", String.class, int.class);
Object method3 = m3.invoke(obj, "林青霞", 30);
System.out.println(method3);
// s.function();
// 这是一个私有方法,所以使用getDeclaredMethod()获取和setAccessible(true);取消访问检查
Method m4 = c.getDeclaredMethod("function");
m4.setAccessible(true);
m4.invoke(obj);
}
}
运行结果:

2.9 反射练习
2.9.1 练习1

向integer集合中添加字符串类型的数据,原本是不可能实现的,但是在反射中是可以的。
代码示例:
public class ReflectTest01 {
public static void main(String[] args) throws NoSuchMethodException, SecurityException, IllegalAccessException,
IllegalArgumentException, InvocationTargetException {
// 创建集合
ArrayList<Integer> array = new ArrayList<Integer>();
// 获取集合的Class对象
Class<? extends ArrayList> c = array.getClass();
// 调用集合Class对象的add方法
Method m = c.getMethod("add", Object.class);
// 添加数据
m.invoke(array, "hello");
m.invoke(array, "world");
m.invoke(array, "java");
System.out.println(array);
}
}
运行结果:

2.9.2 练习2

这样使用灵活性较强
代码示例:
学生(Student)类:
public class Student {
public void study() {
System.out.println("好好学习,天天向上");
}
}
教师(Teacher)类:
public class Teacher {
public void teach() {
System.out.println("用爱成就学生");
}
}
配置文本:
class.text

测试类:
public class ReflectTest02 {
public static void main(String[] args)
throws IOException, ClassNotFoundException, NoSuchMethodException, SecurityException,
InstantiationException, IllegalAccessException, IllegalArgumentException, InvocationTargetException {
// 加载数据
Properties prop = new Properties();
FileReader fr = new FileReader("src\\myRrflect03\\class.text");
prop.load(fr);
fr.close();
// className=myRrflect03.Student
// methodNmae=study
String className = prop.getProperty("className");
String methodName = prop.getProperty("methodNmae");
// 通过反射来使用
Class<?> c = Class.forName(className);// myRrflect03.Student
Constructor<?> con = c.getConstructor();
Object obj = con.newInstance();
Method m = c.getMethod(methodName);// study
m.invoke(obj);
}
}
运行结果:

修改配置类运行:


Java基础00-反射35的更多相关文章
- 黑马程序员:Java基础总结----反射
黑马程序员:Java基础总结 反射 ASP.Net+Android+IO开发 . .Net培训 .期待与您交流! 反射 反射的基石:Class类 Class类代表Java类,它的各个实例对象又分别 ...
- Java基础之一反射
反射是框架设计的灵魂 (使用的前提条件:必须先得到代表的字节码的Class,Class类用于表示.class文件(字节码)) 一.反射的概述 JAVA反射机制是在运行状态中,对于任意一个类,都能够 ...
- Java基础之—反射
反射是框架设计的灵魂 (使用的前提条件:必须先得到代表的字节码的Class,Class类用于表示.class文件(字节码)) 一.反射的概述 JAVA反射机制是在运行状态中,对于任意一个类,都能够 ...
- JAVA基础知识|反射
一.理解反射 1.1.基础概念 反射:在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法:对于任意一个对象,都能够调用它的任意方法和属性:这种动态获取信息以及动态调用对象方法的功能称为ja ...
- java基础之反射机制
一.概念 JAVA反射机制是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法:对于任意一个对象,都能够调用它的任意一个方法和属性:这种动态获取的信息以及动态调用对象的方法的功能称为jav ...
- Java基础(00)
Java发展史 Java之父:詹姆斯.高斯林(James Gosling). SUN(Stanford University Network 斯坦福大学网络公司)产物. 1995年5月23日,java ...
- java基础(十一 )-----反射——Java高级开发必须懂的
本文我们通过一个实际的例子来演示反射在编程中的应用,可能之前大家对反射的学习,仅仅是停留在概念层面,不知道反射究竟应用在哪,所以是一头雾水.相信通过这篇教程,会让你对反射有一个更深层次的认知. 概念 ...
- java基础之反射---重要
java反射: 反射是框架设计的灵魂 (使用的前提条件:必须先得到代表的字节码的Class,Class类用于表示.class文件(字节码)): 1:获取Class字节码文件对象的三种方式: /** ...
- 【Java基础】反射和注解
前言 在Java中,反射机制和注解机制一直是一个很重要的概念,那么他们其中的原理是怎么样呢,我们不仅仅需要会使用,更要知其然而之所以然. 目录 反射机制 反射如何使用 注解定义 注解机制原理 注解如何 ...
- java基础篇---反射机制
一.JAVA是动态语言吗? 一般而言,说到动态言,都是指在程序运行时允许改变程序结构或者变量类型,从这个观点看,JAVA和C++一样,都不是动态语言. 但JAVA它却有着一个非常突出的动态相关机制:反 ...
随机推荐
- 自动驾驶QNX,Linux,Autosar概述
自动驾驶QNX,Linux,Autosar概述 QNX是一个分布式.嵌入式.可规模扩展的实时操作系统.遵循POSIX.1 (程序接口)和POSIX.2 (Shell和工具).部分遵循POSIX.1b( ...
- Consistent 与 Mirrored 视角
Consistent 与 Mirrored 视角 在进行分布式训练时,OneFlow 框架提供了两种角度看待数据与模型的关系,被称作 consistent 视角与 mirrored 视角. 本文将介绍 ...
- 基于TensorRT的BERT实时自然语言理解(上)
基于TensorRT的BERT实时自然语言理解(上) 大规模语言模型(LSLMs)如BERT.GPT-2和XL-Net为许多自然语言理解(NLU)任务带来了最先进的精准飞跃.自2018年10月发布以来 ...
- ContOS8 配置MariaDB
导语: 该篇文章主要记录ContOS8安装MariaDB后的一些配置内容,若想要详细了解安装过程请移步至上一篇博文! 正文: 首先对MariaDB进行相关的简单配置 使用mysql_secure_in ...
- GD32F330 | ADC实例 基于DMA方式
GD32F330 | ADC实例 基于DMA方式 简单记录一下 ADC多通道转换 DMA搬运 的使用,以 GD32F330G8U6 为例: 一.ADC 基础知识 12位ADC是一种采用逐次逼近方式的模 ...
- 『居善地』接口测试 — 12、Moco框架介绍
目录 1.Mock功能介绍 2.Moco框架介绍 3.Moco框架在接口测试中的作用 4.Moco框架的优点 5.Moco框架的下载与启动 (1)Moco框架的下载 (2)Moco框架的启动 1.Mo ...
- 再看 Java 中的单例
此前面试遇到了单例问题,本以为已经背的滚瓜烂熟,没想到被问单例如何避免被反射和序列化破坏,虽然后来还是等到了通知,但还是复习一下单例的实现方式,并学习防止反射和序列化破坏的手段. 基本实现方式 其他相 ...
- 我的物联网大学【第二章】:Luat的出世
壹 启动火种 有一位软件行业的大神,名字叫做许小刚. 小刚是一位憨厚的年轻的码农,嵌入式.后端.前端,无所不能,是一个很牛的物联网全栈工程师,也是一家物联网软件公司的创始人兼CEO. 有次跟我.老陆. ...
- 【模板】Linux下输出文件的对比
命令格式: diff+[参数]+[文件1或目录1]+[文件2或目录2] 命令参数: 指定要显示多少行的文本.此参数必须与-c或-u参数一并使用. -a或--text diff预设只会逐行比较文本文件. ...
- ES6、ES7的一些新特性
1.常见的就是let 和 const 命令 let 只在命令所在的代码块内有效 const声明一个只读的常量 2.变量的赋值 let [a, b, c] = [1, 2, 3]; 这样输出的话a=1, ...