Thread.currentThread().getContextClassLoader() 与 ObjectInstance.class.getClassLoader() 的区别

假设现在有一个类 Car

package reflection;


class Car {
    private String brand;
    private String color;
    private int maxSpeed;

    //①默认构造函数
    public Car() {
    }

    //②带参构造函数
    public Car(String brand, String color, int maxSpeed) {
        this.brand = brand;
        this.color = color;
        this.maxSpeed = maxSpeed;
    }

    //③未带参的方法
    public void introduce() {
        System.out.println("brand:" + brand + ";color:" + color + ";maxSpeed:" + maxSpeed);
    }

    public String getBrand() {
        return brand;
    }

    public void setBrand(String brand) {
        this.brand = brand;
    }

    public String getColor() {
        return color;
    }

    public void setColor(String color) {
        this.color = color;
    }

    public int getMaxSpeed() {
        return maxSpeed;
    }

    public void setMaxSpeed(int maxSpeed) {
        this.maxSpeed = maxSpeed;
    }
}

这是另外的一个类 ReflectTest

package reflection;

import java.lang.reflect.Constructor;
import java.lang.reflect.Method;


public class ReflectTest {
    @SuppressWarnings("unchecked")
    public static Car initByDefaultConst() throws Throwable {
        //①通过类装载器获取Car类对象
        ClassLoader loader = Thread.currentThread().getContextClassLoader();

        ClassLoader loader1 = Car.class.getClassLoader();

        System.out.println(loader.toString());
        System.out.println(loader1.toString());
        System.out.println(loader.equals(loader1));
        System.out.println("------------------------");


        Class clazz = loader.loadClass("reflection.Car");
        Class clazz1 = loader1.loadClass("reflection.Car");

        System.out.println(clazz.toString());
        System.out.println(clazz1.toString());
        System.out.println(clazz==clazz1);
        System.out.println(clazz.equals(clazz1));
        System.out.println("------------------------------");

        //②获取类的默认构造器对象并通过它实例化Car
//        Constructor cons = clazz.getDeclaredConstructor((Class[]) null);
//        Constructor[] cons = clazz.getConstructors();
        Constructor cons = clazz.getDeclaredConstructor();
        System.out.println(cons.toString());
        System.out.println(clazz.getDeclaredConstructor(String.class, String.class, int.class).toString());
        Car car = (Car) cons.newInstance();


        //③通过反射方法设置属性
        Method setBrand = clazz.getMethod("setBrand", String.class);
        setBrand.invoke(car, "红旗CA72");
        Method setColor = clazz.getMethod("setColor", String.class);
        setColor.invoke(car, "黑色");
        Method setMaxSpeed = clazz.getMethod("setMaxSpeed", int.class);
        setMaxSpeed.invoke(car, 200);
        return car;
    }

    public static void main(String[] args) throws Throwable {
        Car car = initByDefaultConst();
        car.introduce();
    }
}

主要看这部分,其他的都不重要

        ClassLoader loader = Thread.currentThread().getContextClassLoader();

        ClassLoader loader1 = Car.class.getClassLoader();

        System.out.println(loader.toString());
        System.out.println(loader1.toString());
        System.out.println(loader.equals(loader1));
        System.out.println("------------------------");


        Class clazz = loader.loadClass("reflection.Car");
        Class clazz1 = loader1.loadClass("reflection.Car");

        System.out.println(clazz.toString());
        System.out.println(clazz1.toString());
        System.out.println(clazz==clazz1);
        System.out.println(clazz.equals(clazz1));
        System.out.println("------------------------------");

这是输出的结果

sun.misc.Launcher$AppClassLoader@18b4aac2
sun.misc.Launcher$AppClassLoader@18b4aac2
true
------------------------
class reflection.Car
class reflection.Car
true
true
------------------------------

在大部分的时候,这两者基本是差不多的


Each class will use its own classloader to load other classes. So if ClassA.class references ClassB.class then ClassB needs to be on the classpath of the classloader of ClassA, or its parents.

每个 class 将会使用它自己的 classloader 来加载其他的 classes

所以如果 ClassB 需要位于 ClassA 的类加载器或其父代的类路径上


What does it mean to say that “ClassA.class references ClassB.class”?


When ClassA has an import statement for ClassB, or if there is a method in ClassA that has a local variable of type ClassB. That will trigger ClassB to be loaded, if it’s not loaded already.

ClassA.class 引用 ClassB.class 意味着,当 ClassA 具有 ClassB 的导入语句时,或者 ClassA 中有一个具有类型 ClassB 的局部变量的方法时。这将触发ClassB被加载,如果它尚未加载。


The thread context classloader is the current classloader for the current thread. An object can be created from a class in ClassLoaderC and then passed to a thread owned by ClassLoaderD. In this case the object needs to use Thread.currentThread().getContextClassLoader() directly if it wants to load resources that are not available on its own classloader.

thread context classloader 是当前线程的类加载器。

可以从 ClassLoaderC 中的类创建对象,然后将其传递给 ClassLoaderD 拥有的线程。

在这种情况下,如果对象需要加载其自己的类加载器上不可用的资源,则该对象需要直接使用 Thread.currentThread().getContextClassLoader()


reference

1、Difference between thread’s context class loader and normal classloader

https://stackoverflow.com/questions/1771679/difference-between-threads-context-class-loader-and-normal-classloader

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
1. 单元测试:(掌握) 1. 写一个单元测试类,命名方式:XxxTest(测试类没有main方法) 2. 导入包,Junit4包 选中项目,右键 => Build Path => Add Library => 选中Junit 选中Junit4 => finish 3. 在测试类中,设计测试方法,命名方式:testXxx() 在方法上方会自动添加一个@Test注解 4. 运行,右键run as JUnit方式 如果是全部执行,直接选中 @Test注解,右键run as JUnit方式 如果是某一个方法,直接选中方法名,右键run as JUnit方式 @Before// 预执行注解,每次执行方法前都会执行该注解 @After// 每次执行方法后都会执行该注解 5. 运行后结果解释: 绿条:表示成功执行 红条:表示执行失败 1. 代码有异常 2. 执行失败,逻辑异常 6. 自己扩展(测试类中的断言assert) 2. 工具类:(掌握) 1. 概念:就是类中只有(静态、非静态)方法,就是为了调用方法。 2. 作用:就是一个轮子 3. 分类: 1. 静态的 方法全部都是static修饰的,调用方式:类名.方法名(...); 2. 非静态的 通过单例模式获取到对象后。就是只有一个对象的类 方法全部都是非static修饰的,调用方式:对象名.方法名(...); 4. 工具类命名: XxxUtil、XxxUtils、XxxTool、XxxTools 3. jar 包 (掌握) 1. 什么是jar包:就是别人封装好的字节码文件 2. 作用:就是提高开发效率的。使用轮子 3. 使用: 3.1 使用别人写好的jar包 step1:在当前项目下,创建一文件夹folder,叫lib step2:将jar包复制到当前的lib文件夹中 step3:将所有的jar包选中右键,build path add library step4:在我们代码中通过创建对象或者类名的方式使用即可 3.2 使用自己的jar包 (造轮子) step1:选中自己想要封装成jar包的类,右键export导出 在输入框中输入 jar: 1. jar File : 普通的jar包,没有main方法(最常用) 在下面写一个jar包的名字,然后选择生成jar包的路径,finish即可 2. Runnable jar File:可以自己执行的jar包,有main方法 (几乎不用) 要封装为可以执行的jar包,必须先运行一下当前类。 然后在下面写一个jar包的名字,然后选择生成jar包的路径,finish即可 在cmd控制台中,切换路径到jar文件所在的目录。 输入 :java -jar jar包名.jar step2:剩下的就是按照 3.1中的步骤使用即可 4. Properties资源(配置)文件的解析(重点) ---------------------------------(注意:重点)------------------------------------- 以后配置文件都要放到项目中的一个或者几个单独的文件夹中,为了好管理。 该文件夹类型是source folder类型,源文件夹,eclipse工具会自动编译 --------------------------------------------------------------------------------- 传统方式获取流是new创建的,而在web开发中有可能获取不到配置文件,为了避免这种情况,用以下方式获取流: 1. 通过当前类字节码文件的方式,一般是用当前类的字节码文件 当前类.class.getResourceAsStream("/文件路径/文件名"); /:如果是resource文件夹,直接写文件名,如果是普通文件夹写文件夹名/文件名 2. 通过类加载器的方式 1.同当前类的加载器获取 1.当前类.class.getClassLoader();//获取当前类加载器 2.classLoader.getResourceAsStream("文件路径/文件名");//通过类加载器获取流对象,如果是源文件夹,直接文件名 2.通过当前线程的类加载器获取流 1、ClassLoader classLoader = Thread.currentThread().getContextClassLoader(); //获取当前线程类加载器 2、InputStream is = classLoader.getResourceAsStream("文件路径/文件名");//通过当前线程的类加载器获取流对象,如果是源文件夹,直接文件名 建议用当前线程类的加载器方式获取流,线程安全问题 类加载器:( 扩展,5个月后会讲) 加载字节码的一个类而已: 1. 启动类加载器(Bootstrap classLoader) c++ 本地代码实现的类加载器,它负责将 <JAVA_HOME>/lib下面的核心类库 或 -Xbootclasspath选项指定的jar包等 虚拟机识别的类库 加载到内存中。 由于引导类加载器涉及到虚拟机本地实现细节,开发者无法直接获取到启动类加载器的引用, 所以 不允许直接通过引用进行操作。 2. 拓展类加载器(Extension classLoader): 扩展类加载器是由Sun的ExtClassLoader(sun.misc.Launcher$ExtClassLoader) 实现的,它负责将 <JAVA_HOME >/lib/ext或者由系统变量-Djava.ext.dir指定位置 中的类库 加载到内存中。开发者可以直接使用标准扩展类加载器。 3. 系统类 (应用类)加载器(Application classLoader): 系统类加载器是由 Sun 的 AppClassLoader(sun.misc.Launcher$AppClassLoader)实现的, 它负责将 用户类路径(java -classpath或-Djava.class.path变量所指的目录, 即当前类所在路径及其引用的第三方类库的路径,如第四节中的问题6所述)下的类库 加载到内存中。 开发者可以直接使用系统类加载器。 5. 设计模式:(框架中使用,是程序设计的高级思想) 1. 单例模式:(重点) 1. 概念:设计一个类,这个类只能创建一个对象。(限制创建对象对象数量) 2. 怎么设计? 控制创建对象的数量 => 创建对象通过new 调用构造方法 => 控制构造方法就能控制创建对象 控制调用构造方法 => 用private修饰 => 需要给外部提供一个对象 => 先在类中创建一个对象 (联想到封装) => 提供一个公共的 getInstance给外部返回一个对象 3. 步骤: 1. 私有化构造方法 2. 在类中创建一个对象,并且用private、static、final修饰 private为了避免在外部直接访问当前对象 static是为了在静态方法中可以返回当前类中的对象 final:可加可不加,加了可以保证不可修改,且提供获取效率 3. 提供一个public修饰的方法getInstance给外部返回一个对象 4. 单例模式获取方式: 1. 饿汉模式:预加载模式 (优化方式:静态内部类) 优点:在类加载的时候,就创建好对象放到静态区了,获取对象效率高。线程安全 缺点:类加载效率低,并且static修饰的成员占用资源。 2. 懒汉模式:懒加载模式 (优化方式:双重校验锁) 优点:节省资源,在需要的时候创建对象。 缺点:线程不安全。获取对象的时候,效率低 最简单的线程安全的方式:同步方法,效率低 更好的的线程安全的方式:双重校验锁 3. 枚举: public enum Singleton{ INSTANCE; } 5. 作用: 1. 全局配置文件 2. 全局日志文件 3. 节省资源,例如,回收站、资源管理器、游戏单开窗口 6. 使用选择: 一般用饿汉模式,如果有序列化(自己百度扩展)要求,用枚举。 7. 不需要频繁创建对象的时候;不允许多个对象 用单例 2. 装饰者模式:(了解) 装饰者模式指的是在不必改变原类(Input)文件和使用继承的情况下,动态地扩展一个对象的功能。 它是通过创建一个包装对象,也就是装饰来包裹真实的对象。 实现步骤 :通过对原类文件继承,对原有方法功能的基础上,增强新的功能 使用场景: 不必改变原类,并且对原有功能进行加强的时候,就需要用装饰者模式 3. 适配器模式:(了解) 适配器类: 命名方式: XxxXxxAdaptor 解决了两个功能的协同工作。(苹果充电器和华为手机充电的问题) 扩展性强,成本低廉 使用场景: 不同的类需要配合完成功能 4. 简单工厂模式:(了解)Spring框架中有用到 简单工厂模式:(后面可以用反射优化代码) 优点: 1.将生产和消费分离(解耦),即创建对象和使用对象的功能分离,便于管理 缺点: 1.扩展性弱,如果添加了新的产品,则需要修改工厂方法 使用场景: 适用于产品数量较少,且不经常改变的情况 6. ThreadLocal类 (掌握简单使用): 解决了线程安全问题,通过线程隔离有安全问题的数据实现的,底层是通过map保存线程id和值的。
⼤数据⾯试题 Big Data ⾯试题总结 JAVA相关 1-1)List 与set 的区别? ⽼掉⽛的问题了,还在这⾥⽼⽣常谈:List特点:元素有放⼊顺序,元素可重复 ,Set特点:元素⽆放⼊顺序,元素不可重复。 1-2)数据库的三⼤范式? 原⼦性、⼀致性、唯⼀性 1-3)java 的io类的图解 1-4)对象与引⽤对象的区别 对象就是好没有初始化的对象,引⽤对象即使对这个对象进⾏了初始化,这个初始化可以使⾃⼰的直接new的也可以是直接其他的赋值的, 那么背new或者背其他赋值的我们叫做是引⽤对象,最⼤的区别于 1-5)谈谈你对反射机制的理解及其⽤途? 反射有三种获取的⽅式,分别是:forName / getClass / 直接使⽤class⽅式 使⽤反射可以获取类的实例 1-6)列出⾄少五种设计模式 设计⽅式有⼯⼚法,懒加载,观察者模式,静态⼯⼚,迭代器模式,外观模式、、、、 1-7)RPC 原理? Rpc分为同步调⽤和⼀部调⽤,异步与同步的区别在于是否等待服务器端的返回值。Rpc的组件 有RpcServer,RpcClick,RpcProxy,RpcConnection,RpcChannel,RpcProtocol,RpcInvoker等组件, 1-8)ArrayList、Vector、LinkedList 的区别及其优缺点?HashMap、HashTable 的区别及优缺点? ArrayList 和 Vector 是采⽤数组⽅式存储数据的,是根据索引来访问元素的,都可以 根据需要⾃动扩展内部数据长度,以便增加和插⼊元素,都允许直接序号索引元素,但 是插⼊数据要涉及到数组元素移动等内存操作,所以索引数据快插⼊数据慢,他们最⼤ 的区别就是 synchronized 同步的使⽤。 LinkedList 使⽤双向链表实现存储,按序号索引数据需要进⾏向前或向后遍历,但 是插⼊数据时只需要记录本项的前后项即可,所以插⼊数度较快! 如果只是查找特定位置的元素或只在集合的末端增加、移除元素,那么使⽤ Vector 或 ArrayList 都可以。如果是对其它指定位置的插⼊、删除操作,最好选择 LinkedList HashMap、HashTable 的区别及其优缺点: HashTable 中的⽅法是同步的 HashMap 的⽅法在缺省情况下是⾮同步的 因此在多线程环境下需要做额外的同步机制。 HashTable 不允许有 null 值 key 和 value 都不允许,⽽ HashMap 允许有 null 值 key和 value 都允许 因此 HashMap 使 ⽤ containKey()来判断是否存在某个键。 HashTable 使⽤ Enumeration ,⽽ HashMap 使⽤ iterator。 Hashtable 是 Dictionary 的⼦类,HashMap 是 Map 接⼝的⼀个实现类。 1-9)使⽤ StringBuffer ⽽不是 String 当需要对字符串进⾏操作时,使⽤ StringBuffer ⽽不是 String,String 是 read-only 的,如果对它进⾏修改,会产⽣临时对象, ⽽ StringBuffer 是可修改的,不会产⽣临时对象。 1-10)集合的扩充 ArrayList list = new ArrayList(90000); list扩充多少次?? public ArrayList() { this(10); } 默认的扩充是10由此计算 1-11)java的拆包与封包的问题 System.out.println("5" + 2); 52 1-12)Java中Class.forName和ClassLoader.loadClass区别 Class.forName("xx.xx")等同于Class.forName("xx.xx",true,CALLClass.class.getClassLoader()),第⼆个参数(bool)表⽰装载类的时候是否 初始化该类,即调⽤类的静态块的语句及初始化静态成员变量。 ClassLoader loader = Thread.currentThread.getContextClassLoader(); //也可以⽤(ClassLoader.getSystemClassLoader()) Class cls = loader.loadClass("xx.xx"); //这句话没有执⾏初始化 forName可以控制是否初始化类,⽽loadClass加载时是没有初始化的。 1-13)hashMap与hashTable的区别 HashMap Hashtable ⽗类 AbstractMap Dictiionary 是否同步 否 是 k,v可否nu

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值