java中Class.getResourceAsStream()和ClassLoader.getResourceAsStream()的区别

简介

Class.getResourceAsStream()和ClassLoader.getResourceAsStream()方法都是从项目中读取文件,但很容易被搞混。

ClassLoader

public class Client2 {

  public static void main(String[] args) {
    //从classpath下查询
    InputStream in = Client2.class.getClassLoader().getResourceAsStream("files/asd.txt");
    if (in == null) {
      return;
    }
    try (BufferedReader br = new BufferedReader(new InputStreamReader(in))) {
      String line = null;
      while ((line = br.readLine()) != null) {
        System.out.println(line);
      }
    } catch (IOException e) {
      e.printStackTrace();
    }
  }

}

我们将文件放到classpath下,ClassLoader会直接从classpath的根目录下查找文件,
输出结果为

this is a test file2

Class

public class Client3 {

  public static void main(String[] args) {
    InputStream in = Client3.class.getResourceAsStream("/files/asd.txt");
    if (in == null) {
      return;
    }
    try (BufferedReader br = new BufferedReader(new InputStreamReader(in))) {
      String line = null;
      while ((line = br.readLine()) != null) {
        System.out.println(line);
      }
    } catch (IOException e) {
      e.printStackTrace();
    }
  }

}

通过Class也可以读到classpath下的文件,我们需要以/开头。

public class Client4 {

  public static void main(String[] args) {
    InputStream in = Client4.class.getResourceAsStream("abc.txt");
    if (in == null) {
      return;
    }
    try (BufferedReader br = new BufferedReader(new InputStreamReader(in))) {
      String line = null;
      while ((line = br.readLine()) != null) {
        System.out.println(line);
      }
    } catch (IOException e) {
      e.printStackTrace();
    }
  }

}

我们将文件放到当前类所在的包下,这个时候不能以/开头,直接相对路径就可以。

源码分析

public final
    class Class<T> implements java.io.Serializable,
                              java.lang.reflect.GenericDeclaration,
                              java.lang.reflect.Type,
                              java.lang.reflect.AnnotatedElement {
	public InputStream getResourceAsStream(String name) {
        	name = resolveName(name);
        	ClassLoader cl = getClassLoader0();
        	if (cl==null) {
            		// A system class.
            		return ClassLoader.getSystemResourceAsStream(name);
        	}
   		//实际上还是调用ClassLoader的getResourceAsStream()方法
        	return cl.getResourceAsStream(name);
    	}
	//解析文件路径,如果以/开头,截取/之后的,不以/开头,当做相对路径,添加包的路径
	private String resolveName(String name) {
        	if (name == null) {
            		return name;
        	}
        	if (!name.startsWith("/")) {
            		Class<?> c = this;
            		while (c.isArray()) {
                		c = c.getComponentType();
           		}
            		String baseName = c.getName();
            		int index = baseName.lastIndexOf('.');
            		if (index != -1) {
                		name = baseName.substring(0, index).replace('.', '/')
                   		 +"/"+name;
            		}
       		} else {
            		name = name.substring(1);
        	}
        	return name;
    }

}

总结

ClassLoader从classpath下查询,不能以/开头,不能相对路径,Class如果以/开头,直接截取/之后的路径,不以/开头,转换成包含package的全路径,内部还是调用的ClassLoader的方法。

原文地址:https://www.cnblogs.com/strongmore/p/14070524.html