Java 学习(22)---(类的加载与反射)

简介: 类的加载当程序要使用某个类时, 如果该类还未被加载到内存中, 则系统会通过加载,连接,初始化三步来实现对这个类进行初始化。

类的加载

当程序要使用某个类时, 如果该类还未被加载到内存中, 则系统会通过加载,连接,初始化三步来实现对这个类进行初始化

加载

就是指将 class 文件读入内存,并为之创建一个 Class对象。任何类被使用时系统都会建立一个 Class对象。

连接

验证是否有正确的内部结构,并和其他类协调一致准备负责为类的静态成员分配内存,并设置默认初始化值解析将类的二进制数据中的符号引用替换为直接引用

初始化

初始化步骤:

image

2 、类初始化时机

1.创建类的实例

2.访问类的静态变量,或者为静态变量赋值调用类的静态方法

3.使用反射方式来强制创建某个类或接口对应的 java.lang.Class对象

4.初始化某个类的子类

5.直接使用 java.exe 命令来运行某个主类

3 、类加载器

类加载器: 负责将 .class 文件加载到内在中,并为之生成对应的 Class对象。

虽然我们不需要关心类加载机制, 但是了解这个机制我们就能更好的理解程序的运行。

类加载器的组成

    1. Bootstrap ClassLoader 根类加载器

也被称为引导类加载器,负责 Java核心类的加载

比如 System,String 等。在 JDK中 JRE的 lib 目录下 rt.jar 文件中

    2. Extension ClassLoader 扩展类加载器

负责 JRE的扩展目录中 jar 包的加载。

在 JDK中 JRE的 lib 目录下 ext 目录

    3.Sysetm ClassLoader 系统类加载器

负责在 JVM 启动时加载来自 java 命令的 class 文件,以及 classpath 环境变量所指定的 jar 包和类路径

反射

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

要想解剖一个类 ,必须先要获取到该类的字节码文件对象。而解剖使用的就是 Class

类中的方法 .所以先要获取到每一个字节码文件对应的 Class 类型的对象 .

1.获取 class 文件对象的方式:

Object 类的 getClass() 方法

如: s.getClass();

数据类型的静态属性 class

如 : Student.class;

Class 类中的静态方法: public static Class forName(String className) ; // 完整类名

如: Class. forName( “cn.itcast.Student ” ) ;

一般我们到底使用谁呢 ?

A:自己玩 任选一种,

第二种比较方便

B:开发 第三种

因为第三种是一个字符串,而不是一个具体的类名。这样我们就可以把这样的字符串配置到配置文件中

2.获取构造方法

A、得到构造方法对象

 public Constructor[] getConstructors() : 所有公共构造方法

public Constructor[] getDeclaredConstructors(): 所有构造方法

获取单个构造方法

public Constructor<T> getConstructor(Class<?>... parameterTypes)

参数表示:你要获取的构造方法的构造参数个数及数据类型的 class 字节码文件对象

B、创建对象

 public T newInstance(Object... initargs)

使用此 Constructor 对象表示的构造方法来创建该构造方法的声明类的新实例, 并用指定的初始化参数初始化该实例

//	通过无参构造器
Constructor con = c.getConstructor(); Object obj = con.newInstance();
//	通过带参构造
Constructor	con  = c.getConstructor(String.	class	,	int	. class	,String.	class	); Object obj = con.newInstance(	" 林青霞 " , 27,		" 北京 " );
//	通过私用构造方法
Constructor con = c.getDeclaredConstructor(String.class);
//	暴力访问,值为	true	则指示反射的对象在使用时应该取消	Java 语言访问检查。
con.setAccessible(	true	);
Object obj = con.newInstance("	风清扬 ");

3.获取成员变量

public Field getField(String name) ;

返回一个 Field  对象,它反映此 Class 对象所表示的类或接口的指定公共成员字段

 public Field[] getFields() ;

返回一个包含某些 Field 对象的数组, 这些对象反映此 Class 对象所表示的类或接口的所有可访问公共字段。

//	获取字节码文件对象
Class c = Class.forName("cn.itcast_01.Person");
通过无参构造方法创建对象Constructor con = c.getConstructor(); Object obj = con.newInstance();
//	获取单个的成员变量
Field addressField = c.getField("address"	);
// public void set(Object obj,Object value)
//	将指定对象变量上此	Field	对象表示的字段设置为指定的新值。
addressField.set(obj,	" 北京 " );	//	给obj 对象的 addressField	字段设置值为	" 北京 "
//	获取 name并对其赋值
// NoSuchFieldException	,name属性为私有
Field nameField = c.getDeclaredField("name" );
// IllegalAccessException nameField.setAccessible(true); nameField.set(obj,	" 林青霞 " );
//	获取 age 并对其赋值
Field ageField = c.getDeclaredField("age"); ageField.setAccessible(	true);
ageField.set(obj, 27);

4.获取成员方法并执行

public Method getMethod(String name,Class<?>... parameterTypes) ;

第一个参数表示的方法名,第二个参数表示的是方法的参数的 class 类型 public Method[] getMethods() ;获取自己的包括父亲的公共方法 public Method getDeclaredMethod(String name,

Class<?>... parameterTypes)

获取自己的包括父亲的任意方法

public Method[] getDeclaredMethods() ;

获取自己的包括父亲的所有方法

执行

Method 类的方法: public Object invoke(Object obj,Object... args) ;

返回值是 Object 接收 , 第一个参数表示对象是谁, 第二参数表示调用该方法的实际

参数

执行私有方法: public void setAccessible(boolean flag) ;取消访问检查

 

案例

通过配置文件运行类中的方法

//	加载键值对数据
Properties prop = new Properties();
FileReader fr =new FileReader( "class.txt");
prop.load(fr);
fr.close();
//	获取数据
String className = prop.getProperty("className"	);
String methodName = prop.getProperty("methodName");
//反射
Class c = Class.forName(className); Constructor con = c.getConstructor(); Object obj = con.newInstance();
//	调用方法
Method m = c.getMethod(methodName);
m.invoke(obj);

在  ArrayList<Integer> 这个集合里添加一个字符串数据

通过反射来实现

ArrayList<Integer> array = new ArrayList<Integer>();
// array.add("hello");
// array.add(10);
Class c = array.getClass(); //集合 ArrayList 的class	文件对象
Method m = c.getMethod(	"add"	, Object.	class	);
m.invoke(array,	"hello"	);	//	调用 array	的add 方法,传入的值是	hello m.invoke(array,	"world"	);
m.invoke(array,	"java"	);

5.代理模式

1)动态代理

1)代理对象,不需要实现接口,目标对象必须实现接口;

2)代理对象的生成,是利用 JDKAP,I  动态的在内存中构建代理对象

(需要我们指定创建代理对象 / 目标对象实现的接口的类型; );

3) 动态代理, JDK代理,接口代理;

publicclass	ProxyFactory {
//	维护一个目标对象
private	Object	target	;
public	ProxyFactory(Object target){ this. target= target;
}
//	给目标对象,生成代理对象
public	Object getProxyInstance() { return	Proxy.newProxyInstance(
target	.getClass().getClassLoader(),
target	.getClass().getInterfaces(), newInvocationHandler() {
@Override
public	Object invoke(Object proxy, Method method, Object[] args)	throws	Throwable { System.  out .println(	" 开启事务 " );
//	执行目标对象方法
Object returnValue = method.invoke(	target	, args); System.  out .println(	" 提交事务 " );
return	returnValue;
}
});
}
}
//	目标对象
IUserDao target =	new UserDao();
//	[原始的类型	class cn.itcast.b_dynamic.UserDao]
System.out.println(target.getClass());
//	给目标对象,创建代理对象
IUserDao proxy=(IUserDao) newProxyFactory(target).getProxyInstance();
// class $Proxy0	内存中动态生成的代理对象
System.out.println(proxy.getClass());
//	执行方法[代理对象]
proxy.save();

2) 静态代理

1)代理对象,要实现与目标对象一样的接口

2)举例 :

保存用户 (模拟)

Dao , 直接保存

DaoProxy, 给保存方法添加事务处理

publicclass	UserDaoProxy	implements	IUserDao{
//	接收保存目标对象
private  IUserDao target;
public UserDaoProxy(IUserDao target) {
this. target= target;
}
@Override
publicvoid	save() {
System.  out .println(	" 开始事务 ..."	);
target	.save();	//	执行目标对象的方法
System. out .println(" 提交事务 ..."	);
    }
}

总结静态代理

1)可以做到在不修改目标对象的功能前提下,对目标对象功能扩展。

2)缺点:因为代理对象,需要与目标对象实现一样的接口。所以会有很多代理类,类太多。

一旦接口增加方法,目标对象与代理对象都要维护。

目录
相关文章
|
7天前
|
存储 安全 Java
java.util的Collections类
Collections 类位于 java.util 包下,提供了许多有用的对象和方法,来简化java中集合的创建、处理和多线程管理。掌握此类将非常有助于提升开发效率和维护代码的简洁性,同时对于程序的稳定性和安全性有大有帮助。
34 17
|
2天前
|
存储 Java 程序员
Java基础的灵魂——Object类方法详解(社招面试不踩坑)
本文介绍了Java中`Object`类的几个重要方法,包括`toString`、`equals`、`hashCode`、`finalize`、`clone`、`getClass`、`notify`和`wait`。这些方法是面试中的常考点,掌握它们有助于理解Java对象的行为和实现多线程编程。作者通过具体示例和应用场景,详细解析了每个方法的作用和重写技巧,帮助读者更好地应对面试和技术开发。
26 4
|
2天前
|
Java 大数据 API
14天Java基础学习——第1天:Java入门和环境搭建
本文介绍了Java的基础知识,包括Java的简介、历史和应用领域。详细讲解了如何安装JDK并配置环境变量,以及如何使用IntelliJ IDEA创建和运行Java项目。通过示例代码“HelloWorld.java”,展示了从编写到运行的全过程。适合初学者快速入门Java编程。
|
3天前
|
Java 编译器 开发者
Java异常处理的最佳实践,涵盖理解异常类体系、选择合适的异常类型、提供详细异常信息、合理使用try-catch和finally语句、使用try-with-resources、记录异常信息等方面
本文探讨了Java异常处理的最佳实践,涵盖理解异常类体系、选择合适的异常类型、提供详细异常信息、合理使用try-catch和finally语句、使用try-with-resources、记录异常信息等方面,帮助开发者提高代码质量和程序的健壮性。
11 2
|
8天前
|
存储 安全 Java
如何保证 Java 类文件的安全性?
Java类文件的安全性可以通过多种方式保障,如使用数字签名验证类文件的完整性和来源,利用安全管理器和安全策略限制类文件的权限,以及通过加密技术保护类文件在传输过程中的安全。
|
12天前
|
Java 数据格式 索引
使用 Java 字节码工具检查类文件完整性的原理是什么
Java字节码工具通过解析和分析类文件的字节码,检查其结构和内容是否符合Java虚拟机规范,确保类文件的完整性和合法性,防止恶意代码或损坏的类文件影响程序运行。
|
12天前
|
Java API Maven
如何使用 Java 字节码工具检查类文件的完整性
本文介绍如何利用Java字节码工具来检测类文件的完整性和有效性,确保类文件未被篡改或损坏,适用于开发和维护阶段的代码质量控制。
|
11天前
|
存储 Java 编译器
java wrapper是什么类
【10月更文挑战第16天】
19 3
|
10天前
|
JavaScript Java 项目管理
Java毕设学习 基于SpringBoot + Vue 的医院管理系统 持续给大家寻找Java毕设学习项目(附源码)
基于SpringBoot + Vue的医院管理系统,涵盖医院、患者、挂号、药物、检查、病床、排班管理和数据分析等功能。开发工具为IDEA和HBuilder X,环境需配置jdk8、Node.js14、MySQL8。文末提供源码下载链接。
|
14天前
|
Java 程序员 测试技术
Java|让 JUnit4 测试类自动注入 logger 和被测 Service
本文介绍如何通过自定义 IDEA 的 JUnit4 Test Class 模板,实现生成测试类时自动注入 logger 和被测 Service。
20 5