文章详情

短信预约-IT技能 免费直播动态提醒

请输入下面的图形验证码

提交验证

短信预约提醒成功

java动态代理

2023-08-30 15:36

关注
1. Proxy.newProxyInstance2. Constructor<?> cons = getProxyConstructor(caller, loader, interfaces);3. (ld, clv) -> new ProxyBuilder(ld, clv.key()).build()4. byte[] proxyClassFile = ProxyGenerator.generateProxyClass(proxyName,interfaces.toArray(EMPTY_CLASS_ARRAY), accessFlags);5. final byte[] classFile = gen.generateClassFile();

IPerson.java

public interface IPerson {    String stduy(String name);}

JDKProxy

package A002动态代理;import java.lang.reflect.InvocationHandler;import java.lang.reflect.Method;import java.lang.reflect.Proxy;public class JDKProxy<T> {    //需要代理的对象。这里我们使用Iperson来接收Tom对象    private T target;    public void setTarget(T target) {        this.target = target;    }    public T getProxy() {        Object o = Proxy.newProxyInstance(target.getClass().getClassLoader(),                target.getClass().getInterfaces(), new InvocationHandler() {                                        @Override                    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {                        System.out.println("方法执行前");                        //执行原有的方法                        Object invoke = method.invoke(target, args);                        System.out.println("方法执行后");                        return invoke;                    }                });        return (T) o;    }}

Tom

package A002动态代理;public class Tom implements IPerson {    @Override    public String stduy(String name) {        System.out.println("执行原生方法");        return Tom.class.getName()+name;    }}

Test

package A002动态代理;import java.io.FileNotFoundException;import java.io.FileOutputStream;import java.io.IOException;public class Test {    public static void main(String[] args) throws IOException {        JDKProxy<IPerson> iPersonJDKProxy = new JDKProxy<>();        //需要被代理的对象        IPerson tom = new Tom();        iPersonJDKProxy.setTarget(tom);        //获取代理对象,此时这个对象就不再是上面的tom了        IPerson proxy = iPersonJDKProxy.getProxy();        proxy.stduy("java");        // 代理类的字节码数组        byte[] proxyClassFile = ProxyGenerator.generateProxyClass(                "RProxy0",                new Class[]{IPerson.class});        FileOutputStream fileOutputStream = new FileOutputStream("/Users/zhaojian/code/java/InterviewDemo/src/main/kotlin/A002动态代理/IPersonProxy.class");        fileOutputStream.write(proxyClassFile);        fileOutputStream.flush();        fileOutputStream.close();    }}

ProxyGenerator

package A002动态代理;import java.io.*;import java.lang.reflect.Array;import java.lang.reflect.Method;import java.lang.reflect.Modifier;import java.nio.file.Files;import java.nio.file.Path;import java.util.*;//import sun.security.action.GetBooleanAction;class ProxyGenerator {            private static final int CLASSFILE_MAJOR_VERSION = 49;    private static final int CLASSFILE_MINOR_VERSION = 0;            private static final int CONSTANT_UTF8 = 1;    private static final int CONSTANT_UNICODE = 2;    private static final int CONSTANT_INTEGER = 3;    private static final int CONSTANT_FLOAT = 4;    private static final int CONSTANT_LONG = 5;    private static final int CONSTANT_DOUBLE = 6;    private static final int CONSTANT_CLASS = 7;    private static final int CONSTANT_STRING = 8;    private static final int CONSTANT_FIELD = 9;    private static final int CONSTANT_METHOD = 10;    private static final int CONSTANT_INTERFACEMETHOD = 11;    private static final int CONSTANT_NAMEANDTYPE = 12;        private static final int ACC_PUBLIC = 0x00000001;    private static final int ACC_PRIVATE = 0x00000002;    //  private static final int ACC_PROTECTED              = 0x00000004;    private static final int ACC_STATIC = 0x00000008;    private static final int ACC_FINAL = 0x00000010;    //  private static final int ACC_SYNCHRONIZED           = 0x00000020;//  private static final int ACC_VOLATILE               = 0x00000040;//  private static final int ACC_TRANSIENT              = 0x00000080;//  private static final int ACC_NATIVE                 = 0x00000100;//  private static final int ACC_INTERFACE              = 0x00000200;//  private static final int ACC_ABSTRACT               = 0x00000400;    private static final int ACC_SUPER = 0x00000020;//  private static final int ACC_STRICT                 = 0x00000800;    //  private static final int opc_nop                    = 0;    private static final int opc_aconst_null = 1;    //  private static final int opc_iconst_m1              = 2;    private static final int opc_iconst_0 = 3;    //  private static final int opc_iconst_1               = 4;//  private static final int opc_iconst_2               = 5;//  private static final int opc_iconst_3               = 6;//  private static final int opc_iconst_4               = 7;//  private static final int opc_iconst_5               = 8;//  private static final int opc_lconst_0               = 9;//  private static final int opc_lconst_1               = 10;//  private static final int opc_fconst_0               = 11;//  private static final int opc_fconst_1               = 12;//  private static final int opc_fconst_2               = 13;//  private static final int opc_dconst_0               = 14;//  private static final int opc_dconst_1               = 15;    private static final int opc_bipush = 16;    private static final int opc_sipush = 17;    private static final int opc_ldc = 18;    private static final int opc_ldc_w = 19;    //  private static final int opc_ldc2_w                 = 20;    private static final int opc_iload = 21;    private static final int opc_lload = 22;    private static final int opc_fload = 23;    private static final int opc_dload = 24;    private static final int opc_aload = 25;    private static final int opc_iload_0 = 26;    //  private static final int opc_iload_1                = 27;//  private static final int opc_iload_2                = 28;//  private static final int opc_iload_3                = 29;    private static final int opc_lload_0 = 30;    //  private static final int opc_lload_1                = 31;//  private static final int opc_lload_2                = 32;//  private static final int opc_lload_3                = 33;    private static final int opc_fload_0 = 34;    //  private static final int opc_fload_1                = 35;//  private static final int opc_fload_2                = 36;//  private static final int opc_fload_3                = 37;    private static final int opc_dload_0 = 38;    //  private static final int opc_dload_1                = 39;//  private static final int opc_dload_2                = 40;//  private static final int opc_dload_3                = 41;    private static final int opc_aload_0 = 42;    //  private static final int opc_aload_1                = 43;//  private static final int opc_aload_2                = 44;//  private static final int opc_aload_3                = 45;//  private static final int opc_iaload                 = 46;//  private static final int opc_laload                 = 47;//  private static final int opc_faload                 = 48;//  private static final int opc_daload                 = 49;//  private static final int opc_aaload                 = 50;//  private static final int opc_baload                 = 51;//  private static final int opc_caload                 = 52;//  private static final int opc_saload                 = 53;//  private static final int opc_istore                 = 54;//  private static final int opc_lstore                 = 55;//  private static final int opc_fstore                 = 56;//  private static final int opc_dstore                 = 57;    private static final int opc_astore = 58;    //  private static final int opc_istore_0               = 59;//  private static final int opc_istore_1               = 60;//  private static final int opc_istore_2               = 61;//  private static final int opc_istore_3               = 62;//  private static final int opc_lstore_0               = 63;//  private static final int opc_lstore_1               = 64;//  private static final int opc_lstore_2               = 65;//  private static final int opc_lstore_3               = 66;//  private static final int opc_fstore_0               = 67;//  private static final int opc_fstore_1               = 68;//  private static final int opc_fstore_2               = 69;//  private static final int opc_fstore_3               = 70;//  private static final int opc_dstore_0               = 71;//  private static final int opc_dstore_1               = 72;//  private static final int opc_dstore_2               = 73;//  private static final int opc_dstore_3               = 74;    private static final int opc_astore_0 = 75;    //  private static final int opc_astore_1               = 76;//  private static final int opc_astore_2               = 77;//  private static final int opc_astore_3               = 78;//  private static final int opc_iastore                = 79;//  private static final int opc_lastore                = 80;//  private static final int opc_fastore                = 81;//  private static final int opc_dastore                = 82;    private static final int opc_aastore = 83;    //  private static final int opc_bastore                = 84;//  private static final int opc_castore                = 85;//  private static final int opc_sastore                = 86;    private static final int opc_pop = 87;    //  private static final int opc_pop2                   = 88;    private static final int opc_dup = 89;    //  private static final int opc_dup_x1                 = 90;//  private static final int opc_dup_x2                 = 91;//  private static final int opc_dup2                   = 92;//  private static final int opc_dup2_x1                = 93;//  private static final int opc_dup2_x2                = 94;//  private static final int opc_swap                   = 95;//  private static final int opc_iadd                   = 96;//  private static final int opc_ladd                   = 97;//  private static final int opc_fadd                   = 98;//  private static final int opc_dadd                   = 99;//  private static final int opc_isub                   = 100;//  private static final int opc_lsub                   = 101;//  private static final int opc_fsub                   = 102;//  private static final int opc_dsub                   = 103;//  private static final int opc_imul                   = 104;//  private static final int opc_lmul                   = 105;//  private static final int opc_fmul                   = 106;//  private static final int opc_dmul                   = 107;//  private static final int opc_idiv                   = 108;//  private static final int opc_ldiv                   = 109;//  private static final int opc_fdiv                   = 110;//  private static final int opc_ddiv                   = 111;//  private static final int opc_irem                   = 112;//  private static final int opc_lrem                   = 113;//  private static final int opc_frem                   = 114;//  private static final int opc_drem                   = 115;//  private static final int opc_ineg                   = 116;//  private static final int opc_lneg                   = 117;//  private static final int opc_fneg                   = 118;//  private static final int opc_dneg                   = 119;//  private static final int opc_ishl                   = 120;//  private static final int opc_lshl                   = 121;//  private static final int opc_ishr                   = 122;//  private static final int opc_lshr                   = 123;//  private static final int opc_iushr                  = 124;//  private static final int opc_lushr                  = 125;//  private static final int opc_iand                   = 126;//  private static final int opc_land                   = 127;//  private static final int opc_ior                    = 128;//  private static final int opc_lor                    = 129;//  private static final int opc_ixor                   = 130;//  private static final int opc_lxor                   = 131;//  private static final int opc_iinc                   = 132;//  private static final int opc_i2l                    = 133;//  private static final int opc_i2f                    = 134;//  private static final int opc_i2d                    = 135;//  private static final int opc_l2i                    = 136;//  private static final int opc_l2f                    = 137;//  private static final int opc_l2d                    = 138;//  private static final int opc_f2i                    = 139;//  private static final int opc_f2l                    = 140;//  private static final int opc_f2d                    = 141;//  private static final int opc_d2i                    = 142;//  private static final int opc_d2l                    = 143;//  private static final int opc_d2f                    = 144;//  private static final int opc_i2b                    = 145;//  private static final int opc_i2c                    = 146;//  private static final int opc_i2s                    = 147;//  private static final int opc_lcmp                   = 148;//  private static final int opc_fcmpl                  = 149;//  private static final int opc_fcmpg                  = 150;//  private static final int opc_dcmpl                  = 151;//  private static final int opc_dcmpg                  = 152;//  private static final int opc_ifeq                   = 153;//  private static final int opc_ifne                   = 154;//  private static final int opc_iflt                   = 155;//  private static final int opc_ifge                   = 156;//  private static final int opc_ifgt                   = 157;//  private static final int opc_ifle                   = 158;//  private static final int opc_if_icmpeq              = 159;//  private static final int opc_if_icmpne              = 160;//  private static final int opc_if_icmplt              = 161;//  private static final int opc_if_icmpge              = 162;//  private static final int opc_if_icmpgt              = 163;//  private static final int opc_if_icmple              = 164;//  private static final int opc_if_acmpeq              = 165;//  private static final int opc_if_acmpne              = 166;//  private static final int opc_goto                   = 167;//  private static final int opc_jsr                    = 168;//  private static final int opc_ret                    = 169;//  private static final int opc_tableswitch            = 170;//  private static final int opc_lookupswitch           = 171;    private static final int opc_ireturn = 172;    private static final int opc_lreturn = 173;    private static final int opc_freturn = 174;    private static final int opc_dreturn = 175;    private static final int opc_areturn = 176;    private static final int opc_return = 177;    private static final int opc_getstatic = 178;    private static final int opc_putstatic = 179;    private static final int opc_getfield = 180;    //  private static final int opc_putfield               = 181;    private static final int opc_invokevirtual = 182;    private static final int opc_invokespecial = 183;    private static final int opc_invokestatic = 184;    private static final int opc_invokeinterface = 185;    private static final int opc_new = 187;    //  private static final int opc_newarray               = 188;    private static final int opc_anewarray = 189;    //  private static final int opc_arraylength            = 190;    private static final int opc_athrow = 191;    private static final int opc_checkcast = 192;    //  private static final int opc_instanceof             = 193;//  private static final int opc_monitorenter           = 194;//  private static final int opc_monitorexit            = 195;    private static final int opc_wide = 196;//  private static final int opc_multianewarray         = 197;//  private static final int opc_ifnull                 = 198;//  private static final int opc_ifnonnull              = 199;//  private static final int opc_goto_w                 = 200;//  private static final int opc_jsr_w                  = 201;    // end of constants copied from sun.tools.java.RuntimeConstants        private static final String superclassName = "java/lang/reflect/Proxy";        private static final String handlerFieldName = "h";        private static final boolean saveGeneratedFiles = true;    //java.security.AccessController.doPrivileged(new GetBooleanAction("jdk.proxy.ProxyGenerator.saveGeneratedFiles")).booleanValue();        private static final Method hashCodeMethod;    private static final Method equalsMethod;    private static final Method toStringMethod;    static {        try {            hashCodeMethod = Object.class.getMethod("hashCode");            equalsMethod =                    Object.class.getMethod("equals", Object.class);            toStringMethod = Object.class.getMethod("toString");        } catch (NoSuchMethodException e) {            throw new NoSuchMethodError(e.getMessage());        }    }        private final String className;        private final Class<?>[] interfaces;        private final int accessFlags;        private final ConstantPool cp = new ConstantPool();        private final List<FieldInfo> fields = new ArrayList<>();        private final List<MethodInfo> methods = new ArrayList<>();        private final Map<String, List<ProxyMethod>> proxyMethods = new HashMap<>();        private int proxyMethodCount = 0;        private ProxyGenerator(String className, Class<?>[] interfaces, int accessFlags) {        this.className = className;        this.interfaces = interfaces;        this.accessFlags = accessFlags;    }        static byte[] generateProxyClass(final String name,         Class<?>[] interfaces) {        return generateProxyClass(name, interfaces, (ACC_PUBLIC | ACC_FINAL | ACC_SUPER));    }        static byte[] generateProxyClass(final String name,         Class<?>[] interfaces,         int accessFlags) {        ProxyGenerator gen = new ProxyGenerator(name, interfaces, accessFlags);        final byte[] classFile = gen.generateClassFile();        if (saveGeneratedFiles) {            java.security.AccessController.doPrivileged(                    new java.security.PrivilegedAction<Void>() {                        public Void run() {try {    int i = name.lastIndexOf('.');    Path path;    if (i > 0) {        Path dir = Path.of(name.substring(0, i).replace('.', File.separatorChar));        Files.createDirectories(dir);        path = dir.resolve(name.substring(i + 1) + ".class");    } else {        path = Path.of(name + ".class");    }    Files.write(path, classFile);    return null;} catch (IOException e) {    throw new InternalError(            "I/O exception saving generated file: " + e);}                        }                    });        }        return classFile;    }        private static void checkReturnTypes(List<ProxyMethod> methods) {                if (methods.size() < 2) {            return;        }                LinkedList<Class<?>> uncoveredReturnTypes = new LinkedList<>();        nextNewReturnType:        for (ProxyMethod pm : methods) {            Class<?> newReturnType = pm.returnType;            if (newReturnType.isPrimitive()) {                throw new IllegalArgumentException(                        "methods with same signature " +    getFriendlyMethodSignature(pm.methodName,            pm.parameterTypes) +    " but incompatible return types: " +    newReturnType.getName() + " and others");            }            boolean added = false;                        ListIterator<Class<?>> liter = uncoveredReturnTypes.listIterator();            while (liter.hasNext()) {                Class<?> uncoveredReturnType = liter.next();                                if (newReturnType.isAssignableFrom(uncoveredReturnType)) {                    assert !added;                    continue nextNewReturnType;                }                                if (uncoveredReturnType.isAssignableFrom(newReturnType)) {                    // (we can assume that each return type is unique)                    if (!added) {                        liter.set(newReturnType);                        added = true;                    } else {                        liter.remove();                    }                }            }                        if (!added) {                uncoveredReturnTypes.add(newReturnType);            }        }                if (uncoveredReturnTypes.size() > 1) {            ProxyMethod pm = methods.get(0);            throw new IllegalArgumentException(                    "methods with same signature " +getFriendlyMethodSignature(pm.methodName, pm.parameterTypes) +" but incompatible return types: " + uncoveredReturnTypes);        }    }        private static String dotToSlash(String name) {        return name.replace('.', '/');    }        private static String getMethodDescriptor(Class<?>[] parameterTypes,                  Class<?> returnType) {        return getParameterDescriptors(parameterTypes) +                ((returnType == void.class) ? "V" : getFieldType(returnType));    }        private static String getParameterDescriptors(Class<?>[] parameterTypes) {        StringBuilder desc = new StringBuilder("(");        for (int i = 0; i < parameterTypes.length; i++) {            desc.append(getFieldType(parameterTypes[i]));        }        desc.append(')');        return desc.toString();    }        private static String getFieldType(Class<?> type) {        if (type.isPrimitive()) {            return PrimitiveTypeInfo.get(type).baseTypeString;        } else if (type.isArray()) {                        return type.getName().replace('.', '/');        } else {            return "L" + dotToSlash(type.getName()) + ";";        }    }        private static String getFriendlyMethodSignature(String name,                         Class<?>[] parameterTypes) {        StringBuilder sig = new StringBuilder(name);        sig.append('(');        for (int i = 0; i < parameterTypes.length; i++) {            if (i > 0) {                sig.append(',');            }            Class<?> parameterType = parameterTypes[i];            int dimensions = 0;            while (parameterType.isArray()) {                parameterType = parameterType.getComponentType();                dimensions++;            }            sig.append(parameterType.getName());            while (dimensions-- > 0) {                sig.append("[]");            }        }        sig.append(')');        return sig.toString();    }        private static int getWordsPerType(Class<?> type) {        if (type == long.class || type == double.class) {            return 2;        } else {            return 1;        }    }        private static void collectCompatibleTypes(Class<?>[] from,                   Class<?>[] with,                   List<Class<?>> list) {        for (Class<?> fc : from) {            if (!list.contains(fc)) {                for (Class<?> wc : with) {                    if (wc.isAssignableFrom(fc)) {                        list.add(fc);                        break;                    }                }            }        }    }        private static List<Class<?>> computeUniqueCatchList(Class<?>[] exceptions) {        List<Class<?>> uniqueList = new ArrayList<>();        // unique exceptions to catch        uniqueList.add(Error.class);            // always catch/rethrow these        uniqueList.add(RuntimeException.class);        nextException:        for (Class<?> ex : exceptions) {            if (ex.isAssignableFrom(Throwable.class)) {                                uniqueList.clear();                break;            } else if (!Throwable.class.isAssignableFrom(ex)) {                                continue;            }                        for (int j = 0; j < uniqueList.size(); ) {                Class<?> ex2 = uniqueList.get(j);                if (ex2.isAssignableFrom(ex)) {                                        continue nextException;                } else if (ex.isAssignableFrom(ex2)) {                                        uniqueList.remove(j);                } else {                    j++;        // else continue comparing.                }            }            // This exception is unique (so far): add it to the list to catch.            uniqueList.add(ex);        }        return uniqueList;    }                private byte[] generateClassFile() {                        addProxyMethod(hashCodeMethod, Object.class);        addProxyMethod(equalsMethod, Object.class);        addProxyMethod(toStringMethod, Object.class);                for (Class<?> intf : interfaces) {            for (Method m : intf.getMethods()) {                if (!Modifier.isStatic(m.getModifiers())) {                    addProxyMethod(m, intf);                }            }        }                for (List<ProxyMethod> sigmethods : proxyMethods.values()) {            checkReturnTypes(sigmethods);        }                try {            methods.add(generateConstructor());            for (List<ProxyMethod> sigmethods : proxyMethods.values()) {                for (ProxyMethod pm : sigmethods) {                    // add static field for method's Method object                    fields.add(new FieldInfo(pm.methodFieldName,"Ljava/lang/reflect/Method;",ACC_PRIVATE | ACC_STATIC));                    // generate code for proxy method and add it                    methods.add(pm.generateMethod());                }            }            methods.add(generateStaticInitializer());        } catch (IOException e) {            throw new InternalError("unexpected I/O Exception", e);        }        if (methods.size() > 65535) {            throw new IllegalArgumentException("method limit exceeded");        }        if (fields.size() > 65535) {            throw new IllegalArgumentException("field limit exceeded");        }                        cp.getClass(dotToSlash(className));        cp.getClass(superclassName);        for (Class<?> intf : interfaces) {            cp.getClass(dotToSlash(intf.getName()));        }                cp.setReadOnly();        ByteArrayOutputStream bout = new ByteArrayOutputStream();        DataOutputStream dout = new DataOutputStream(bout);        try {                        // u4 magic;            dout.writeInt(0xCAFEBABE);            // u2 minor_version;            dout.writeShort(CLASSFILE_MINOR_VERSION);            // u2 major_version;            dout.writeShort(CLASSFILE_MAJOR_VERSION);            cp.write(dout);             // (write constant pool)            // u2 access_flags;            dout.writeShort(accessFlags);            // u2 this_class;            dout.writeShort(cp.getClass(dotToSlash(className)));            // u2 super_class;            dout.writeShort(cp.getClass(superclassName));            // u2 interfaces_count;            dout.writeShort(interfaces.length);            // u2 interfaces[interfaces_count];            for (Class<?> intf : interfaces) {                dout.writeShort(cp.getClass(                        dotToSlash(intf.getName())));            }            // u2 fields_count;            dout.writeShort(fields.size());            // field_info fields[fields_count];            for (FieldInfo f : fields) {                f.write(dout);            }            // u2 methods_count;            dout.writeShort(methods.size());            // method_info methods[methods_count];            for (MethodInfo m : methods) {                m.write(dout);            }            // u2 attributes_count;            dout.writeShort(0); // (no ClassFile attributes for proxy classes)        } catch (IOException e) {            throw new InternalError("unexpected I/O Exception", e);        }        return bout.toByteArray();    }        private void addProxyMethod(Method m, Class<?> fromClass) {        String name = m.getName();        Class<?>[] parameterTypes = m.getParameterTypes();        Class<?> returnType = m.getReturnType();        Class<?>[] exceptionTypes = m.getExceptionTypes();        String sig = name + getParameterDescriptors(parameterTypes);        List<ProxyMethod> sigmethods = proxyMethods.get(sig);        if (sigmethods != null) {            for (ProxyMethod pm : sigmethods) {                if (returnType == pm.returnType) {                                        List<Class<?>> legalExceptions = new ArrayList<>();                    collectCompatibleTypes(exceptionTypes, pm.exceptionTypes, legalExceptions);                    collectCompatibleTypes(pm.exceptionTypes, exceptionTypes, legalExceptions);                    pm.exceptionTypes = new Class<?>[legalExceptions.size()];                    pm.exceptionTypes =legalExceptions.toArray(pm.exceptionTypes);                    return;                }            }        } else {            sigmethods = new ArrayList<>(3);            proxyMethods.put(sig, sigmethods);        }        sigmethods.add(new ProxyMethod(name, parameterTypes, returnType,                exceptionTypes, fromClass));    }        private MethodInfo generateConstructor() throws IOException {        MethodInfo minfo = new MethodInfo(                "", "(Ljava/lang/reflect/InvocationHandler;)V",                ACC_PUBLIC);        DataOutputStream out = new DataOutputStream(minfo.code);        code_aload(0, out);        code_aload(1, out);        out.writeByte(opc_invokespecial);        out.writeShort(cp.getMethodRef(                superclassName,                "", "(Ljava/lang/reflect/InvocationHandler;)V"));        out.writeByte(opc_return);        minfo.maxStack = 10;        minfo.maxLocals = 2;        minfo.declaredExceptions = new short[0];        return minfo;    }        private MethodInfo generateStaticInitializer() throws IOException {        MethodInfo minfo = new MethodInfo(                "", "()V", ACC_STATIC);        int localSlot0 = 1;        short pc, tryBegin = 0, tryEnd;        DataOutputStream out = new DataOutputStream(minfo.code);        for (List<ProxyMethod> sigmethods : proxyMethods.values()) {            for (ProxyMethod pm : sigmethods) {                pm.codeFieldInitialization(out);            }        }        out.writeByte(opc_return);        tryEnd = pc = (short) minfo.code.size();        minfo.exceptionTable.add(new ExceptionTableEntry(                tryBegin, tryEnd, pc,                cp.getClass("java/lang/NoSuchMethodException")));        code_astore(localSlot0, out);        out.writeByte(opc_new);        out.writeShort(cp.getClass("java/lang/NoSuchMethodError"));        out.writeByte(opc_dup);        code_aload(localSlot0, out);        out.writeByte(opc_invokevirtual);        out.writeShort(cp.getMethodRef(                "java/lang/Throwable", "getMessage", "()Ljava/lang/String;"));        out.writeByte(opc_invokespecial);        out.writeShort(cp.getMethodRef(                "java/lang/NoSuchMethodError", "", "(Ljava/lang/String;)V"));        out.writeByte(opc_athrow);        pc = (short) minfo.code.size();        minfo.exceptionTable.add(new ExceptionTableEntry(                tryBegin, tryEnd, pc,                cp.getClass("java/lang/ClassNotFoundException")));        code_astore(localSlot0, out);        out.writeByte(opc_new);        out.writeShort(cp.getClass("java/lang/NoClassDefFoundError"));        out.writeByte(opc_dup);        code_aload(localSlot0, out);        out.writeByte(opc_invokevirtual);        out.writeShort(cp.getMethodRef(                "java/lang/Throwable", "getMessage", "()Ljava/lang/String;"));        out.writeByte(opc_invokespecial);        out.writeShort(cp.getMethodRef(                "java/lang/NoClassDefFoundError",                "", "(Ljava/lang/String;)V"));        out.writeByte(opc_athrow);        if (minfo.code.size() > 65535) {            throw new IllegalArgumentException("code size limit exceeded");        }        minfo.maxStack = 10;        minfo.maxLocals = (short) (localSlot0 + 1);        minfo.declaredExceptions = new short[0];        return minfo;    }    private void code_iload(int lvar, DataOutputStream out)            throws IOException {        codeLocalLoadStore(lvar, opc_iload, opc_iload_0, out);    }//  private void code_istore(int lvar, DataOutputStream out)//      throws IOException//  {//      codeLocalLoadStore(lvar, opc_istore, opc_istore_0, out);//  }//  private void code_lstore(int lvar, DataOutputStream out)//      throws IOException//  {//      codeLocalLoadStore(lvar, opc_lstore, opc_lstore_0, out);//  }//  private void code_fstore(int lvar, DataOutputStream out)//      throws IOException//  {//      codeLocalLoadStore(lvar, opc_fstore, opc_fstore_0, out);//  }//  private void code_dstore(int lvar, DataOutputStream out)//      throws IOException//  {//      codeLocalLoadStore(lvar, opc_dstore, opc_dstore_0, out);//  }    private void code_lload(int lvar, DataOutputStream out)            throws IOException {        codeLocalLoadStore(lvar, opc_lload, opc_lload_0, out);    }    private void code_fload(int lvar, DataOutputStream out)            throws IOException {        codeLocalLoadStore(lvar, opc_fload, opc_fload_0, out);    }    private void code_dload(int lvar, DataOutputStream out)            throws IOException {        codeLocalLoadStore(lvar, opc_dload, opc_dload_0, out);    }    private void code_aload(int lvar, DataOutputStream out)            throws IOException {        codeLocalLoadStore(lvar, opc_aload, opc_aload_0, out);    }    private void code_astore(int lvar, DataOutputStream out)            throws IOException {        codeLocalLoadStore(lvar, opc_astore, opc_astore_0, out);    }            private void codeLocalLoadStore(int lvar, int opcode, int opcode_0,        DataOutputStream out)            throws IOException {        assert lvar >= 0 && lvar <= 0xFFFF;        if (lvar <= 3) {            out.writeByte(opcode_0 + lvar);        } else if (lvar <= 0xFF) {            out.writeByte(opcode);            out.writeByte(lvar & 0xFF);        } else {                        out.writeByte(opc_wide);            out.writeByte(opcode);            out.writeShort(lvar & 0xFFFF);        }    }        private void code_ldc(int index, DataOutputStream out)            throws IOException {        assert index >= 0 && index <= 0xFFFF;        if (index <= 0xFF) {            out.writeByte(opc_ldc);            out.writeByte(index & 0xFF);        } else {            out.writeByte(opc_ldc_w);            out.writeShort(index & 0xFFFF);        }    }        private void code_ipush(int value, DataOutputStream out)            throws IOException {        if (value >= -1 && value <= 5) {            out.writeByte(opc_iconst_0 + value);        } else if (value >= Byte.MIN_VALUE && value <= Byte.MAX_VALUE) {            out.writeByte(opc_bipush);            out.writeByte(value & 0xFF);        } else if (value >= Short.MIN_VALUE && value <= Short.MAX_VALUE) {            out.writeByte(opc_sipush);            out.writeShort(value & 0xFFFF);        } else {            throw new AssertionError();        }    }        private void codeClassForName(Class<?> cl, DataOutputStream out)            throws IOException {        code_ldc(cp.getString(cl.getName()), out);        out.writeByte(opc_invokestatic);        out.writeShort(cp.getMethodRef(                "java/lang/Class",                "forName", "(Ljava/lang/String;)Ljava/lang/Class;"));    }        private static class ExceptionTableEntry {        public short startPc;        public short endPc;        public short handlerPc;        public short catchType;        public ExceptionTableEntry(short startPc, short endPc,       short handlerPc, short catchType) {            this.startPc = startPc;            this.endPc = endPc;            this.handlerPc = handlerPc;            this.catchType = catchType;        }    }        private static class PrimitiveTypeInfo {        private static final Map<Class<?>, PrimitiveTypeInfo> table = new HashMap<>();        static {            add(byte.class, Byte.class);            add(char.class, Character.class);            add(double.class, Double.class);            add(float.class, Float.class);            add(int.class, Integer.class);            add(long.class, Long.class);            add(short.class, Short.class);            add(boolean.class, Boolean.class);        }                public String baseTypeString;                public String wrapperClassName;                public String wrapperValueOfDesc;                public String unwrapMethodName;                public String unwrapMethodDesc;        private PrimitiveTypeInfo(Class<?> primitiveClass, Class<?> wrapperClass) {            assert primitiveClass.isPrimitive();            baseTypeString =                    Array.newInstance(primitiveClass, 0).getClass().getName().substring(1);            wrapperClassName = dotToSlash(wrapperClass.getName());            wrapperValueOfDesc =                    "(" + baseTypeString + ")L" + wrapperClassName + ";";            unwrapMethodName = primitiveClass.getName() + "Value";            unwrapMethodDesc = "()" + baseTypeString;        }        private static void add(Class<?> primitiveClass, Class<?> wrapperClass) {            table.put(primitiveClass,                    new PrimitiveTypeInfo(primitiveClass, wrapperClass));        }        public static PrimitiveTypeInfo get(Class<?> cl) {            return table.get(cl);        }    }        private static class ConstantPool {                private final List<ConstantPool.Entry> pool = new ArrayList<>(32);                private final Map<Object, Integer> map = new HashMap<>(16);                private boolean readOnly = false;                public short getUtf8(String s) {            if (s == null) {                throw new NullPointerException();            }            return getValue(s);        }                public short getInteger(int i) {            return getValue(i);        }                public short getFloat(float f) {            return getValue(f);        }                public short getClass(String name) {            short utf8Index = getUtf8(name);            return getIndirect(new ConstantPool.IndirectEntry(                    CONSTANT_CLASS, utf8Index));        }                public short getString(String s) {            short utf8Index = getUtf8(s);            return getIndirect(new ConstantPool.IndirectEntry(                    CONSTANT_STRING, utf8Index));        }                public short getFieldRef(String className,     String name, String descriptor) {            short classIndex = getClass(className);            short nameAndTypeIndex = getNameAndType(name, descriptor);            return getIndirect(new ConstantPool.IndirectEntry(                    CONSTANT_FIELD, classIndex, nameAndTypeIndex));        }                public short getMethodRef(String className,      String name, String descriptor) {            short classIndex = getClass(className);            short nameAndTypeIndex = getNameAndType(name, descriptor);            return getIndirect(new ConstantPool.IndirectEntry(                    CONSTANT_METHOD, classIndex, nameAndTypeIndex));        }                public short getInterfaceMethodRef(String className, String name,               String descriptor) {            short classIndex = getClass(className);            short nameAndTypeIndex = getNameAndType(name, descriptor);            return getIndirect(new ConstantPool.IndirectEntry(                    CONSTANT_INTERFACEMETHOD, classIndex, nameAndTypeIndex));        }                public short getNameAndType(String name, String descriptor) {            short nameIndex = getUtf8(name);            short descriptorIndex = getUtf8(descriptor);            return getIndirect(new ConstantPool.IndirectEntry(                    CONSTANT_NAMEANDTYPE, nameIndex, descriptorIndex));        }                public void setReadOnly() {            readOnly = true;        }                public void write(OutputStream out) throws IOException {            DataOutputStream dataOut = new DataOutputStream(out);            // constant_pool_count: number of entries plus one            dataOut.writeShort(pool.size() + 1);            for (ConstantPool.Entry e : pool) {                e.write(dataOut);            }        }                private short addEntry(ConstantPool.Entry entry) {            pool.add(entry);                        if (pool.size() >= 65535) {                throw new IllegalArgumentException(                        "constant pool size limit exceeded");            }            return (short) pool.size();        }                private short getValue(Object key) {            Integer index = map.get(key);            if (index != null) {                return index.shortValue();            } else {                if (readOnly) {                    throw new InternalError("late constant pool addition: " + key);                }                short i = addEntry(new ConstantPool.ValueEntry(key));                map.put(key, (int) i);                return i;            }        }                private short getIndirect(ConstantPool.IndirectEntry e) {            Integer index = map.get(e);            if (index != null) {                return index.shortValue();            } else {                if (readOnly) {                    throw new InternalError("late constant pool addition");                }                short i = addEntry(e);                map.put(e, (int) i);                return i;            }        }                private abstract static class Entry {            public abstract void write(DataOutputStream out)                    throws IOException;        }                private static class ValueEntry extends ConstantPool.Entry {            private final Object value;            public ValueEntry(Object value) {                this.value = value;            }            public void write(DataOutputStream out) throws IOException {                if (value instanceof String) {                    out.writeByte(CONSTANT_UTF8);                    out.writeUTF((String) value);                } else if (value instanceof Integer) {                    out.writeByte(CONSTANT_INTEGER);                    out.writeInt(((Integer) value).intValue());                } else if (value instanceof Float) {                    out.writeByte(CONSTANT_FLOAT);                    out.writeFloat(((Float) value).floatValue());                } else if (value instanceof Long) {                    out.writeByte(CONSTANT_LONG);                    out.writeLong(((Long) value).longValue());                } else if (value instanceof Double) {                    out.writeDouble(CONSTANT_DOUBLE);                    out.writeDouble(((Double) value).doubleValue());                } else {                    throw new InternalError("bogus value entry: " + value);                }            }        }                private static class IndirectEntry extends ConstantPool.Entry {            private final int tag;            private final short index0;            private final short index1;                        public IndirectEntry(int tag, short index) {                this.tag = tag;                this.index0 = index;                this.index1 = 0;            }                        public IndirectEntry(int tag, short index0, short index1) {                this.tag = tag;                this.index0 = index0;                this.index1 = index1;            }            public void write(DataOutputStream out) throws IOException {                out.writeByte(tag);                out.writeShort(index0);                                if (tag == CONSTANT_FIELD ||                        tag == CONSTANT_METHOD ||                        tag == CONSTANT_INTERFACEMETHOD ||                        tag == CONSTANT_NAMEANDTYPE) {                    out.writeShort(index1);                }            }            public int hashCode() {                return tag + index0 + index1;            }            public boolean equals(Object obj) {                if (obj instanceof ConstantPool.IndirectEntry) {                    ConstantPool.IndirectEntry other = (ConstantPool.IndirectEntry) obj;                    return tag == other.tag &&index0 == other.index0 && index1 == other.index1;                }                return false;            }        }    }        private class FieldInfo {        public int accessFlags;        public String name;        public String descriptor;        public FieldInfo(String name, String descriptor, int accessFlags) {            this.name = name;            this.descriptor = descriptor;            this.accessFlags = accessFlags;                        cp.getUtf8(name);            cp.getUtf8(descriptor);        }        public void write(DataOutputStream out) throws IOException {                        // u2 access_flags;            out.writeShort(accessFlags);            // u2 name_index;            out.writeShort(cp.getUtf8(name));            // u2 descriptor_index;            out.writeShort(cp.getUtf8(descriptor));            // u2 attributes_count;            out.writeShort(0);  // (no field_info attributes for proxy classes)        }    }        private class MethodInfo {        public int accessFlags;        public String name;        public String descriptor;        public short maxStack;        public short maxLocals;        public ByteArrayOutputStream code = new ByteArrayOutputStream();        public List<ExceptionTableEntry> exceptionTable = new ArrayList<ExceptionTableEntry>();        public short[] declaredExceptions;        public MethodInfo(String name, String descriptor, int accessFlags) {            this.name = name;            this.descriptor = descriptor;            this.accessFlags = accessFlags;                        cp.getUtf8(name);            cp.getUtf8(descriptor);            cp.getUtf8("Code");            cp.getUtf8("Exceptions");        }        public void write(DataOutputStream out) throws IOException {                        // u2 access_flags;            out.writeShort(accessFlags);            // u2 name_index;            out.writeShort(cp.getUtf8(name));            // u2 descriptor_index;            out.writeShort(cp.getUtf8(descriptor));            // u2 attributes_count;            out.writeShort(2);  // (two method_info attributes:)            // Write "Code" attribute. See JVMS section 4.7.3.            // u2 attribute_name_index;            out.writeShort(cp.getUtf8("Code"));            // u4 attribute_length;            out.writeInt(12 + code.size() + 8 * exceptionTable.size());            // u2 max_stack;            out.writeShort(maxStack);            // u2 max_locals;            out.writeShort(maxLocals);            // u2 code_length;            out.writeInt(code.size());            // u1 code[code_length];            code.writeTo(out);            // u2 exception_table_length;            out.writeShort(exceptionTable.size());            for (ExceptionTableEntry e : exceptionTable) {                // u2 start_pc;                out.writeShort(e.startPc);                // u2 end_pc;                out.writeShort(e.endPc);                // u2 handler_pc;                out.writeShort(e.handlerPc);                // u2 catch_type;                out.writeShort(e.catchType);            }            // u2 attributes_count;            out.writeShort(0);            // write "Exceptions" attribute.  See JVMS section 4.7.4.            // u2 attribute_name_index;            out.writeShort(cp.getUtf8("Exceptions"));            // u4 attributes_length;            out.writeInt(2 + 2 * declaredExceptions.length);            // u2 number_of_exceptions;            out.writeShort(declaredExceptions.length);            // u2 exception_index_table[number_of_exceptions];            for (short value : declaredExceptions) {                out.writeShort(value);            }        }    }        private class ProxyMethod {        public String methodName;        public Class<?>[] parameterTypes;        public Class<?> returnType;        public Class<?>[] exceptionTypes;        public Class<?> fromClass;        public String methodFieldName;        private ProxyMethod(String methodName, Class<?>[] parameterTypes,Class<?> returnType, Class<?>[] exceptionTypes,Class<?> fromClass) {            this.methodName = methodName;            this.parameterTypes = parameterTypes;            this.returnType = returnType;            this.exceptionTypes = exceptionTypes;            this.fromClass = fromClass;            this.methodFieldName = "m" + proxyMethodCount++;        }                private MethodInfo generateMethod() throws IOException {            String desc = getMethodDescriptor(parameterTypes, returnType);            MethodInfo minfo = new MethodInfo(methodName, desc,                    ACC_PUBLIC | ACC_FINAL);            int[] parameterSlot = new int[parameterTypes.length];            int nextSlot = 1;            for (int i = 0; i < parameterSlot.length; i++) {                parameterSlot[i] = nextSlot;                nextSlot += getWordsPerType(parameterTypes[i]);            }            int localSlot0 = nextSlot;            short pc, tryBegin = 0, tryEnd;            DataOutputStream out = new DataOutputStream(minfo.code);            code_aload(0, out);            out.writeByte(opc_getfield);            out.writeShort(cp.getFieldRef(                    superclassName,                    handlerFieldName, "Ljava/lang/reflect/InvocationHandler;"));            code_aload(0, out);            out.writeByte(opc_getstatic);            out.writeShort(cp.getFieldRef(                    dotToSlash(className),                    methodFieldName, "Ljava/lang/reflect/Method;"));            if (parameterTypes.length > 0) {                code_ipush(parameterTypes.length, out);                out.writeByte(opc_anewarray);                out.writeShort(cp.getClass("java/lang/Object"));                for (int i = 0; i < parameterTypes.length; i++) {                    out.writeByte(opc_dup);                    code_ipush(i, out);                    codeWrapArgument(parameterTypes[i], parameterSlot[i], out);                    out.writeByte(opc_aastore);                }            } else {                out.writeByte(opc_aconst_null);            }            out.writeByte(opc_invokeinterface);            out.writeShort(cp.getInterfaceMethodRef(                    "java/lang/reflect/InvocationHandler",                    "invoke",                    "(Ljava/lang/Object;Ljava/lang/reflect/Method;" +"[Ljava/lang/Object;)Ljava/lang/Object;"));            out.writeByte(4);            out.writeByte(0);            if (returnType == void.class) {                out.writeByte(opc_pop);                out.writeByte(opc_return);            } else {                codeUnwrapReturnValue(returnType, out);            }            tryEnd = pc = (short) minfo.code.size();            List<Class<?>> catchList = computeUniqueCatchList(exceptionTypes);            if (catchList.size() > 0) {                for (Class<?> ex : catchList) {                    minfo.exceptionTable.add(new ExceptionTableEntry(tryBegin, tryEnd, pc,cp.getClass(dotToSlash(ex.getName()))));                }                out.writeByte(opc_athrow);                pc = (short) minfo.code.size();                minfo.exceptionTable.add(new ExceptionTableEntry(                        tryBegin, tryEnd, pc, cp.getClass("java/lang/Throwable")));                code_astore(localSlot0, out);                out.writeByte(opc_new);                out.writeShort(cp.getClass(                        "java/lang/reflect/UndeclaredThrowableException"));                out.writeByte(opc_dup);                code_aload(localSlot0, out);                out.writeByte(opc_invokespecial);                out.writeShort(cp.getMethodRef(                        "java/lang/reflect/UndeclaredThrowableException",                        "", "(Ljava/lang/Throwable;)V"));                out.writeByte(opc_athrow);            }            if (minfo.code.size() > 65535) {                throw new IllegalArgumentException("code size limit exceeded");            }            minfo.maxStack = 10;            minfo.maxLocals = (short) (localSlot0 + 1);            minfo.declaredExceptions = new short[exceptionTypes.length];            for (int i = 0; i < exceptionTypes.length; i++) {                minfo.declaredExceptions[i] = cp.getClass(                        dotToSlash(exceptionTypes[i].getName()));            }            return minfo;        }                private void codeWrapArgument(Class<?> type, int slot,          DataOutputStream out)                throws IOException {            if (type.isPrimitive()) {                PrimitiveTypeInfo prim = PrimitiveTypeInfo.get(type);                if (type == int.class ||                        type == boolean.class ||                        type == byte.class ||                        type == char.class ||                        type == short.class) {                    code_iload(slot, out);                } else if (type == long.class) {                    code_lload(slot, out);                } else if (type == float.class) {                    code_fload(slot, out);                } else if (type == double.class) {                    code_dload(slot, out);                } else {                    throw new AssertionError();                }                out.writeByte(opc_invokestatic);                out.writeShort(cp.getMethodRef(                        prim.wrapperClassName,                        "valueOf", prim.wrapperValueOfDesc));            } else {                code_aload(slot, out);            }        }                private void codeUnwrapReturnValue(Class<?> type, DataOutputStream out)                throws IOException {            if (type.isPrimitive()) {                PrimitiveTypeInfo prim = PrimitiveTypeInfo.get(type);                out.writeByte(opc_checkcast);                out.writeShort(cp.getClass(prim.wrapperClassName));                out.writeByte(opc_invokevirtual);                out.writeShort(cp.getMethodRef(                        prim.wrapperClassName,                        prim.unwrapMethodName, prim.unwrapMethodDesc));                if (type == int.class ||                        type == boolean.class ||                        type == byte.class ||                        type == char.class ||                        type == short.class) {                    out.writeByte(opc_ireturn);                } else if (type == long.class) {                    out.writeByte(opc_lreturn);                } else if (type == float.class) {                    out.writeByte(opc_freturn);                } else if (type == double.class) {                    out.writeByte(opc_dreturn);                } else {                    throw new AssertionError();                }            } else {                out.writeByte(opc_checkcast);                out.writeShort(cp.getClass(dotToSlash(type.getName())));                out.writeByte(opc_areturn);            }        }                private void codeFieldInitialization(DataOutputStream out)                throws IOException {            codeClassForName(fromClass, out);            code_ldc(cp.getString(methodName), out);            code_ipush(parameterTypes.length, out);            out.writeByte(opc_anewarray);            out.writeShort(cp.getClass("java/lang/Class"));            for (int i = 0; i < parameterTypes.length; i++) {                out.writeByte(opc_dup);                code_ipush(i, out);                if (parameterTypes[i].isPrimitive()) {                    PrimitiveTypeInfo prim =PrimitiveTypeInfo.get(parameterTypes[i]);                    out.writeByte(opc_getstatic);                    out.writeShort(cp.getFieldRef(prim.wrapperClassName, "TYPE", "Ljava/lang/Class;"));                } else {                    codeClassForName(parameterTypes[i], out);                }                out.writeByte(opc_aastore);            }            out.writeByte(opc_invokevirtual);            out.writeShort(cp.getMethodRef(                    "java/lang/Class",                    "getMethod",                    "(Ljava/lang/String;[Ljava/lang/Class;)" +"Ljava/lang/reflect/Method;"));            out.writeByte(opc_putstatic);            out.writeShort(cp.getFieldRef(                    dotToSlash(className),                    methodFieldName, "Ljava/lang/reflect/Method;"));        }    }}

生成的字节码

//// Source code recreated from a .class file by IntelliJ IDEA// (powered by FernFlower decompiler)//import A002动态代理.IPerson;import java.lang.reflect.InvocationHandler;import java.lang.reflect.Method;import java.lang.reflect.Proxy;import java.lang.reflect.UndeclaredThrowableException;public final class RProxy0 extends Proxy implements IPerson {    private static Method m1;    private static Method m3;    private static Method m2;    private static Method m0;//protected Proxy(InvocationHandler h) {    //    Objects.requireNonNull(h);    //    this.h = h;    //}    public RProxy0(InvocationHandler var1) throws  {        super(var1);    }    public final boolean equals(Object var1) throws  {        try {            return (Boolean)super.h.invoke(this, m1, new Object[]{var1});        } catch (RuntimeException | Error var3) {            throw var3;        } catch (Throwable var4) {            throw new UndeclaredThrowableException(var4);        }    }    public final String stduy(String var1) throws  {        try {            return (String)super.h.invoke(this, m3, new Object[]{var1});        } catch (RuntimeException | Error var3) {            throw var3;        } catch (Throwable var4) {            throw new UndeclaredThrowableException(var4);        }    }    public final String toString() throws  {        try {            return (String)super.h.invoke(this, m2, (Object[])null);        } catch (RuntimeException | Error var2) {            throw var2;        } catch (Throwable var3) {            throw new UndeclaredThrowableException(var3);        }    }    public final int hashCode() throws  {        try {            return (Integer)super.h.invoke(this, m0, (Object[])null);        } catch (RuntimeException | Error var2) {            throw var2;        } catch (Throwable var3) {            throw new UndeclaredThrowableException(var3);        }    }    static {        try {            m1 = Class.forName("java.lang.Object").getMethod("equals", Class.forName("java.lang.Object"));            m3 = Class.forName("A002动态代理.IPerson").getMethod("stduy", Class.forName("java.lang.String"));            m2 = Class.forName("java.lang.Object").getMethod("toString");            m0 = Class.forName("java.lang.Object").getMethod("hashCode");        } catch (NoSuchMethodException var2) {            throw new NoSuchMethodError(var2.getMessage());        } catch (ClassNotFoundException var3) {            throw new NoClassDefFoundError(var3.getMessage());        }    }}

jdk动态代理&cglb动态代理到底生成了啥(一)
动态代理类
动态代理
JAVA创建一个私有域_【package-private】包私有类的食用姿势

来源地址:https://blog.csdn.net/AdrianAndroid/article/details/132580269

阅读原文内容投诉

免责声明:

① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。

② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341

软考中级精品资料免费领

  • 历年真题答案解析
  • 备考技巧名师总结
  • 高频考点精准押题
  • 2024年上半年信息系统项目管理师第二批次真题及答案解析(完整版)

    难度     813人已做
    查看
  • 【考后总结】2024年5月26日信息系统项目管理师第2批次考情分析

    难度     354人已做
    查看
  • 【考后总结】2024年5月25日信息系统项目管理师第1批次考情分析

    难度     318人已做
    查看
  • 2024年上半年软考高项第一、二批次真题考点汇总(完整版)

    难度     435人已做
    查看
  • 2024年上半年系统架构设计师考试综合知识真题

    难度     224人已做
    查看

相关文章

发现更多好内容

猜你喜欢

AI推送时光机
位置:首页-资讯-人工智能
咦!没有更多了?去看看其它编程学习网 内容吧
首页课程
资料下载
问答资讯