设计模式 Proxy

Java+MySQL宿舍管理系统毕业设计:Eclipse+JDBC完整实现与避坑指南 JDBC是Java连接MySQL数据库的标准API,通过驱动加载、连接建立、PreparedStatement执行SQL实现数据持久化。三层架构将表现层、业务层、数据层分离,提升可维护性。在毕业设计场景中,基于Eclipse和MySQL的Java桌面应用是常见选题,涉及Swing界面、数据库建表、权限管理、增删改查等核心技能。本文围绕学生宿舍管理系统,提供从环境搭建、八张表设计到JDBC连接配置、三层架构拆解的完整方案,并针对驱动版本、中文乱码、外键约束等常见问题给出排查方法,帮助开发者快速构建可运行的Ja 阅读详情

什么是代理

# 增强一个对象的功能
# 买火车票,App 就是一个代理,他代理了火车站,小区当中的代售窗口
# Java 当中如何实现代理

Java 实现的代理的两种办法

代理的名词

代理对象 ===> 增强后的对象
目标对象 ===> 被增强的对象
他们不是绝对的,会根据情况发生变化

静态代理

1、继承
代理对象继承目标对象,重写需要增强的方法;
缺点:会代理类过多,非常复杂
​
2、聚合
目标对象和代理对象实现同一个接口,代理对象当中要包含目标对象。
缺点:也会产生类爆炸,只不过比继承少一点点
​
# 总结:如果在不确定的情况下,尽量不要去使用静态代理。因为一旦你写代码,就会产生类,一旦产生类就爆炸。

动态代理

自己模拟 JDK 动态代理

# 不需要订阅专栏手动创建类文件(因为一旦手动创建类文件,就会产生类爆炸),通过接口反射生成一个类文件,然后调用第三方的编译技术,动态编译这个产生的类文件成class文件,继而利用UrlclassLoader(因为这个动态产生的class不在工程当中所以需要使用UrlclassLoader)把这个动态编译的类加载到jvm当中,最后通过反射把这个类实例化。
​
缺点:首先要生成文件
缺点:动态编译class文件
缺点:需要一个 URLclassloader
软件性能的最终体现在 IO 操作

接口:FutureDao

/**
 * @description: 接口
 * @author: Mr.Li
 * @date: Created in 2020/7/1 15:42
 * @version: 1.0
 * @modified By:
 */
public interface FutureDao {
​
    public void query();
    
    public String returnString();
}

实现类:FutureDaoImpl

/**
 * @description: 实现类
 * @author: Mr.Li
 * @date: Created in 2020/7/1 15:43
 * @version: 1.0
 * @modified By:
 */
public class FutureDaoImpl implements FutureDao {
​
    @Override
    public void query(){
        System.out.println("FutureLL");
​
    }
    
    @Override
    public String returnString() {
        return "Return String";
    }
}

自己实现动态代理:ProxyUtil

import javax.tools.JavaCompiler;
import javax.tools.StandardJavaFileManager;
import javax.tools.ToolProvider;
import java.io.File;
import java.io.FileWriter;
import java.lang.reflect.Constructor;
import java.lang.reflect.Method;
import java.net.URL;
import java.net.URLClassLoader;
​
/**
 * @description: 自己实现动态代理
 * @author: Mr.Li
 * @date: Created in 2020/7/1 13:19
 * @version: 1.0
 * @modified By:
 */
public class ProxyUtil {
​
    /**
     * content --->string
     * .java  io
     * .class
     * <p>
     * .new   反射----》class
     *
     * @return
     */
    public static Object newInstance(Object target) {
​
        // 定义代理对象
        Object proxy = null;
        // getClass(): Returns the runtime class of this {@code Object}.
        // getInterfaces(): Determines the interfaces implemented by the class or interface represented by this object.
        Class targetInf = target.getClass().getInterfaces()[0];
        Method methods[] = targetInf.getDeclaredMethods();
        String line = "\n";
        String tab = "\t";
        // getSimpleName(): Returns the simple name of the underlying class as given in the source code.
        // infName = "FutureDao";
        String infName = targetInf.getSimpleName();
        String content = "";
        String packageContent = "package com.google;" + line;
        // Returns the name of the entity represented by this {@code Class} object, as a {@code String}.
        // targetInf.getName() = "com.futurell.dao.FutureDao"
        String importContent = "import " + targetInf.getName() + ";" + line;
        String clazzFirstLineContent = "public class $Proxy implements " + infName + "{" + line;
        String filedContent = tab + "private " + infName + " target;" + line;
        String constructorContent = tab + "public $Proxy (" + infName + " target){" + line
                + tab + tab + "this.target = target;"
                + line + tab + "}" + line;
        String methodContent = "";
        for (Method method : methods) {
            // getReturnType(): Returns a Class object that represents the formal return type of the method represented by this {@code Method} object.
            String returnTypeName = method.getReturnType().getSimpleName();
            // getName(): Returns the name of the method represented by this {@code Method} object, as a {@code String}.
            String methodName = method.getName();
            // Sting.class String.class
            Class args[] = method.getParameterTypes();
            String argsContent = "";
            String paramsContent = "";
            int flag = 0;
            for (Class arg : args) {
                //getSimpleName(): Returns the simple name of the underlying class as given in the source code.
                String temp = arg.getSimpleName();
                // String
                // String p0,Sting p1,
                argsContent += temp + " p" + flag + ",";
                paramsContent += "p" + flag + ",";
                flag ++;
            }
            if (argsContent.length() > 0) {
                // lastIndexOf(): Returns the index within this string of the last occurrence of the specified substring.
                argsContent = argsContent.substring(0, argsContent.lastIndexOf(",") - 1);
                paramsContent = paramsContent.substring(0, paramsContent.lastIndexOf(",") - 1);
            }
​
            methodContent += tab + "public " + returnTypeName + " " + methodName + "(" + argsContent + ") {" + line
                    + tab + tab + "System.out.println(\" Log \");" + line;
​
            if (returnTypeName.equals("void")) {
                methodContent += tab + tab + "target." + methodName + "(" + paramsContent + ");" + line
                        + tab + "}" + line;
            } else {
                methodContent += tab + tab + "return target." + methodName + "(" + paramsContent + ");" + line
                        + tab + "}" + line;
            }
        }
​
        content = packageContent + importContent + clazzFirstLineContent + filedContent + constructorContent + methodContent + "}";
​
        File file = new File("e:\\com\\google\\$Proxy.java");
        try {
            if (!file.exists()) {
                file.createNewFile();
            }
​
            FileWriter fw = new FileWriter(file);
            fw.write(content);
            fw.flush();
            fw.close();
​
            /**
             * 编译过程如下:
             */
            // getSystemJavaCompiler(): Gets the Java; programming language compiler provided with this platform.
            // 得到编译类,可以动态的编译一些文件
            JavaCompiler compiler = ToolProvider.getSystemJavaCompiler();
​
            // getStandardFileManager(): Gets a new instance of the standard file manager implementation for this tool.
            // 编译文件需要文件管理器
            StandardJavaFileManager fileMgr = compiler.getStandardFileManager(null, null, null);
            // getJavaFileObjects(): Gets file objects representing the given files.
            // 把文件放到文件管理器中
            Iterable units = fileMgr.getJavaFileObjects(file);
​
            // getTask(): Creates a future for a compilation task with the given components and arguments.
            // JavaCompiler.CompilationTask: Interface representing a future for a compilation task.
            // 把文件管理器当成一个任务来执行
            JavaCompiler.CompilationTask t = compiler.getTask(null, fileMgr, null, null, null, units);
            // call(): Performs this compilation task.
            t.call();
            fileMgr.close();
​
            // URL[]: Class {@code URL} represents a Uniform Resource Locator, a pointer to a "resource" on the World Wide Web.
            URL[] urls = new URL[]{new URL("file:E:\\\\")};
            // URLClassLoader: This class loader(类加载器) is used to load classes and resources from a search path of URLs
            //                 referring(引用) to both JAR files(Java Archive, Java归档) and directories(目录).
            // JAR: 通常用于聚合大量的Java类文件、相关的元数据和资源(文本、图片等)文件到一个文件,以便开发Java平台应用软件或库。
            URLClassLoader urlClassLoader = new URLClassLoader(urls);
            // loadClass(): Loads the class with the specified <a href="#name">binary name</a>.
            Class clazz = urlClassLoader.loadClass("com.google.$Proxy");
            // getConstructor(): Returns a {@code Constructor} object that reflects(反应) the specified
            //                   public constructor of the class represented by this {@code Class} object.
            // clazz这个类它有构造方法,只能以构造方法来new这个类的实例,所以需要先得到该类的构造方法
            Constructor constructor = clazz.getConstructor(targetInf);
​
            // newInstance(): Uses the constructor represented by this {@code Constructor} object to
            //                create and initialize a new instance of the constructor's
            //                declaring class, with the specified initialization parameters.
            // 通过构造方法来创建实例
            proxy = constructor.newInstance(target);
            // clazz.newInstance();
            // Class.forName()
        } catch (Exception e) {
            e.printStackTrace();
        }
​
        /**
         * public UserDaoLog(UserDao target){
         *     this.target = target;
         * }
         */
        return proxy;
    }
}

测试类:Test

import com.futurell.dao.FutureDao;
import com.futurell.dao.FutureDaoImpl;
import com.futurell.proxy.ProxyUtil;
​
/**
 * @description: 测试
 * @author: Mr.Li
 * @date: Created in 2020/7/1 10:56
 * @version: 1.0
 * @modified By:
 */
public class Test {
​
    public static void main(String[] args) {
​
        FutureDao fProxy = (FutureDao) ProxyUtil.newInstance(new FutureDaoImpl());
        fProxy.query();
​
        System.out.println("------------------");
​
        FutureDao fProxyString = (FutureDao) ProxyUtil.newInstance(new FutureDaoImpl());
        System.out.println(fProxyString.returnString());
​
    }
}
/**
 *  输出: 
 * ------------------
 *  Log 
 * FutureLL
 * ------------------
 *  Log 
 * Return String
 */

JDK 动态代理

接口和实现类与上述自定义相同

代理类:FutureInvocationHandler

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
​
/**
 * @description:
 * @author: Mr.Li
 * @date: Created in 2020/7/2 12:24
 * @version: 1.0
 * @modified By:
 */
public class FutureInvocationHandler implements InvocationHandler {
​
    Object target;
​
    public FutureInvocationHandler(Object target) {
        this.target = target;
    }
​
    /**
     *
     * @param proxy 代理对象
     * @param method 代理对象包含目标对象,目标对象中的方法,就是method
     * @param args 目标方法的参数
     * @return
     * @throws Throwable
     */
    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        System.out.println("proxy");
        return method.invoke(target, args);
    }
}

测试类:Test

import com.futurell.JDK.dao.FutureDao;
import com.futurell.JDK.dao.FutureDaoImpl;
import com.futurell.JDK.proxy.FutureInvocationHandler;
​
import java.lang.reflect.Proxy;
​
/**
 * @description: 测试
 * @author: Mr.Li
 * @date: Created in 2020/7/1 10:56
 * @version: 1.0
 * @modified By:
 */
public class Test {
​
    public static void main(String[] args) {
​
        FutureDao jdkProxy = (FutureDao) Proxy.newProxyInstance(
                // getClassLoader(): Returns the class loader for the class.
                // 判断一个类是否相同,需要根据类加载器是否相同来判断,为了保证加载器可用,那么传入当前所在类的ClassLoader
                // 在自定义动态代理的代码中,使用了URLClassLoader,因为自定义的类不在工程当中
                Test.class.getClassLoader(),
                // Class targetInf = target.getClass().getInterfaces()[0];
                // 自定义使用了上边的代码,我们需要得到接口,用来得到接口中的方法,然后对方法进行代理
                new Class[]{FutureDao.class},
                new FutureInvocationHandler(new FutureDaoImpl()));
​
        jdkProxy.query();
        System.out.println("--------------");
        System.out.println(jdkProxy.returnString());
    }
}

CGLIB

如果是要实现 CGLIB,需要先添加 cglib 依赖,然后实现一个接口 MethodInterceptor,重写 intercept() 方法

依赖

<!-- 使用CGLIB代理需要导入jar包 -->
<dependency>
  <groupId>cglib</groupId>
  <artifactId>cglib</artifactId>
  <version>3.3.0</version>
  <scope>compile</scope>
</dependency>

代理类:MyMethodInterceptor

import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy;
 
import java.lang.reflect.Method;
 
/**
 * 自定义MethodInterceptor
 */
public class MyMethodInterceptor implements MethodInterceptor{
 
    /**
     * sub:cglib生成的代理对象
     * method:被代理对象方法
     * objects:方法入参
     * methodProxy: 代理方法
     */
    @Override
    public Object intercept(Object sub, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
        System.out.println("======插入前置通知======");
        Object object = methodProxy.invokeSuper(sub, objects);
        System.out.println("======插入后者通知======");
        return object;
    }
}

JDK 底层原理

测试类:Test

FutureDao jdkProxy = (FutureDao) Proxy.newProxyInstance(
    // getClassLoader(): Returns the class loader for the class.
    // 判断一个类是否相同,需要根据类加载器是否相同来判断,为了保证加载器可用,那么传入当前所在类的ClassLoader
    // 在自定义动态代理的代码中,使用了URLClassLoader,因为自定义的类不在工程当中
    Test.class.getClassLoader(),
    // Class targetInf = target.getClass().getInterfaces()[0];
    // 自定义使用了上边的代码,我们需要得到接口,用来得到接口中的方法,然后对方法进行代理
    new Class[]{FutureDao.class},
    new FutureInvocationHandler(new FutureDaoImpl())
);

测试类调用 Proxy 类的 newProxyInstance() 方法

/**
 * Returns an instance of a proxy class for the specified interfaces
 * that dispatches method invocations to the specified invocation
 * handler.
 */
@CallerSensitive
public static Object newProxyInstance(ClassLoader loader,
                                      Class<?>[] interfaces,
                                      InvocationHandler h) throws IllegalArgumentException {
    
    Objects.requireNonNull(h);
​
    // 拿到实现类的接口,使用接口可以对接口中的方法进行处理
    final Class<?>[] intfs = interfaces.clone();
    // 系统做的安全验证,这个不需要我们去管
    // getSecurityManager(): Gets the system security interface.
    final SecurityManager sm = System.getSecurityManager();
    if (sm != null) {
        checkProxyAccess(Reflection.getCallerClass(), loader, intfs);
    }
​
    /*
     * Look up or generate the designated proxy class.
     * 找到或生成指定的代理类
     */
    Class<?> cl = getProxyClass0(loader, intfs);
​
    /*
     * Invoke its constructor with the designated invocation handler.
     */
    try {
        if (sm != null) {
            checkNewProxyPermission(Reflection.getCallerClass(), cl);
        }
​
        // 通过 cl.getConstructor() 得到一个构造方法
        final Constructor<?> cons = cl.getConstructor(constructorParams);
        final InvocationHandler ih = h;
        if (!Modifier.isPublic(cl.getModifiers())) {
            AccessController.doPrivileged(new PrivilegedAction<Void>() {
                public Void run() {
                    cons.setAccessible(true);
                    return null;
                }
            });
        }
        // 这里将得到的构造方法 new 成一个对象
        // 所以我们需要看这里 new 出来的对象是不是我们需要的代理对象
        // 首先复制 cons.newInstance(new Object[]{h}),鼠标右键点击 Evaluate Expression,将复制的代码粘贴回车,看到 result 的值就是我们的代理对象
        // 得到 cl 代理类,代理对象就轻易被 new 出来了,在我们的传入的是 new FutureInvocationHandler(new FutureDaoImpl())
        // 所以最重要的是我们怎么得到的 cl 代理类,进入 getProxyClass0() 这个方法
        return cons.newInstance(new Object[]{h});
    } catch (IllegalAccessException|InstantiationException e) {
        throw new InternalError(e.toString(), e);
    } catch (InvocationTargetException e) {
        Throwable t = e.getCause();
        if (t instanceof RuntimeException) {
            throw (RuntimeException) t;
        } else {
            throw new InternalError(t.toString(), t);
        }
    } catch (NoSuchMethodException e) {
        throw new InternalError(e.toString(), e);
    }
}

进入 getProxyClass0() 我们要知道如何得到的 cl 代理类

/**
 * Generate a proxy class.  Must call the checkProxyAccess method
 * to perform permission checks before calling this.
 */
private static Class<?> getProxyClass0(ClassLoader loader,
                                       Class<?>... interfaces) {
    if (interfaces.length > 65535) {
        throw new IllegalArgumentException("interface limit exceeded");
    }
​
    // If the proxy class defined by the given loader implementing
    // the given interfaces exists, this will simply return the cached copy;
    // otherwise, it will create the proxy class via the ProxyClassFactory
    // 如果实现给定接口的给定加载器定义的代理类存在,这将简单地返回缓存的副本;否则,它将通过 ProxyClassFactory 创建代理类
    // 这个方法只有一行代码,我们进入 get() 方法
    return proxyClassCache.get(loader, interfaces);
}

进入 get() 方法

/**
 * Look-up the value through the cache. This always evaluates the
 * {@code subKeyFactory} function and optionally evaluates
 * {@code valueFactory} function if there is no entry in the cache for given
 * pair of (key, subKey) or the entry has already been cleared.
 */
public V get(K key, P parameter) {
    Objects.requireNonNull(parameter);
​
    expungeStaleEntries();
​
    Object cacheKey = CacheKey.valueOf(key, refQueue);
​
    // lazily install the 2nd level valuesMap for the particular cacheKey
    ConcurrentMap<Object, Supplier<V>> valuesMap = map.get(cacheKey);
    if (valuesMap == null) {
        ConcurrentMap<Object, Supplier<V>> oldValuesMap
            = map.putIfAbsent(cacheKey,
                              valuesMap = new ConcurrentHashMap<>());
        if (oldValuesMap != null) {
            valuesMap = oldValuesMap;
        }
    }
​
    // create subKey and retrieve the possible Supplier<V> stored by that
    // subKey from valuesMap
    Object subKey = Objects.requireNonNull(subKeyFactory.apply(key, parameter));
    Supplier<V> supplier = valuesMap.get(subKey);
    Factory factory = null;
​
    while (true) {
        if (supplier != null) {
            // supplier might be a Factory or a CacheValue<V> instance
            // 进入这个 get() 方法
            V value = supplier.get();
            if (value != null) {
                // 最终返回的是这个 value,我们不知道从哪里看的时候,就找到结果从下往上反推即可
                // 向上看有一个 supplier.get() 它将返回值赋给了 value
                return value;
            }
        }
        // else no supplier in cache
        // or a supplier that returned null (could be a cleared CacheValue
        // or a Factory that wasn't successful in installing the CacheValue)
​
        // lazily construct a Factory
        if (factory == null) {
            factory = new Factory(key, parameter, subKey, valuesMap);
        }
​
        if (supplier == null) {
            supplier = valuesMap.putIfAbsent(subKey, factory);
            if (supplier == null) {
                // successfully installed Factory
                supplier = factory;
            }
            // else retry with winning supplier
        } else {
            if (valuesMap.replace(subKey, supplier, factory)) {
                // successfully replaced
                // cleared CacheEntry / unsuccessful Factory
                // with our Factory
                supplier = factory;
            } else {
                // retry with current supplier
                supplier = valuesMap.get(subKey);
            }
        }
    }
}

进入另一个 get() 方法

@Override
public synchronized V get() { // serialize access
    // re-check
    Supplier<V> supplier = valuesMap.get(subKey);
    if (supplier != this) {
        // something changed while we were waiting:
        // might be that we were replaced by a CacheValue
        // or were removed because of failure ->
        // return null to signal WeakCache.get() to retry
        // the loop
        return null;
    }
    // else still us (supplier == this)
​
    // create new value
    // 这个方法我们可以看出,结果需要返回 value,而 value 最终的取值是在下边的 try-finally 中取值
    V value = null;
    try {
        // 首先我们进入 apply() 方法
        value = Objects.requireNonNull(valueFactory.apply(key, parameter));
    } finally {
        if (value == null) { // remove us on failure
            valuesMap.remove(subKey, this);
        }
    }
    // the only path to reach here is with non-null value
    assert value != null;
​
    // wrap value with CacheValue (WeakReference)
    CacheValue<V> cacheValue = new CacheValue<>(value);
​
    // put into reverseMap
    reverseMap.put(cacheValue, Boolean.TRUE);
​
    // try replacing us with CacheValue (this should always succeed)
    if (!valuesMap.replace(subKey, this, cacheValue)) {
        throw new AssertionError("Should not reach here");
    }
​
    // successfully replaced us with new CacheValue -> return the value
    // wrapped by it
    // 返回 value
    return value;
}

进入 apply() 方法

@Override
public Class<?> apply(ClassLoader loader, Class<?>[] interfaces) {
​
    Map<Class<?>, Boolean> interfaceSet = new IdentityHashMap<>(interfaces.length);
    // 这里的 interfaces 的所有接口只有一个 FutureDao,循环所有接口,将接口赋给 intf
    for (Class<?> intf : interfaces) {
        /*
         * Verify that the class loader resolves the name of this
         * interface to the same Class object.
         */
        Class<?> interfaceClass = null;
        try {
            // 这个有个点需要注意, intf 本身就是一个 Class,为什么这里还要再次得到一个 Class
            // 判断对象是否相同的一个前提,是否是同一个类加载器
            // 原因: 这里要判断两个接口是不是同一个接口,
            interfaceClass = Class.forName(intf.getName(), false, loader);
        } catch (ClassNotFoundException e) {
            
        }
        // 如果两个不相同那么抛出异常: IllegalArgumentException,相等继续执行后面的代码
        if (interfaceClass != intf) {
            throw new IllegalArgumentException(
                intf + " is not visible from class loader");
        }
        /*
         * Verify that the Class object actually represents an
         * interface.
         */
        if (!interfaceClass.isInterface()) {
            throw new IllegalArgumentException(
                interfaceClass.getName() + " is not an interface");
        }
        /*
         * Verify that this interface is not a duplicate.
         */
        if (interfaceSet.put(interfaceClass, Boolean.TRUE) != null) {
            throw new IllegalArgumentException(
                "repeated interface: " + interfaceClass.getName());
        }
    }
​
    String proxyPkg = null;     // package to define proxy class in
    int accessFlags = Modifier.PUBLIC | Modifier.FINAL;
​
    /*
     * Record the package of a non-public proxy interface so that the
     * proxy class will be defined in the same package.  Verify that
     * all non-public proxy interfaces are in the same package.
     */
    for (Class<?> intf : interfaces) {
        int flags = intf.getModifiers();
        // 如果这个接口不是 public,那么引用的时候会有问题,这里需要做一个转换
        if (!Modifier.isPublic(flags)) {
            accessFlags = Modifier.FINAL;
            String name = intf.getName();
            int n = name.lastIndexOf('.');
            String pkg = ((n == -1) ? "" : name.substring(0, n + 1));
            if (proxyPkg == null) {
                proxyPkg = pkg;
            } else if (!pkg.equals(proxyPkg)) {
                throw new IllegalArgumentException(
                    "non-public interfaces from different packages");
            }
        }
    }
​
    if (proxyPkg == null) {
        // if no non-public proxy interfaces, use com.sun.proxy package
        proxyPkg = ReflectUtil.PROXY_PACKAGE + ".";
    }
​
    /*
     * Choose a name for the proxy class to generate.
     */
    long num = nextUniqueNumber.getAndIncrement();
    // 这里给 proxyPkg 加一个标识,防止并发的情况下类名相同
    String proxyName = proxyPkg + proxyClassNamePrefix + num;
​
    /*
     * Generate the specified proxy class.
     * 生成指定的代理类的二进制文件,
     */
    byte[] proxyClassFile = ProxyGenerator.generateProxyClass(proxyName, interfaces, accessFlags);
    
    try {
        // 我们知道一个对象的产生顺序: 
        // .java ---> .class ---ClassLoader---> JVM ---byte[]---> object
        // 而这里需要返回一个 Class,那么将二进制文件转换成对象就在 defineClass0() 方法中进行
        return defineClass0(loader, proxyName, proxyClassFile, 0, proxyClassFile.length);
    } catch (ClassFormatError e) {
        /*
         * A ClassFormatError here means that (barring bugs in the
         * proxy class generation code) there was some other
         * invalid aspect of the arguments supplied to the proxy
         * class creation (such as virtual machine limitations
         * exceeded).
         */
        throw new IllegalArgumentException(e.toString());
    }
}

进入 defineClass0() 方法

// 这个方法是一个被 native 修饰的方法是一个本地方法,也就是一个 Java 调用非 Java 代码的接口,再开发 JDK 的时候底层使用了 C 或 C++ 开发(可以去看一下 OpenJDK),也就是说 C 和 C++ 负责把 byte[] 变成 Class 对象
private static native Class<?> defineClass0(ClassLoader loader, String name, byte[] b, int off, int len);

总结:

# 通过接口反射得到字节码,然后把字节码转换成 Class,就得到了我们想要的对象

有兴趣的同学可以关注我的个人公众号,期待我们共同进步!!!

BOSS直聘数据采集、解析处理、分析与可视化实战 招聘和求职是一对永恒的话题,不论什么时候都有招聘或者是求职的需求,找不找得到工作可能最主要的就是匹配度是否高,待遇福利是否诱人,如今互联网的快速发展,找工作的方式早已发生了翻天覆地的变化,从以往的面对面形式的招聘简历投递和面试方式,变成了电子简历网络直接投递、远程面试录用的形式,便捷性大大提升,需求的快速增长,促生了一批互联网招聘类的企业,诸如:51job、BOSS直聘、拉勾网等等,为了能... 阅读详情

相关推荐

Docker离线部署OpenWebUI操作步骤

docker离线部署openwebui

m0_49333265的博客 4345

java.lang.System

Modulejava.base Packagejava.lang Class System java.lang.Object java.lang.System public final class System extends Object TheSystemclass contains several useful class fields and methods. It cannot be instantiated. Among the facilities provi...

新征程的博客 591

魔兽RPG老地图逆向工程:解密三国列传3.0武将招募限制(附JASS实战)

本文详细解析了《三国列传3.0》魔兽RPG地图的武将招募限制机制,通过逆向工程和JASS脚本修改技术,突破SLK加密防线并解密游戏逻辑。文章提供了从工具准备到代码修改的完整实战指南,帮助玩家解除武将数量限制,重温经典游戏的乐趣。

i1j2k的博客 359

对线程的启动——dubug过程调试

调试demo public class MyThread extends Thread { @Override public void run() { for (int i=0;i&lt;50000;i++){ System.out.println("i==========="+i); } } publi...

奇点 439

SigFit实战:从FEA到光学仿真的热力耦合分析全流程解析

在光机系统与芯片封装等精密工程领域,热与力的耦合效应是影响产品性能与可靠性的核心物理问题。有限元分析(FEA)是预测结构在热、力载荷下变形与应力的基础工具,但其结果通常无法直接用于评估光学性能。这需要一座桥梁,将物理场数据转化为光学设计语言。其核心原理在于数据映射与面形表征技术,例如通过泽尼克多项式拟合,将离散的节点位移分解为离焦、像散等标准光学像差。这项技术的工程价值在于,它实现了多物理场仿真的闭环,使工程师能在设计阶段精准预测热变形或应力对波前误差、调制传递函数等关键光学指标的影响。其典型应用场景包括高

weixin_28630185的博客 334

嵌入式开发:用状态机实现STM32按键消抖,告别阻塞延时

在嵌入式系统开发中,处理异步事件和实时响应是核心挑战。状态机作为一种强大的编程模型,通过定义有限的状态、事件和状态转换规则,将复杂的、非线性的控制逻辑转化为清晰、确定且易于维护的代码结构。其技术价值在于实现逻辑的模块化、异步化和非阻塞化,能显著提升代码的可读性、可扩展性和系统实时性。这一思想广泛应用于协议解析、用户界面交互、传感器数据处理等场景。本文以嵌入式开发中基础的按键处理为例,针对传统“延时消抖”方法会阻塞主循环、影响实时性的痛点,深入讲解如何运用状态机思维重构按键消抖逻辑。通过分析状态机的核心三要素

weixin_33377602的博客 339

java获取系统属性System.getProperty

在java中System.getProperty可以获取系统的属性,这个大家都知道。但是能获取到那些属性呢? 今天看了一下源码,如下: /* * @(#)System.java 1.158 06/03/13 * * Copyright 2006 Sun Microsystems, Inc. All rights reserved. * SUN PROPRIETARY/CONFIDENT...

669

Silly Tavern(酒馆)AI 角色扮演下载与安装教程(Windows本地部署)

SillyTavern是一款开源AI角色扮演前端工具,支持沉浸式对话和长期角色互动。本文详细介绍了在Windows系统F盘部署SillyTavern的完整流程,包括下载项目、安装Node.js和Git环境、配置路径、启动服务等关键步骤,并特别说明非系统盘路径可能遇到的npm安装问题及解决方法。成功启动后,用户可通过浏览器访问本地地址使用该工具进行AI角色扮演互动。

Tan3851的博客 1万+

Java Executor 框架

     Executor框架是指java5中引入的一系列并发库中与executor相关的功能类,包括Executor、Executors、ExecutorService、CompletionService、Future、Callable等。(图片引用自http://www.javaclubcn.com/a/jichuzhishi/2012/1116/170.html)      本篇博文分...

weixin_33994429的博客 282

Android AMS——AMS初始化(二)

Android AMS 也是一个系统服务,属于系统服务中的引导服务,在 startBootstrapServices() 方法中启动。这里我们就来看一下 ActivityManagerService 的启动流程。

小旭的专栏 773

真题库系列之 CCF GESP 2025年12月认证 Python 1级真题含正确答案与解析

学生通过计算机基础知识的学习,了解计算机的构成与操作,以及计算机的发 展历程。通过编程基础知识以及语句的掌握,可以独立完成简单功能的顺序结构、 分支结构、循环结构的程序。

iCloudEnd的博客 314

Thread类学习(一)

Thread类API中的英文描述: file:///D:/Java/JDK8/Docs/docs/api/index.html 英语不好,大致的意思是: 线程是程序执行时的线程,java虚拟机(JVM)允许一个应用运行多个线程(并发)。 每一个线程都自己的优先权,优先级高的线程会比优先级低的线程优先执行。每一个线程可以被设置成守护线程(daemon),当一段代码运行一些线程时,会创建一...

weixin_30794499的博客 152

Power domain 划分该如何下手

假如PD1比PD3更always on的话,我们只需要插入普通buffer即可,因为PD3 on,PD1也肯定是ON,PD1 off,PD3肯定时off,PD1能cover PD3的电源情况,因此使用普通buffer也可,但是处于省电角度,我们还是使用AO buffer;在我们做多power domain时,在切分power domain时,需要谨慎,稍有不慎,就会出现congestion以及timing问题,那问题来了,我们在切分power domain时有什么考究么,今天小编就和大家一起讨论讨论。

芯冰乐 205

[设计模式] Proxy

Proxy 推荐阅读 C++ 设计模式 目录 动机 在面向对象系统中,有些对象由于某种原因(比如对象创建的开销很大,或者某些操作需要安全控制,或者需要进程外的访问等), 直接访问会给使用者、或者系统结构带来很多麻烦。 如何在不失去透明操作对象的同时来管理/控制这些对象特有的复杂性?增加一层间接层是软件开发中常见的解决方式。 模式定义 为其他对象提供一种代理以控制(隔离,使用接口)对这对象的访问。 ——《设计模式》GoF 结构设计 这次先看结构设计 Subject是一个接口 本来我们Client创建

鱼竿钓鱼干 215

WINCC7.3破解文件

WINCC7.3硬件够破解文件,有需要的下载!WINCC7.3硬件够破解文件,有需要的下载!

NTscan扫描工具

ntscan是一个扫描器,可以扫描没有密码和弱密码的共享,先到配置文件中填写猜测的用户名和密码,扫描过程中右侧出现的是扫描日志。

DesignPattern之Proxy

《JAVA与模式》之代理模式 在阎宏博士的《JAVA与模式》一书中开头是这样描述代理(Proxy)模式的:   代理模式是对象的结构模式。代理模式给某一个对象提供一个代理对象,并由代理对象控制对原对象的引用。 代理模式的结构   所谓代理,就是一个人或者机构代表另一个人或者机构采取行动。在一些情况下,一个客户不想或者不能够直接引用一个对象,而代理对象可以在客户端和目标对象之间起

EckoTan的专栏 719

数学建模模型总结

这是本人在两年内准备参加数学建模竞赛搜集到的模型资料,已经经过了本人的筛选和整理,希望能够对准备参加数学建模竞赛的学弟学妹们提供一些帮助!

设计模式(DesignPattern)之代理模式(Proxy)

1、定义         代理模式也称为委托模式,为一个对象提供一个代理对象,以此来控制被代理对象的访问,简单来说就是代理对象代替被代理对象来完成一些事情。         代理模式一般分为静态代理和动态代理:         静态代理:代理类在代码编译以前就已经存在。         动态代理:运行时动态的创建代理对象,可以很灵活的代理自己想要代理的对象,通过反射机制来实现。 2、使用...

inventor1024的博客 535

jre9下载 jdk9

(Java SE Runtime Environment 9.0) 9.0u175 官方最新版 【x86|x64】

设计模式---代理模式(DesignPattern_Proxy)

摘录自:设计模式与游戏完美开发 十年磨一剑,作者将设计模式理论巧妙地融入到实践中,以一个游戏的完整实现呈现设计模式的应用及经验的传承 《轩辕剑》之父——蔡明宏、资深游戏制作人——李佳泽、Product Evangelist at Unity Technologies——Kelvin Lo、信仁软件设计创办人—— 赖信仁、资深3D游戏美术——刘明恺 联合推荐全书采用了整合...

su9257的博客 138

Proxy Design Pattern 代理设计模式

代理设计模式,这个模式很多用于服务器客户端之类的,上网也经常使用代理之类的,想起来感觉是很复杂的,不过这个设置模式本身是很简单的。 就是一个类调用另外一个类的函数,客户调用的是一个类,而实际的工作是由另外一个类做的。 体现这个设计模式的代码: #include class RealObj { public: virtual void handleReq() = 0; };

靖空间 1488

明华澳汉读卡器驱动安装与API调用全攻略:从选型到卡号处理

读卡器驱动安装与API调用是门禁、考勤、社保等系统集成中的常见技术环节。其核心原理在于设备类型识别、驱动匹配与卡号格式转换,技术价值在于确保数据读取的准确性与系统稳定性。典型应用场景包括门禁考勤、社保医疗、自助终端等。在实际工程中,接触式与非接触式读卡器的驱动选型、USB免驱配置、DLL位数匹配以及卡号字节序处理是关键难点。本文围绕明华澳汉读卡器,系统梳理驱动安装步骤、API调用逻辑与故障排查方法,帮助开发者快速定位并解决读卡问题。

weixin_33841503的博客 227

设计模式之Proxy

 理解并使用设计模式,能够培养我们良好的面向对象编程习惯,同时在实际应用中,可以如鱼得水,享受游刃有余的乐趣.Proxy是比较有用途的一种模式,而且变种较多,应用场合覆盖从小结构到整个系统的大结构,Proxy是代理的意思,我们也许有代理服务器等概念,代理概念可以解释为:在出发点到目的地之间有一道中间层,意为代理.设计模式中定义: 为其他对象提供一种代理以控制对这个对象的访问.

kinglino520的专栏 434

proxy设计模式

proxy设计模式实例  public interface Myinterface{public int getId();} public class businessimplements Myinterface{....} public classMyproxyimplements Myinterface{  privateMyinterfac...

ddz93642的博客 87

简话设计模式之Proxy-Stub模式

从Proxy设计模式到Proxy-Stub

u012604322的专栏 4664

设计模式 —— Proxy 代理模式

简介 Proxy代理模式是一种结构型设计模式。通过代理模式可以实现程序之间的解耦,可以解决在直接访问对象时带来的程序之间耦合度增大的问题。 按照代理的创建时期,代理类分为两种: 静态代理:在编译期,手动创建代理类,而不是由编译器生成代理类。 动态代理:在运行期,运用反射机制动态而生成代理类。 JDK代理基于接口接口 CGlib代理基于继承 静态代理 优点 静态代理可以将目标类和...

阿水的博客 275

设计模式之Proxy——买票篇(原创)

设计模式之Proxy——买票篇 今年过年手气好,打牌赢了100块,我得意的笑,我得意的笑,总之一个字“爽”。因为往年打牌从没赢过啊!我高兴的回到家里,还没等我开口报告战况,老婆撂给我一句话“我弟要回上海,你给买张票吧。”我心里虽然不高兴,但脸上却表现出很开心的样子,立刻用坚定语气说到:“请领导放心,保证完成任务!”。保证归保证,可是大过年的票也确实难买,在经过一番挫折后(呜呜),我只好去找

lxgljj的专栏 4505

设计模式——PROXY

设计模式——PROXY 作者:DecaMinCow 博客:http://blog.youkuaiyun.com/m0_37567301 邮箱:decamincow#gmail.com (#->@) 使用场景 当我们使用别人的代码的时候,可以通过代理,对方法增强,避免了修改别人的代码 开发的时候专注业务逻辑,后期通过代理完成日志、消息、权限等处理 示例 静态代理模式 public class St...

DecaMinCow的博客 195

设计模式之Proxy(代理)

理解并使用设计模式,能够培养我们良好的面向对象编程习惯,同时在实际应用中,可以如鱼 得水,享受游刃有余的乐趣. Proxy 是比较有用途的一种模式,而且变种较多,应用场合覆盖从小结构到整个系统的大结 构,Proxy 是代理的意思,我们也许有代理服务器等概念,代理概念可以解释为:在出发点到 目的地之间有一道中间层,意为代理. 设计模式中定义: 为其他对象提供一种代理以控制对这个对象的访问. 为什么...

软软的沙窝!小憩的场所! 157
上一篇: JDK动态代理和CGLIB代理的一些点
下一篇: Spring 中 BeanFactory 和 FactoryBean
Future_LL
博客等级 码龄9年 215粉丝 255原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值