零、 前言
在一个获取文件路径的代码内容上发现单元测试出现NullPointer, 但是这段代码却在服务器正常运行了两年多, 借此机会想认真探索下这两个方法的区别。
一、 区别
区别从代码输出结果来看比较清晰,
文件结构图:
以下为在多个场景下使用方式的代码:
package com.wenniuwuren.test; /** * 获取文件路径 * Created by wenniuwuren on 15/8/14. */ public class GetResourceTest { public static void main(String[] args) { // 带 “/” 的其实就是返回根目录 System.out.println("GetResourceTest.class.getResource(\"/\") -----> " + GetResourceTest.class.getResource("/")); System.out.println("GetResourceTest.class.getResource(\"/DD.DD\") -----> " + GetResourceTest.class.getResource("/DD.DD")); // ************************************************* // 返回当前路径 System.out.println("GetResourceTest.class.getResource(\"\") -----> " + GetResourceTest.class.getResource("")); System.out.println("GetResourceTest.class.getResource(\"AA.AA\") -----> " + GetResourceTest.class.getResource("AA.AA")); System.out.println("GetResourceTest.class.getResource(\"subtest/BB.BB\") -----> " + GetResourceTest.class.getResource("subtest/BB.BB")); System.out.println("GetResourceTest.class.getResource(\"../CC.CC\") -----> " + GetResourceTest.class.getResource("../CC.CC")); // 查找classloader root。 用 getClassLoader 最容易出问题, 因为是根据类加载器来的, 类加载器多种多样可能在不同环境下产生不同结果 GetResourceTest getResourceTest = new GetResourceTest(); System.out.println("getResourceTest.getClass().getClassLoader().getResource(\"\") -----> " + getResourceTest.getClass().getClassLoader().getResource("")); System.out.println("getResourceTest.getClass().getClassLoader().getResource(\"/\") -----> " + getResourceTest.getClass().getClassLoader().getResource("/")); /** * 从输出结果来看总结上述: Class.class.getResource("/") == Class.getClass().getClassLoader().getResource("") */ // 这是一种可以避免在不同Web容器下获取路径异常的方法 System.out.println("GetResourceTest.class.getProtectionDomain().getCodeSource().getLocation().getPath() -----> " + GetResourceTest.class.getProtectionDomain().getCodeSource().getLocation().getPath()); } }
二、 从源码角度分析
分析前先看个 Java 类加载的架构图, 有助于下文理解:
1. Class.getResource
算法基本为: 搜索策略为此类关联的类加载器实现的, 即这个方法委托给这个对象的类加载器,如果对象是被 Bootstrap 类加载器加载的, 则进入 ClassLoader.getSystemResource() 方法, 这个方法先找系统级别的类加载器(这个加载器是一般应用启动的类加载器), 如果找不到则使用虚拟机内置的类加载器。
如果传的参数是“/”则返回根路径, 传的是具体文件名就返回文件绝对路径。
public java.net.URL getResource(String name) { name = resolveName(name); ClassLoader cl = getClassLoader0(); if (cl==null) { // A system class. return ClassLoader.getSystemResource(name); } return cl.getResource(name); }
2. ClassLoader.getResource
会先从父加载器去找资源, 如果父加载器为 null 则从虚拟机内置加载器去查找(这步何上面最后一步相同), 如果还没有, 则去findResource() [可以重写这个方法自己实现个类加载器去寻找资源]去找。
public URL getResource(String name) { URL url; if (parent != null) { url = parent.getResource(name); } else { url = getBootstrapResource(name); } if (url == null) { url = findResource(name); } return url; }
版权声明:本文为博主原创文章,未经博主允许不得转载。
时间: 2024-10-13 22:26:06