您好,是这样的
JAVA里面对于类进行调用配置资源的文件数据,以thisgetClass()getResourceAsStream()来读取比较合适。
路径采用相对路径直接可以从工程的path路径去找。
主要问题是如果类中采用的是静态块的话,则该thisgetClass()报错,因为读静态块时,可能该对象并为构造,所以用this来指向当前对象不行。
ClassLoader提供了两个方法用于从装载的类路径中取得资源:
public URL getResource(String name);
public InputStream getResourceAsStream(String name);
这里name是资源的类路径,它是相对与“/”根路径下的位置。getResource得到的是一个URL对象来定位资源,而getResourceAsStream取得该资源输入流的引用保证程序可以从正确的位置抽取数据。
然而,程序中调用的通常并不是ClassLoader的这两个方法,而是Class的getResource和getResourceAsStream方法,因为Class对象可以从你的类得到(如YourClassclass或YourClassgetClass()),而ClassLoader则需要再调用一次YourClassgetClassLoader()方法,但根据JDK文档的说法,Class对象的这两个方法其实是“委托”(delegate)给装载它的ClassLoader来做的,所以只需要使用Class对象的这两个方法就可以了。
举例说明:
mypackageHelloclassgetResourceAsStream("/config/configini");
从classpath下的config相对路径中读取configini
希望能够帮到你,亲,若您还有其他的问题咨询,您可以进入TCL手机企业平台向客服咨询提问喔。
这个类和这个方法没有直接的关系,只是当后面的fileName是一个相对路径的时候,就会在当前这个ULTraCollectUtil这个类的当前位置开始查找资源文件,如果是个绝对路径的话,那前面的类是任意的Java类都可以了,因为classgetClassLoader()是为了获得一个类加载器,用来加载classpath下的class文件而已。
getResource返回的是一个URL对象,不要简单的认为是这个资源的绝对地址,这是一个Java中封装的对象,你可以去看看相关的API,里面有很多方法可以获取你当前资源文件的信息的。
另外,提醒一下,很少是单独用上面这个URL对象的,一般是通过这个URL对象来构造Java中的FIle对象以及Icon对象等等,这是一些参考的代码,希望对你有帮助,谢谢
File file3 = new File(TestclassgetClassLoader()getResource("javaapplication/file3txt")getFile());
String icon = "/image/1gif ";
buttonsetIcon(new ImageIcon(getClass() getResource(icon)));
Java类的加载是动态的,它并不会一次性将所有类全部加载后再运行,而是保证程序运行的基础类(像是基类)完全加载到jvm中,至于其他类,则在需要的时候才加载。这当然就是为了节省内存开销。
Java的类加载器有三个,对应Java的三种类:
Bootstrap Loader // 负责加载系统类 (指的是内置类,像是String,对应于C#中的System类和C/C++标准库中的类)
|
- - ExtClassLoader // 负责加载扩展类(就是继承类和实现类)
|
- - AppClassLoader // 负责加载应用类(程序员自定义的类)
三个加载器各自完成自己的工作,但它们是如何协调工作呢?哪一个类该由哪个类加载器完成呢?为了解决这个问题,Java采用了委托模型机制。
委托模型机制的工作原理很简单:当类加载器需要加载类的时候,先请示其Parent(即上一层加载器)在其搜索路径载入,如果找不到,才在自己的搜索路径搜索该类。这样的顺序其实就是加载器层次上自顶而下的搜索,因为加载器必须保证基础类的加载。之所以是这种机制,还有一个安全上的考虑:如果某人将一个恶意的基础类加载到jvm,委托模型机制会搜索其父类加载器,显然是不可能找到的,自然就不会将该类加载进来。
我们可以通过这样的代码来获取类加载器:
ClassLoader loader = ClassNameclassgetClassLoader();
ClassLoader ParentLoader = loadergetParent();
注意一个很重要的问题,就是Java在逻辑上并不存在BootstrapKLoader的实体!因为它是用C++编写的,所以打印其内容将会得到null。
前面是对类加载器的简单介绍,它的原理机制非常简单,就是下面几个步骤:
1装载:查找和导入class文件;
2连接:
(1)检查:检查载入的class文件数据的正确性;
(2)准备:为类的静态变量分配存储空间;
(3)解析:将符号引用转换成直接引用(这一步是可选的)
3初始化:初始化静态变量,静态代码块。
这样的过程在程序调用类的静态成员的时候开始执行,所以静态方法main()才会成为一般程序的入口方法。类的构造器也会引发该动作。
在我们的应用中,很多时候我们需要得到我们加载的类文件的路径,那么我们如何得到呢转载
在此我使用了一种方法,也许可以给需要的朋友们提供一种参考
看我的一个例子代码:
package orgzybase;
import javaioFile;
public class FileDemo {
public FileDemo() {
super();
}
//----------------------------------------
public String getFileDirectory() {
return null;
}
public String getCurrentWorkingDirectory() {
File f = new File("");
return fgetAbsolutePath();
}
public String getClassDirectory() {
String cla = thisgetClass()getClassLoader()getResource("")getPath();
return cla;
}
//----------------------------------------------------------------------------
public static void main(String[] args) {
FileDemo filedemo = new FileDemo();
Systemoutprintln(filedemogetCurrentWorkingDirectory());
Systemoutprintln(filedemogetClassDirectory());
}
}
运行的结果是:
G:\develop\demo\JSFDemo\
/G:/develop/demo/JSFDemo/classes/
由此,我们看到,我们可以通过类加载器来取得其在加载类时的类路径
getCurrentWorkingDirectory()方法得到市当前的工程的工作目录
以上是我的浅见,以供参考
每一个class都有一个Class对象。一个java文件经过编译,再生成的class文件中,就会创建一个Class对象。只有一个。他表示整个类的类型信息。
那么通常我们创建对象的方式又有几种呢?
五种:
1通过new 语句创建对象。
2通过静态工厂方法创建,比如AgetNewInstance();
3通过反射技术来实现。可以调用Class类或Constructor类的newInstance()方法。
4通过调用对象的clone()方法
5利用I/O流技术的反序列化来实现。
回归正题获取Class对象(实例)有三种方法:
1通过class的方式创建Class实例:类名class
2通过对象的getClass()方法获得。
3通过Class类的forName()方法来获得。
反射:可以说是一中技术手段,利用反射可以访问,检测,修改本身行为状态的一种方式。利用反射我们可以创建实例。
其实质就是:反编译:class---反编译成java文件。
所以说他是一个强大的工具,他可以创建更加灵活的代码,在运行期装配。使我们可以在运行期,动态的访问对象有哪些方法,动态,并可以为修改对象的属性,在运行期动态的访问任何对象的任何方法。
而且他降低了代码的耦合度,提高了可扩展性。
但是反射使用不当会成本很高。而且反射本身比直接硬编码更加复杂,所以一般性小程序尽量不要用,他适合一些对灵活度和可扩展性比较强的框架中。
而且他会模糊程序结构,不利于理解程序流程。可维护性不好。
注意:
双亲委派模式是在Java 12后引入的,其工作原理的是:
双亲委派模式优势
一般来说,例如程序 hellojar 执行到:
会按照双亲委派模型进行加载类 Demo 。如果 Demo 在 hellojar 内, AppClassLoader 就将其加载完成;但是如果例如 SPI 这种,既不在应用 hellojar 内又不在系统类路径内,那么就要抛弃双亲委派模型,获取 线程上下文类加载器 加载( 线程上下文类加载器 默认是 AppClassLoader ,此时的 线程上下文类加载器 肯定是自定义的类加载器)。
自定义一个 破坏双亲委派模型的类加载器 的方法:
深入理解Java类加载器
这里介绍2种加载方式:
例如要加载类:
将其编译为class文件,存放在路径 /Users/root/Projects/idea/my/com 。
这时要加载它:
对于SPI这种,就需要用到ServiceLoader加载。可以参考地址: >
双亲委托机制
类在进行类加载的时候,把加载任务托管给父类加载器,如能加载成功,则返回,否则依次向子类加载器递归尝试类加载。
意义:
①避免类的重复加载,父类加载已加载该类时,子ClassLoader就没有必要加载一次了。
②安全性,防止核心API被随意篡改。
ClassLoader
ClassLoader本身是一个抽象方法。它的主要实现类有BootClassLoader、PathClassLoader、DexClassLoader
BootClassLoader:用于加载Android Framwork层(SDK)的class文件
PathClassLoader:用于Android应用程序加载器,可以加载指定的dex和jar、zip、apk中的classesdex(系统使用)
DexClassLoader:用于加载指定的dex和jar、zip、apk中的classesdex。(供开发者使用)
拓展:
在API26之前。
optimizedDirectory 参数就是dexopt的产出目录(odex)。那 PathClassLoader 创建时,这个目录为null,就
意味着不进行dexopt?并不是, optimizedDirectory 为null时的默认路径为:/data/dalvik-cache。
在API26之后DexClassLoader也取消了optimizedDirectory
热修复相关
LoadClass:
findClass:PathClassLoader和DexClassLoader的父类BaseDexClassLoader中实现findClass。
BaseDexClassLoader中
PathClassLoader加载过后,pathlist 中存在一个Element数组,Element类中存在一个dexFile成员表示dex文件,即:APK中有X个dex,则Element数组就有X个元素。
总结:
可能看到这里我们比较乱了,理一下。一个类的加载经历了哪些。我们以PathClassLoader为例。
①加载一个类的时候,首先通过Class缓存寻找是否已经加载过该类。参考抽象类的loadClass方法。
②若在缓存中未找到该类,则交由父加载器加载该类。参考抽象类的loadClass方法。
③调用父加载器PathClassLoader的父类BaseDexClassLoader实现的findClass方法加载该类。
④PathClassLoader在初始化的时候调用父构造方法实例化DexPathList属性,DexPathList属性初始化时构造方法内通过makePathElements(或makeDexElements 不同API可能不同)加载APK内的dex文件生成Element数组。
⑤BaseDexClassLoader实现的findClass方法中顺序循环已存在的Element数组,通过Element中的DexFile加载类。。
⑥未找到,抛出类未找到异常。
热修复(multide 形式(thinker、qfix))
热修复的原理。我们只需在应用启动的时候,一般是在application方法中(因为class加载首先从缓存中加载),在应用启动后,经过PathClassLoader加载过后所有的类都在 pathList的Element 数组,把生成的Elment数组插入到PathList的Element数组的最前方。在加载类的时候就只会加载到我们需要更新的类了,因为是顺序寻找,找到就返回。(先从我们补丁的dex文件生成的element寻找,找不到再从APK的dex生成的element种寻找)。
热修复基本思路总结:
①获取到当前引用的PathClassLoader
②反射获取其中DexPathList属性:DexPathList pathList
③获取到补丁包pathdex文件的Element[]数组 pElements。参考PathClassLoader怎么把dex文件转换为Element数组的。于是我们反射执行DexPathList 中的makePathElements方法(视API而定)传入dex路径得到补丁包的element数组。
④获取pathList的dexElements数组。
⑤把补丁包的pElements数组合并到pathList的dexElements数组的前方,即newElements=pElements+dexElements
⑥反射赋值把newElements替换掉pathList的dexElements
热修复没这么简单,还需考虑混淆,API版本不同导致的使用makePathElements方法或makeDexElements方法等因素。
热修复(InstantRun 形式(Robust))待了解。
以上就是关于this.getclass ().getclassloader() .getresourceasstream(...)全部的内容,包括:this.getclass ().getclassloader() .getresourceasstream(...)、class.getClassLoader().getResource(xxx)是什么意思啊最后这个xxx和这个类有什么关系、java重新加载class文件等相关内容解答,如果想了解更多相关内容,可以关注我们,你们的支持是我们更新的动力!
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)