1. 类加载器

深入理解java类加载器类加载器

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

  1. 黑马程序员:Java基础总结----反射

    黑马程序员:Java基础总结 反射   ASP.Net+Android+IO开发 . .Net培训 .期待与您交流! 反射 反射的基石:Class类 Class类代表Java类,它的各个实例对象又分别 ...

  2. Java基础之一反射

    反射是框架设计的灵魂 (使用的前提条件:必须先得到代表的字节码的Class,Class类用于表示.class文件(字节码))   一.反射的概述 JAVA反射机制是在运行状态中,对于任意一个类,都能够 ...

  3. Java基础之—反射

    反射是框架设计的灵魂 (使用的前提条件:必须先得到代表的字节码的Class,Class类用于表示.class文件(字节码))   一.反射的概述 JAVA反射机制是在运行状态中,对于任意一个类,都能够 ...

  4. JAVA基础知识|反射

    一.理解反射 1.1.基础概念 反射:在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法:对于任意一个对象,都能够调用它的任意方法和属性:这种动态获取信息以及动态调用对象方法的功能称为ja ...

  5. java基础之反射机制

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

  6. Java基础(00)

    Java发展史 Java之父:詹姆斯.高斯林(James Gosling). SUN(Stanford University Network 斯坦福大学网络公司)产物. 1995年5月23日,java ...

  7. java基础(十一 )-----反射——Java高级开发必须懂的

    本文我们通过一个实际的例子来演示反射在编程中的应用,可能之前大家对反射的学习,仅仅是停留在概念层面,不知道反射究竟应用在哪,所以是一头雾水.相信通过这篇教程,会让你对反射有一个更深层次的认知. 概念 ...

  8. java基础之反射---重要

    java反射: 反射是框架设计的灵魂 (使用的前提条件:必须先得到代表的字节码的Class,Class类用于表示.class文件(字节码)):   1:获取Class字节码文件对象的三种方式: /** ...

  9. 【Java基础】反射和注解

    前言 在Java中,反射机制和注解机制一直是一个很重要的概念,那么他们其中的原理是怎么样呢,我们不仅仅需要会使用,更要知其然而之所以然. 目录 反射机制 反射如何使用 注解定义 注解机制原理 注解如何 ...

  10. java基础篇---反射机制

    一.JAVA是动态语言吗? 一般而言,说到动态言,都是指在程序运行时允许改变程序结构或者变量类型,从这个观点看,JAVA和C++一样,都不是动态语言. 但JAVA它却有着一个非常突出的动态相关机制:反 ...

随机推荐

  1. Tensor基础实践

    Tensor基础实践 飞桨(PaddlePaddle,以下简称Paddle)和其他深度学习框架一样,使用Tensor来表示数据,在神经网络中传递的数据均为Tensor. Tensor可以将其理解为多维 ...

  2. Java中List集合转Map集合报错:Duplicate key

    一.问题由来 最近生成环境刚发布了一个版本,本人负责优化的一个功能在进行测试时,报错了一个异常,duplicate key;去百度里面看了一下, 意思很明确就是建重复,而且错误是在Java代码中抛出来 ...

  3. Django(63)drf权限源码分析与自定义权限

    前言 上一篇我们分析了认证的源码,一个请求认证通过以后,第二步就是查看权限了,drf默认是允许所有用户访问 权限源码分析 源码入口:APIView.py文件下的initial方法下的check_per ...

  4. 1738. 找出第 K 大的异或坐标值

    2021-05-19 LeetCode每日一题 链接:https://leetcode-cn.com/problems/find-kth-largest-xor-coordinate-value/ 标 ...

  5. 【渗透实战】那些奇葩的WAF_第二期_无意发现通杀漏洞,空字节突破上传!

    /文章作者:Kali_MG1937 CSDN博客号:ALDYS4 QQ:3496925334 未经许可,禁止转载/ 该博文为本人18年左右的渗透记录,文法粗糙,技术含量极低,流水账文章,且今日不知为何 ...

  6. Golang获取CPU、内存、硬盘使用率

    Golang获取CPU.内存.硬盘使用率 工具包 go get github.com/shirou/gopsutil 实现 func GetCpuPercent() float64 { percent ...

  7. hdu1232 并查集总结

    前言 在一些有N个元素的集合应用问题中,我们通常是在开始时让每个元素构成一个单元素的集合,然后按一定顺序将属于同一组的元素所在的集合合并,其间要反复查找一个元素在哪个集合中. 这一类问题其特点是看似并 ...

  8. kubelet分析-csi driver注册源码分析

    kubelet注册csi driver分析 kubelet注册csi driver的相关功能代码与kubelet的pluginManager有关,所以接下来对pluginManager进行分析.分析将 ...

  9. c++实现希尔密码

    实验名称: 希尔密码的实现(c++版;本文只以26个大写英文字符作为加密后的密文的可选项) 实验原理: 引用知识: 记 Zm={0,1,2,...,m-1} 定义1:设A为定义在集合Zm 上的n阶方阵 ...

  10. 乘风破浪,遇见下一代操作系统Windows 11,迄今为止最美版本,原生支持安卓应用

    遇见下一代操作系统Windows 11 全新Windows体验,让您与热爱的人和事物离得更近. Windows一直是世界创新的舞台.它是全球企业的基石,助力众多蓬勃发展的初创公司变得家喻户晓.网络在W ...