JVM-字节码应用

一、字节码的应用远超你的想象

二、ASM介绍与读取字节码实战

用CoreAPI解析和TreeAPI都能做字节码解析,区别,TreeAPI必须读取完整字节码信息,才能做解析。

下面代码,使用CoreAPI做解析:

package asm;

public class MyMain {

    public int a = 10;
    public int b = 11;

    public void test1() {

    }

    public void test2() {

    }

    public static void main(String[] args) {

    }
}
package util;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;

public class FileUtil {

    public static byte[] getContent(String filePath) throws IOException {
        File file = new File(filePath);
        long fileSize = file.length();
        if (fileSize > Integer.MAX_VALUE) {
            System.out.println("file too big...");
            return null;
        }
        FileInputStream fi = new FileInputStream(file);
        byte[] buffer = new byte[(int) fileSize];
        int offset = 0;
        int numRead = 0;
        while (offset < buffer.length
                && (numRead = fi.read(buffer, offset, buffer.length - offset)) >= 0) {
            offset += numRead;
        }
        // 确保所有数据均被读取
        if (offset != buffer.length) {
            throw new IOException("Could not completely read file "
                    + file.getName());
        }
        fi.close();
        return buffer;
    }

    public static void writeByteArrayToFile(String filePath, byte[] byteArray) {
        try {
            FileOutputStream fileOutputStream = new FileOutputStream(new File(filePath));
            fileOutputStream.write(byteArray);
            fileOutputStream.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

}
package asm;



import jdk.internal.org.objectweb.asm.*;
import util.FileUtil;

import java.io.IOException;

import static jdk.internal.org.objectweb.asm.Opcodes.ASM5;

/**
 * case1 读取一个字节码里的方法等信息
 */
public class ASMReadClassTest {

    public static void getClassInfoByCoreAPI(byte[] bytes) {
        ClassReader classReader = new ClassReader(bytes);
        ClassWriter classWriter = new ClassWriter(0);
        ClassVisitor classVisitor = new ClassVisitor(ASM5, classWriter) {
            @Override
            public void visit(int version, int access, String name, String signature, String superName, String[] interfaces) {
                super.visit(version, access, name, signature, superName, interfaces);
            }

            @Override
            public void visitSource(String source, String debug) {
                System.out.println("source in visitSource:" + source);
                super.visitSource(source, debug);
            }

            @Override
            public void visitOuterClass(String owner, String name, String desc) {
                super.visitOuterClass(owner, name, desc);
            }

            @Override
            public AnnotationVisitor visitAnnotation(String desc, boolean visible) {
                return super.visitAnnotation(desc, visible);
            }

            @Override
            public AnnotationVisitor visitTypeAnnotation(int typeRef, TypePath typePath, String desc, boolean visible) {
                return super.visitTypeAnnotation(typeRef, typePath, desc, visible);
            }

            @Override
            public void visitAttribute(Attribute attr) {
                System.out.println("visitAttribute attr: " + attr);
                super.visitAttribute(attr);
            }

            @Override
            public void visitInnerClass(String name, String outerName, String innerName, int access) {
                super.visitInnerClass(name, outerName, innerName, access);
            }

            @Override
            public FieldVisitor visitField(int access, String name, String desc, String signature, Object value) {
                System.out.println("visitField filed: " + name);
                return super.visitField(access, name, desc, signature, value);
            }

            @Override
            public MethodVisitor visitMethod(int access, String name, String desc, String signature, String[] exceptions) {
                System.out.println("visitMethod method: " + name);
                return super.visitMethod(access, name, desc, signature, exceptions);
            }

            @Override
            public void visitEnd() {
                System.out.println("visitEnd .... ");
                super.visitEnd();
            }
        };


        classReader.accept(classVisitor, ClassReader.SKIP_DEBUG);

    }
//
//
//    public static void getClassInfoByTreeAPI(byte[] bytes) {
//        ClassReader classReader = new ClassReader(bytes);
//        ClassNode classNode = new ClassNode();
//        classReader.accept(classNode, ClassReader.SKIP_DEBUG | ClassReader.SKIP_CODE);
//
//        List<FieldNode> fieldNodeList = classNode.fields;
//        for (FieldNode fieldNode : fieldNodeList) {
//            System.out.println("field node :" + fieldNode.name);
//        }
//
//        List<MethodNode> methodNodeList = classNode.methods;
//        for (MethodNode methodNode : methodNodeList) {
//            System.out.println("method :" + methodNode.name);
//        }
//
//    }

    public static void main(String[] args) throws IOException {
        String filePath = "/Users/mac/IdeaProjects/OOM/JVMSample/target/classes/asm/MyMain.class";
        byte[] bytes = FileUtil.getContent(filePath);
//        第一种方式,通过CoreAPI获得字节码信息
        getClassInfoByCoreAPI(bytes);
//        getClassInfoByTreeAPI(bytes);

    }
}

解释:

ASM5 - ASM的版本;

classWriter - 即上面的classWriter,处理完成后,将信息携带哪里去。

classReader.accept方法的第一个参数是classVisitor,即上面定义的classVisitor, 第二个ClassReader.SKIP_DEBUG,操作的时候,哪些信息不看,这里是跳过debug信息,一般来说设置忽略debug信息就可以了 。

对照MyMain.class

package asm;

public class MyMain {

    public int a = 10;
    public int b = 11;

    public void test1() {

    }

    public void test2() {

    }

    public static void main(String[] args) {

    }
}

输出内容跟实际Java类内容是一样的。

用TreeAPI做字节码信息解析:

package asm;



import jdk.internal.org.objectweb.asm.*;
import jdk.internal.org.objectweb.asm.tree.ClassNode;
import jdk.internal.org.objectweb.asm.tree.FieldNode;
import jdk.internal.org.objectweb.asm.tree.MethodNode;
import util.FileUtil;

import java.io.IOException;
import java.util.List;

import static jdk.internal.org.objectweb.asm.Opcodes.ASM5;

/**
 * case1 读取一个字节码里的方法等信息
 */
public class ASMReadClassTest {

//    public static void getClassInfoByCoreAPI(byte[] bytes) {
//        ClassReader classReader = new ClassReader(bytes);
//        ClassWriter classWriter = new ClassWriter(0);
//        ClassVisitor classVisitor = new ClassVisitor(ASM5, classWriter) {
//            @Override
//            public void visit(int version, int access, String name, String signature, String superName, String[] interfaces) {
//                super.visit(version, access, name, signature, superName, interfaces);
//            }
//
//            @Override
//            public void visitSource(String source, String debug) {
//                System.out.println("source in visitSource:" + source);
//                super.visitSource(source, debug);
//            }
//
//            @Override
//            public void visitOuterClass(String owner, String name, String desc) {
//                super.visitOuterClass(owner, name, desc);
//            }
//
//            @Override
//            public AnnotationVisitor visitAnnotation(String desc, boolean visible) {
//                return super.visitAnnotation(desc, visible);
//            }
//
//            @Override
//            public AnnotationVisitor visitTypeAnnotation(int typeRef, TypePath typePath, String desc, boolean visible) {
//                return super.visitTypeAnnotation(typeRef, typePath, desc, visible);
//            }
//
//            @Override
//            public void visitAttribute(Attribute attr) {
//                System.out.println("visitAttribute attr: " + attr);
//                super.visitAttribute(attr);
//            }
//
//            @Override
//            public void visitInnerClass(String name, String outerName, String innerName, int access) {
//                super.visitInnerClass(name, outerName, innerName, access);
//            }
//
//            @Override
//            public FieldVisitor visitField(int access, String name, String desc, String signature, Object value) {
//                System.out.println("visitField filed: " + name);
//                return super.visitField(access, name, desc, signature, value);
//            }
//
//            @Override
//            public MethodVisitor visitMethod(int access, String name, String desc, String signature, String[] exceptions) {
//                System.out.println("visitMethod method: " + name);
//                return super.visitMethod(access, name, desc, signature, exceptions);
//            }
//
//            @Override
//            public void visitEnd() {
//                System.out.println("visitEnd .... ");
//                super.visitEnd();
//            }
//        };
//
//
//        classReader.accept(classVisitor, ClassReader.SKIP_DEBUG);
//
//    }


    public static void getClassInfoByTreeAPI(byte[] bytes) {
        ClassReader classReader = new ClassReader(bytes);
        ClassNode classNode = new ClassNode();

        //如果需要忽略多个,写法如下
        classReader.accept(classNode, ClassReader.SKIP_DEBUG|ClassReader.SKIP_CODE);

        List<FieldNode> fieldNodeList = classNode.fields;
        for (FieldNode fieldNode: fieldNodeList) {
            System.out.println("field node :" + fieldNode.name);
        }

        List<MethodNode> methodNodeList = classNode.methods;
        for(MethodNode methodNode: methodNodeList){
            System.out.println("method node :" + methodNode.name);
        }

    }

    public static void main(String[] args) throws IOException {
        String filePath = "/Users/mac/IdeaProjects/OOM/JVMSample/target/classes/asm/MyMain.class";
        byte[] bytes = FileUtil.getContent(filePath);
//        第二种方式,通过TreeAPI获得字节码信息
        getClassInfoByTreeAPI(bytes);
//        getClassInfoByCoreAPI

    }
}
/Library/Java/JavaVirtualMachines/jdk1.8.0_333.jdk/Contents/Home/bin/java -javaagent:/Applications/IntelliJ IDEA.app/Contents/lib/idea_rt.jar=56427:/Applications/IntelliJ IDEA.app/Contents/bin -Dfile.encoding=UTF-8 -classpath /Library/Java/JavaVirtualMachines/jdk1.8.0_333.jdk/Contents/Home/jre/lib/charsets.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_333.jdk/Contents/Home/jre/lib/deploy.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_333.jdk/Contents/Home/jre/lib/ext/cldrdata.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_333.jdk/Contents/Home/jre/lib/ext/dnsns.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_333.jdk/Contents/Home/jre/lib/ext/jaccess.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_333.jdk/Contents/Home/jre/lib/ext/jfxrt.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_333.jdk/Contents/Home/jre/lib/ext/localedata.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_333.jdk/Contents/Home/jre/lib/ext/nashorn.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_333.jdk/Contents/Home/jre/lib/ext/sunec.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_333.jdk/Contents/Home/jre/lib/ext/sunjce_provider.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_333.jdk/Contents/Home/jre/lib/ext/sunpkcs11.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_333.jdk/Contents/Home/jre/lib/ext/zipfs.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_333.jdk/Contents/Home/jre/lib/javaws.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_333.jdk/Contents/Home/jre/lib/jce.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_333.jdk/Contents/Home/jre/lib/jfr.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_333.jdk/Contents/Home/jre/lib/jfxswt.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_333.jdk/Contents/Home/jre/lib/jsse.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_333.jdk/Contents/Home/jre/lib/management-agent.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_333.jdk/Contents/Home/jre/lib/plugin.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_333.jdk/Contents/Home/jre/lib/resources.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_333.jdk/Contents/Home/jre/lib/rt.jar:/Users/mac/IdeaProjects/OOM/JVMSample/target/classes:/Users/mac/repo/org/openjdk/jol/jol-core/0.9/jol-core-0.9.jar asm.ASMReadClassTest
field node :a
field node :b
method node :<init>
method node :test1
method node :test2
method node :main

Process finished with exit code 0

三、基于ASM增加属性实战

//通过CoreAPI增加属性

package asm;
import org.objectweb.asm.*;
import util.FileUtil;

import java.io.IOException;

import static org.objectweb.asm.Opcodes.*;

public class ASMAddFieldClassTest {

    /**
     * 方法1,通过core API 增加一个String类型的变量xyz
     *
     * @param bytes
     */
    public static void editClassInfoByCoreAPI(byte[] bytes) {

        ClassReader classReader = new ClassReader(bytes);
        ClassWriter classWriter = new ClassWriter(0);
        ClassVisitor classVisitor = new ClassVisitor(ASM5, classWriter) {

            @Override
            public void visitEnd() {
                //todo 我们的目标是增加一个属性,其他都不需要动,所以按照这个思路,其他方法都不需要改动,只要在这个结束方法增加一个属性即可
                super.visitEnd();
                FieldVisitor fieldVisitor = super.visitField(ACC_PUBLIC, "xyz", "Ljava/lang/String;", null, null);
                if(fieldVisitor != null){
                    fieldVisitor.visitEnd();
                }

            }
        };

        classReader.accept(classVisitor, ClassReader.SKIP_DEBUG);

        //拿到修改好的字节码,重新写到一个文件里去
        byte[] newBytes = classWriter.toByteArray();

        String filePath = "/Users/mac/IdeaProjects/OOM/JVMSample/target/classes/asm/MyMainNew.class";
        FileUtil.writeByteArrayToFile(filePath, newBytes);

    }

//    /**
//     * 第二种方式,听过TreeAPI来增加字段
//     *
//     * @param bytes
//     */
//    public static void editClassInfoByTreeAPI(byte[] bytes) {
//        ClassReader classReader = new ClassReader(bytes);
//        ClassNode classNode = new ClassNode();
//        classReader.accept(classNode, ClassReader.SKIP_DEBUG);
//        FieldNode fieldNode = new FieldNode(ACC_PUBLIC|ACC_STATIC|ACC_FINAL, "xyz", "Ljava/lang/String;", null, null);
//        classNode.fields.add(fieldNode);
//
//        ClassWriter classWriter=new ClassWriter(0);
//        classNode.accept(classWriter);
//        byte[] newBytes=classWriter.toByteArray();
//
//        String filePath = "/Users/liuqingchao/Desktop/my_code/jvm_imooc/out/production/jvm_imooc/main/java/ch14_bytecode_application/asm/MyMainTree.class";
//        FileUtil.writeByteArrayToFile(filePath, newBytes);
//
//    }


    public static void main(String[] args) throws IOException {
        String filePath = "/Users/mac/IdeaProjects/OOM/JVMSample/target/classes/asm//MyMain.class";
        byte[] bytes = FileUtil.getContent(filePath);
        editClassInfoByCoreAPI(bytes);
    }
}
mac@MacdeMBP asm % javap -v MyMainNew.class
Classfile /Users/mac/IdeaProjects/OOM/JVMSample/target/classes/asm/MyMainNew.class
  Last modified 2024-1-22; size 349 bytes
  MD5 checksum a1777a658317cd8700e6eab4edb436d6
public class asm.MyMain
  minor version: 0
  major version: 49
  flags: ACC_PUBLIC, ACC_SUPER
Constant pool:
   #1 = Utf8               asm/MyMain
   #2 = Class              #1             // asm/MyMain
   #3 = Utf8               java/lang/Object
   #4 = Class              #3             // java/lang/Object
   #5 = Utf8               a
   #6 = Utf8               I
   #7 = Utf8               b
   #8 = Utf8               <init>
   #9 = Utf8               ()V
  #10 = NameAndType        #8:#9          // "<init>":()V
  #11 = Methodref          #4.#10         // java/lang/Object."<init>":()V
  #12 = NameAndType        #5:#6          // a:I
  #13 = Fieldref           #2.#12         // asm/MyMain.a:I
  #14 = NameAndType        #7:#6          // b:I
  #15 = Fieldref           #2.#14         // asm/MyMain.b:I
  #16 = Utf8               test1
  #17 = Utf8               test2
  #18 = Utf8               main
  #19 = Utf8               ([Ljava/lang/String;)V
  #20 = Utf8               xyz
  #21 = Utf8               Ljava/lang/String;
  #22 = Utf8               Code
{
  public int a;
    descriptor: I
    flags: ACC_PUBLIC

  public int b;
    descriptor: I
    flags: ACC_PUBLIC

  public java.lang.String xyz;
    descriptor: Ljava/lang/String;
    flags: ACC_PUBLIC

  public asm.MyMain();
    descriptor: ()V
    flags: ACC_PUBLIC
    Code:
      stack=2, locals=1, args_size=1
         0: aload_0
         1: invokespecial #11                 // Method java/lang/Object."<init>":()V
         4: aload_0
         5: bipush        10
         7: putfield      #13                 // Field a:I
        10: aload_0
        11: bipush        11
        13: putfield      #15                 // Field b:I
        16: return

  public void test1();
    descriptor: ()V
    flags: ACC_PUBLIC
    Code:
      stack=0, locals=1, args_size=1
         0: return

  public void test2();
    descriptor: ()V
    flags: ACC_PUBLIC
    Code:
      stack=0, locals=1, args_size=1
         0: return

  public static void main(java.lang.String[]);
    descriptor: ([Ljava/lang/String;)V
    flags: ACC_PUBLIC, ACC_STATIC
    Code:
      stack=0, locals=1, args_size=1
         0: return
}
mac@MacdeMBP asm % 

//TreeAPI增加一个属性

package asm;
import org.objectweb.asm.*;
import org.objectweb.asm.tree.ClassNode;
import org.objectweb.asm.tree.FieldNode;
import util.FileUtil;

import java.io.IOException;
import java.util.List;

import static org.objectweb.asm.Opcodes.*;

public class ASMAddFieldClassTest {

//    /**
//     * 方法1,通过core API 增加一个String类型的变量xyz
//     *
//     * @param bytes
//     */
//    public static void editClassInfoByCoreAPI(byte[] bytes) {
//
//        ClassReader classReader = new ClassReader(bytes);
//        ClassWriter classWriter = new ClassWriter(0);
//        ClassVisitor classVisitor = new ClassVisitor(ASM5, classWriter) {
//
//            @Override
//            public void visitEnd() {
//                //todo 我们的目标是增加一个属性,其他都不需要动,所以按照这个思路,其他方法都不需要改动,只要在这个结束方法增加一个属性即可
//                super.visitEnd();
//                FieldVisitor fieldVisitor = super.visitField(ACC_PUBLIC, "xyz", "Ljava/lang/String;", null, null);
//                if(fieldVisitor != null){
//                    fieldVisitor.visitEnd();
//                }
//
//            }
//        };
//
//        classReader.accept(classVisitor, ClassReader.SKIP_DEBUG);
//
//        //拿到修改好的字节码,重新写到一个文件里去
//        byte[] newBytes = classWriter.toByteArray();
//
//        String filePath = "/Users/mac/IdeaProjects/OOM/JVMSample/target/classes/asm/MyMainNew.class";
//        FileUtil.writeByteArrayToFile(filePath, newBytes);
//
//    }

    /**
     * 第二种方式,听过TreeAPI来增加字段
     *
     * @param bytes
     */
    public static void editClassInfoByTreeAPI(byte[] bytes) {
        ClassReader classReader = new ClassReader(bytes);
        ClassNode classNode = new ClassNode();
        classReader.accept(classNode, ClassReader.SKIP_DEBUG);

        FieldNode fieldNode = new FieldNode(ACC_PUBLIC|ACC_STATIC, "abc", "Ljava/lang/String;", null, null);

        classNode.fields.add(fieldNode);

        ClassWriter classWriter = new ClassWriter(0);
        classNode.accept(classWriter);

        //拿到修改好的字节码,重新写到一个文件里去
        byte[] newBytes = classWriter.toByteArray();

        String filePath = "/Users/mac/IdeaProjects/OOM/JVMSample/target/classes/asm/MyMainTree.class";
        FileUtil.writeByteArrayToFile(filePath, newBytes);
    }


    public static void main(String[] args) throws IOException {
        String filePath = "/Users/mac/IdeaProjects/OOM/JVMSample/target/classes/asm//MyMain.class";
        byte[] bytes = FileUtil.getContent(filePath);
        editClassInfoByTreeAPI(bytes);
    }
}
mac@MacdeMBP asm % ls                       
ASMAddFieldClassTest.class      MyMain.class                    MyMainNew2.class
ASMReadClassTest.class          MyMainNew.class                 MyMainTree.class
mac@MacdeMBP asm % javap -v MyMainTree.class
Classfile /Users/mac/IdeaProjects/OOM/JVMSample/target/classes/asm/MyMainTree.class
  Last modified 2024-1-22; size 349 bytes
  MD5 checksum c4d1ac0f63f8fe9b91d552e7a6ac1330
public class asm.MyMain
  minor version: 0
  major version: 49
  flags: ACC_PUBLIC, ACC_SUPER
Constant pool:
   #1 = Utf8               asm/MyMain
   #2 = Class              #1             // asm/MyMain
   #3 = Utf8               java/lang/Object
   #4 = Class              #3             // java/lang/Object
   #5 = Utf8               a
   #6 = Utf8               I
   #7 = Utf8               b
   #8 = Utf8               abc
   #9 = Utf8               Ljava/lang/String;
  #10 = Utf8               <init>
  #11 = Utf8               ()V
  #12 = NameAndType        #10:#11        // "<init>":()V
  #13 = Methodref          #4.#12         // java/lang/Object."<init>":()V
  #14 = NameAndType        #5:#6          // a:I
  #15 = Fieldref           #2.#14         // asm/MyMain.a:I
  #16 = NameAndType        #7:#6          // b:I
  #17 = Fieldref           #2.#16         // asm/MyMain.b:I
  #18 = Utf8               test1
  #19 = Utf8               test2
  #20 = Utf8               main
  #21 = Utf8               ([Ljava/lang/String;)V
  #22 = Utf8               Code
{
  public int a;
    descriptor: I
    flags: ACC_PUBLIC

  public int b;
    descriptor: I
    flags: ACC_PUBLIC

  public static java.lang.String abc;
    descriptor: Ljava/lang/String;
    flags: ACC_PUBLIC, ACC_STATIC

  public asm.MyMain();
    descriptor: ()V
    flags: ACC_PUBLIC
    Code:
      stack=2, locals=1, args_size=1
         0: aload_0
         1: invokespecial #13                 // Method java/lang/Object."<init>":()V
         4: aload_0
         5: bipush        10
         7: putfield      #15                 // Field a:I
        10: aload_0
        11: bipush        11
        13: putfield      #17                 // Field b:I
        16: return

  public void test1();
    descriptor: ()V
    flags: ACC_PUBLIC
    Code:
      stack=0, locals=1, args_size=1
         0: return

  public void test2();
    descriptor: ()V
    flags: ACC_PUBLIC
    Code:
      stack=0, locals=1, args_size=1
         0: return

  public static void main(java.lang.String[]);
    descriptor: ([Ljava/lang/String;)V
    flags: ACC_PUBLIC, ACC_STATIC
    Code:
      stack=0, locals=1, args_size=1
         0: return
}
mac@MacdeMBP asm % 

四、使用asm编辑方法实战

添加一个zyx方法:

package asm;

import org.objectweb.asm.*;
import util.FileUtil;

import java.io.IOException;

import static org.objectweb.asm.Opcodes.ACC_PUBLIC;
import static org.objectweb.asm.Opcodes.ASM5;

public class ASMEditMethodClassTest {

    /**
     * 增加一个方法
     *
     * @throws IOException
     */

    public static void addMethod(byte[] bytes) {
        ClassReader classReader = new ClassReader(bytes);
        ClassWriter classWriter = new ClassWriter(0);
        ClassVisitor classVisitor = new ClassVisitor(ASM5, classWriter) {
            @Override
            public void visitEnd() {
                super.visitEnd();
                MethodVisitor methodVisitor = super.visitMethod(ACC_PUBLIC, "zyx", "(IILjava/lang/String;)V", null, null);
                if(methodVisitor != null){
                    methodVisitor.visitEnd();
                }
            }
        };

        classReader.accept(classVisitor, ClassReader.SKIP_DEBUG);

        //拿到修改好的字节码,重新写到一个文件里去
        byte[] newBytes = classWriter.toByteArray();

        String filePath = "/Users/mac/IdeaProjects/OOM/JVMSample/target/classes/asm/MyMainAddMethod.class";
        FileUtil.writeByteArrayToFile(filePath, newBytes);
    }

    public static void main(String[] args) throws IOException {
        String filePath = "/Users/mac/IdeaProjects/OOM/JVMSample/target/classes/asm/MyMain.class";
        byte[] bytes = FileUtil.getContent(filePath);
        addMethod(bytes);
    }
}
mac@MacdeMBP asm % ls                            
ASMAddFieldClassTest.class      ASMEditMethodClassTest.class    MyMain.class                    MyMainNew.class                 MyMainTree.class
ASMEditMethodClassTest$1.class  ASMReadClassTest.class          MyMainAddMethod.class           MyMainNew2.class
mac@MacdeMBP asm % javap -v MyMainAddMethod.class
Classfile /Users/mac/IdeaProjects/OOM/JVMSample/target/classes/asm/MyMainAddMethod.class
  Last modified 2024-1-22; size 354 bytes
  MD5 checksum 9fdee43198912003ad1896011d11ccc4
public class asm.MyMain
  minor version: 0
  major version: 49
  flags: ACC_PUBLIC, ACC_SUPER
Constant pool:
   #1 = Utf8               asm/MyMain
   #2 = Class              #1             // asm/MyMain
   #3 = Utf8               java/lang/Object
   #4 = Class              #3             // java/lang/Object
   #5 = Utf8               a
   #6 = Utf8               I
   #7 = Utf8               b
   #8 = Utf8               <init>
   #9 = Utf8               ()V
  #10 = NameAndType        #8:#9          // "<init>":()V
  #11 = Methodref          #4.#10         // java/lang/Object."<init>":()V
  #12 = NameAndType        #5:#6          // a:I
  #13 = Fieldref           #2.#12         // asm/MyMain.a:I
  #14 = NameAndType        #7:#6          // b:I
  #15 = Fieldref           #2.#14         // asm/MyMain.b:I
  #16 = Utf8               test1
  #17 = Utf8               test2
  #18 = Utf8               main
  #19 = Utf8               ([Ljava/lang/String;)V
  #20 = Utf8               zyx
  #21 = Utf8               (IILjava/lang/String;)V
  #22 = Utf8               Code
{
  public int a;
    descriptor: I
    flags: ACC_PUBLIC

  public int b;
    descriptor: I
    flags: ACC_PUBLIC

  public asm.MyMain();
    descriptor: ()V
    flags: ACC_PUBLIC
    Code:
      stack=2, locals=1, args_size=1
         0: aload_0
         1: invokespecial #11                 // Method java/lang/Object."<init>":()V
         4: aload_0
         5: bipush        10
         7: putfield      #13                 // Field a:I
        10: aload_0
        11: bipush        11
        13: putfield      #15                 // Field b:I
        16: return

  public void test1();
    descriptor: ()V
    flags: ACC_PUBLIC
    Code:
      stack=0, locals=1, args_size=1
         0: return

  public void test2();
    descriptor: ()V
    flags: ACC_PUBLIC
    Code:
      stack=0, locals=1, args_size=1
         0: return

  public static void main(java.lang.String[]);
    descriptor: ([Ljava/lang/String;)V
    flags: ACC_PUBLIC, ACC_STATIC
    Code:
      stack=0, locals=1, args_size=1
         0: return

  public void zyx(int, int, java.lang.String);
    descriptor: (IILjava/lang/String;)V
    flags: ACC_PUBLIC
}
mac@MacdeMBP asm % 

删除zyx方法:

package asm;

import org.objectweb.asm.*;
import util.FileUtil;

import java.io.IOException;

import static org.objectweb.asm.Opcodes.ACC_PUBLIC;
import static org.objectweb.asm.Opcodes.ASM5;

public class ASMEditMethodClassTest {

//    /**
//     * 增加一个方法
//     *
//     * @throws IOException
//     */
//
//    public static void addMethod(byte[] bytes) {
//        ClassReader classReader = new ClassReader(bytes);
//        ClassWriter classWriter = new ClassWriter(0);
//        ClassVisitor classVisitor = new ClassVisitor(ASM5, classWriter) {
//            @Override
//            public void visitEnd() {
//                super.visitEnd();
//                MethodVisitor methodVisitor = super.visitMethod(ACC_PUBLIC, "zyx", "(IILjava/lang/String;)V", null, null);
//                if(methodVisitor != null){
//                    methodVisitor.visitEnd();
//                }
//            }
//        };
//
//        classReader.accept(classVisitor, ClassReader.SKIP_DEBUG);
//
//        //拿到修改好的字节码,重新写到一个文件里去
//        byte[] newBytes = classWriter.toByteArray();
//
//        String filePath = "/Users/mac/IdeaProjects/OOM/JVMSample/target/classes/asm/MyMainAddMethod.class";
//        FileUtil.writeByteArrayToFile(filePath, newBytes);
//    }

    /**
     * 删除一个方法
     *
     * @param bytes
     */
    public static void deleteMethod(byte[] bytes) {
        ClassReader classReader = new ClassReader(bytes);
        ClassWriter classWriter = new ClassWriter(0);
        ClassVisitor classVisitor = new ClassVisitor(ASM5, classWriter) {
            @Override
            public void visit(int version, int access, String name, String signature, String superName, String[] interfaces) {
                super.visit(version, access, name, signature, superName, interfaces);
            }

            @Override
            public void visitSource(String source, String debug) {
                super.visitSource(source, debug);
            }

            @Override
            public void visitOuterClass(String owner, String name, String desc) {
                super.visitOuterClass(owner, name, desc);
            }

            @Override
            public AnnotationVisitor visitAnnotation(String desc, boolean visible) {
                return super.visitAnnotation(desc, visible);
            }

            @Override
            public AnnotationVisitor visitTypeAnnotation(int typeRef, TypePath typePath, String desc, boolean visible) {
                return super.visitTypeAnnotation(typeRef, typePath, desc, visible);
            }

            @Override
            public void visitAttribute(Attribute attr) {
                super.visitAttribute(attr);
            }

            @Override
            public void visitInnerClass(String name, String outerName, String innerName, int access) {
                super.visitInnerClass(name, outerName, innerName, access);
            }

            @Override
            public FieldVisitor visitField(int access, String name, String desc, String signature, Object value) {
                //如果要删除某个字段返回空
                return super.visitField(access, name, desc, signature, value);
            }

            @Override
            public MethodVisitor visitMethod(int access, String name, String desc, String signature, String[] exceptions) {
                //如果要删除某个方法返回空
                if ("zyx".equals(name)) {
                    return null;
                }
                return super.visitMethod(access, name, desc, signature, exceptions);
            }

            @Override
            public void visitEnd() {
                //删除一个方法或字段,就不能再写在这里了,可以在过滤前面字段或方法的时候,返回空就可以删除了
                super.visitEnd();
            }
        };
        classReader.accept(classVisitor, ClassReader.SKIP_DEBUG);
        byte[] newBytes = classWriter.toByteArray();
        String filePath = "/Users/mac/IdeaProjects/OOM/JVMSample/target/classes/asm/MyMainDeleteMethod.class";
        FileUtil.writeByteArrayToFile(filePath, newBytes);

    }

    public static void main(String[] args) throws IOException {
        String filePath = "/Users/mac/IdeaProjects/OOM/JVMSample/target/classes/asm/MyMainAddMethod.class";
        byte[] bytes = FileUtil.getContent(filePath);
        deleteMethod(bytes);
    }
}
mac@MacdeMBP asm % ls
ASMAddFieldClassTest.class      ASMEditMethodClassTest.class    MyMain.class                    MyMainDeleteMethod.class        MyMainNew2.class
ASMEditMethodClassTest$1.class  ASMReadClassTest.class          MyMainAddMethod.class           MyMainNew.class                 MyMainTree.class
mac@MacdeMBP asm % javap -v MyMainDeleteMethod.class 
Classfile /Users/mac/IdeaProjects/OOM/JVMSample/target/classes/asm/MyMainDeleteMethod.class
  Last modified 2024-1-22; size 314 bytes
  MD5 checksum b8ea36457b5d3574b2a244b17374421b
public class asm.MyMain
  minor version: 0
  major version: 49
  flags: ACC_PUBLIC, ACC_SUPER
Constant pool:
   #1 = Utf8               asm/MyMain
   #2 = Class              #1             // asm/MyMain
   #3 = Utf8               java/lang/Object
   #4 = Class              #3             // java/lang/Object
   #5 = Utf8               a
   #6 = Utf8               I
   #7 = Utf8               b
   #8 = Utf8               <init>
   #9 = Utf8               ()V
  #10 = NameAndType        #8:#9          // "<init>":()V
  #11 = Methodref          #4.#10         // java/lang/Object."<init>":()V
  #12 = NameAndType        #5:#6          // a:I
  #13 = Fieldref           #2.#12         // asm/MyMain.a:I
  #14 = NameAndType        #7:#6          // b:I
  #15 = Fieldref           #2.#14         // asm/MyMain.b:I
  #16 = Utf8               test1
  #17 = Utf8               test2
  #18 = Utf8               main
  #19 = Utf8               ([Ljava/lang/String;)V
  #20 = Utf8               Code
{
  public int a;
    descriptor: I
    flags: ACC_PUBLIC

  public int b;
    descriptor: I
    flags: ACC_PUBLIC

  public asm.MyMain();
    descriptor: ()V
    flags: ACC_PUBLIC
    Code:
      stack=2, locals=1, args_size=1
         0: aload_0
         1: invokespecial #11                 // Method java/lang/Object."<init>":()V
         4: aload_0
         5: bipush        10
         7: putfield      #13                 // Field a:I
        10: aload_0
        11: bipush        11
        13: putfield      #15                 // Field b:I
        16: return

  public void test1();
    descriptor: ()V
    flags: ACC_PUBLIC
    Code:
      stack=0, locals=1, args_size=1
         0: return

  public void test2();
    descriptor: ()V
    flags: ACC_PUBLIC
    Code:
      stack=0, locals=1, args_size=1
         0: return

  public static void main(java.lang.String[]);
    descriptor: ([Ljava/lang/String;)V
    flags: ACC_PUBLIC, ACC_STATIC
    Code:
      stack=0, locals=1, args_size=1
         0: return
}
mac@MacdeMBP asm % 

五、Javassit介绍与操作字节码案例

package javassist;

import java.io.IOException;

/**
 * 创建类测试
 */
public class JavassistTest {
    public static void main(String[] args) throws CannotCompileException, IOException {
        ClassPool cp = ClassPool.getDefault();
        CtClass ctClass = cp.makeClass("main.java.javassist.HelloJavassist");
        CtField ctField = new CtField(CtClass.intType, "value", ctClass);//ctClass是将属性关联到ctClass
        ctField.setModifiers(Modifier.PUBLIC);
        ctClass.addField(ctField);//这一步真正在ctClass加属性

        CtField ctField2 = new CtField(CtClass.longType, "value2", ctClass);
        ctField2.setModifiers(Modifier.PUBLIC | Modifier.STATIC);
        ctClass.addField(ctField2);//这一步真正在ctClass加属性
        
        ctClass.writeFile("./javassist_gen_file");
    }
}

六、Javassist模拟实现lombok框架

package javassist;

import java.io.IOException;

public class JavassitTest {

    public static void addMethod() throws Exception {
        ClassPool cp = ClassPool.getDefault();
        CtClass ctClass = cp.makeClass("main.java.javassist.HelloJavassist2");

        CtMethod ctMethod = new CtMethod(CtClass.intType,
                "fun",
                new CtClass[]{CtClass.longType, CtClass.charType}, ctClass);
        ctMethod.setModifiers(Modifier.PUBLIC);
        ctClass.addMethod(ctMethod);

        ctClass.writeFile("./javassist_gen_file");
    }

    public static void addMethod2() throws Exception {
        ClassPool cp = ClassPool.getDefault();
        CtClass ctClass = cp.makeClass("main.java.javassist.HelloJavassist2");

        CtField ctField = new CtField(CtClass.intType, "value", ctClass);//ctClass是将属性关联到ctClass
        ctField.setModifiers(Modifier.PRIVATE);
        ctClass.addField(ctField);//这一步真正在ctClass加属性

        CtMethod getMethod = new CtMethod(CtClass.intType,
                "getValue",
                new CtClass[]{}, ctClass);
        getMethod.setModifiers(Modifier.PUBLIC);
        getMethod.setBody(" return this.value;");
        ctClass.addMethod(getMethod);

        CtMethod setMethod = new CtMethod(CtClass.voidType,
                "setValue",
                new CtClass[]{CtClass.intType}, ctClass);
        setMethod.setModifiers(Modifier.PUBLIC);
        setMethod.setBody("this.value = $1;");
        ctClass.addMethod(setMethod);


//        public int add(int a, int b) {
//            return a + b;
//        }
//        CtMethod addMethod = new CtMethod(CtClass.intType,
//                "add",
//                new CtClass[]{CtClass.intType}, ctClass);
//        setMethod.setModifiers(Modifier.PUBLIC);
//        setMethod.setBody("this.value = $1 + $2;");
//        ctClass.addMethod(setMethod);

        ctClass.writeFile("./javassist_gen_file");
    }


    public static void main(String[] args) throws Exception {
        addMethod2();
    }
}
//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by FernFlower decompiler)
//

package main.java.javassist;

public class HelloJavassist2 {
    private int value;

    public int getValue() {
        return this.value;
    }

    public void setValue(int var1) {
        this.value = var1;
    }

    public HelloJavassist2() {
    }
}

七、反射之一透彻理解反射的作用

通过反射创建对象的多种方式:

package ch14_bytecode_application.class7;

import java.util.Random;

/**
 * 感受反射的作用
 */
public class ReflectionDemo {
    public static void main(String[] args) throws Exception {

//        Student student1 = new Student();
//        student1.getName();
//        System.out.println(student1);
//
//        //反射创建对象方式1:基于已经创建的对象来反射
//        Student student2 = student1.getClass().newInstance();
//        System.out.println(student2);
//
      反射创建对象方式2:  基于类信息来创建Class
//        Class clazz = Student.class;
//        Student student = (Student) clazz.newInstance();
//        System.out.println(student);


        for (int i = 0; i < 5; i++) {
            int num = new Random().nextInt(3);//0,1,2
            String classPath = "";
            switch (num) {
                case 0:
                    classPath = "java.util.Date";
                    break;
                case 1:
                    classPath = "java.lang.Object";
                    break;
                case 2:
                    classPath = "main.java.ch14_bytecode_application.class8.Student";
                    break;
            }

            try {
                Object obj = getInstance(classPath);
                System.out.println(obj);
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }

    /*
 创建一个指定类的对象。
 classPath:指定类的全类名
  */
    public static Object getInstance(String classPath) throws Exception {
        //反射创建对象方式3:基于已经创建的对象来反射
//        jdbc

        Class clazz = Class.forName(classPath);
        return clazz.newInstance();
    }
}

八、反射之二反射管理类信息案例实战

package class8;

import javassist.Person;

/***
 * 获取class类的四种方式
 */

public class GetClassDemo {
    public static void main(String[] args) throws ClassNotFoundException {
        //方式一:调用运行时类的属性:.class
        Class clazz1 = Person.class;
        System.out.println(clazz1);

        //方式二:通过运行时类的对象,调用getClass()
        Person p1 = new Person();
        Class clazz2 = p1.getClass();

        System.out.println(clazz2);

        //方式三:调用Class的静态方法:forName(String classPath)
        Class clazz3 = Class.forName("main.java.ch14_bytecode_application.class8.Person");
        Class clazz5 = Class.forName("java.lang.String");
        System.out.println(clazz3);
        System.out.println(clazz5);

        System.out.println(clazz1 == clazz2);//true
        System.out.println(clazz1 == clazz3);//true

        //方式四:使用类的加载器:ClassLoader  (了解)
        ClassLoader classLoader = GetClassDemo.class.getClassLoader();
        Class clazz4 = classLoader.loadClass("main.java.ch14_bytecode_application.class8.Person");
        System.out.println(clazz4);
        System.out.println(clazz1 == clazz4);//true
    }
}

package class8;

import java.lang.reflect.Field;
import java.lang.reflect.Modifier;

public class FiledMainTest {

    public static void main(String[] args) {
//        test1();
        test2();

    }

    public static void test1() {

        Class clazz = Person.class;

        //获取属性结构
        //getFields():获取当前运行时类及其父类中声明为public访问权限的属性
        Field[] fields = clazz.getFields();
        for (Field f : fields) {
            System.out.println(f);
        }
        System.out.println();

        //getDeclaredFields():获取当前运行时类中声明的所有属性。(不包含父类中声明的属性)
        Field[] declaredFields = clazz.getDeclaredFields();
        for (Field f : declaredFields) {
            System.out.println(f);
        }
    }

    //权限修饰符  数据类型 变量名
    public static void test2() {
        Class clazz = Person.class;
        Field[] declaredFields = clazz.getDeclaredFields();
        for (Field f : declaredFields) {
            //1.权限修饰符
            int modifier = f.getModifiers();
            System.out.print(Modifier.toString(modifier) + "\t");

            //2.数据类型
            Class type = f.getType();
            System.out.print(type.getName() + "\t");

            //3.变量名
            String fName = f.getName();
            System.out.print(fName);

            System.out.println();
        }
    }
}

test1()执行结果:

/Library/Java/JavaVirtualMachines/jdk1.8.0_333.jdk/Contents/Home/bin/java -javaagent:/Applications/IntelliJ IDEA.app/Contents/lib/idea_rt.jar=55111:/Applications/IntelliJ IDEA.app/Contents/bin -Dfile.encoding=UTF-8 -classpath /Library/Java/JavaVirtualMachines/jdk1.8.0_333.jdk/Contents/Home/jre/lib/charsets.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_333.jdk/Contents/Home/jre/lib/deploy.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_333.jdk/Contents/Home/jre/lib/ext/cldrdata.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_333.jdk/Contents/Home/jre/lib/ext/dnsns.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_333.jdk/Contents/Home/jre/lib/ext/jaccess.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_333.jdk/Contents/Home/jre/lib/ext/jfxrt.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_333.jdk/Contents/Home/jre/lib/ext/localedata.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_333.jdk/Contents/Home/jre/lib/ext/nashorn.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_333.jdk/Contents/Home/jre/lib/ext/sunec.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_333.jdk/Contents/Home/jre/lib/ext/sunjce_provider.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_333.jdk/Contents/Home/jre/lib/ext/sunpkcs11.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_333.jdk/Contents/Home/jre/lib/ext/zipfs.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_333.jdk/Contents/Home/jre/lib/javaws.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_333.jdk/Contents/Home/jre/lib/jce.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_333.jdk/Contents/Home/jre/lib/jfr.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_333.jdk/Contents/Home/jre/lib/jfxswt.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_333.jdk/Contents/Home/jre/lib/jsse.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_333.jdk/Contents/Home/jre/lib/management-agent.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_333.jdk/Contents/Home/jre/lib/plugin.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_333.jdk/Contents/Home/jre/lib/resources.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_333.jdk/Contents/Home/jre/lib/rt.jar:/Users/mac/IdeaProjects/OOM/JVMSample/target/classes:/Users/mac/repo/org/ow2/asm/asm-all/5.0.3/asm-all-5.0.3.jar:/Users/mac/repo/org/javassist/javassist/3.21.0-GA/javassist-3.21.0-GA.jar class8.FiledMainTest
public int class8.Person.id
public double class8.Creature.weight

private java.lang.String class8.Person.name
int class8.Person.age
public int class8.Person.id

Process finished with exit code 0

test2()执行结果:

/Library/Java/JavaVirtualMachines/jdk1.8.0_333.jdk/Contents/Home/bin/java -javaagent:/Applications/IntelliJ IDEA.app/Contents/lib/idea_rt.jar=55137:/Applications/IntelliJ IDEA.app/Contents/bin -Dfile.encoding=UTF-8 -classpath /Library/Java/JavaVirtualMachines/jdk1.8.0_333.jdk/Contents/Home/jre/lib/charsets.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_333.jdk/Contents/Home/jre/lib/deploy.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_333.jdk/Contents/Home/jre/lib/ext/cldrdata.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_333.jdk/Contents/Home/jre/lib/ext/dnsns.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_333.jdk/Contents/Home/jre/lib/ext/jaccess.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_333.jdk/Contents/Home/jre/lib/ext/jfxrt.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_333.jdk/Contents/Home/jre/lib/ext/localedata.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_333.jdk/Contents/Home/jre/lib/ext/nashorn.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_333.jdk/Contents/Home/jre/lib/ext/sunec.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_333.jdk/Contents/Home/jre/lib/ext/sunjce_provider.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_333.jdk/Contents/Home/jre/lib/ext/sunpkcs11.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_333.jdk/Contents/Home/jre/lib/ext/zipfs.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_333.jdk/Contents/Home/jre/lib/javaws.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_333.jdk/Contents/Home/jre/lib/jce.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_333.jdk/Contents/Home/jre/lib/jfr.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_333.jdk/Contents/Home/jre/lib/jfxswt.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_333.jdk/Contents/Home/jre/lib/jsse.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_333.jdk/Contents/Home/jre/lib/management-agent.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_333.jdk/Contents/Home/jre/lib/plugin.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_333.jdk/Contents/Home/jre/lib/resources.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_333.jdk/Contents/Home/jre/lib/rt.jar:/Users/mac/IdeaProjects/OOM/JVMSample/target/classes:/Users/mac/repo/org/ow2/asm/asm-all/5.0.3/asm-all-5.0.3.jar:/Users/mac/repo/org/javassist/javassist/3.21.0-GA/javassist-3.21.0-GA.jar class8.FiledMainTest
private	java.lang.String	name
	int	age
public	int	id

Process finished with exit code 0

package main.java.ch14_bytecode_application.class8;

import java.lang.annotation.Annotation;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;

//获取当前运行时类的方法结构
public class MethodMainTest {

    public static void main(String[] args) {
//        test1();
        test2();

    }


    public static void test1() {

        Class clazz = Person.class;

        //getMethods():获取当前运行时类及其所有父类中声明为public权限的方法
        Method[] methods = clazz.getMethods();
        for (Method m : methods) {
            System.out.println(m);
        }
        System.out.println();
        //getDeclaredMethods():获取当前运行时类中声明的所有方法。(不包含父类中声明的方法)
        Method[] declaredMethods = clazz.getDeclaredMethods();
        for (Method m : declaredMethods) {
            System.out.println(m);
        }
    }
    /*
      @Xxxx
      权限修饰符  返回值类型  方法名(参数类型1 形参名1,...) throws XxxException{}
       */

    public static void test2() {
        Class clazz = Person.class;
        Method[] declaredMethods = clazz.getDeclaredMethods();
        for (Method m : declaredMethods) {
            //1.获取方法声明的注解
            Annotation[] annos = m.getAnnotations();
            for (Annotation a : annos) {
                System.out.println(a);
            }

            //2.权限修饰符
            System.out.print(Modifier.toString(m.getModifiers()) + "\t");

            //3.返回值类型
            System.out.print(m.getReturnType().getName() + "\t");

            //4.方法名
            System.out.print(m.getName());
            System.out.print("(");
            //5.形参列表
            Class[] parameterTypes = m.getParameterTypes();
            if (!(parameterTypes == null && parameterTypes.length == 0)) {
                for (int i = 0; i < parameterTypes.length; i++) {

                    if (i == parameterTypes.length - 1) {
                        System.out.print(parameterTypes[i].getName() + " args_" + i);
                        break;
                    }

                    System.out.print(parameterTypes[i].getName() + " args_" + i + ",");
                }
            }

            System.out.print(")");

            //6.抛出的异常
            Class[] exceptionTypes = m.getExceptionTypes();
            if (exceptionTypes.length > 0) {
                System.out.print("throws ");
                for (int i = 0; i < exceptionTypes.length; i++) {
                    if (i == exceptionTypes.length - 1) {
                        System.out.print(exceptionTypes[i].getName());
                        break;
                    }

                    System.out.print(exceptionTypes[i].getName() + ",");
                }
            }

            System.out.println();
        }

    }
}


test1()执行结果:

/Library/Java/JavaVirtualMachines/jdk1.8.0_333.jdk/Contents/Home/bin/java -javaagent:/Applications/IntelliJ IDEA.app/Contents/lib/idea_rt.jar=55361:/Applications/IntelliJ IDEA.app/Contents/bin -Dfile.encoding=UTF-8 -classpath /Library/Java/JavaVirtualMachines/jdk1.8.0_333.jdk/Contents/Home/jre/lib/charsets.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_333.jdk/Contents/Home/jre/lib/deploy.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_333.jdk/Contents/Home/jre/lib/ext/cldrdata.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_333.jdk/Contents/Home/jre/lib/ext/dnsns.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_333.jdk/Contents/Home/jre/lib/ext/jaccess.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_333.jdk/Contents/Home/jre/lib/ext/jfxrt.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_333.jdk/Contents/Home/jre/lib/ext/localedata.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_333.jdk/Contents/Home/jre/lib/ext/nashorn.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_333.jdk/Contents/Home/jre/lib/ext/sunec.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_333.jdk/Contents/Home/jre/lib/ext/sunjce_provider.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_333.jdk/Contents/Home/jre/lib/ext/sunpkcs11.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_333.jdk/Contents/Home/jre/lib/ext/zipfs.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_333.jdk/Contents/Home/jre/lib/javaws.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_333.jdk/Contents/Home/jre/lib/jce.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_333.jdk/Contents/Home/jre/lib/jfr.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_333.jdk/Contents/Home/jre/lib/jfxswt.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_333.jdk/Contents/Home/jre/lib/jsse.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_333.jdk/Contents/Home/jre/lib/management-agent.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_333.jdk/Contents/Home/jre/lib/plugin.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_333.jdk/Contents/Home/jre/lib/resources.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_333.jdk/Contents/Home/jre/lib/rt.jar:/Users/mac/IdeaProjects/OOM/JVMSample/target/classes:/Users/mac/repo/org/ow2/asm/asm-all/5.0.3/asm-all-5.0.3.jar:/Users/mac/repo/org/javassist/javassist/3.21.0-GA/javassist-3.21.0-GA.jar class8.MethodMainTest
public void class8.Person.info()
public java.lang.String class8.Person.display(java.lang.String,int) throws java.lang.NullPointerException,java.lang.ClassCastException
public java.lang.String class8.Person.toString()
public int class8.Person.compareTo(java.lang.Object)
public int class8.Person.compareTo(java.lang.String)
public void class8.Creature.eat()
public final void java.lang.Object.wait(long,int) throws java.lang.InterruptedException
public final native void java.lang.Object.wait(long) throws java.lang.InterruptedException
public final void java.lang.Object.wait() throws java.lang.InterruptedException
public boolean java.lang.Object.equals(java.lang.Object)
public native int java.lang.Object.hashCode()
public final native java.lang.Class java.lang.Object.getClass()
public final native void java.lang.Object.notify()
public final native void java.lang.Object.notifyAll()

public void class8.Person.info()
public java.lang.String class8.Person.display(java.lang.String,int) throws java.lang.NullPointerException,java.lang.ClassCastException
private java.lang.String class8.Person.show(java.lang.String)
private static void class8.Person.showDesc()
public java.lang.String class8.Person.toString()
public int class8.Person.compareTo(java.lang.Object)
public int class8.Person.compareTo(java.lang.String)

Process finished with exit code 0

test2()执行结果:

/Library/Java/JavaVirtualMachines/jdk1.8.0_333.jdk/Contents/Home/bin/java -javaagent:/Applications/IntelliJ IDEA.app/Contents/lib/idea_rt.jar=55387:/Applications/IntelliJ IDEA.app/Contents/bin -Dfile.encoding=UTF-8 -classpath /Library/Java/JavaVirtualMachines/jdk1.8.0_333.jdk/Contents/Home/jre/lib/charsets.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_333.jdk/Contents/Home/jre/lib/deploy.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_333.jdk/Contents/Home/jre/lib/ext/cldrdata.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_333.jdk/Contents/Home/jre/lib/ext/dnsns.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_333.jdk/Contents/Home/jre/lib/ext/jaccess.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_333.jdk/Contents/Home/jre/lib/ext/jfxrt.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_333.jdk/Contents/Home/jre/lib/ext/localedata.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_333.jdk/Contents/Home/jre/lib/ext/nashorn.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_333.jdk/Contents/Home/jre/lib/ext/sunec.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_333.jdk/Contents/Home/jre/lib/ext/sunjce_provider.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_333.jdk/Contents/Home/jre/lib/ext/sunpkcs11.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_333.jdk/Contents/Home/jre/lib/ext/zipfs.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_333.jdk/Contents/Home/jre/lib/javaws.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_333.jdk/Contents/Home/jre/lib/jce.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_333.jdk/Contents/Home/jre/lib/jfr.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_333.jdk/Contents/Home/jre/lib/jfxswt.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_333.jdk/Contents/Home/jre/lib/jsse.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_333.jdk/Contents/Home/jre/lib/management-agent.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_333.jdk/Contents/Home/jre/lib/plugin.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_333.jdk/Contents/Home/jre/lib/resources.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_333.jdk/Contents/Home/jre/lib/rt.jar:/Users/mac/IdeaProjects/OOM/JVMSample/target/classes:/Users/mac/repo/org/ow2/asm/asm-all/5.0.3/asm-all-5.0.3.jar:/Users/mac/repo/org/javassist/javassist/3.21.0-GA/javassist-3.21.0-GA.jar class8.MethodMainTest
@class8.MyAnnotation(value=hello)
private	java.lang.String	show(java.lang.String args_0)
public	java.lang.String	display(java.lang.String args_0,int args_1)throws java.lang.NullPointerException,java.lang.ClassCastException
public	void	info()
private static	void	showDesc()
public	java.lang.String	toString()
public volatile	int	compareTo(java.lang.Object args_0)
public	int	compareTo(java.lang.String args_0)

Process finished with exit code 0

九、反射之三反射修改类信息案例实战

通过反射设置和获取对象属性值:

package class9;

public class Person {
    public int id;
    private String name;
    protected int age;


    private static String showDesc() {
        return "aa";
    }

    private String show(String test) {
        return test + " 是一位好老师";
    }


    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }

    public int getId() {
        return id;
    }

    public void setId(int id) {
        this.id = id;
    }

    @Override
    public String toString() {
        return "Person{" +
                "name='" + name + '\'' +
                ", age=" + age +
                ", id=" + id +
                '}';
    }
}
package class9;

import java.lang.reflect.Field;

/**
 * public : getField() 之后可以直接用反射来set
 * protected :使用getDeclaredField()方法获取,之后可以直接用反射来set
 * private:使用getDeclaredField()方法获取,然后设置权限setAccessible,之后才可以用反射来set
 *
 */

public class ReflectionModifyFiledTest {

    public static void main(String[] args) throws Exception {
//        testField2();
        testField();

    }

    public static void testField2() throws Exception {
        Class clazz = Person.class;

        Person person = (Person) clazz.newInstance();
        Field age = clazz.getDeclaredField("age");
//        age.setAccessible(true);
        age.set(person, 100);

        System.out.println(person);
        System.out.println("---------------------");

        Person person2 = (Person) clazz.newInstance();
        Field name = clazz.getDeclaredField("name");
        name.setAccessible(true);
        name.set(person2, "海涛");
        System.out.println(person2);

    }


    /**
     * 修改类的属性信息
     *
     * @throws Exception
     */
    public static void testField() throws Exception {
        Class clazz = Person.class;

        Person person = (Person) clazz.newInstance();
        Field id = clazz.getField("id");
        id.set(person, 100);

        int pId = (Integer) id.get(person);
        System.out.println(pId);
    }


}
/Library/Java/JavaVirtualMachines/jdk1.8.0_333.jdk/Contents/Home/bin/java -javaagent:/Applications/IntelliJ IDEA.app/Contents/lib/idea_rt.jar=63419:/Applications/IntelliJ IDEA.app/Contents/bin -Dfile.encoding=UTF-8 -classpath /Library/Java/JavaVirtualMachines/jdk1.8.0_333.jdk/Contents/Home/jre/lib/charsets.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_333.jdk/Contents/Home/jre/lib/deploy.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_333.jdk/Contents/Home/jre/lib/ext/cldrdata.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_333.jdk/Contents/Home/jre/lib/ext/dnsns.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_333.jdk/Contents/Home/jre/lib/ext/jaccess.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_333.jdk/Contents/Home/jre/lib/ext/jfxrt.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_333.jdk/Contents/Home/jre/lib/ext/localedata.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_333.jdk/Contents/Home/jre/lib/ext/nashorn.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_333.jdk/Contents/Home/jre/lib/ext/sunec.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_333.jdk/Contents/Home/jre/lib/ext/sunjce_provider.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_333.jdk/Contents/Home/jre/lib/ext/sunpkcs11.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_333.jdk/Contents/Home/jre/lib/ext/zipfs.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_333.jdk/Contents/Home/jre/lib/javaws.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_333.jdk/Contents/Home/jre/lib/jce.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_333.jdk/Contents/Home/jre/lib/jfr.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_333.jdk/Contents/Home/jre/lib/jfxswt.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_333.jdk/Contents/Home/jre/lib/jsse.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_333.jdk/Contents/Home/jre/lib/management-agent.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_333.jdk/Contents/Home/jre/lib/plugin.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_333.jdk/Contents/Home/jre/lib/resources.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_333.jdk/Contents/Home/jre/lib/rt.jar:/Users/mac/IdeaProjects/OOM/JVMSample/target/classes:/Users/mac/repo/org/ow2/asm/asm-all/5.0.3/asm-all-5.0.3.jar:/Users/mac/repo/org/javassist/javassist/3.21.0-GA/javassist-3.21.0-GA.jar class9.ReflectionModifyFiledTest
100

Process finished with exit code 0

通过反射获取对象的所有属性值:

package class9;

import java.lang.reflect.Field;

/**
 * public : getField() 之后可以直接用反射来set
 * protected :使用getDeclaredField()方法获取,之后可以直接用反射来set
 * private:使用getDeclaredField()方法获取,然后设置权限setAccessible,之后才可以用反射来set
 *
 */

public class ReflectionModifyFiledTest {

    public static void main(String[] args) throws Exception {
        testField2();
//        testField();

    }

    public static void testField2() throws Exception {
        Class clazz = Person.class;

        Person person = (Person) clazz.newInstance();
        Field age = clazz.getDeclaredField("age");
//        age.setAccessible(true);
        age.set(person, 100);

        System.out.println(person);
        System.out.println("---------------------");

        Person person2 = (Person) clazz.newInstance();
        Field name = clazz.getDeclaredField("name");
        name.setAccessible(true);//正常情况下,通过上面方法,访问私有属性,需要将accessible设置为true,否则会访问不到,报异常
        name.set(person2, "海涛");
        System.out.println(person2);

    }


    /**
     * 修改类的属性信息
     *
     * @throws Exception
     */
    public static void testField() throws Exception {
        Class clazz = Person.class;

        Person person = (Person) clazz.newInstance();
        Field id = clazz.getField("id");
        id.set(person, 100);

        int pId = (Integer) id.get(person);
        System.out.println(pId);
    }


}
/Library/Java/JavaVirtualMachines/jdk1.8.0_333.jdk/Contents/Home/bin/java -javaagent:/Applications/IntelliJ IDEA.app/Contents/lib/idea_rt.jar=49952:/Applications/IntelliJ IDEA.app/Contents/bin -Dfile.encoding=UTF-8 -classpath /Library/Java/JavaVirtualMachines/jdk1.8.0_333.jdk/Contents/Home/jre/lib/charsets.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_333.jdk/Contents/Home/jre/lib/deploy.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_333.jdk/Contents/Home/jre/lib/ext/cldrdata.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_333.jdk/Contents/Home/jre/lib/ext/dnsns.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_333.jdk/Contents/Home/jre/lib/ext/jaccess.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_333.jdk/Contents/Home/jre/lib/ext/jfxrt.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_333.jdk/Contents/Home/jre/lib/ext/localedata.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_333.jdk/Contents/Home/jre/lib/ext/nashorn.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_333.jdk/Contents/Home/jre/lib/ext/sunec.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_333.jdk/Contents/Home/jre/lib/ext/sunjce_provider.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_333.jdk/Contents/Home/jre/lib/ext/sunpkcs11.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_333.jdk/Contents/Home/jre/lib/ext/zipfs.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_333.jdk/Contents/Home/jre/lib/javaws.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_333.jdk/Contents/Home/jre/lib/jce.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_333.jdk/Contents/Home/jre/lib/jfr.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_333.jdk/Contents/Home/jre/lib/jfxswt.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_333.jdk/Contents/Home/jre/lib/jsse.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_333.jdk/Contents/Home/jre/lib/management-agent.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_333.jdk/Contents/Home/jre/lib/plugin.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_333.jdk/Contents/Home/jre/lib/resources.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_333.jdk/Contents/Home/jre/lib/rt.jar:/Users/mac/IdeaProjects/OOM/JVMSample/target/classes:/Users/mac/repo/org/ow2/asm/asm-all/5.0.3/asm-all-5.0.3.jar:/Users/mac/repo/org/javassist/javassist/3.21.0-GA/javassist-3.21.0-GA.jar class9.ReflectionModifyFiledTest
Person{name='null', age=100, id=0}
---------------------
Person{name='海涛', age=0, id=0}

Process finished with exit code 0

总结:

* public : getField() 之后可以直接用反射来set
* protected :使用getDeclaredField()方法获取,之后可以直接用反射来set
* private:使用getDeclaredField()方法获取,然后设置权限setAccessible,之后才可以用反射来set

十、反射之四通过反射调用类方法实战

package class9;

import java.lang.reflect.Method;

public class ReflectionMethodTest {
    public static void main(String[] args) throws Exception {
        testMethod();
    }

    public static void testMethod() throws Exception {

        Class clazz = Person.class;

        Person person = (Person) clazz.newInstance();

        Method showMethod = clazz.getDeclaredMethod("show", String.class);
        showMethod.setAccessible(true);

        Object value = showMethod.invoke(person, "海涛");
        System.out.println(value);

        Method desc = clazz.getDeclaredMethod("showDesc");
        desc.setAccessible(true);
        Object descValue = desc.invoke(Person.class);
        System.out.println(descValue);


    }


}
/Library/Java/JavaVirtualMachines/jdk1.8.0_333.jdk/Contents/Home/bin/java -javaagent:/Applications/IntelliJ IDEA.app/Contents/lib/idea_rt.jar=59139:/Applications/IntelliJ IDEA.app/Contents/bin -Dfile.encoding=UTF-8 -classpath /Library/Java/JavaVirtualMachines/jdk1.8.0_333.jdk/Contents/Home/jre/lib/charsets.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_333.jdk/Contents/Home/jre/lib/deploy.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_333.jdk/Contents/Home/jre/lib/ext/cldrdata.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_333.jdk/Contents/Home/jre/lib/ext/dnsns.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_333.jdk/Contents/Home/jre/lib/ext/jaccess.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_333.jdk/Contents/Home/jre/lib/ext/jfxrt.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_333.jdk/Contents/Home/jre/lib/ext/localedata.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_333.jdk/Contents/Home/jre/lib/ext/nashorn.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_333.jdk/Contents/Home/jre/lib/ext/sunec.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_333.jdk/Contents/Home/jre/lib/ext/sunjce_provider.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_333.jdk/Contents/Home/jre/lib/ext/sunpkcs11.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_333.jdk/Contents/Home/jre/lib/ext/zipfs.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_333.jdk/Contents/Home/jre/lib/javaws.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_333.jdk/Contents/Home/jre/lib/jce.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_333.jdk/Contents/Home/jre/lib/jfr.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_333.jdk/Contents/Home/jre/lib/jfxswt.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_333.jdk/Contents/Home/jre/lib/jsse.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_333.jdk/Contents/Home/jre/lib/management-agent.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_333.jdk/Contents/Home/jre/lib/plugin.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_333.jdk/Contents/Home/jre/lib/resources.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_333.jdk/Contents/Home/jre/lib/rt.jar:/Users/mac/IdeaProjects/OOM/JVMSample/target/classes:/Users/mac/repo/org/ow2/asm/asm-all/5.0.3/asm-all-5.0.3.jar:/Users/mac/repo/org/javassist/javassist/3.21.0-GA/javassist-3.21.0-GA.jar class9.A
海涛 是一位好老师
aa

Process finished with exit code 0

十一、代理之一代理思想介绍screenflow

静态代理实现:

业务接口

package class11;

public interface ITicketService {

    //问询
    public void inquire();

    //售票
    public void sellTicket();


}

业务自身接口实现:

package class11;

public class Station implements ITicketService{

    @Override
    public void inquire() {
        System.out.println("海涛老师 问询...");
    }

    @Override
    public void sellTicket() {
        System.out.println("海涛老师 售票.....");
    }





}

代理实现:

package class11;

public class StationProxy implements ITicketService{
    private Station station;

    public StationProxy(Station station){
        this.station = station;
    }

    @Override
    public void inquire() {
        System.out.println("代理人 协助海涛老师问询");
        station.inquire();
        System.out.println("代理人 协助海涛老师问询结束,并做记录");
    }

    @Override
    public void sellTicket() {
        System.out.println("代理人 协助海涛老师售票");
        station.sellTicket();
        System.out.println("代理人 协助海涛老师报销");
    }
}

执行代码:

package class11;

public class MainTest {
    public static void main(String[] args) {
        Station station = new Station();
        ITicketService ticketService = new StationProxy(station);
        ticketService.inquire();

        System.out.println("------------------");

        ticketService.sellTicket();
    }
}

执行结果:

/Library/Java/JavaVirtualMachines/jdk1.8.0_333.jdk/Contents/Home/bin/java -javaagent:/Applications/IntelliJ IDEA.app/Contents/lib/idea_rt.jar=50058:/Applications/IntelliJ IDEA.app/Contents/bin -Dfile.encoding=UTF-8 -classpath /Library/Java/JavaVirtualMachines/jdk1.8.0_333.jdk/Contents/Home/jre/lib/charsets.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_333.jdk/Contents/Home/jre/lib/deploy.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_333.jdk/Contents/Home/jre/lib/ext/cldrdata.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_333.jdk/Contents/Home/jre/lib/ext/dnsns.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_333.jdk/Contents/Home/jre/lib/ext/jaccess.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_333.jdk/Contents/Home/jre/lib/ext/jfxrt.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_333.jdk/Contents/Home/jre/lib/ext/localedata.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_333.jdk/Contents/Home/jre/lib/ext/nashorn.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_333.jdk/Contents/Home/jre/lib/ext/sunec.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_333.jdk/Contents/Home/jre/lib/ext/sunjce_provider.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_333.jdk/Contents/Home/jre/lib/ext/sunpkcs11.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_333.jdk/Contents/Home/jre/lib/ext/zipfs.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_333.jdk/Contents/Home/jre/lib/javaws.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_333.jdk/Contents/Home/jre/lib/jce.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_333.jdk/Contents/Home/jre/lib/jfr.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_333.jdk/Contents/Home/jre/lib/jfxswt.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_333.jdk/Contents/Home/jre/lib/jsse.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_333.jdk/Contents/Home/jre/lib/management-agent.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_333.jdk/Contents/Home/jre/lib/plugin.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_333.jdk/Contents/Home/jre/lib/resources.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_333.jdk/Contents/Home/jre/lib/rt.jar:/Users/mac/IdeaProjects/OOM/JVMSample/target/classes:/Users/mac/repo/org/ow2/asm/asm-all/5.0.3/asm-all-5.0.3.jar:/Users/mac/repo/org/javassist/javassist/3.21.0-GA/javassist-3.21.0-GA.jar class11.MainTest
代理人 协助海涛老师问询
海涛老师 问询...
代理人 协助海涛老师问询结束,并做记录
------------------
代理人 协助海涛老师售票
海涛老师 售票.....
代理人 协助海涛老师报销

Process finished with exit code 0

十二、代理之二基于JDK实现动态代理实战

业务接口:

package class12.jdkdemp;

public interface ISubject {
    public void rent();

    public void hello(String str);
}

业务实现:

package class12.jdkdemp;

public class SubjectImpl implements ISubject {
    @Override
    public void rent() {
        System.out.println("I want to rent my house");
    }

    @Override
    public void hello(String str) {
        System.out.println("hello: " + str);
    }

}

动态代理实现:

package class12.jdkdemp;

public class SubjectImpl implements ISubject {
    @Override
    public void rent() {
        System.out.println("I want to rent my house");
    }

    @Override
    public void hello(String str) {
        System.out.println("hello: " + str);
    }

}

执行代码:

package class12.jdkdemp;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Proxy;

public class MainTest {
    public static void main(String[] args) {
        ISubject subject = new SubjectImpl();
        InvocationHandler handler = new DynamicProxy(subject);

        /**
         * 第一个参数 classLoader - handler的加载器,subject.getClass().getInterfaces() 也是可以的,真正是只传两个加载器
         * 第二个参数 代理的接口
         * 第三个参数 handler
         */
        ISubject subject1 = (ISubject) Proxy.newProxyInstance(
                handler.getClass().getClassLoader(),
                subject.getClass().getInterfaces(),
                handler
        );

        subject1.rent();
    }
}

执行结果:

/Library/Java/JavaVirtualMachines/jdk1.8.0_333.jdk/Contents/Home/bin/java -javaagent:/Applications/IntelliJ IDEA.app/Contents/lib/idea_rt.jar=57555:/Applications/IntelliJ IDEA.app/Contents/bin -Dfile.encoding=UTF-8 -classpath /Library/Java/JavaVirtualMachines/jdk1.8.0_333.jdk/Contents/Home/jre/lib/charsets.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_333.jdk/Contents/Home/jre/lib/deploy.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_333.jdk/Contents/Home/jre/lib/ext/cldrdata.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_333.jdk/Contents/Home/jre/lib/ext/dnsns.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_333.jdk/Contents/Home/jre/lib/ext/jaccess.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_333.jdk/Contents/Home/jre/lib/ext/jfxrt.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_333.jdk/Contents/Home/jre/lib/ext/localedata.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_333.jdk/Contents/Home/jre/lib/ext/nashorn.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_333.jdk/Contents/Home/jre/lib/ext/sunec.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_333.jdk/Contents/Home/jre/lib/ext/sunjce_provider.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_333.jdk/Contents/Home/jre/lib/ext/sunpkcs11.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_333.jdk/Contents/Home/jre/lib/ext/zipfs.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_333.jdk/Contents/Home/jre/lib/javaws.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_333.jdk/Contents/Home/jre/lib/jce.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_333.jdk/Contents/Home/jre/lib/jfr.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_333.jdk/Contents/Home/jre/lib/jfxswt.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_333.jdk/Contents/Home/jre/lib/jsse.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_333.jdk/Contents/Home/jre/lib/management-agent.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_333.jdk/Contents/Home/jre/lib/plugin.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_333.jdk/Contents/Home/jre/lib/resources.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_333.jdk/Contents/Home/jre/lib/rt.jar:/Users/mac/IdeaProjects/OOM/JVMSample/target/classes:/Users/mac/repo/org/ow2/asm/asm-all/5.0.3/asm-all-5.0.3.jar:/Users/mac/repo/org/javassist/javassist/3.21.0-GA/javassist-3.21.0-GA.jar class12.jdkdemp.MainTest
租房之前。。。
Method public abstract void class12.jdkdemp.ISubject.rent()
I want to rent my house
租到房子。。。

Process finished with exit code 0

缺点:使用基于JDK动态代理,必须有接口,如果没有接口,就无法使用动态代理。

十三、代理之三基于CGlib实现动态代理实战

引入CGLIB:

<dependency>
      <groupId>cglib</groupId>
      <artifactId>cglib-full</artifactId>
      <version>2.0.2</version>
    </dependency>

核心业务类:

package cglib;

public class SubjectClass {
    public void testproxy()
    {
        System.out.println("找房源.....");
    }
}

代理实现类:

package cglib;

import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy;

import java.lang.reflect.Method;

public class SubjectProxy implements MethodInterceptor {
    @Override
    public Object intercept(Object obj, Method method, Object[] args,
                            MethodProxy methodProxy) throws Throwable {
        System.out.println("房屋中介搜索房源");
        methodProxy.invokeSuper(obj, args);
        System.out.println("房屋中介中介费");
        return null;
    }

}

执行代码:

package cglib;

import net.sf.cglib.proxy.Enhancer;

public class MainTest {
    public static void main(String[] args) {
        SubjectProxy subjectProxy = new SubjectProxy();
        //cglib 中加强器,用来创建动态代理
        Enhancer enhancer = new Enhancer();
        //设置要创建动态代理的类
        enhancer.setSuperclass(SubjectClass.class);
        // 设置回调,这里相当于是对于代理类上所有方法的调用,都会调用CallBack,而Callback则需要实行intercept()方法进行拦截
        enhancer.setCallback(subjectProxy);
        SubjectClass proxy = (SubjectClass) enhancer.create();
        proxy.testproxy();

    }

}

运行结果:

/Library/Java/JavaVirtualMachines/jdk1.8.0_333.jdk/Contents/Home/bin/java -javaagent:/Applications/IntelliJ IDEA.app/Contents/lib/idea_rt.jar=54389:/Applications/IntelliJ IDEA.app/Contents/bin -Dfile.encoding=UTF-8 -classpath /Library/Java/JavaVirtualMachines/jdk1.8.0_333.jdk/Contents/Home/jre/lib/charsets.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_333.jdk/Contents/Home/jre/lib/deploy.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_333.jdk/Contents/Home/jre/lib/ext/cldrdata.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_333.jdk/Contents/Home/jre/lib/ext/dnsns.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_333.jdk/Contents/Home/jre/lib/ext/jaccess.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_333.jdk/Contents/Home/jre/lib/ext/jfxrt.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_333.jdk/Contents/Home/jre/lib/ext/localedata.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_333.jdk/Contents/Home/jre/lib/ext/nashorn.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_333.jdk/Contents/Home/jre/lib/ext/sunec.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_333.jdk/Contents/Home/jre/lib/ext/sunjce_provider.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_333.jdk/Contents/Home/jre/lib/ext/sunpkcs11.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_333.jdk/Contents/Home/jre/lib/ext/zipfs.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_333.jdk/Contents/Home/jre/lib/javaws.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_333.jdk/Contents/Home/jre/lib/jce.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_333.jdk/Contents/Home/jre/lib/jfr.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_333.jdk/Contents/Home/jre/lib/jfxswt.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_333.jdk/Contents/Home/jre/lib/jsse.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_333.jdk/Contents/Home/jre/lib/management-agent.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_333.jdk/Contents/Home/jre/lib/plugin.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_333.jdk/Contents/Home/jre/lib/resources.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_333.jdk/Contents/Home/jre/lib/rt.jar:/Users/mac/IdeaProjects/jvm/cglib-test/target/classes:/Users/mac/repo/cglib/cglib-full/2.0.2/cglib-full-2.0.2.jar:/Users/mac/repo/com/alibaba/fastjson/1.2.83/fastjson-1.2.83.jar:/Users/mac/repo/org/ow2/asm/asm-all/5.0.3/asm-all-5.0.3.jar cglib.MainTest
房屋中介搜索房源
找房源.....
房屋中介中介费

Process finished with exit code 0

原理:类似子类继承父类,调用子类方法,先执行子类的前置代码,再调用父类的方法,最后再执行子类的后置代码。所以,这里enhancer.setSupeclass(SubjectClass.class)。

十四、字节码技术在FastJson里的应用案例

引入fastjson:

<dependency>
      <groupId>com.alibaba</groupId>
      <artifactId>fastjson</artifactId>
      <version>1.2.83</version>
    </dependency>
package class12.fastjson;

import java.util.Date;

public class Person {
    private int age;
    private String name;
    private Date birth;

    public Person(int age, String name, Date birth) {
        this.age = age;
        this.name = name;
        this.birth = birth;
    }

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public Date getBirth() {
        return birth;
    }

    public void setBirth(Date birth) {
        this.birth = birth;
    }

    @Override
    public String toString() {
        return "Person{" +
                "age=" + age +
                ", name='" + name + '\'' +
                ", birth=" + birth +
                '}';
    }
}
package class12.fastjson;

import com.alibaba.fastjson.JSON;

import java.util.Date;

public class MainTest {
    public static void main(String[] args) {
        Person person = new Person(11, "海涛", new Date());

        String jsonStr = JSON.toJSONString(person);
        System.out.println(jsonStr);

        String str = "{\"age\":22,\"birth\":1696157343030,\"name\":\"海涛老师\"}";
        Person personJson = JSON.parseObject(str, Person.class);
        System.out.println(personJson);
    }
}

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

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

相关文章

leetcode.2846. 边权重均等查询【lca+树形dp】

原题链接&#xff1a;2846. 边权重均等查询 题目描述&#xff1a; 现有一棵由 n 个节点组成的无向树&#xff0c;节点按从 0 到 n - 1 编号。给你一个整数 n 和一个长度为 n - 1 的二维整数数组 edges &#xff0c;其中 edges[i] [ui, vi, wi] 表示树中存在一条位于节点 ui …

微服务-微服务Alibaba-Nacos注册中心实现

1. 系统架构的演变 俗话说&#xff0c; 没有最好的架构&#xff0c;只有最合适的架构。 微服务架构也是随着信息产业的发展而出现的最有普 遍适用性的一套架构模式。通常来说&#xff0c;我们认为架构发展历史经历了这样一个过程&#xff1a;单体架构——> 垂直架构 ——&g…

leetcode 42.接雨水

问题1&#xff1a;怎么算接水量 总的接水量第一列接水量第二列接水量第三列接水量…最后一列接水量 问题2&#xff1a;当前列的接水量怎么计算 当前的接水量min(当前列左边最高的墙x1&#xff0c;当前列右边最高的墙x3&#xff09;- 当前列x2的高度 问题2图解&#xff1a; …

蓝桥杯-sort排序(上)

sort排序 &#x1f388;1.算法说明&#x1f388;2.例题&#x1f52d;2.1例题一&#x1f52d;2.2例题二&#x1f52d;2.3例题三&#x1f52d;2.4例题四&#x1f52d;2.5例题五&#x1f52d;2.6例题六 &#x1f388;1.算法说明 &#x1f50e;对于一个数组&#xff0c;通过对数组中…

新版UI界面影视小程序亲测无问题带详细搭建教程

新版UI界面影视小程序亲测无问题带详细搭建教程 环境php7.0 — fileinfo–redis–sg11 mysql5.5 apache2.4 添加站点php7.0—-创建ftp—-上传后端文件《后端文件修改&#xff0c;/maccms/wxapi/config/dbs.php–修改当前数据库》—-设置ssl—-打开数据库安装cms 安装好后管…

如何写出有效的单元测试?

什么是单元测试 《单元测试的艺术》中对单元测试的定义&#xff1a; 一个单元测试是一段自动化的代码&#xff0c;这段代码调用被测试的工作单元&#xff0c;之后对这个单元的单个最终结果的某些假设进行校验。 单元测试几乎都是用单元测试框架编写的&#xff1b;只要产品代码…

免费数据恢复软件,帮你轻松恢复丢失数据!

“由于我经常会丢失各种文件&#xff0c;因此非常需要一款实用又有效的数据恢复软件&#xff0c;大家有什么推荐的吗&#xff1f;希望能给我出出主意&#xff01;” 随着数字技术的不断发展&#xff0c;数据恢复软件在我们的生活中扮演着越来越重要的角色。当我们的硬盘或其他存…

Bluetooth Device Address(BD_ADDR) - 2

蓝牙核心规范&#xff1a;Core v5.3中关于蓝牙地址的其他说明 Vol 3: Host, Part C: Generic Access Profile 3 User interface aspects 3.2 Representation of Bluetooth parameters 3.2.1 Bluetooth Device Address (BD_ADDR) BD_ADDR 是蓝牙设备使用的地址。在设备发现过…

nav02 学习03 机器人传感器

机器人传感器 移动机器人配备了大量传感器&#xff0c;使它们能够看到和感知周围的环境。这些传感器获取的信息可用于构建和维护环境地图、在地图上定位机器人以及查看环境中的障碍物。这些任务对于能够安全有效地在动态环境中导航机器人至关重要。 机器人的传感器类似人的感官…

单片机学习笔记---独立按键控制LED状态

上一节学习的是独立按键控制LED亮灭 这一节我们先来讲一下按键的抖动&#xff1a; 对于机械开关&#xff0c;当机械触点断开、闭合时&#xff0c;由于机械触点的弹性作用&#xff0c;一个开关在闭合时不会马上稳定地接通&#xff0c;在断开时也不会一下子断开&#xff0c;所以…

Leetcode刷题笔记题解(C++):1971. 寻找图中是否存在路径

思路&#xff1a; 1.建立图集&#xff0c;二维数组&#xff0c;path[0]里面存放的就是与0相连的节点集合 2.用布尔数组来记录当前节点是否被访问过&#xff0c;深度优先会使用到 3.遍历从起点开始能直接到达的点&#xff08;即与起点相邻的点&#xff09;&#xff0c;判断那…

判断给定的字符串s是否为Python的保留关键字keyword.iskeyword(s)

【小白从小学Python、C、Java】 【计算机等考500强证书考研】 【Python-数据分析】 判断给定的字符串s 是否为Python的保留关键字 keyword.iskeyword(s) [太阳]选择题 请问以下代码输出的结果是&#xff1f; import keyword print("【执行】keyword.iskeyword(for)"…

【蓝桥杯冲冲冲】[NOIP2000 提高组] 方格取数

蓝桥杯备赛 | 洛谷做题打卡day19 文章目录 蓝桥杯备赛 | 洛谷做题打卡day19[NOIP2000 提高组] 方格取数题目背景题目描述输入格式输出格式样例 #1样例输入 #1样例输出 #1 提示题解代码我的一些话 [NOIP2000 提高组] 方格取数 题目背景 NOIP 2000 提高组 T4 题目描述 设有 N N…

PBM模型学习(五)UDF生长模型

DEFINE_PB_GROWTH_RATE(name, cell, thread, d_i) 该UDF在每个时间步开始时执行,只有在时间步开始时,颗粒粒径才会更新,同时才会UDF才会向文件写入数据GR单位是m/sC_PHASE DIAMETER(c,ts):返回颗粒粒径???,ts为颗粒相的线程C_VOF(cell,thread):颗粒相总体积C_PB DISCI(c…

Kotlin快速入门系列2

Kotlin的基本数据类型 Kotlin 的基本数值类型包括 Byte、Short、Int、Long、Float、Double 等。不同于 Java 的是&#xff0c;字符不属于数值类型&#xff0c;是一个独立的数据类型。 Java和kotlin数据类型对照如下&#xff1a; Java基本数据类型 Kotlin对象数据类型 数据类…

vue3+naiveUI二次封装的v-model 联动输入框

根据官网说明使用 源码 <template><div class"clw-input pt-3"><n-inputref"input":value"modelValue":type"type":title"title"clearable:disabled"disabled":size"size"placeholder&…

商家转账到零钱使用教程

商家转账到零钱是什么&#xff1f; 使用商家转账到零钱这个功能&#xff0c;可以让商户同时向多个用户的零钱转账。商户可以使用这个功能用于费用报销、员工福利发放、合作伙伴货款或分销返佣等场景&#xff0c;提高效率。 商家转账到零钱的使用场景有哪些&#xff1f; 商家…

(大众金融)SQL server面试题(1)-总销售量最少的3个型号的车及其总销售量

今天&#xff0c;面试了一家公司&#xff0c;什么也不说先来三道面试题做做&#xff0c;第一题。 那么&#xff0c;我们就开始做题吧&#xff0c;谁叫我们是打工人呢。 题目是这样的&#xff1a; 统计除豪车外&#xff0c;销售最差的车 车辆按批销售&#xff0c;每次销售若干…

IDC机房交换机核心技术与应用指南

IDC机房交换机核心技术与应用指南 ​ 在这个快速发展的数字时代&#xff0c;数据中心作为信息技术的心脏&#xff0c;不仅承载着海量数据的处理、存储和传输&#xff0c;更是支撑着全球企业运营和互联网服务的关键基础设施。在众多构成数据中心的组件中&#xff0c;IDC机房交换…

在autodl训练yolov8时卡在下载字体

1.问题 在autodl训练yolov8到这一步之后会卡住很久 2. 解决办法 Ctric中断后发现是下载Arial字体卡住了&#xff0c;这个字体需要从外网中下载 先手动从链接中下载https://ultralytics.com/assets/Arial.ttf &#xff0c;然后上传到autodl。然后将这个文件移动到/root/.config/…
最新文章