
getClass():取得当前对象所属的Class对象
getClassLoader():取得该Class对象的类装载器
类装载器负责从Java字符文件将字符流读入内存,并构造Class类对象,在你说的问题哪里,通过它可以得到一个文件的输入流
getClass :
public final Class getClass()
Returns the runtime class of an object That Class object is the object that is locked by static synchronized methods of the represented class
Returns:
the object of type Class that represents the runtime class of the object
getClassLoader
public ClassLoader getClassLoader()
Returns the class loader for the class Some implementations may use null to represent the bootstrap class loader This method will return null in such implementations if this class was loaded by the bootstrap class loader
If a security manager is present, and the caller´s class loader is not null and the caller´s class loader is not the same as or an ancestor of the class loader for the class whose class loader is requested, then this method calls the security manager´s checkPermission method with a RuntimePermission("getClassLoader") permission to ensure it´s ok to access the class loader for the class
If this object represents a primitive type or void, null is returned
Returns:
the class loader that loaded the class or interface represented by this object
Throws:
SecurityException - if a security manager exists and its checkPermission method denies access to the class loader for the class
See Also:
ClassLoader, SecurityManagercheckPermission(javasecurityPermission), RuntimePermission
ClassgetClassLoader()的一个小陷阱:)
昨天我的code总在IntegerclassgetClassLoader()getResource("");这一句抛出空指针异常,定位为getClassLoader()返回null,查了一下jdk的文档,原来这里还有一个陷阱:
jdk中关于getClassLoader()的描述:
/
Returns the class loader for the class Some implementations may use
null to represent the bootstrap class loader This method will return
null in such implementations if this class was loaded by the bootstrap
class loader
<p> If a security manager is present, and the caller's class loader is
not null and the caller's class loader is not the same as or an ancestor of
the class loader for the class whose class loader is requested, then
this method calls the security manager's <code>checkPermission</code>
method with a <code>RuntimePermission("getClassLoader")</code>
permission to ensure it's ok to access the class loader for the class
<p>If this object
represents a primitive type or void, null is returned
.....
上面的英文可以用下面的话来理解:
装载类的过程非常简单:查找类所在位置,并将找到的Java类的字节码装入内存,生成对应的Class对象。Java的类装载器专门用来实现这样的过程,JVM并不止有一个类装载器,事实上,如果你愿意的话,你可以让JVM拥有无数个类装载器,当然这除了测试JVM外,我想不出还有其他的用途。你应该已经发现到了这样一个问题,类装载器自身也是一个类,它也需要被装载到内存中来,那么这些类装载器由谁来装载呢,总得有个根吧?没错,确实存在这样的根,它就是神龙见首不见尾的Bootstrap ClassLoader 为什么说它神龙见首不见尾呢,因为你根本无法在Java代码中抓住哪怕是它的一点点的尾巴,尽管你能时时刻刻体会到它的存在,因为java的运行环境所需要的所有类库,都由它来装载,而它本身是C++写的程序,可以独立运行,可以说是JVM的运行起点,伟大吧。在Bootstrap完成它的任务后,会生成一个AppClassLoader(实际上之前系统还会使用扩展类装载器ExtClassLoader,它用于装载Java运行环境扩展包中的类),这个类装载器才是我们经常使用的,可以调用ClassLoadergetSystemClassLoader() 来获得,我们假定程序中没有使用类装载器相关 *** 作设定或者自定义新的类装载器,那么我们编写的所有java类通通会由它来装载,值得尊敬吧。AppClassLoader查找类的区域就是耳熟能详的Classpath,也是初学者必须跨过的门槛,有没有灵光一闪的感觉,我们按照它的类查找范围给它取名为类路径类装载器。还是先前假定的情况,当Java中出现新的类,AppClassLoader首先在类传递给它的父类类装载器,也就是Extion ClassLoader,询问它是否能够装载该类,如果能,那AppClassLoader就不干这活了,同样Extion ClassLoader在装载时,也会先问问它的父类装载器。我们可以看出类装载器实际上是一个树状的结构图,每个类装载器有自己的父亲,类装载器在装载类时,总是先让自己的父类装载器装载(多么尊敬长辈),如果父类装载器无法装载该类时,自己就会动手装载,如果它也装载不了,那么对不起,它会大喊一声:Exception,class not found。有必要提一句,当由直接使用类路径装载器装载类失败抛出的是NoClassDefFoundException异常。如果使用自定义的类装载器loadClass方法或者ClassLoader的findSystemClass方法装载类,如果你不去刻意改变,那么抛出的是ClassNotFoundException。
这里jdk告诉我们:如果一个类是通过bootstrap 载入的,那我们通过这个类去获得classloader的话,有些jdk的实现是会返回一个null的,比如说我用 new Object()getClass()getClassLoader()的话,会返回一个null,这样的话上面的代码就会出现NullPointer异常.所以保险起见我们最好还是使用我们自己写的类来获取classloader("thisgetClass()getClassLoader()“),这样一来就不会有问题。
在Java里面,我们可以把一些类放到jar文件里面,然后用ClassLoader动态加载。例如:[java]viewplaincopyURLClassLoaderucl=URLClassLoadernewInstance(newURL[]{newURL("file:/sdcard/files/testjar")});Classclazz=uclloadClass("comtestTestClass");但是在Android上面,情况有所不同。首先第一个是jar文件的制作,Java里面直接把class文件打包到jar文件里面就可以了,但是Android的DalvikVM是不认Java的bytecode的,所以不能直接这么打包,而要用dx工具转成Dalvikbytecode才可以。当然,dx工具转了之后,jar包里面就不是class文件了,而是dex文件。第二个是,Android里面虽然也提供了URLClassLoader的实现,但是并不能用。要动态加载其它类,可以用的ClassLoader有:DexClassLoaderPathClassLoader其中,DexClassLoader可以加载apk,jar或者dex文件,例如:[java]viewplaincopyFilejarFile=newFile("/sdcard/testdex");if(jarFileexists()){DexClassLoadercl=newDexClassLoader(jarFiletoString(),"/sdcard/test",null,ClassLoadergetSystemClassLoader());Classc=clloadClass("comqihoo360testTest");}但是DexClassLoader要求指定一个可写的目录,即DexClassLoader构造函数的第二个参数,在上例中是/sdcard/test这个参数的含义是:directorywhereoptimizedDEXfilesshouldbewritten因为Dalvik在加载dex文件时,会动态进行优化,DexClassLoader要求指定优化后dex文件存放的位置。PathClassLoader的限制要一些,它只能加载已经安装到Android系统中的apk文件,也就是/data/app目录下的apk文件。其它位置的文件加载的时候都会出现ClassNotFoundException例如:[java]viewplaincopyPathClassLoadercl=newPathClassLoader(jarFiletoString(),"/data/app/",ClassLoadergetSystemClassLoader());为什么有这个限制呢?我认为这其实是当前Android的一个bug,因为PathClassLoader会去读取/data/dalvik-cache目录下的经过Dalvik优化过的dex文件,这个目录的dex文件是在安装apk包的时候由Dalvik生成的。例如,如果包的名字是comqihoo360test,Android应用安装之后都保存在/data/app目录下,即/data/app/comqihoo360test-1apk,那么/data/dalvik-cache目录下就会生成data@app@comqihoo360test-1apk@classesdex文件。在调用PathClassLoader时,它就会按照这个规则去找dex文件,如果你指定的apk文件是/sdcard/testapk,它按照这个规则就会去读/data/dalvik-cache/sdcard@testapk@classesdex文件,显然这个文件不会存在,所以PathClassLoader会报错。在Google修正这个问题之前,我们要么就只能用DexClassLoader,要么就只能用PathClassLoader加载已安装的apk了。
前文: JavaClassLoader与双亲委派机制
Android中的类加载器有三种, DexClassLoader 、 PathClassLoader 、 BootClassLoader 。
其中 BootClassLoader 是系统启动时预加载常用类的,一般使用不到。 DexClassLoader 、 PathClassLoader 都是继承自 BaseDexClassLoader 。
但 DexClassLoader 和 PathClassLoader 并没有重写 BaseDexClassLoader 中的任何方法,所以源码只需要看 BaseDexClassLoader 即可。
由于Android SDK并没有包含 BaseDexClassLoader ,所以需要到源码查询网站查询源码,如下:
复制这个java文件到对应源码文件夹下就可以在Android Studio中查看了。
通过调试可以看到,Android中普通类的加载器其实是 PathClassLoader 。追踪 PathClassLoaderfindClass 方法,即可获取Android的类加载过程:
PathClassLoaderfindClass -- 继承自 --> BaseDexClassLoaderfindClass()
-> BaseDexClassLoaderpathListfindClass()
-> DexPathListdexElementsforeach { elementfindClass() }
-> ElementfindClass()
-> ElementdexFileloadClassBinaryName()
-> DexFiledefineClass()
即类加载过程通过 BaseDexClassLoaderfindClass 、 DexPathListfindClass 、 ElementfindClass 、 DexFileloadClassBinaryName ,最终会落到 DexFiledefineClass 方法中,然后就交给native层了。
其中需要注意的是,在 BaseDexClassLoaderfindClass 的开头有这么一段:
这段是在Android 10新加入的,据称是为了实现 shared library 功能的,在之前的版本中没有这一段。
在上一节中知道了,类加载的流程如下:
BaseDexClassLoaderfindClass() ->
BaseDexClassLoaderpathListfindClass() ->
DexPathListdexElementsforeach { elementfindClass() } ->
ElementfindClass() ->
看 DexPathListfindClass 方法:
可以发现, DexPathList 加载类的方法是遍历 dexElements 数组依次加载,知道获取到值为止。所以可以通过修改这个数组,把新的dex文件放在数组的前面,使其加载修改后的类,从而实现热修复。
根据以上原理,写下这个工具类,有效性待验证:
1、Test t = new Test()Class clazz = tgetClass()Systemoutprintln(clazzgetCanonicalName())Systemoutprintln(clazzgetSimpleName())
2、public class TestReflect {public static void main(String[] args) throws Exception {TestReflect testReflect = new TestReflect()Systemoutprintln(testReflectgetClass()getName())// 结果 netxsoftlabbaikeTestReflect}}
3、Java程序
new 反射newIntence 走的流程应该是一样的,但是就是字节码解释加载时机不同。
java运行简单过程(编译、解释和执行)。
两者往往都是提前编译的(反射也有动态编译的)
new是事前解释,直接执行。
反射是运行期动态解释,然后才执行。
最直接的区别
>>new 不需要知道类的路径,而反射需要类的路径。
原因是因为new的类已经在自己的命名空间里面。JVM在执行一个java程序时,
类加载器会把需要的字节码都装载到自己的命名空间,不需要再次加载。性能上比反射要快。
反射是因为用户不确定加载哪个类,而想运行过程中加载需要类的方式。
类加载器在运行过程加载java字节码,并布局运行程序的内存空间,然后执行。它更灵活。
参考:
>
1、面向对象思想的继承是子类继承父类,父类被其它子类继承在JAVA虚拟机的容器中并没有直接接口获取;
2、如果是在一个项目内获取父类的子类继承情况,参考这个代码:
package find;import javaioFile;
import javaioIOException;
import javanetURL;
import javautilArrayList;
import javautilList;
import findtestIntf;
import findtestMan;
public class ClassUtil {
public static void main(String[] args) {
try {
Systemoutprintln("接口实现类:");
for (Class<> c : getAllAssignedClass(Intfclass)) {
Systemoutprintln(cgetName());
}
Systemoutprintln("子类:");
for (Class<> c : getAllAssignedClass(Manclass)) {
Systemoutprintln(cgetName());
}
} catch (ClassNotFoundException e) {
// TODO Auto-generated catch block
eprintStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
eprintStackTrace();
}
}
/
获取同一路径下所有子类或接口实现类
@param intf
@return
@throws IOException
@throws ClassNotFoundException
/
public static List<Class<>> getAllAssignedClass(Class<> cls) throws IOException,
ClassNotFoundException {
List<Class<>> classes = new ArrayList<Class<>>();
for (Class<> c : getClasses(cls)) {
if (clsisAssignableFrom(c) && !clsequals(c)) {
classesadd(c);
}
}
return classes;
}
/
取得当前类路径下的所有类
@param cls
@return
@throws IOException
@throws ClassNotFoundException
/
public static List<Class<>> getClasses(Class<> cls) throws IOException,
ClassNotFoundException {
String pk = clsgetPackage()getName();
String path = pkreplace('', '/');
ClassLoader classloader = ThreadcurrentThread()getContextClassLoader();
URL url = classloadergetResource(path);
return getClasses(new File(urlgetFile()), pk);
}
/
迭代查找类
@param dir
@param pk
@return
@throws ClassNotFoundException
/
private static List<Class<>> getClasses(File dir, String pk) throws ClassNotFoundException {
List<Class<>> classes = new ArrayList<Class<>>();
if (!direxists()) {
return classes;
}
for (File f : dirlistFiles()) {
if (fisDirectory()) {
classesaddAll(getClasses(f, pk + "" + fgetName()));
}
String name = fgetName();
if (nameendsWith("class")) {
classesadd(ClassforName(pk + "" + namesubstring(0, namelength() - 6)));
}
}
return classes;
}
}
以上就是关于java中 this.getClass().getCLassLoder()是什么意思全部的内容,包括:java中 this.getClass().getCLassLoder()是什么意思、如何使用URLClassLoader加载本地的Class文件、【Android】Android中的类加载等相关内容解答,如果想了解更多相关内容,可以关注我们,你们的支持是我们更新的动力!
欢迎分享,转载请注明来源:内存溢出
微信扫一扫
支付宝扫一扫
评论列表(0条)