黑马程序员——类加载器及其委托机制的深入分析

本文详细探讨了Java类加载器的工作原理,包括类加载器的分类、特殊作用、委托机制以及如何自定义类加载器。重点介绍了类加载过程中的加密与解密操作,并提供了自定义类加载器的编写原理分析与代码实现。

------- android培训java培训、期待与您交流! ----------

类加载器及其委托机制的深入分析。
(1),由来:JVM将类的字节码(编译好的class文件)加载到内存中。
这是一件很重要的事,这件事是由JVM分配给类加载器在做。
(2),分类:JVM可以有多个加载器。系统默认了3个主要的类加载器。 BootStrap(不是java类),ExtClassLoader,AppClassLoader 负责加载特定位置的类。
   (3),特殊:BootStrap。竟然类加载器也是java类,在用到它们的时候。同样,也需要类加载器进行加载。很显然,这个时候就需要一个不是Java类的加载器。需要找到这个鼻祖,充当这个鼻祖的就是:BootStrap。它不是java类。
   (4),关系:
 
每个加载器只能加载指定位置的类。也可以自己定义一个加载器,指定加载
的位置。级别关系:BootStrap->ExtClassLoader->AppClassLoader
体现这种关系的方法是:ClassLoader里面的getParent()方法。

(5),委托
原理,每个类加载器加载类时,都会委托给它的上级加载器。当所有的祖宗都没法加载这个类的时候,就会回到发起者类加载器。还是加载不了,就会抛出
ClassNotFoundException。不会再去找发起者类加载器的儿子,因为没有getChild方法。
好处,可以集中管理。上级加载完后,下级直接哪来用就行了。否则,会加载很多已经加载的类。
面试题:写一个java.lang.System
(6),指定加载器。
首先当前线程的类加载器去加载线程中的第一个类。如果类A中引用了类B,Java虚拟机将使用加载类A的类装载器来加载类B。还可以直接调用ClassLoader对象的.loadClass()方法来用当前的类加载器去加载某个类。

自定义类加载器的编写原理分析。
目标:自定义一个类加载器,并指定加载位置。保证该位置中的类都能被自定义类加载器加载。并且这些类的字节码都有进行加密处理。加载过程中进行解密。
设计模式:模版方法设计模式,父类指定处理大纲,子类规定具体内容的设计模式。一般,在父类中声明子类需要重写的抽象方法(findClass),并且父类中存在一个方法(loadClass)调用了这些方法,保证事件的流程来完成一件相对的大事。

返回字节码:defineClass
 
protected  Class<?> defineClass(String name, byte[] b, int off, int len, ProtectionDomain protectionDomain)
          使用可选的 ProtectionDomain 将一个 byte 数组转换为 Class 类的实例。 
只要得到字节码,完成这一步就算成功了。

 

编写对class文件进行加密的工具类。
(1),加密方法:
// 定义一个加密方法,对ClassLoaderAttachment进行加密。
 public static void cypher(InputStream in, OutputStream out)
   throws Exception {
  int b = -1;
  while ((b = in.read()) != -1) {
   b = b ^ 0xff;
   out.write(b);
  }
  in.close();
  out.close();
 }

(2),findClass方法:
@Override
protected Class<?> findClass(String name) throws ClassNotFoundException {
  String classPath = classDir+"\\"+name.subString(name.lastIndexOf(‘.’)+1)+".class";
  FileInputStream fis = null;
  ByteArrayOutputStream fos = null;
  try {
    fis = new FileInputStream(classPath);
    fos = new ByteArrayOutputStream();
    cypher(fis,fos);
    byte[] buf = fos.toByteArray();
//    byte[] buf = new byte[fis.available()];
//    fis.read(buf);
   
//    读取class文件,把读取的字节转换成字节码到内存中。
    return defineClass(buf, 0, buf.length);
  } catch (FileNotFoundException e) {
   e.printStackTrace();
  } catch (IOException e) {
   e.printStackTrace();
  } catch (Exception e) {
   e.printStackTrace();
  }finally{
   if(fis!=null){
    try {
     fis.close();
    } catch (IOException e) {
     e.printStackTrace();
    }
   }
  }
  return super.findClass(name);
 }

(3),调用:
 Class clazz = new MyClassLoader("classloaderlib").loadClass("classloader.ClassLoaderAttachment");
  ClassLoader loader = clazz.getClassLoader();
  while(loader!=null){
   System.out.println(loader.getClass().getName());
   loader = loader.getParent();
  }
//  ClassLoaderAttachment cla = (ClassLoaderAttachment) clazz.newInstance();
  System.out.println(loader);


 

### TCP传输原理与实现 TCP(Transmission Control Protocol)是一种面向连接的、可靠的、基于字节流的传输层协议。其核心原理是通过建立端到端的连接,确保数据在不可靠的网络中能够可靠地传输。TCP 使用确认机制、流量控制、拥塞控制等机制来保障数据的完整性和有序性。 在 Java 中,TCP 通信可以通过 `Socket` 和 `ServerSocket` 类实现。客户端使用 `Socket` 连接到服务器,服务器端使用 `ServerSocket` 监听连接请求。通信过程中,数据通过输入流和输出流进行传输。 #### 客户端实现 客户端的主要任务是与服务器建立连接,并通过输出流向服务器发送数据,同时可以通过输入流接收服务器的响应。例如: ```java Socket s = new Socket(InetAddress.getLocalHost(), 10004); OutputStream out = s.getOutputStream(); out.write("Hello TCPClient".getBytes()); InputStream is = s.getInputStream(); byte[] buffer = new byte[1024]; int len = is.read(buffer); System.out.println(new String(buffer, 0, len)); s.close(); ``` 该代码实现了客户端与服务器的连接,并发送了一条文本消息,同时接收服务器的响应[^1]。 #### 服务端实现 服务端通过 `ServerSocket` 监听指定端口,等待客户端连接。一旦连接建立,服务端通过输入流接收客户端发送的数据,并通过输出流向客户端发送响应。例如: ```java ServerSocket ss = new ServerSocket(10012); Socket s = ss.accept(); InputStream in = s.getInputStream(); byte[] buffer = new byte[1024]; int len = in.read(buffer); System.out.println(new String(buffer, 0, len)); PrintWriter out = new PrintWriter(s.getOutputStream(), true); out.println("<font color='red' size=7>客户端s你好</font>"); s.close(); ss.close(); ``` 该代码展示了如何在服务端接收客户端发送的数据,并向客户端发送 HTML 格式的响应[^3]。 #### TCP连接的建立与释放 TCP 连接的建立采用三次握手(Three-way Handshake): 1. 客户端发送 SYN(同步)报文给服务器,表示请求建立连接。 2. 服务器收到 SYN 报文后,发送 SYN-ACK(同步-确认)报文作为响应。 3. 客户端收到 SYN-ACK 后,发送 ACK(确认)报文,连接建立。 连接的释放采用四次挥手(Four-way Handshake): 1. 客户端发送 FIN(结束)报文,表示数据发送完成。 2. 服务器发送 ACK 报文,确认收到 FIN。 3. 服务器发送 FIN 报文,表示数据发送完成。 4. 客户端发送 ACK 报文,连接关闭。 #### TCP的可靠性机制 TCP 通过以下机制确保数据的可靠传输: - **确认机制**:接收方收到数据后,向发送方发送确认信息。 - **重传机制**:如果发送方未收到确认信息,则重传数据。 - **流量控制**:通过滑动窗口机制,控制发送速率,避免接收方缓冲区溢出。 - **拥塞控制**:通过慢启动、拥塞避免等算法,防止网络拥塞。 #### TCP的编程模型 TCP 编程模型通常包括以下几个步骤: 1. **创建 Socket**:客户端创建 `Socket` 对象,连接服务器;服务端创建 `ServerSocket` 对象,监听端口。 2. **获取流对象**:获取 `Socket` 的输入流和输出流,用于数据传输。 3. **数据读写**:通过输入流读取数据,通过输出流写入数据。 4. **关闭连接**:通信结束后,关闭 `Socket` 和流对象。 ### 示例代码:完整的 TCP 通信 以下是一个完整的 TCP 通信示例,包含客户端和服务端的代码。 #### 客户端代码 ```java import java.io.*; import java.net.*; public class TcpClient { public static void main(String[] args) { try { Socket socket = new Socket("localhost", 8888); OutputStream out = socket.getOutputStream(); out.write("Hello Server!".getBytes()); InputStream in = socket.getInputStream(); byte[] buffer = new byte[1024]; int len = in.read(buffer); System.out.println("Server response: " + new String(buffer, 0, len)); socket.close(); } catch (IOException e) { e.printStackTrace(); } } } ``` #### 服务端代码 ```java import java.io.*; import java.net.*; public class TcpServer { public static void main(String[] args) { try { ServerSocket serverSocket = new ServerSocket(8888); System.out.println("Server is listening on port 8888..."); Socket socket = serverSocket.accept(); InputStream in = socket.getInputStream(); byte[] buffer = new byte[1024]; int len = in.read(buffer); System.out.println("Client message: " + new String(buffer, 0, len)); OutputStream out = socket.getOutputStream(); out.write("Hello Client!".getBytes()); socket.close(); serverSocket.close(); } catch (IOException e) { e.printStackTrace(); } } } ``` ###
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值