美文网首页
关于构造器的一些思考

关于构造器的一些思考

作者: 风干鸡 | 来源:发表于2017-01-12 11:13 被阅读0次

关于构造器的一些思考

Java编译器会给没有构造器的Class添加一个无参的构造器,而JVM规范并没有要求Class必须有一个构造器。

类似的还有构造器里调用其他/父类构造器必须写在第一行,不得不说这个要求有些愚蠢,他好像只是为了告诉你对象的父类字段应该优先初始化,而这个要求又并不是十分严格。

比如我要在调用父类构造器之前做一些事情,那我就必须写成这样:

class A{
    int val;
    A(int i) {
        val = i;
    }
}

class B extends A{
    B(int i) {
        super(fun(i));
    }

    static int fun(int i) {
        System.out.println("hehe");
        return i;
    }
}

回到正题上来,一个没有构造器的Class 字节码是可以被JVM接受的,我们用ASM(jdk自带)来创建一个简单的类,就是下面这个:

public class Hehe {
    public String hehe() {
        return "hehe";
    }
}

代码:

import jdk.internal.org.objectweb.asm.AnnotationVisitor;
import jdk.internal.org.objectweb.asm.ClassWriter;
import jdk.internal.org.objectweb.asm.MethodVisitor;

import java.io.IOException;
import static jdk.internal.org.objectweb.asm.Opcodes.*;

public class Test {
    
    public static void main(String[] args) throws NoSuchFieldException, IllegalAccessException, InstantiationException, IOException, InvocationTargetException, NoSuchMethodException {
        ClassWriter cw = new ClassWriter(0);
        MethodVisitor mv;
        AnnotationVisitor av0;
        cw.visit(V1_8, ACC_PUBLIC + ACC_SUPER, "Hehe", null, "java/lang/Object", null);
        cw.visitSource("Hehe.java", null);
        mv = cw.visitMethod(ACC_PUBLIC, "hehe", "()Ljava/lang/String;", null, null);
        mv.visitCode();
        mv.visitLdcInsn("hehe");
        mv.visitInsn(ARETURN);
        mv.visitMaxs(1, 1);
        mv.visitEnd();
        cw.visitEnd();
        byte[] bytes = cw.toByteArray();
    }
}

这样就完成了。

因为ClassLoaderdefineClassprotected的,所以只能自己创建一个加载器来加载他。

    static class Loader extends ClassLoader {
        Class<?> define(String name, byte[] b, int off, int length) {
            return defineClass(name, b, off, length);
        }
    }

加载之后通过Unsafe.allocateInstance来实例化,(因为它并没有构造器)。

然后通过反射调用hehe方法,完成了。

接下来创建一个构造器第一行不是调用父类构造器的类,就直接贴一起了。现在有构造器就不用Unsafe来初始化,而且类加载器继承了当前的类加载器,所以子类实例可以直接赋值给Test变量。

import jdk.internal.org.objectweb.asm.AnnotationVisitor;
import jdk.internal.org.objectweb.asm.ClassWriter;
import jdk.internal.org.objectweb.asm.FieldVisitor;
import jdk.internal.org.objectweb.asm.MethodVisitor;

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

public class Test {
    public Test() {
        System.out.println("Test");
    }

    public static void main(String[] args) {
        ClassWriter cw = new ClassWriter(0);
        FieldVisitor fv;
        MethodVisitor mv;
        AnnotationVisitor av0;
        cw.visit(52, ACC_PUBLIC | ACC_SUPER, "Son1", null, "Test", null);
        cw.visitSource("Son1.java", null);
        mv = cw.visitMethod(ACC_PUBLIC, "<init>", "()V", null, null);
        mv.visitCode();
        mv.visitFieldInsn(GETSTATIC, "java/lang/System", "out", "Ljava/io/PrintStream;");
        mv.visitLdcInsn("Son");
        mv.visitMethodInsn(INVOKEVIRTUAL, "java/io/PrintStream", "println", "(Ljava/lang/String;)V", false);
        mv.visitVarInsn(ALOAD, 0);
        mv.visitMethodInsn(INVOKESPECIAL, "Test", "<init>", "()V", false);
        mv.visitInsn(RETURN);
        mv.visitMaxs(2, 1);
        mv.visitEnd();
        cw.visitEnd();
        byte[] bytes = cw.toByteArray();
        ClassLoader loader = new ClassLoader(Thread.currentThread().getContextClassLoader()) {
            @Override
            public Class<?> loadClass(String name) throws ClassNotFoundException {
                return name.equals("Son1") ? super.defineClass(name, bytes, 0, bytes.length) : super.loadClass(name);
            }
        };

        Class<? extends Test> son = null;
        try {
            son = (Class<? extends Test>) loader.loadClass("Son1");
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }

        try {
            Test test = son.newInstance();
        } catch (InstantiationException e) {
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        }
    }
}

子类的构造器打印Son1,父类构造器打印Test。

输出:Son (手动换行)Test。

相关文章

网友评论

      本文标题:关于构造器的一些思考

      本文链接:https://www.haomeiwen.com/subject/wvydbttx.html