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) {@Overridepublic void visit(int version, int access, String name, String signature, String superName, String[] interfaces) {super.visit(version, access, name, signature, superName, interfaces);}@Overridepublic void visitSource(String source, String debug) {System.out.println("source in visitSource:" + source);super.visitSource(source, debug);}@Overridepublic void visitOuterClass(String owner, String name, String desc) {super.visitOuterClass(owner, name, desc);}@Overridepublic AnnotationVisitor visitAnnotation(String desc, boolean visible) {return super.visitAnnotation(desc, visible);}@Overridepublic AnnotationVisitor visitTypeAnnotation(int typeRef, TypePath typePath, String desc, boolean visible) {return super.visitTypeAnnotation(typeRef, typePath, desc, visible);}@Overridepublic void visitAttribute(Attribute attr) {System.out.println("visitAttribute attr: " + attr);super.visitAttribute(attr);}@Overridepublic void visitInnerClass(String name, String outerName, String innerName, int access) {super.visitInnerClass(name, outerName, innerName, access);}@Overridepublic 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);}@Overridepublic 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);}@Overridepublic 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 :mainProcess 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) {@Overridepublic 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.classLast modified 2024-1-22; size 349 bytesMD5 checksum a1777a658317cd8700e6eab4edb436d6
public class asm.MyMainminor version: 0major version: 49flags: 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: Iflags: ACC_PUBLICpublic int b;descriptor: Iflags: ACC_PUBLICpublic java.lang.String xyz;descriptor: Ljava/lang/String;flags: ACC_PUBLICpublic asm.MyMain();descriptor: ()Vflags: ACC_PUBLICCode:stack=2, locals=1, args_size=10: aload_01: invokespecial #11                 // Method java/lang/Object."<init>":()V4: aload_05: bipush        107: putfield      #13                 // Field a:I10: aload_011: bipush        1113: putfield      #15                 // Field b:I16: returnpublic void test1();descriptor: ()Vflags: ACC_PUBLICCode:stack=0, locals=1, args_size=10: returnpublic void test2();descriptor: ()Vflags: ACC_PUBLICCode:stack=0, locals=1, args_size=10: returnpublic static void main(java.lang.String[]);descriptor: ([Ljava/lang/String;)Vflags: ACC_PUBLIC, ACC_STATICCode:stack=0, locals=1, args_size=10: 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.classLast modified 2024-1-22; size 349 bytesMD5 checksum c4d1ac0f63f8fe9b91d552e7a6ac1330
public class asm.MyMainminor version: 0major version: 49flags: 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: Iflags: ACC_PUBLICpublic int b;descriptor: Iflags: ACC_PUBLICpublic static java.lang.String abc;descriptor: Ljava/lang/String;flags: ACC_PUBLIC, ACC_STATICpublic asm.MyMain();descriptor: ()Vflags: ACC_PUBLICCode:stack=2, locals=1, args_size=10: aload_01: invokespecial #13                 // Method java/lang/Object."<init>":()V4: aload_05: bipush        107: putfield      #15                 // Field a:I10: aload_011: bipush        1113: putfield      #17                 // Field b:I16: returnpublic void test1();descriptor: ()Vflags: ACC_PUBLICCode:stack=0, locals=1, args_size=10: returnpublic void test2();descriptor: ()Vflags: ACC_PUBLICCode:stack=0, locals=1, args_size=10: returnpublic static void main(java.lang.String[]);descriptor: ([Ljava/lang/String;)Vflags: ACC_PUBLIC, ACC_STATICCode:stack=0, locals=1, args_size=10: 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) {@Overridepublic 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.classLast modified 2024-1-22; size 354 bytesMD5 checksum 9fdee43198912003ad1896011d11ccc4
public class asm.MyMainminor version: 0major version: 49flags: 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: Iflags: ACC_PUBLICpublic int b;descriptor: Iflags: ACC_PUBLICpublic asm.MyMain();descriptor: ()Vflags: ACC_PUBLICCode:stack=2, locals=1, args_size=10: aload_01: invokespecial #11                 // Method java/lang/Object."<init>":()V4: aload_05: bipush        107: putfield      #13                 // Field a:I10: aload_011: bipush        1113: putfield      #15                 // Field b:I16: returnpublic void test1();descriptor: ()Vflags: ACC_PUBLICCode:stack=0, locals=1, args_size=10: returnpublic void test2();descriptor: ()Vflags: ACC_PUBLICCode:stack=0, locals=1, args_size=10: returnpublic static void main(java.lang.String[]);descriptor: ([Ljava/lang/String;)Vflags: ACC_PUBLIC, ACC_STATICCode:stack=0, locals=1, args_size=10: returnpublic void zyx(int, int, java.lang.String);descriptor: (IILjava/lang/String;)Vflags: 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) {@Overridepublic void visit(int version, int access, String name, String signature, String superName, String[] interfaces) {super.visit(version, access, name, signature, superName, interfaces);}@Overridepublic void visitSource(String source, String debug) {super.visitSource(source, debug);}@Overridepublic void visitOuterClass(String owner, String name, String desc) {super.visitOuterClass(owner, name, desc);}@Overridepublic AnnotationVisitor visitAnnotation(String desc, boolean visible) {return super.visitAnnotation(desc, visible);}@Overridepublic AnnotationVisitor visitTypeAnnotation(int typeRef, TypePath typePath, String desc, boolean visible) {return super.visitTypeAnnotation(typeRef, typePath, desc, visible);}@Overridepublic void visitAttribute(Attribute attr) {super.visitAttribute(attr);}@Overridepublic void visitInnerClass(String name, String outerName, String innerName, int access) {super.visitInnerClass(name, outerName, innerName, access);}@Overridepublic FieldVisitor visitField(int access, String name, String desc, String signature, Object value) {//如果要删除某个字段返回空return super.visitField(access, name, desc, signature, value);}@Overridepublic 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);}@Overridepublic 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.classLast modified 2024-1-22; size 314 bytesMD5 checksum b8ea36457b5d3574b2a244b17374421b
public class asm.MyMainminor version: 0major version: 49flags: 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: Iflags: ACC_PUBLICpublic int b;descriptor: Iflags: ACC_PUBLICpublic asm.MyMain();descriptor: ()Vflags: ACC_PUBLICCode:stack=2, locals=1, args_size=10: aload_01: invokespecial #11                 // Method java/lang/Object."<init>":()V4: aload_05: bipush        107: putfield      #13                 // Field a:I10: aload_011: bipush        1113: putfield      #15                 // Field b:I16: returnpublic void test1();descriptor: ()Vflags: ACC_PUBLICCode:stack=0, locals=1, args_size=10: returnpublic void test2();descriptor: ()Vflags: ACC_PUBLICCode:stack=0, locals=1, args_size=10: returnpublic static void main(java.lang.String[]);descriptor: ([Ljava/lang/String;)Vflags: ACC_PUBLIC, ACC_STATICCode:stack=0, locals=1, args_size=10: 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是将属性关联到ctClassctField.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是将属性关联到ctClassctField.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,2String 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:基于已经创建的对象来反射
//        jdbcClass clazz = Class.forName(classPath);return clazz.newInstance();}
}

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

package class8;import javassist.Person;/**** 获取class类的四种方式*/public class GetClassDemo {public static void main(String[] args) throws ClassNotFoundException {//方式一:调用运行时类的属性:.classClass 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);//trueSystem.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.weightprivate java.lang.String class8.Person.name
int class8.Person.age
public int class8.Person.idProcess 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	nameint	age
public	int	idProcess 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;}@Overridepublic 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
100Process 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
海涛 是一位好老师
aaProcess finished with exit code 0

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

静态代理实现:

业务接口

package class11;public interface ITicketService {//问询public void inquire();//售票public void sellTicket();}

业务自身接口实现:

package class11;public class Station implements ITicketService{@Overridepublic void inquire() {System.out.println("海涛老师 问询...");}@Overridepublic void sellTicket() {System.out.println("海涛老师 售票.....");}}

代理实现:

package class11;public class StationProxy implements ITicketService{private Station station;public StationProxy(Station station){this.station = station;}@Overridepublic void inquire() {System.out.println("代理人 协助海涛老师问询");station.inquire();System.out.println("代理人 协助海涛老师问询结束,并做记录");}@Overridepublic 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 {@Overridepublic void rent() {System.out.println("I want to rent my house");}@Overridepublic void hello(String str) {System.out.println("hello: " + str);}}

动态代理实现:

package class12.jdkdemp;public class SubjectImpl implements ISubject {@Overridepublic void rent() {System.out.println("I want to rent my house");}@Overridepublic 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 {@Overridepublic 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;}@Overridepublic 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.mzph.cn/news/650729.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

[已解决]504 Gateway Time-out 网关超时

文章目录 问题&#xff1a;504 Gateway Time-out 504 Gateway Time-out 网关超时思路解决 问题&#xff1a;504 Gateway Time-out 504 Gateway Time-out 网关超时 思路 网上的常规思路是修改nginx配置文件,增加请求执行时间,试过没有用 keepalive_timeout 600; fastcgi_con…

JVM系列-7内存调优

&#x1f44f;作者简介&#xff1a;大家好&#xff0c;我是爱吃芝士的土豆倪&#xff0c;24届校招生Java选手&#xff0c;很高兴认识大家&#x1f4d5;系列专栏&#xff1a;Spring原理、JUC原理、Kafka原理、分布式技术原理、数据库技术、JVM原理&#x1f525;如果感觉博主的文…

案例分享 | 助力数字化转型:嘉为科技项目管理平台上线

嘉为科技项目管理平台&#xff08;一期&#xff09;基于易趋&#xff08;EasyTrack&#xff09;进行实施&#xff0c;通过近一年的开发及试运行&#xff0c;现已成功交付上线、推广使用&#xff0c;取得了良好的应用效果。 1.关于广州嘉为科技有限公司&#xff08;以下简称嘉为…

龙芯,启动!

本文为小白从购买龙芯3A6000主板、硬件安装、软件安装的简单教程。 1 购买 目前&#xff08;2024年1月&#xff09;最新的龙芯主板采用龙芯处理器3A6000和7A2000桥片设计的DTX主板&#xff0c;CPU主频可达2.5GHz&#xff0c;2个DDR4内存插槽。桥片内部集成GPU&#xff0c;支…

如何把openwrt的ipk软件包安装到ubuntu上

前提&#xff1a;都是arm64的架构的软件包。 下载openwrt的ipk软件包 1. 从https://pkgs.org/ 查找下载软件包&#xff1a; 本文以swconfig软件包为例&#xff0c;下载swconfig和相关的依赖软件包&#xff1a; swconfig_12_aarch64_cortex-a72.ipk libuci20130104_2021-10-2…

podman+centos和docker+alpine中作性能对比遇到的问题及解决

1.dockeralpine中遇到这个问题 这是由于缺少相关的配置和依赖造成的 通过以下命令在alpine中安装相关配置 apk add --no-cache build-base cairo-dev cairo cairo-tools jpeg-dev zlib-dev freetype-dev lcms2-dev openjpeg-dev tiff-dev tk-dev tcl-dev 2.alpine中python找…

C++——IO流

C语言中我们学习过文件IO的相关函数&#xff0c;那么在C中也一定有各种IO流的 函数或者功能&#xff0c;由我今天来简单介绍一下C中IO流的大致原理及使用。在C语言中我们经常会使用到scanf、printf、sscanf、sprintf等等来实现进程和文件之间数据的流动&#xff0c;在C中虽然由…

python黑马模块

1、使用内置模块 # import通过.使用模块内部的全部功能 """ import time print("ff") time. sleep(5) print("as")# 使用from 导入某个功能 from time import sleep print("ff") sleep(5) print("as")# 使用 * 导入全部…

taskflow 源码阅读笔记-1

之前写了一篇介绍Taskflow的短文&#xff1a;传送门 Taskflow做那种有前后依赖关系的任务管理还是不错的&#xff0c;而且他的源码里运用了大量C17的写法&#xff0c;觉得还是非常值得学习的&#xff0c;因此决定看一下他的源码&#xff0c;这里顺便写了一篇代码学习笔记。 概…

Amazon 亚马逊新玩具——在线购物试衣服“虚拟试穿”模型:Diffuse to Choose

这个模型拥有强大的能力&#xff0c;它能够将任何商品无缝地融入任何环境之中&#xff0c;确保商品与环境完美匹配。例如&#xff0c;你可以轻松地将在线商店中的椅子图片放入你客厅照片中&#xff0c;预览它实际摆放的效果。无论环境如何变化&#xff0c;该模型都能确保商品展…

Java复习系列之阶段二:数据库

1. 基础语法 1.1 DQL&#xff08;数据查询语句&#xff09; 执行顺序&#xff1a; from、join 、on、where、group by、having、select、distinct、order by、limit 1.2 DML&#xff08;数据修改语言&#xff09; 对数据表的增删改 insert into update set delete form 1.…

【JavaEE进阶】 #{}和${}

文章目录 &#x1f343;前言&#x1f333;#{}和${}使⽤&#x1f6a9;Interger类型的参数&#xff08;基础数据类型&#xff09;&#x1f388;使用#{}&#x1f388;使用${} &#x1f6a9;String类型的参数使用&#x1f388;#{}使用&#x1f388;${} &#x1f38d;#{}和${}区别&a…

C++:引用

目录 概念&#xff1a; 引用的使用格式&#xff1a; 引用特性&#xff1a; 常引用 使用场景&#xff1a; 1、做参数 二级指针时的取别名 一级指针取别名 一般函数取别名 2、做返回值 函数返回值的原理&#xff1a; 引用的返回值使用&#xff1a; 引用和指针的对比&…

Java Swing桌面项目打包成可执行jar

前言 最近有需求&#xff0c;将Swing项目打包为一个可执行的jar包&#xff0c;遇见了一些问题&#xff0c;参考AI助手&#xff0c;解决了遇到的问题&#xff0c;也有一些亲身实践体会&#xff0c;记录一下。开发环境IntelliJ IDEA&#xff0c;JDK8&#xff0c;用kotlin语言实现…

navicat连接postgresql、人大金仓等数据库报错

navicat连接postgresql、人大金仓数据库报错问题是一个偶现的问题&#xff0c;需要我们特别关注&#xff1a; 1、客户端连接人大金仓数据库 这里注意&#xff1a;navicat连接postgresql、人大金仓数据库时均选择postgresql类型&#xff0c;因为人大金仓数据库底层和psql数据库…

【第五天】蓝桥杯备战

1、金币 https://www.lanqiao.cn/problems/357/learning/ 解法&#xff1a;暴力 import java.util.Scanner; // 1:无需package // 2: 类名必须Main, 不可修改public class Main {public static void main(String[] args) {Scanner scan new Scanner(System.in);//在此输入…

01_Anaconda环境搭建

概述 Anaconda包含了许多常用的科学计算和数据分析的库和工具。通过Anaconda&#xff0c;用户可以更方便地安装、管理和更新这些库和工具&#xff0c;从而提高工作效率。 Anaconda还提供了一个名为conda的包管理器&#xff0c;可以帮助用户方便地安装、管理和更新这些库和工具…

写静态页面——魅族声学_前端页面练习

1、效果: 1、html代码: <!DOCTYPE html> <html lang="en"> <head><meta charset="UTF-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>魅族声学</titl…

金智易表通构建学生缴费数据查询+帆软构建缴费大数据报表并整合到微服务

使用金智易表通挂接外部数据,快速建设查询类服务,本次构建学生欠费数据查询,共有3块设计,规划如下: 1、欠费明细查询:学校领导和财务处等部门可查询全校欠费学生明细数据;各二级学院教职工可查询本二级学院欠费学生明细数据。 2、大数据统计报表:从应收总额、欠费总额…

Spring与Redis集成

1.引入RedisTemplate 据以前的情况&#xff0c;我们在Java中使用Redis时一般是使用Jedis来操作的&#xff0c;大致的一段代码如下所示 Overridepublic User findUserById(Integer id) {User user null;Jedis jedis null;try {jedis jedisPool.getResource();String userStr…