先说一个问题,java获取路径的方式有很多,相对绝对,类本身或者servler环境等等。还有什么System.getProperty("user.dir");相关资源也比较多。
参考
今天遇到个什么问题呢:配置文件在src下和在某个包下两种情况。
长话短说:
一:
1.如果在src下使用方法:
InputStream ips = GetPath.class.getClassLoader().getResourceAsStream("first.properties");
2.如果在包下,与类在同一级目录:
InputStream ips2 = GetPath.class.getResourceAsStream("first.properties");
GetPath.class.getClassLoader().getResourceAsStream("包名/first.properties");
二:
编写一个程序,有一个方法获取当前目录。然后将项目打成jar包,在另一个web项目中调用该方法。
使用String path = gp.getClass().getResource("/").getPath(); 如果使用getClass().getClassLoader().get...报错 //有待研究考证
个人感觉,这个classloader只能在编译器的类中使用,像jar中的是已经编译好的。与动态性有关。 //有待研究考证
由上可见,都是classloader引起的问题。这个类加载器到底是什么? 要深挖的话,内容很多。。。简介看看了解下。
java是具有动态性,什么是动态性?有个最直观的例子:windows系统的即插即用,支持即插即用的设备可以在系统不重新启动的情况下既可以热把插使用。
而java的动态性表现在:
我们的程序可以不用全盘的重新编译就能对程序某部分进行更新,
C#也和java一样具有动态性,而且它的这种动态性表现更为直观:直接生成windows的动态连接库文件——dll文件。
而java生成的是class文件,class是怎么实现动态性的了,这个时候就全靠我们今天的主角:java的类加载器。
我们都知道所有的java类都是继承了object这个类,在object这个类中有一个方法:getclass(),这个方法返回的是一个Class类对象,具体见:
一旦一个类被载入JVM中,同一个类就不会被再次载入了(切记,同一个类)。
这里存在一个问题就是什么是“同一个类”?正如一个对象有一个具体的状态,即标识,一个对象始终和其代码(类)相关联(见文)。
同理,载入JVM的类也应该有一个具体的标识,我们知道:在JAVA中,一个类用其完全匹配类名(fully qualified class name)作为标识,这里指的完全匹配类名是包名和类名。
不过在JVM中一个类是用其全名再附加上一个加载类ClassLoader的实例作为唯一标识。
因此,如果一个名为Pg的包中,有一个名为Cl的类,被类加载器KlassLoader的一个实例对象kl1加载,生成Cl的对象,即C1.class(这里指类,而非对象)在JVM中表示为(Cl, Pg, kl1)。
这意味着两个类加载器的实例(Cl, Pg, kl1) 和 (Cl, Pg, kl2)是不同的,被它们所加载的类也因此完全不同,互不兼容的。
在java中每个类都是由某个类加载器的实体来载入的,因此在Class类的实体中,都会有字段记录载入它的类加载器的实体(当为null时,其实是指Bootstrap ClassLoader)。
在java类加载器中除了引导类加载器(既Bootstrap ClassLoader),所有的类加载器都有一个父类加载器(因为他们本身自己就是java类)。
而类的加载机制是遵循一种委托模式:当类加载器有加载类的需求时,会先请求其Parent加载(依次递归),如果在其父加载器树中都没有成功加载该类,则由当前类加载器加载。
java的类加载器分为以下几种:
1,Bootstrap ClassLoader,用C++实现,一切的开始,是所有类加载器的最终父加载器。负责将一些关键的Java类,如java.lang.Object和其他一些运行时代码先加载进内存中。
2,ExtClassLoader,用java实现,是Launcher.java的内部类,编译后的名字为:Launcher$ExtClassLoader.class 。此类由Bootstrap ClassLoader加载,但由于Bootstrap ClassLoader已经脱离了java体系(c++),所以Launcher$ExtClassLoader.class的Parent(父加载器)被设置为null;它用于装载Java运行环境扩展包(jre/lib/ext)中的类,而且一旦建立其加载的路径将不再改变。 3,AppClassLoader,用java实现,也是是Launcher.java的内部类,编译后的名字为:Launcher$AppClassLoader.class 。AppClassLoader是当Bootstrap ClassLoader加载完ExtClassLoader后,再被Bootstrap ClassLoader加载。所以ExtClassLoader和AppClassLoader都是被Bootstrap ClassLoader加载,但AppClassLoader的Parent被设置为ExtClassLoader。可见Parent和由哪个类加载器来加载不一定是对应的。个类装载器是我们经常使用的,可以调用ClassLoader.getSystemClassLoader() 来获得,如果程序中没有使用类装载器相关操作设定或者自定义新的类装载器,那么我们编写的所有java类都会由它来装载。而它的查找区域就是我们常常说到的Classpath,一旦建立其加载路径也不再改变。 4,ClassLoader:一般我们自定义的ClassLoader从ClassLoader类继承而来。比如:URLClassloader是ClassLoader的一个子类,而URLClassloader也是ExtClassLoader和AppClassLoader的父类(注意不是父加载器)。