インタビューの質問:できるカスタムクラスjava.lang.Object

カスタムjava.lang.Object上位を作成します。

まず、プロジェクトに独自のjava.lang.Objectクラスを作成しよう:

package java.lang;

/**
 * 自己创建的java.lang.Object
 *
 * @author hujy
 * @version 1.0
 * @date 2020-01-30 01:12
 */
public class Object {
    static {
        System.out.println("hello");
    }
    public static void main(String[] args) {
        Object o = new Object();
    }
}

mainメソッドを実行し、印刷エラーが見つかりました:

私たちは、プロセスが最上位のBootstrapClassLoaderまで高いクラスローダにターンデリゲートで、クラスが最初にロードされるときに、親クラスローダ委譲の原則に従うことを知っています。java.lang.Objectのシステムクラス、優先順位は、最終的にシステムやネイティブjava.lang.Objectクラスをロードするため、エラーが主な方法を見つけることができないと報告され、BootstrapClassLoaderによってロードされます。


カスタムクラスローダを作成します。

この前提で、我々は、カスタムクラスローダを実装し、両親の委​​任メカニズムのバイパスにカスタムクラスローダを必要としています。

クラスローダ、オーバーライドのloadClassメソッドを継承MyClassLoaderカスタムクラスローダは、カスタムの負荷を実装します。

package com.hujy.classloader;

import java.io.IOException;
import java.io.InputStream;

/**
 * 自定义类加载器
 *
 * @author hujy
 * @date 2020-01-30 00:56
 */
public class MyClassLoader extends ClassLoader {

    @Override
    public Class<?> loadClass(String name) throws ClassNotFoundException {
        if (name == null || "".equals(name)) {
            throw new ClassNotFoundException();
        }
        InputStream is = null;
        try {
            String className = "/" + name.replace('.', '/') + ".class";
            System.out.println(className);
            // 在classpath路径下加载java/lang/Object.class文件
            is = getClass().getResourceAsStream(className);
            System.out.println(is);
            if (is == null) {
                throw new ClassNotFoundException();
            }
            byte[] bytes = new byte[is.available()];
            is.read(bytes);
            // 调用父类classLoader的defineClass方法
            // 将字节数组转换为Class实例
            return defineClass(name, bytes, 0, bytes.length);
        } catch (Exception e) {
            e.printStackTrace();
            throw new ClassNotFoundException();
        } finally {
            if (is != null) {
                try {
                    is.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }

    public static void main(String[] args) {
        MyClassLoader myClassLoader = new MyClassLoader();
        try {
            Class<?> clazz = Class.forName("java.lang.Object", true, myClassLoader);
            System.out.println("自定义类加载器:" + clazz.newInstance().getClass().getClassLoader());
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

主な機能を実行します。

ヒント:「java.langの」:DOはパッケージ名を使用しません。

defineClassソースに従ってください:

    protected final Class<?> defineClass(String name, byte[] b, int off, int len)
        throws ClassFormatError
    {
        return defineClass(name, b, off, len, null);
    }

    /* Determine protection domain, and check that:
        - not define java.* class,
        - signer of this class matches signers for the rest of the classes in
          package.
    */
    private ProtectionDomain preDefineClass(String name,
                                            ProtectionDomain pd)
    {
        if (!checkName(name))
            throw new NoClassDefFoundError("IllegalName: " + name);

        // Note:  Checking logic in java.lang.invoke.MemberName.checkForTypeAlias
        // relies on the fact that spoofing is impossible if a class has a name
        // of the form "java.*"
        if ((name != null) && name.startsWith("java.")) {
            throw new SecurityException
                ("Prohibited package name: " +
                 name.substring(0, name.lastIndexOf('.')));
        }
        if (pd == null) {
            pd = defaultDomain;
        }

        if (name != null) checkCerts(name, pd.getCodeSource());

        return pd;
    }

禁止されて上書きdefineClass論理パケットでは、我々はにカスタムクラスローダでは説明できなかった、「Javaの。」プロセスの開始後に、最終的なメソッドの名前を、禁止されている「Javaの。」クラスを開始します。

私たちは、カスタムjava.lang.Objectのmyjava.lang.Objectに変更され、その後、カスタムクラスローダloadClassメソッドは、いくつかの変更を行うには:「Javaの」負荷への親クラスローダの先頭に。

public class MyClassLoader extends ClassLoader {

    @Override
    public Class<?> loadClass(String name) throws ClassNotFoundException {
        if (name == null || "".equals(name)) {
            throw new ClassNotFoundException();
        } else if (name.startsWith("java.")) {
            // 由父类加载java.开头的类
            return super.loadClass(name);
        }
        InputStream is = null;
        try {
            String className = "/" + name.replace('.', '/') + ".class";
            System.out.println(className);
            // 在classpath路径下加载java/lang/Object.class文件
            is = getClass().getResourceAsStream(className);
            System.out.println(is);
            if (is == null) {
                throw new ClassNotFoundException();
            }
            byte[] bytes = new byte[is.available()];
            is.read(bytes);
            // 调用父类classLoader的defineClass方法
            // 将字节数组转换为Class实例
            return defineClass(name, bytes, 0, bytes.length);
        } catch (Exception e) {
            e.printStackTrace();
            throw new ClassNotFoundException();
        } finally {
            if (is != null) {
                try {
                    is.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }

    public static void main(String[] args) {
        MyClassLoader myClassLoader = new MyClassLoader();
        try {
            Class<?> clazz = Class.forName("myjava.lang.Object", true, myClassLoader);
            System.out.println("自定义类加载器:" + clazz.newInstance().getClass().getClassLoader());
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

再びmainメソッドを実行します。


概要

  • 通常の状況下では、プロセスは、それ自体がロードされ、負荷への高いクラスローダに委託順番に、高いロードされていない、親クラスローダ委譲メカニズムに従います。
  • あなたは両親のデリゲートメカニズム、オーバーライドするクラスのクラスローダを必要としているloadClassメソッドバイパスしたい場合は、一般的には推奨されません。
  • 最後のメソッドdefineClassの制限として、我々はとシステムクラスをロードすることはできません「のjava。」以降。
  • findClass一般的な方法ので、オーバーライドはloadClassが回避セキュリティリスクにシステムを持って、両親のデリゲートを弱体化させるのではなく、唯一のクラスパスの自己定義を達成ClassLoaderをロードするためにクラスローダを定義しました。
发布了162 篇原创文章 · 获赞 198 · 访问量 27万+

おすすめ

転載: blog.csdn.net/u011212394/article/details/104113847