打破双亲代理机制是否可以自己定义一个String 类

打破双亲代理机制是否可以自己定义一个 String 类

面试的时候被问了一个问题:能否打破双亲代理机制是否可以自己定义一个String 类,如果包名和java.lang.String 一致呢?
当时一脸懵逼,这方面的知识还是缺乏啊,下来之后写了代码之后试了一下,答案是:可以
详细一点回答是:使用非 “java.* ” 开头的包名是可以的,但包名不能以 “java.* ” 开头。

类加载器

package myClassLoader;

import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;

public class MyClassLoader extends ClassLoader {
    // 类加载器名称
    private String loaderName;

    public MyClassLoader(String loaderName) {
        // 让系统类加载器成为该 类加载器的父加载器
        super();
        this.loaderName = loaderName;
    }

    public MyClassLoader(ClassLoader parent, String loaderName) {
        // 显示指定该类加载器的父加载器
        super(parent);
        this.loaderName = loaderName;
    }

    @Override
    public String toString() {
        return this.loaderName;
    }

    /**
     * 获取.class文件的字节数组
     * 
     * @param name
     * @return
     * @throws FileNotFoundException 
     */
    private byte[] loaderClassData(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;
    }

    /**
     * 获取Class对象
     */
    @Override
    public Class<?> findClass(String name) throws ClassNotFoundException {
        byte[] b = null;
        try {
            b = loaderClassData(name);
        } catch (IOException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
        return defineClass(null, b, 0, b.length);
    }

    public static void main(String[] args) throws ClassNotFoundException, InstantiationException, IllegalAccessException, SecurityException, NoSuchMethodException, IllegalArgumentException, InvocationTargetException {

            MyClassLoader loader1 = new MyClassLoader("MyClassLoader");

           //两个自定String类,一个的包名为java.lang.String,第二个为Custom.String
            //Class<?> clazz = loader1.loadClass("D:/customclass/java/lang/String.class");
            Class<?> clazz = loader1.loadClass("D:/customclass/Custom/String.class");
            Object obj = clazz.newInstance();
            System.out.println(obj.getClass().getName());
            Method m = clazz.getMethod("hello", null);
            m.invoke(obj, null);
            System.out.println(clazz.getName());

    }
}

两个自定义string类

package java.lang;

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

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

运行结果

包名为 java.lang.String 的类

Exception in thread "main" java.lang.SecurityException: Prohibited package name: java.lang
    at java.lang.ClassLoader.defineClass1(Native Method)
    at java.lang.ClassLoader.defineClass(Unknown Source)
    at java.lang.ClassLoader.defineClass(Unknown Source)
    at myClassLoader.MyClassLoader.findClass(MyClassLoader.java:65)
    at java.lang.ClassLoader.loadClass(Unknown Source)
    at java.lang.ClassLoader.loadClass(Unknown Source)
    at myClassLoader.MyClassLoader.main(MyClassLoader.java:72)

包名为Custom.String的类

Custom.String
I'm String class
Custom.String

看到这里大家应该明白了吧,JVM基于安全考虑,自己写的类的package名称不可以”java. * ”开头,否则不会被类加载器加载。对于自己写java.lang.String,肯定也不会被加载成功了,如果是其它名字开头的,如Custom.String,就能正确加载


参考

Java自定义类加载器实现

展开阅读全文

没有更多推荐了,返回首页