Apache Commons BCEL与Java字节码操作

第1章:Apache Commons BCEL简介

大家好,我是小黑,咱们今天来聊聊Apache Commons BCEL(Byte Code Engineering Library)。你可能会问,BCEL是什么鬼?别急,小黑这就给你娓娓道来。BCEL,它是一款专门用来操作Java字节码的库。想象一下,Java代码编译后变成了字节码,这些字节码是Java虚拟机执行的真正“源代码”。有了BCEL,咱们就能像变魔术一样,对这些字节码进行读取、修改,甚至创造出全新的字节码!

那为啥要搞字节码呢?这事儿得从Java的运行原理说起。Java代码编译后变成字节码,然后由JVM(Java虚拟机)转换成机器码执行。这个过程中,字节码扮演了极其重要的角色。通过操作字节码,咱们可以实现一些高级的技巧,比如动态生成类、修改类的行为,甚至是进行性能优化。所以,了解和掌握BCEL,对于深入理解Java,乃至于高级编程技巧,都是大有裨益的。

第2章:BCEL的依赖与基础配置

假设你用的是Maven,那就在项目的pom.xml文件里加入以下依赖:

<dependency>
    <groupId>org.apache.bcel</groupId>
    <artifactId>bcel</artifactId>
    <version>6.5.0</version> <!-- 这里写你想用的版本号 -->
</dependency>

搞定这些,BCEL就准备好了。但别急着走,小黑再给你看点干货。接下来,咱们来看看怎么用BCEL读取一个类的字节码。下面这段代码,展示了如何加载一个类文件,并打印出它的字节码结构:

import org.apache.bcel.classfile.ClassParser;
import org.apache.bcel.classfile.JavaClass;

import java.io.IOException;

public class BcelExample {
    public static void main(String[] args) {
        try {
            // 假设有个名为ExampleClass.class的类文件
            String classFilePath = "ExampleClass.class";
            JavaClass javaClass = new ClassParser(classFilePath).parse();

            // 打印字节码结构
            System.out.println(javaClass);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

这段代码里,ClassParser是BCEL提供的一个工具类,用来解析类文件。咱们通过它来加载一个类文件,然后就能获取到这个类的JavaClass对象。打印出来的内容,就是这个类的字节码结构啦。

第3章:Java字节码基础

咱们来聊聊Java的心脏部分——字节码。你可能经常听说,但真正搞清楚它是啥的人并不多。字节码,就是Java源代码编译后的产物,它是一种中间代码,既不是完全的机器语言,也不是咱们写的那些高级语言代码。JVM(Java虚拟机)就是通过解释或编译这些字节码来运行咱们的程序。

搞懂字节码,关键在于理解它和Java源代码之间的关系。当小黑写了一个简单的Java类,比如这样一个HelloWorld类:

public class HelloWorld {
    public static void main(String[] args) {
        System.out.println("Hello,World!");
    }
}

编译后,这段代码就变成了一系列的字节码指令。这些指令对应着JVM内的操作。比如,方法调用、变量加载、算术运算等等,都有相应的字节码指令。

现在,让小黑带你看看这个过程。咱们可以用javap这个工具来查看编译后的字节码。就拿上面的HelloWorld类为例,编译后在命令行运行:

javap -c HelloWorld

你会看到类似这样的输出:

Compiled from "HelloWorld.java"
public class HelloWorld {
  public HelloWorld();
    Code:
       0: aload_0
       1: invokespecial #1                  // Method java/lang/Object."<init>":()V
       4: return

  public static void main(java.lang.String[]);
    Code:
       0: getstatic     #2                  // Field java/lang/System.out:Ljava/io/PrintStream;
       3: ldc           #3                  // String Hello,World!
       5: invokevirtual #4                  // Method java/io/PrintStream.println:(Ljava/lang/String;)V
       8: return
}

这就是HelloWorld类的字节码表示。可以看到,每一行都对应着一些特定的操作,像aload_0invokespecial这些就是字节码指令。字节码以一种非常低级和紧凑的格式,表示了Java代码的逻辑。

理解了这些基础后,使用BCEL来操作字节码就不再那么神秘了。实际上,BCEL就是提供了一系列API,帮助咱们读取、修改和生成这些字节码指令。通过学习和实践,咱们可以越来越深入地理解Java的运行机制,甚至能做出一些平时不太可能实现的事情,比如动态生成类或修改类的行为。

第4章:探索BCEL的核心功能

读取字节码

首先来看看怎么用BCEL读取一个已经存在的类的字节码。比如说,小黑之前演示过如何用ClassParser来解析类文件。但BCEL还能做得更深入。它可以让咱们不仅读取类的结构,还能深入到每个方法,甚至是单个指令级别。

import org.apache.bcel.classfile.ClassParser;
import org.apache.bcel.classfile.JavaClass;
import org.apache.bcel.classfile.Method;

import java.io.IOException;

public class ReadBytecodeExample {
    public static void main(String[] args) {
        try {
            JavaClass javaClass = new ClassParser("HelloWorld.class").parse();
            System.out.println("类名: " + javaClass.getClassName());

            // 遍历所有方法
            for (Method method : javaClass.getMethods()) {
                System.out.println("方法名: " + method.getName());
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

在这个例子里,咱们不仅获取了类的名称,还遍历了它的所有方法。这只是开始,BCEL还能让咱们进一步探索每个方法的字节码。

修改字节码

接着,来看看如何使用BCEL修改字节码。这是BCEL最激动人心的部分之一。想象一下,咱们可以动态地改变一个类的行为,甚至在运行时添加新的方法或字段。

不过,修改字节码可不是小事,需要谨慎对待。这里只是给个简单的例子,演示如何修改一个方法中的返回值。

import org.apache.bcel.generic.ClassGen;
import org.apache.bcel.generic.MethodGen;
import org.apache.bcel.generic.InstructionList;
import org.apache.bcel.generic.InstructionFactory;
import org.apache.bcel.generic.ReturnInstruction;
import org.apache.bcel.classfile.Method;

public class ModifyBytecodeExample {
    public static void modifyMethod(ClassGen classGen, String methodName) {
        for (Method method : classGen.getMethods()) {
            if (method.getName().equals(methodName)) {
                InstructionList il = new InstructionList();
                MethodGen methodGen = new MethodGen(method, classGen.getClassName(), classGen.getConstantPool());
                
                // 修改方法内容
                // 这里只是简单地创建一个返回指令,实际情况要复杂得多
                ReturnInstruction returnInstruction = InstructionFactory.createReturn(methodGen.getReturnType());
                il.append(returnInstruction);

                methodGen.setInstructionList(il);
                methodGen.setMaxStack();
                classGen.replaceMethod(method, methodGen.getMethod());
                break;
            }
        }
    }
}

在这个例子中,小黑定义了一个modifyMethod函数,它接受一个ClassGen对象和方法名。这个函数会找到指定的方法,并创建一个新的指令列表替换原来的内容。注意,这里的修改非常简单,只是演示用法。在实际应用中,你可能需要处理更复杂的逻辑。

生成字节码

最后,咱们来看看BCEL如何生成全新的字节码。这意味着你可以从头开始,创建一个全新的类,完全按照你的想法。

import org.apache.bcel.generic.ClassGen;
import org.apache.bcel.generic.MethodGen;
import org.apache.bcel.generic.InstructionList;
import org.apache.bcel.generic.InstructionFactory;
import org.apache.bcel.generic.Type;
import org.apache.bcel.Constants;

public class CreateBytecodeExample {
    public static void main(String[] args) {
        ClassGen classGen = new ClassGen("GeneratedClass", "java.lang.Object", "<generated>", 
                                         Constants.ACC_PUBLIC | Constants.ACC_SUPER, null);

        InstructionList il = new InstructionList();
        MethodGen methodGen = new MethodGen(Constants.ACC_PUBLIC, Type.VOID, 
                                            Type.NO_ARGS, null, "generatedMethod", 
                                            "GeneratedClass", il, classGen.getConstantPool());
        
        // 添加方法指令
        il.append(InstructionFactory.createReturn(Type.VOID));

        methodGen.setMaxStack();
        classGen.addMethod(methodGen.getMethod());
        il.dispose(); // 清理指令列表资源

        // 生成类文件
        try {
            classGen.getJavaClass().dump("GeneratedClass.class");
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

在这个例子里,咱们创建了一个全新的类GeneratedClass,并给它添加了一个方法generatedMethod。这只是个起点,实际上你可以添加任何你想要的方法和字段。

第5章:字节码操作实战案例

案例1:动态添加新方法

想象一下,如果在运行时给一个类动态地添加一个新方法会怎样?听起来像是魔法,但用BCEL,这完全可行。比如,咱们有一个简单的类,想给它添加一个打印消息的方法。

先看看原始的类:

public class SimpleClass {
    // 这里可能有其他代码
}

现在,小黑来展示如何使用BCEL为这个类添加一个新的方法:

import org.apache.bcel.generic.ClassGen;
import org.apache.bcel.generic.MethodGen;
import org.apache.bcel.generic.InstructionList;
import org.apache.bcel.generic.InstructionFactory;
import org.apache.bcel.generic.Type;
import org.apache.bcel.Constants;

public class AddMethodExample {
    public static void main(String[] args) {
        ClassGen classGen = new ClassGen("SimpleClass", "java.lang.Object", "<generated>", 
                                         Constants.ACC_PUBLIC | Constants.ACC_SUPER, null);

        // 创建一个打印消息的指令列表
        InstructionList il = new InstructionList();
        il.append(InstructionFactory.createPrintln("这是动态添加的方法!"));
        il.append(InstructionFactory.createReturn(Type.VOID));

        // 创建一个新方法
        MethodGen methodGen = new MethodGen(Constants.ACC_PUBLIC | Constants.ACC_STATIC, Type.VOID, 
                                            Type.NO_ARGS, null, "dynamicMethod", 
                                            "SimpleClass", il, classGen.getConstantPool());
        
        methodGen.setMaxStack();
        classGen.addMethod(methodGen.getMethod());
        il.dispose(); // 清理资源

        // 生成类文件
        try {
            classGen.getJavaClass().dump("SimpleClass.class");
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

在这个例子中,小黑创建了一个名为dynamicMethod的新方法,并添加了打印消息的指令。之后,这个方法被添加到SimpleClass中,生成了新的类文件。

案例2:修改现有方法的行为

再来一个更实际的例子。假设咱们有一个方法,现在想改变它的行为。比如,有个方法原来是返回一个整数,现在想让它返回这个整数的两倍。

看看原始方法:

public class MathClass {
    public static int doubleValue(int value) {
        return value;
    }
}

小黑来展示怎么用BCEL修改这个方法:

import org.apache.bcel.generic.*;

public class ModifyMethodExample {
    public static void main(String[] args) {
        // ... 加载MathClass,获取ClassGen实例 ...

        for (Method method : classGen.getMethods()) {
            if (method.getName().equals("doubleValue")) {
                InstructionList il = new InstructionList();
                MethodGen methodGen = new MethodGen(method, classGen.getClassName(), classGen.getConstantPool());

                // 创建新的指令列表
                il.append(InstructionFactory.createLoad(Type.INT, 0)); // 加载第一个参数
                il.append(new PUSH(classGen.getConstantPool(), 2));    // 加载常数2
                il.append(InstructionConstants.IMUL);                  // 相乘
                il.append(InstructionFactory.createReturn(Type.INT));  // 返回结果

                methodGen.setInstructionList(il);
                methodGen.setMaxStack();
                classGen.replaceMethod(method, methodGen.getMethod());
            }
        }

        // ... 保存修改后的类文件 ...
    }
}

在这个例子里,小黑修改了doubleValue方法,使其返回参数的两倍值。通过这样的操作,咱们可以动态地改变类的行为。

第6章:性能考量与最佳实践

性能考量

字节码操作直接影响到了程序的底层逻辑。例如,一个不经意的更改可能会引入额外的方法调用或循环,这些都可能对性能产生负面影响。尤其是在高性能要求的应用中,这些影响更是不能忽视。

比如说,咱们在一个被频繁调用的方法中添加了额外的日志记录。这听起来没什么大不了的,但如果这个方法是性能敏感的核心路径上的一个环节,那么这个看似无害的更改就可能引起性能的显著下降。

最佳实践

为了确保使用BCEL时能够兼顾性能和功能,咱们需要遵循一些最佳实践:

  1. 明确目标:在进行字节码操作之前,一定要明确你要实现的功能和目标。不要无目的地修改字节码。

  2. 避免过度优化:有时候,为了追求极致的性能,可能会过度优化字节码,这不仅会使代码难以理解,而且可能引入难以发现的bug。

  3. 测试与评估:在进行字节码操作后,一定要进行充分的测试,包括功能测试和性能测试。确保修改没有引入新的问题,并且性能表现符合预期。

  4. 文档记录:字节码的修改应该有详细的记录和文档,尤其是对于复杂的修改。这样在未来维护或调试时,可以快速了解代码的初衷和逻辑。

  5. 安全性考虑:在修改字节码时,要考虑到安全性的问题。不当的字节码修改可能会引入安全漏洞,例如暴露敏感数据或提供非法访问。

举个简单的例子,假设咱们要为一个方法添加性能监控的代码。这样的需求在实际开发中很常见。看看下面的代码:

import org.apache.bcel.generic.*;

public class PerformanceMonitoringExample {
    // 假设这是咱们要修改的方法
    public static void methodToMonitor() {
        // 方法原始内容
    }

    public static void main(String[] args) {
        // ... 获取ClassGen和MethodGen实例 ...

        // 在方法开始和结束处添加监控代码
        InstructionList il = new InstructionList();
        il.append(InstructionFactory.createPrintln("监控开始"));
        // ... 原有方法的指令 ...
        il.append(InstructionFactory.createPrintln("监控结束"));

        // ... 更新方法 ...
    }
}

在这个例子中,小黑添加了开始和结束监控的打印语句。这是一种非常简单的性能监控,但在实际应用中,咱们可能会使用更复杂的性能监控工具。

第7章:BCEL与其他字节码操作工具的比较

ASM

ASM 是一个非常流行且功能强大的字节码操作和分析框架。它的设计目标是性能和低层次操作。ASM 提供了直接和底层的字节码操作能力,这意味着它的性能通常比其他库更好,但同时也意味着使用它需要更深入的字节码知识。

// 使用ASM修改一个方法的示例
import org.objectweb.asm.ClassWriter;
import org.objectweb.asm.MethodVisitor;
import org.objectweb.asm.Opcodes;

public class AsmExample {
    public static byte[] modifyMethod(String className) {
        ClassWriter cw = new ClassWriter(ClassWriter.COMPUTE_FRAMES);
        // ... 类的创建和方法的访问 ...

        MethodVisitor mv = cw.visitMethod(Opcodes.ACC_PUBLIC, "methodName", "()V", null, null);
        // ... 方法的修改 ...

        cw.visitEnd();
        return cw.toByteArray();
    }
}

在这个例子中,ASM 通过 ClassWriterMethodVisitor 类提供了对字节码的底层访问和修改能力。

CGLIB

CGLIB 是另一个在Java社区中广泛使用的字节码操作库。它主要用于运行时动态生成和操作类。CGLIB 通常被用于实现诸如动态代理、AOP(面向切面编程)等功能。CGLIB 的API比ASM的更高层次,更易于使用,但它的性能和灵活性通常不如ASM。

// 使用CGLIB动态创建代理类的示例
import net.sf.cglib.proxy.Enhancer;
import net.sf.cglib.proxy.MethodInterceptor;

public class CglibExample {
    public static Object createProxy(Class<?> targetClass) {
        Enhancer enhancer = new Enhancer();
        enhancer.setSuperclass(targetClass);
        enhancer.setCallback((MethodInterceptor) (obj, method, args, proxy) -> {
            // ... 方法拦截逻辑 ...
            return proxy.invokeSuper(obj, args);
        });
        return enhancer.create();
    }
}

在这个例子中,CGLIB 的 Enhancer 类用于创建一个新的代理类,可以拦截方法调用。

BCEL vs ASM vs CGLIB
  • 性能:ASM 提供了极高的性能和底层操作能力,适合需要高性能或者深入字节码层面的场景。CGLIB 在性能上略逊于ASM,但依然非常有效。BCEL 提供了更多的易用性,但在性能方面可能不如前两者。

  • 易用性:BCEL 和 CGLIB 都提供了相对易于理解的API,适合不太熟悉字节码的开发者。ASM 的API更低层次,使用起来更复杂,但提供了更大的灵活性。

  • 应用场景:ASM 在需要直接和底层操作字节码的场景中表现最佳,如性能监控工具、高级代码分析工具。CGLIB 常用于AOP和代理场景。BCEL 则在需要读取、分析和修改类文件时非常有用,尤其是在教育和研究领域。

第8章:总结

  • 读取和分析字节码:BCEL为咱们提供了一种强大的方式来读取和分析Java字节码,这在很多高级的Java应用中是非常有用的。

  • 修改和生成字节码:BCEL不仅能读取字节码,还能修改甚至生成新的字节码。这个功能开启了无限的可能性,让咱们能够在运行时改变Java类的行为,甚至动态创建全新的类。

  • 丰富的应用场景:从性能优化到动态代码生成,从教育研究到工业级应用,BCEL的应用场景非常丰富。

但是,操纵字节码不是一件轻松的事情。咱们在使用BCEL的过程中可能会遇到一些挑战:

  • 性能考虑:任何字节码的修改都可能影响到程序的性能,因此在进行修改时,性能考量是不可忽视的。

  • 安全风险:错误的字节码修改可能会引入安全漏洞,因此在修改字节码时,安全性是必须要考虑的。

  • 学习曲线:学习如何正确和高效地使用BCEL需要时间和实践,尤其是对于那些对字节码不太熟悉的开发者来说。

通过比较ASM和CGLIB,咱们可以发现,每个字节码操作工具都有其独特之处。ASM提供了更底层的控制能力和更高的性能,而CGLIB则更易于使用,适合于不需要深入字节码层面的场景。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mfbz.cn/a/292106.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

力扣刷题-二叉树-二叉搜索树中的搜索

700 二叉搜索树中的搜索 给定二叉搜索树&#xff08;BST&#xff09;的根节点和一个值。 你需要在BST中找到节点值等于给定值的节点。 返回以该节点为根的子树。 如果节点不存在&#xff0c;则返回 NULL。 例如&#xff0c; 在上述示例中&#xff0c;如果要找的值是 5&#x…

npm安装sharp出现的问题(安装失败的问题及解决)

npm安装sharp库出现的问题及解决 npm安装sharp出现的问题及解决&#xff1a; Buffer的使用以及对图片的操作&#xff08;通过sharp库对图片进行操作&#xff09; npm安装sharp出现的问题及解决&#xff1a; 在使用npm安装sharp一直安装不成功。后面发现安装sharp需要依赖libvip…

Spring常用注解及模拟用户登录流程示例

注解 Resource注解实现自动注入 (反射)代码块xml配置文件 Autowired注解实现自动化注入代码块xml配置文件 扫描器-四个注解Dao层-RepositoryService层-ServiceController层-Controller测试任意类-Component 常用注解示例-模拟用户登录配置自动扫描的xml文件实体类Userdao层消息…

【机器学习基础】DBSCAN

&#x1f680;个人主页&#xff1a;为梦而生~ 关注我一起学习吧&#xff01; &#x1f4a1;专栏&#xff1a;机器学习 欢迎订阅&#xff01;相对完整的机器学习基础教学&#xff01; ⭐特别提醒&#xff1a;针对机器学习&#xff0c;特别开始专栏&#xff1a;机器学习python实战…

知识图谱企业图谱怎么做

随着人工智能技术的不断发展&#xff0c;知识图谱技术逐渐在各行各业得到了广泛应用&#xff0c;为各行业企业提供了强有力的数据分析手段。尤其是在金融、医疗、电商等领域&#xff0c;企业知识图谱技术可以帮助企业解决数据孤岛、信息孤岛等问题&#xff0c;实现数据整合与共…

腾讯云企业用户优惠活动整理汇总

腾讯云一直致力于为广大企业用户提供高品质、高性价比的云计算产品和服务。为了帮助企业用户更好地了解腾讯云的优惠活动&#xff0c;本文将对腾讯云企业用户的优惠活动进行整理汇总。 一、新客专享福利 腾讯云为新用户提供了一系列的优惠活动&#xff0c;除了可以领取专属代金…

[Mac软件]Boxy SVG 4.20.0 矢量图形编辑器

Boxy SVG 是一款入门级矢量图形编辑器&#xff0c;具有全套基本功能、易于学习的选项卡式界面和可自定义的键盘快捷键。有了它&#xff0c;您可以轻松创建横幅、图标、按钮、图形、界面草图&#xff0c;甚至有趣的表情包。 编辑器支持使用多种工具创建和编辑矢量对象&#xff…

【普中开发板】基于51单片机的篮球计分器液晶LCD1602显示( proteus仿真+程序+设计报告+讲解视频)

基于普中开发板51单片机的篮球计分器液晶LCD1602显示 1.主要功能&#xff1a;讲解视频&#xff1a;2.仿真3. 程序代码4. 设计报告5. 设计资料内容清单&&下载链接资料下载链接&#xff08;可点击&#xff09;&#xff1a; 基于51单片机的篮球计分器液晶LCD1602显示 ( pr…

【LLM】大型语言模型综述论文

今天我将与大家分享一篇精彩的论文。这项调查提供了LLM文献的最新综述&#xff0c;这对研究人员和工程师来说都是一个有用的资源。 为什么选择LLM&#xff1f; 当参数尺度超过一定水平时&#xff0c;这些扩展的语言模型不仅实现了显著的性能改进&#xff0c;而且还表现出一些…

1*2*3+3*4*5+...+99*100*101python,1加到100的程序算法python

大家好&#xff0c;本文将围绕python中123一直加到100程序怎么写展开说明&#xff0c;计算123456...100的值python是一个很多人都想弄明白的事情&#xff0c;想搞清楚计算1-23-45 … -100的值python需要先了解以下几个事情。 今天下午上python课的时候&#xff0c;老师留了一个…

Nginx 的SSL证书配置

目录 1.申请域名&#xff0c;证书下载 2.准备站点源代码 3.修改nginx 对应网站的配置文件 4.修改 host 文件 http协议访问的网站默认会显示不安全&#xff0c;因为数据默认是明文传输的 https是httpssl&#xff0c;ssl是加密协议&#xff0c;通过证书来进行加密的&#xff…

【Leetcode】2487. 从链表中移除节点

文章目录 题目思路代码 题目 2487. 从链表中移除节点 思路 1、递归移除节点&#xff1a; 如果头节点为空&#xff0c;直接返回空。递归调用函数处理下一个节点 head->next。在递归返回后&#xff0c;判断当前节点的值是否小于之前记录的最大值 maxVal。如果小于 maxVal…

全国计算机等级考试| 二级Python | 真题及解析(7)

一、选择题 1.python中,表达式5%2 = ( )。 A.2.5 B.2 C.1 D.0 2.已知字符串a="python",则a[ 1 : 3 ]的值为( ) A."pyth" B."pyt" C."py" D…

2023年工作初体验

23年终于正式入职&#xff0c;参与了正式上线的电商平台、crm平台等项目的研发&#xff0c;公司规模较小&#xff0c;气氛融洽&#xff0c;没有任何勾心斗角、末位淘汰&#xff0c;几乎没什么压力。虽然是我的第一家公司&#xff0c;但实际是个适合养老的公司&#xff08;笑 总…

郑州大学算法设计与分析实验2

判断题 1 #include<bits/stdc.h> using namespace std;const int N 50; int f[N], n;int main() { // freopen("1.in", "r", stdin);ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);cin >> n;f[1] 1; f[2] 1;for(int i 3; i &l…

教程:Centos6迁移旧虚拟机文件后的网络配置教程,完美解决虚拟机移动后的网络ip变化问题

博主在工作后,想整整之前大学的虚拟机集群,因此特意从之前的旧电脑把虚拟机文件给拷贝了过来,在导入到vm-workstation,顺便能启动虚拟机后,发现之前的静态ip已经跟现在的宿主机网络不一样。想着重新配置,但觉得太麻烦,故想到了修改网卡的mac地址+网卡重配置方法,完美解…

基于多反应堆的高并发服务器【C/C++/Reactor】(中)Buffer的创建和销毁、扩容、写入数据

TcpConnection:封装的就是建立连接之后得到的用于通信的文件描述符&#xff0c;然后基于这个文件描述符&#xff0c;在发送数据的时候&#xff0c;需要把数据先写入到一块内存里边&#xff0c;然后再把这块内存里边的数据发送给客户端&#xff0c;除了发送数据&#xff0c;剩下…

Ajax基础入门_Ajax概述,同步与异步,Axios的使用,JSON数据及FastJSON的使用

Ajax 文章目录 Ajax1 概述2 作用3 同步和异步3.1 同步3.2 异步 4 代码编写4.1 服务端4.2 客户端 5 Axios5.1 使用5.2 代码5.2.1 前端5.2.2 后端 5.3 请求方法别名 6 JSON6.1 概述6.2 JSON 基础语法6.2.1 定义格式6.2.2 js 对象与JSON的转换 6.3 发送异步请求携带参数6.4 JSON串…

从0到1入门C++编程——03 内存分区、引用、函数高级应用

文章目录 一、内存分区二、引用三、函数的高级应用1.默认参数2.占位参数3.函数重载 一、内存分区 C程序在执行时&#xff0c;会将内存大致分为4个区&#xff0c;分别是代码区、全局区、栈区和堆区。 代码区用来存放函数体和二进制代码&#xff0c;由操作系统进行管理。 全局区…

docker镜像仓库详解(Docker Registry)

本片文章主要是对docker的镜像仓库进行了详解。其中包含了一些常用了 docker 指令&#xff0c;通过举例进行详解。也详细解释了镜像仓库的工作机制和常见的镜像仓库。也实际拉去和运行了一些镜像。希望本篇文章会对你有所帮助&#xff01; 文章目录 一、什么是Docker Registry …