精华内容
下载资源
问答
  • 2021-12-23 18:29:55

    目录

    一、写在前面

    二、加依赖

    三、打包时不需要将配置处理器打进去,排除即可

    四、测试


    一、写在前面

    springboot自定义的bean,绑定配置文件之后通常是不会有提示的。

    二、加依赖

    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-configuration-processor</artifactId>
        <optional>true</optional>
    </dependency>

    三、打包时不需要将配置处理器打进去,排除即可

    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
                <configuration>
                    <excludes>
                        <exclude>
                            <groupId>org.springframework.boot</groupId>
                            <artifactId>spring-boot-configuration-processor</artifactId>
                        </exclude>
                    </excludes>
                </configuration>
            </plugin>
        </plugins>
    </build>

    四、测试

    // bean 只有在容器中的组件,才会拥有SpringBoot提供的强大功能
    @ToString
    @Data
    @Component
    // 导入配置文件的配置,映射到字段中
    @ConfigurationProperties(prefix = "mycar")
    public class Car {
    private String brand;
    private Integer price;
    
    // application.properties
    mycar.brand=YD
    mycar.price=100000

    更多相关内容
  • Java 自定义类加载器教程

    千次阅读 2021-08-03 23:33:09
    Java 自定义类加载器教程 除了面试中遇到类的加载器的概率会高外,实际的工作中很少接触。但是一个程序员想要成长为大牛就必须对一些 JVM 的底层设计有些了解。此基础上我们阅读一些源码和框架会显得更轻松。 ...


    Java 自定义类加载器教程

    除了在面试中遇到类的加载器的概率会高外,在实际的工作中很少接触。但是一个程序员想要成长为大牛就必须对一些 JVM 的底层设计有些了解。在此基础上我们阅读一些源码和框架会显得更轻松。

    好了废话不多说,我们接着前面的文章,乘热打铁。来实现一个 Java 自定义类加载器吧。

    要实现 Java 自定义的类加载器,我们需要继承 ClassLoader 。并且需要了解Java的双亲委派模型。

    loadClass

    loadClass默认实现如下:

    public Class<?> loadClass(String name) throws ClassNotFoundException {
        return loadClass(name, false);
    }
    

    再看看loadClass(String name, boolean resolve)函数:

    protected Class<?> loadClass(String name, boolean resolve)
        throws ClassNotFoundException{
        synchronized (getClassLoadingLock(name)) {
            // First, check if the class has already been loaded
            Class c = findLoadedClass(name);
            if (c == null) {
                long t0 = System.nanoTime();
                try {
                    if (parent != null) {
                        c = parent.loadClass(name, false);
                    } else {
                        c = findBootstrapClassOrNull(name);
                    }
                } catch (ClassNotFoundException e) {
                    // ClassNotFoundException thrown if class not found
                    // from the non-null parent class loader
                }
                // 业余草:www.xttblog.com
                if (c == null) {
                    // If still not found, then invoke findClass in order
                    // to find the class.
                    long t1 = System.nanoTime();
                    c = findClass(name);
                    // this is the defining class loader; record the stats
                    sun.misc.PerfCounter.getParentDelegationTime().addTime(t1 - t0);
                    sun.misc.PerfCounter.getFindClassTime().addElapsedTimeFrom(t1);
                    sun.misc.PerfCounter.getFindClasses().increment();
                }
            }
            if (resolve) {
                resolveClass(c);
            }
            return c;
        }
    }
    

    从上面代码可以明显看出,loadClass(String, boolean)函数即实现了双亲委派模型!整个大致过程如下:

    1. 首先,检查一下指定名称的类是否已经加载过,如果加载过了,就不需要再加载,直接返回。
    2. 如果此类没有加载过,那么,再判断一下是否有父加载器;如果有父加载器,则由父加载器加载(即调用parent.loadClass(name, false);).或者是调用bootstrap类加载器来加载。
    3. 如果父加载器及bootstrap类加载器都没有找到指定的类,那么调用当前类加载器的findClass方法来完成类加载。
      话句话说,如果自定义类加载器,就必须重写findClass方法!

    findClass

    findClass的默认实现如下:

    protected Class<?> findClass(String name) throws ClassNotFoundException {
        throw new ClassNotFoundException(name);
    }
    

    可以看出,抽象类ClassLoader的findClass函数默认是抛出异常的。而前面我们知道,loadClass在父加载器无法加载类的时候,就会调用我们自定义的类加载器中的findeClass函数,因此我们必须要在loadClass这个函数里面实现将一个指定类名称转换为Class对象.

    如果是是读取一个指定的名称的类为字节数组的话,这很好办。但是如何将字节数组转为Class对象呢?很简单,Java提供了defineClass方法,通过这个方法,就可以把一个字节数组转为Class对象。

    defineClass

    defineClass主要的功能是:将一个字节数组转为Class对象,这个字节数组是class文件读取后最终的字节数组。如,假设class文件是加密过的,则需要解密后作为形参传入defineClass函数。

    defineClass默认实现如下:

    protected final Class<?> defineClass(String name, byte[] b, int off, int len)
    	throws ClassFormatError  {
    	return defineClass(name, b, off, len, null);
    }
    

    函数调用过程

    函数调用过程,如下图所示:
    在这里插入图片描述
    通常情况下,我们都是直接使用系统类加载器。但是,有的时候,我们也需要自定义类加载器。比如应用是通过网络来传输 Java类的字节码,为保证安全性,这些字节码经过了加密处理,这时系统类加载器就无法对其进行加载,这样则需要自定义类加载器来实现。自定义类加载器一般都是继承自ClassLoader类,从上面对loadClass方法来分析来看,我们只需要重写 findClass 方法即可。下面我们通过一个示例来演示自定义类加载器的流程:

    package com.xttblog.classloader;
    import java.io.*;
    public class MyClassLoader extends ClassLoader {
        private String root;
    	// 业余草:www.xttblog.com
        protected Class<?> findClass(String name) throws ClassNotFoundException {
            byte[] classData = loadClassData(name);
            if (classData == null) {
                throw new ClassNotFoundException();
            } else {
                return defineClass(name, classData, 0, classData.length);
            }
        }
        private byte[] loadClassData(String className) {
            String fileName = root + File.separatorChar
                    + className.replace('.', File.separatorChar) + ".class";
            try {
                InputStream ins = new FileInputStream(fileName);
                ByteArrayOutputStream baos = new ByteArrayOutputStream();
                int bufferSize = 1024;
                byte[] buffer = new byte[bufferSize];
                int length = 0;
                while ((length = ins.read(buffer)) != -1) {
                    baos.write(buffer, 0, length);
                }
                return baos.toByteArray();
            } catch (IOException e) {
                e.printStackTrace();
            }
            return null;
        }
        public String getRoot() {
            return root;
        }
        public void setRoot(String root) {
            this.root = root;
        }
        public static void main(String[] args)  {
            MyClassLoader classLoader = new MyClassLoader();
            classLoader.setRoot("E:\\temp");
            Class<?> testClass = null;
            try {
                testClass = classLoader.loadClass("com.xttblog.classloader.Test2");
                Object object = testClass.newInstance();
                System.out.println(object.getClass().getClassLoader());
            } catch (ClassNotFoundException e) {
                e.printStackTrace();
            } catch (InstantiationException e) {
                e.printStackTrace();
            } catch (IllegalAccessException e) {
                e.printStackTrace();
            }
        }
    }
    

    自定义类加载器的核心在于对字节码文件的获取,如果是加密的字节码则需要在该类中对文件进行解密。由于这里只是演示,我并未对class文件进行加密,因此没有解密的过程。这里有几点需要注意:

    1. 这里传递的文件名需要是类的全限定性名称,即com.paddx.test.classloading.Test格式的,因为 defineClass 方法是按这种格式进行处理的。
    2. 最好不要重写loadClass方法,因为这样容易破坏双亲委托模式。
    3. 这类Test 类本身可以被AppClassLoader类加载,因此我们不能把com/paddx/test/classloading/Test.class放在类路径下。否则,由于双亲委托机制的存在,会直接导致该类由AppClassLoader加载,而不会通过我们自定义类加载器来加载。
    展开全文
  • 3.2.4. 自定义类加载器ClassLoader 3.2.4.1. 自定义类加载器介绍 1)自定义类加载器的作用 a.安全。避免核心类库被随意篡改。此外,Bootstrap、Extension、Application类加载器只能加载指定路径下的类字节码,如果想...

    3.2.4. 自定义类加载器ClassLoader

    3.2.4.1. 自定义类加载器介绍

    1)自定义类加载器的作用
    a.安全。避免核心类库被随意篡改。此外,Bootstrap、Extension、Application类加载器只能加载指定路径下的类字节码,如果想要加载某些特定位置的类文件或者加载网络上的某个类文件时上述三种类加载器就不适用了,需要使用自定义的类加载器。
    b.加密。java字节码很容易被反编译,通过定制ClassLoader使得字节码先加密防止别人下载后反编译,这里的ClassLoader相当于一个动态的解码器
    c.归档。可能为了节省网络资源,对自己的代码做一些特殊的归档,然后用定制的ClassLoader来解档 。
    d.自展开程序。把java应用程序编译成单个可执行类文件,这个文件包含压缩的和加密的类文件数据,同时有一个固定的ClassLoader,当程序运行时它在内存中完全自行解开,无需先安装
    e.动态生成。可以生成应用其他还未生成类的类,实时创建整个类并可在任何时刻引入JVM
    f.热部署。当需要实现热部署功能时(一个class文件通过不同的类加载器产生不同class对象从而实现热部署功能),不过需要实现自定义ClassLoader的逻辑。

    2)实现自定义类加载器的方式
    在自定义类加载器时,如果没有太过于复杂的需求,可以直接继承URLClassLoader类,这样就可以避免自己去编写findClass()方法及其获取字节码流的方式,使得自定义类加载器编码更简洁。如果在定义类加载器时选择继承ClassLoader类而非URLClassLoader,必须手动编写findclass()方法的加载逻辑以及该方法中获取字节码流的逻辑。
    3)自定义类加载器的流程
    实现自定义的类加载器需继承ClassLoader,然后重写里面的findClass()方法,再调用defineClass()方法将字节码转为类,即可完成类的加载。
    重写findClass()方法时,根据要加载类的对象不同而采用不同的实现。这里是加载本地程序java文件Hello中的Hello类,采用读取文件流的形式读取Hello.java文件,形成二进制流,然后将二进制流转为字节数组,再通过defineClass方法转为class对象。

    3.2.4.2. 自定义类加载的三种实现

    1)自定义文件类加载器
    【方法1】 加载ClassLoaderIntroduce路径下sayHello文件中得的Hello类。这里采用继承ClassLoader而非URLClassLoader,因此需要手动编写findclass()方法的加载逻辑以及该方法中获取字节码流的逻辑。

    public class MyClassLoader {
    
        private static class customizedClassLoader extends ClassLoader{
            @Override
            protected Class<?> findClass(String name) throws ClassNotFoundException {
                File file = new File("D:/CodeEdit/Java/BasicKnowledgeLearning/JVM/src/ClassLoaderIntroduce/", name.replace(".","/").concat(".class"));
                try{
                    FileInputStream fis = new FileInputStream(file);
                    ByteArrayOutputStream bos = new ByteArrayOutputStream();
    
                    int length = 0 ;
                    while((length=fis.read()) != 0){  // 以二进制流的形式读取文件
                        bos.write(length);
                    }
    
                    byte[] data = bos.toByteArray();   // 将二进制流转为byte数组
    
                    bos.close();
                    fis.close();
    
                    return defineClass(name,data, 0, data.length);  // 将二进制流转为类对象
    
                }catch(Exception e){
                    e.printStackTrace();
                }
    
                return super.findClass(name);  // 抛出ClassNotFindException异常
            }
    
        }
    
    
        public static void main(String[] args) throws ClassNotFoundException, IllegalAccessException, InstantiationException {
            ClassLoader classLoader = new customizedClassLoader();
            Class clazz = classLoader.loadClass("ClassLoaderIntroduce.Hello");  // 加载其他的类
    
            Hello h = (Hello)clazz.newInstance();   // 类实例化
            h.sayHello();
    
            System.out.println(classLoader.getClass().getClassLoader());
            System.out.println(classLoader.getParent());
        }
    }
    运行结果:Hello JVM!
    jdk.internal.loader.ClassLoaders$AppClassLoader@78308db1
    jdk.internal.loader.ClassLoaders$AppClassLoader@78308db1
    
    

    【方法2】 加载ClassLoaderIntroduce路径下sayHello文件中得的Hello类。这里采用继承URLClassLoader,因此实现自定义加载类就很简洁。

    public class MyClassLoader {
        // 基于URLClassLoader实现自定义类加载器
        private static class customizedClassLoader extends URLClassLoader{
            public customizedClassLoader(URL[] urls) {
                super(urls);
            }
        }
    
        public static void main(String[] args) throws ClassNotFoundException, IllegalAccessException, InstantiationException, MalformedURLException {
           String rootDir = "D:/CodeEdit/Java/BasicKnowledgeLearning/JVM/src/";
           File file = new File(rootDir);
           URI uri = file.toURI();
           URL[] urls = {uri.toURL()};
    
           customizedClassLoader loader = new customizedClassLoader(urls);
    
           Class<?> object = loader.loadClass("ClassLoaderIntroduce.Hello");
           System.out.println(object.newInstance().toString());
           
        }
    
    }
    

    2)自定义网络类加载器
    自定义网络类加载器,主要用于读取通过网络传递的class文件(在这里我们省略class文件的解密过程),并将其转换成字节流生成对应的class对象,如下:

    public class NetClassLoader extends ClassLoader {
    
        private String url;//class文件的URL
    
        public NetClassLoader(String url) {
            this.url = url;
        }
    
        @Override
        protected Class<?> findClass(String name) throws ClassNotFoundException {
            byte[] classData = getClassDataFromNet(name);
            if (classData == null) {
                throw new ClassNotFoundException();
            } else {
                return defineClass(name, classData, 0, classData.length);
            }
        }
    
        /**
         * 从网络获取class文件
         * @param className
         * @return
         */
        private byte[] getClassDataFromNet(String className) {
            String path = classNameToPath(className);
            try {
                URL url = new URL(path);
                InputStream ins = url.openStream();
                ByteArrayOutputStream baos = new ByteArrayOutputStream();
                int bufferSize = 4096;
                byte[] buffer = new byte[bufferSize];
                int bytesNumRead = 0;
                // 读取类文件的字节
                while ((bytesNumRead = ins.read(buffer)) != -1) {
                    baos.write(buffer, 0, bytesNumRead);
                }
                //这里省略解密的过程.......
                return baos.toByteArray();
            } catch (Exception e) {
                e.printStackTrace();
            }
            return null;
        }
    
        private String classNameToPath(String className) {
            // 得到类文件的URL
            return url + "/" + className.replace('.', '/') + ".class";
        }
    
    }
    

    3)自定义热部署类加载器
    热部署就是利用同一个class文件不同的类加载器在内存创建出两个不同的class对象(利用不同的类加载实例),由于JVM在加载类之前会检测请求的类是否已加载过(即在loadClass()方法中调用findLoadedClass()方法),如果被加载过,则直接从缓存获取,不会重新加载。注意同一个类加载器的实例和同一个class文件只能被加载器一次,多次加载将报错,因此我们实现的热部署必须让同一个class文件可以根据不同的类加载器重复加载,以实现所谓的热部署。
    在JVM中,如果两个类对象(Class对象)源于同一个class文件会被同一个JVM加载,但只要加载他们的ClassLoader实例对象不同,那么这两个类对象也是不同的。因为不同的ClassLoader实例对象拥有不同的独立的类名称空间,所以加载的class对象也会存在不同的类名空间中,但是需要覆写loadclass方法,从前面双亲委派模式对loadClass()方法的源码分析中可以知,在方法第一步会通过Class<?> c = findLoadedClass(name);从缓存查找,类名完整名称相同则不会再次被加载,因此必须绕过缓存查询才能重新加载class对象。当然也可直接调用findClass()方法,这样也避免从缓存查找,如下

    String rootDir="/Users/zejian/Downloads/Java8_Action/src/main/java/";
    //创建两个不同的自定义类加载器实例
    FileClassLoader loader1 = new FileClassLoader(rootDir);
    FileClassLoader loader2 = new FileClassLoader(rootDir);
    
    //通过findClass创建类的Class对象,避开在自定义类的缓存中查找
    Class<?> object1=loader1.findClass("com.zejian.classloader.DemoObj");
    Class<?> object2=loader2.findClass("com.zejian.classloader.DemoObj");
    
    System.out.println("findClass->obj1:"+object1.hashCode());
    System.out.println("findClass->obj2:"+object2.hashCode());
    运行结果:findClass->obj1:723074861 
    findClass->obj2:895328852
    	如果调用父类的loadClass方法,结果如下,除非重写loadClass()方法去掉缓存查找步骤,不过现在一般都不建议重写loadClass()方法,不重写loadClass()方法时不能实现要求,其结果如下:
    String rootDir="/Users/zejian/Downloads/Java8_Action/src/main/java/";
    //创建两个不同的自定义类加载器实例
    FileClassLoader loader1 = new FileClassLoader(rootDir);
    FileClassLoader loader2 = new FileClassLoader(rootDir);
    
    //通过findClass创建类的Class对象,绕过了自定义类加载器中的缓存
    Class<?> object1=loader1.findClass("com.zejian.classloader.DemoObj");
    Class<?> object2=loader2.findClass("com.zejian.classloader.DemoObj");
    
    System.out.println("findClass->obj1:"+object1.hashCode());
    System.out.println("findClass->obj2:"+object2.hashCode());
    运行结果:loadClass->obj1:1872034366
     loadClass->obj2:1872034366 
    Class-> obj3:1872034366
    
    
    展开全文
  • 为什么需要自定义类加载器? 既然JDK已经有类加载器了,为什么还需要自定义类加载器呢?大概有以下几个原因: 隔离加载类 模块隔离,将类加载到不同的应用程序中。比如Tomcat这类web应用服务器,内部定义了好几种...

    前言

    前面 认识类加载器及双亲委派模型/ 中我们认识了类加载器,本文我们来自定义一个类加载器。

    为什么需要自定义类加载器?

    既然JDK已经有类加载器了,为什么还需要自定义类加载器呢?大概有以下几个原因:

    • 隔离加载类

      模块隔离,将类加载到不同的应用程序中。比如Tomcat这类web应用服务器,内部定义了好几种类加载器,用于隔离web应用服务器上不同的应用程序。

    • 扩展加载源

    ​ 还可以从数据库、网络或其他终端上加载类

    • 防止源码泄露

    ​ Java代码容易被编译和篡改,可以进行编译加密,类加载需要自定义还原加密字节码。

    类加载器的调用过程

    我们需要从ClassLoader的源码入手来看类加载的过程。

    ClassLoader中的loadClass方法源码如下:

        protected Class<?> loadClass(String name, boolean resolve)
            throws ClassNotFoundException
        {
            synchronized (getClassLoadingLock(name)) {
                // First, check if the class has already been loaded
                Class<?> c = findLoadedClass(name);
                if (c == null) {
                    long t0 = System.nanoTime();
                    try {
                        if (parent != null) {
                            c = parent.loadClass(name, false);
                        } else {
                            c = findBootstrapClassOrNull(name);
                        }
                    } catch (ClassNotFoundException e) {
                        // ClassNotFoundException thrown if class not found
                        // from the non-null parent class loader
                    }
    
                    if (c == null) {
                        // If still not found, then invoke findClass in order
                        // to find the class.
                        long t1 = System.nanoTime();
                        c = findClass(name);
    
                        // this is the defining class loader; record the stats
                        sun.misc.PerfCounter.getParentDelegationTime().addTime(t1 - t0);
                        sun.misc.PerfCounter.getFindClassTime().addElapsedTimeFrom(t1);
                        sun.misc.PerfCounter.getFindClasses().increment();
                    }
                }
                if (resolve) {
                    resolveClass(c);
                }
                return c;
            }
        }
    

    双亲委派的核心代码逻辑如下:

    image-20210924205725008

    而findClass()默认的实现是抛出ClassNotFoundException异常:

    image-20210924205901750

    还有一个方法我们需要注意的是defineClass(),它的作用是将字节数组转换成Class对象,源码如下:

    image-20210924210505455

    整个类加载的流程如下图所示:

    image-20210924205135256

    总结下这几个核心的方法:

    loadClass:双亲委派的核心实现逻辑;

    findClass:将class文件加载到内存中,是二进制的形式,最后得由defineClass来讲二进制文件转换成class文件。

    自定义类加载器

    所有用户自定义类加载器都应该继承ClassLoader类。
    在自定义ClassLoader的子类是,我们通常有两种做法:

    • 重写loadClass方法(是实现双亲委派逻辑的地方,修改他会破坏双亲委派机制,不推荐)
    • 重写findClass方法 (推荐)

    代码实现

    package com.jvm;
    
    import java.io.*;
    
    //自定义类加载器
    public class MyClassLoader extends ClassLoader{
    
    
        //磁盘上类的路径
        private String codePath;
    
        public MyClassLoader(ClassLoader parent, String codePath) {
            super(parent);
            this.codePath = codePath;
        }
    
        public MyClassLoader(String codePath) {
            this.codePath = codePath;
        }
    
        @Override
        protected Class<?> findClass(String name) throws ClassNotFoundException {
    
            BufferedInputStream bis=null;
            ByteArrayOutputStream baos=null;
    
            //完整的类名
            String file = codePath+name+".class";
            try {
    
                //初始化输入流
                bis = new BufferedInputStream(new FileInputStream(file));
                //获取输出流
                baos=new ByteArrayOutputStream();
    
                int len;
                byte[] data=new byte[1024];
                while ((len=bis.read(data))!=-1){
                    baos.write(data,0,len);
                }
    
                //获取内存中的字节数组
                byte[] bytes = baos.toByteArray();
    
                //调用defineClass将字节数组转换成class实例
                Class<?> clazz = defineClass(null, bytes, 0, bytes.length);
                return clazz;
    
            } catch (Exception e) {
                e.printStackTrace();
            }finally {
                try {
                    bis.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
                try {
                    baos.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
    
            return null;
        }
    }
    
    

    测试

    在本地D盘的目录下放置一个class文件:

    image-20210924213131313

    测试代码如下:

    public class MyClassLoaderTest {
    
        public static void main(String[] args) {
            MyClassLoader myClassLoader = new MyClassLoader("D:/");
            try {
                Class<?> clazz = myClassLoader.loadClass("AddressTest");
                //打印具体的类加载器,验证是否是由我们自己定义的类加载器加载的
                System.out.println("测试字节码是由"+clazz.getClassLoader().getClass().getName()+"加载的。。");
                Object o = clazz.newInstance();
                System.out.println(o.toString());
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }
    

    运行结果:

    image-20210924213346405

    可以看出我们使用自定义的类加载器加载了我们本地的一个class文件。

    总结

    双亲委派模型的实现核心方法是loadClass()、findClass()和defineClass(),其中loadClass()是核心逻辑,findClass()将文件加载到内存成为,defineClass()是将二进制文件转换为活的class文件,自定义类加载器也是从这三个核心方法入手的,我们通过重写findClass()方法来自定义了一个类加载器,成功加载了本地的一个class文件。

    展开全文
  • title: 类加载机制(五):自定义类加载器与深入双亲委托机制 date: 2019-03-17 08:24:05 categories: Java虚拟机 tags: 类加载机制 自定义类加载器 引言 我们知道类加载器共分为两大类型,Java虚拟机自带的类...
  • 自定义classloader实现java程序加密 背景 项目使用java语言开发,发布包会整合到C++客户端,直接安装到用户机器上,不同于之前常见的后端服务发布,这种发布能让用户直接接触到java发布包,由于java语言的特性,有...
  • 文章目录1、Java虚拟机的加载机制概述2、Java虚拟机中的加载器2.1、查看加载器加载的路径2.1.1、查看启动加载器2.1.2、查看扩展加载器3、加载器之间的关系3.1、每个加载器都有一个父加载器3.2、父加载...
  • 为何要花时间实现自己的ClassLoader ...我们需要不一定存放已经设置好的classPath下(有系统加载器AppClassLoader加载的路径),对于自定义路径中的class文件的加载,我们需要自己的ClassLoader有时...
  • 自定义函数一直是程序编写过程中必不可少和最重要的内容之一。定义函数的时候,我们把参数的名字和位置确定下来,函数的接口定义就完成了。对于函数的调用者来说,只需要知道如何传递正确的参数,以及函数将返回什么...
  • Warning: Function components cannot be given refs. Attempts to access this ref will fail....检查需要ref出来的组件是否使用了redux或dva的connect,如果用了的话connect内加入{forwardRef:true}: exp...
  • Jetbrains Rider自定义类模板

    千次阅读 2020-07-24 13:20:01
    Rider自定义类模板,添加文件创建时间等。。。 1. 打开 文件–》设置–》编辑器–》File Templates。如下图: 2. 下面的模板代码前面中添加下面的内容: #region << 文 件 说 明 >> /*---------------...
  • 2.元注解:@interface上面按需要注解上一些东西,包括@Retention、@Target、@Document、@Inherited四种。 3.注解的保留策略: @Retention(RetentionPolicy.SOURCE) // 注解仅存在于源码中,class字节码文件中不...
  • Android 5.0framework里添加自定义

    千次阅读 2016-03-24 20:32:07
    最近因项目需要frameworks\base\core\java\android\preference里面新添加了一个继承TwoStatePreference的XXXSwitchPreference,编译的时候出现了以下问题: ****************************** You have tried ...
  • 自定义泛型时的注意点: 泛型中可能有多个类型参数,此时我们要将多个类型参数放到一个尖括号中,中间使用逗号隔开 public class Demo <T,E,K,V> {} 泛型不同的引用之间不可以相互赋值 ArrayList<...
  • 自定义线程

    2017-04-09 21:00:24
    根据需求定义线程 import threading from time import * #创建线程,继承threading.Thread # 初始化func,args,name等参数,这里TestThread重写父类threading.Thread了__init__方法 # super()函数:解决了子类...
  • java自定义工具

    千次阅读 2017-11-03 21:04:25
    import java.io.File; import ...// 前面pre个集合,每个大小都是count个元素 for ( int i = 0 ; i ; i++) { List<T> itemList = new ArrayList(); for ( int j = 0 ; j ; j++) { ...
  • 由于application-local.yml中定义了一个自定义的配置,需要在工具中读取到这个值,但是网上找了很多的文章,也都尝试了,最终无果,好在功夫不负有心人,不断的试错过程中,终于获取到了,这个过程大概花了...
  •   其实,双亲委派模型并不...但是,如果每次想自定义类加载器就必须搜一遍别人的文章,然后复制,这样显然不行。可是自定义类加载器又不经常用,时间久了容易忘记。相信你经常会记不太清loadClass、findClass、de...
  • Python3自定义函数快速入门函数1. 自定义函数2. 函数的调用3. 函数参数3.1 位置参数3.2 默认参数3.3 可变参数3.4 关键字参数3.5 命名关键字参数4. 返回多个值 函数 程序中,函数就是具备某一功能且可以重复调用的...
  • 自定义枚举

    千次阅读 2015-12-13 22:07:57
    前言:说到枚举,就要说一下单例模式,单例模式是在类本身只创建出一个实例,且外界不能够创建该的实例。而枚举与单例类似,要求... (2)枚举项必须写枚举的最前面,每个枚举项之间用逗号隔开,如果枚举
  • 给列表项标记添加自定义图像

    千次阅读 2021-06-15 02:11:07
    要给列表项标记修改样式的话,list-style-image以及list-style-type是很好选择,前者可以使用自己定义的图像,后者可以选择圆形,矩形之的矢量图形。但是由于不同浏览器的实现不同,这些样式可能会出现一些小的...
  • 本文演示利用自定义的 ClassLoader 加密 Java ... 为了让客户端使用,需要定义一个 MyClassInterface, 这样客户端就不会直接引用 MyClassBase了,发布到客户端的class文件中是不存在 MyClassBase这个的。 MyC
  • 自定义线程池

    千次阅读 2022-04-03 22:44:47
    我们要想自定义线程池,必须先了解线程池的工作流程,才能自己定义线程池。下图是ThreadPoolExecutor的构造方法。 我们可以通过下面的场景理解ThreadPoolExecutor中的各个参数; a客户(任务)去银行(线程池)办理业务,...
  • springboot自定义注解

    2019-10-10 11:31:21
    我们使用springboot的时候,需要使用自定义的注解,如日志的获取及保存,权限的前期判断,都可以自定义注解来实现功能, 自定义注解的核心原理,还是使用了spring自身的AOP功能,在学自定义注解前,可以先了解下...
  • PHP中使用composer加载自定义

    千次阅读 2018-06-26 11:14:19
    首先需要创建一个 存放 文件的目录 , 不建议放在vendor下, 2.修改composer.json文件, 加入/修改 "autoload":{ "psr-4":{ "Elastic\\":"enhance/elastic" } } 其中 ...
  • 自定义函数

    2021-02-04 12:01:46
    如果函数有返回值,那么需要在函数中使用return语句返回计算结果,声明函数的一般形式如下。1.1.1 声明函数并调用def (参数列表):return 其中参数列表和返回值不是必须的,return后也可以不跟返回...
  • 双亲委派模型与自定义类加载器

    千次阅读 2016-08-24 12:38:57
    自定义类加载器也不难!随便从网上搜一下就能搜出一大把结果,然后copy一下就能用。但是,如果每次想自定义类加载器就必须搜一遍别人的文章,然后复制,这样显然不行。可是自定义类加载器又不经常用,时间久了容易...
  • 虚拟机设计团队把加载阶段中的“通过一个的全限定名来获取描述此类的二进制字节流”这个动作放到Java虚拟机外部实现,以便让应用程序自己决定如何去获取所需要。实现这个动作的代码块被称为“加载器”。 ...
  • Keras 添加自定义Losses

    2021-01-11 15:56:22
    有时候,我们需要往模型里面添加一些自定义的loss。 这些自定义的loss主要分为两大: loss是基于样本的正确标签 yrealy_{real}yreal​ 和预测的logit ypredy_{pred}ypred​ 计算得到。这种loss主要集中对分类...
  • Android—自定义Dialog

    2021-05-26 11:26:05
    Android 日常的开发中,Dialog 使用是比较广泛的。无论是提示一个提示语,还是确认信息,还是有一定交互的(弹出验证码,输入账号密码登录等等)对话框。而我们去看一下原生的对话框,虽然随着 Android 版本的更新...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 206,666
精华内容 82,666
关键字:

在自定义类的前面需要加