自己写的java.lang.String能否被加载

如题,作者之前对于自己写的java.lang.String类能否被加载,一直感到非常困惑,今天写代码证实了一下。上干货。
自己写类加载器:

public class MyClassLoader extends ClassLoader{
	public Class findClass(String name){
		byte[] b = null;
		try {
			b = getByte(name);
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		return defineClass(null, b, 0, b.length);
	}
	private byte[] getByte(String name) throws IOException{
		FileInputStream in = new FileInputStream(name);
		byte[] b = new byte[1024];
		ByteArrayOutputStream out = new ByteArrayOutputStream();
		int len = 0;
		while((len = in.read(b)) != -1){
			out.write(b, 0, len);
		}
		out.close();
		b = out.toByteArray();
		return b;
	}
	}

测试类(path1,path2是我存放编译后的class文件的路径):

	public class MyClassLoaderTest {
	public static void main(String [] args) throws Exception{
		MyClassLoader myloader = new MyClassLoader();
		String path1 = "F:/Software/java/jdk/lib/String.class";
		String path2 = "E:/JavaTest/String.class";
		Class c = myloader.findClass(path1);
		//Class c = myloader.findClass(path2);
		Object obj = c.newInstance();
		System.out.println(obj.getClass().getName());
		Method m = c.getMethod("say", null);
		m.invoke(obj, null);
	}
	}

下面展示了几个自己写的package不同其他内容相同的String类,编译后放在上述path1,path2下各一份。

package java.lang;
	public class String{
		public void say(){
		System.out.println("I'm String class");
		}
	}

执行main方法,抛异常了:

Exception in thread "main" java.lang.SecurityException: Prohibited package name: java.lang

若String写成下面这样(注意,只是package有变化):

package java;
	public class String{
		public void say(){
		System.out.println("I'm String class");
		}
	}

抛异常如下:

Exception in thread "main" java.lang.SecurityException: Prohibited package name: java

把String的package改成下面这样

package java.haha;
	public class String{
		public void say(){
		System.out.println("I'm String class");
		}
	}

还是抛异常:

Exception in thread "main" java.lang.SecurityException: Prohibited package name: java.haha

注意,以上三个String类只是package不同。而从以上所抛异常来看,jvm不允许我们自己用"java"开头的package。再看以下两种package写法:

(不写package)

public class String{
		public void say(){
		System.out.println("I'm String class");
		}
	}

(package不以“java”开头)

package lang.java;
	public class String{
		public void say(){
		System.out.println("I'm String class");
		}
	}

两种写法的执行结果,输出如下:

	String
	I'm String class

这时候我自己写的String类,被我自己写的类加载器加载成功,并且通过反射机制,执行了其中的say()方法。

那么来一个小结吧。

  • 自己写的类的package名称不可以"java"开头,否则不会被类加载器加载。
    (所以自己写的java.lang.String,肯定也不会被加载成功了,即使是自己写的类加载器)
  • package不以"java"开头的类,可被成功加载。
    然而,此时的String类,类名叫做"String",还是叫做"Ergou",还是叫做"ZhangSan"都是无所谓的,只是非常普通的一个名字而已,因为所属的package不同,该String类和java.lang.String并不冲突。

结题:

至此,自己写的java.lang.String能否被加载已经有了答案。
不能!
能被加载的,是lang.java.String,是haha.String,是zhangsan.String…是所有package不以"java"开头的String。此时,他早已不是那个他…

以上,乃个人愚见,谨与诸君分享,若有不对之处,请不吝赐教。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章