<small id='PAOevs'></small> <noframes id='2xfDV89ZQ'>

  • <tfoot id='U6LFoWtd8i'></tfoot>

      <legend id='Hi72N'><style id='pxu7TQc'><dir id='4Im83'><q id='TGXcv'></q></dir></style></legend>
      <i id='hzxOqVnekZ'><tr id='0ZDf2mrQ'><dt id='G7pXh3'><q id='jZNSCy'><span id='tjn7UKi2w'><b id='P9FM7TGD'><form id='0oALDe'><ins id='fTNmr'></ins><ul id='dOh9BYj1'></ul><sub id='s9udtA8USD'></sub></form><legend id='F12eNpxLw'></legend><bdo id='tUdAH73v'><pre id='8ZFp2PAj9'><center id='T2OgjHF7q'></center></pre></bdo></b><th id='V9cH8eb5'></th></span></q></dt></tr></i><div id='ZSIE'><tfoot id='mVnLR'></tfoot><dl id='Y1dm0AG'><fieldset id='zcs10Em'></fieldset></dl></div>

          <bdo id='VCdj6inM'></bdo><ul id='zwCag'></ul>

          1. <li id='zS7yJu'></li>
            登陆

            java 能不能自己写一个类叫 java.lang.System/String 正确答案

            admin 2019-09-06 279人围观 ,发现0个评论

            作者:一汪清水

            blog.csdn.net/tang9140/article/detail谷智鑫s/42738433

            最近学习了下java类加载相关的常识。然后看到网上有一道面试题是

            能不能自己写个类叫java.lang.System?

            网上供给的答案:一般不能够,但能够采纳特别办法抵达这个需求。所谓的特别办法指自己写个类加载器来加载java.lang.System抵达意图。

            首要标明下我的观念。上述答案彻底是误导读者,是不正确的答案。我就疑惑了网上怎样把这种彻底不正确的查找成果排在前面,并且简直搜到的都是这种不正确的答案。或许许多不明真相的朋友就这么被误导了,所以仍是期望咱们对网上的内容先持怀疑态度为好。下面具体阐明为什么。

            首要,摘录网上过错答案的具体解说

            “为了不让咱们写System类,类加载选用托付机制,这样能够确保爸爸们优先,爸爸们能找到的类,儿子就没有机会加载。而System类是Bootstrap加载器加载的,就算自己重写,也总是运用Java体系供给的System,自己写的System类底子没有机会得到加载。

            可是,咱们能够自己界说一个类加载器来抵达这个意图,为了防止双亲托付机制,这个类加载器也有必要是特别的。由于体系自带的三个类加载器都加载特定目录下的类,假如咱们自己的类加载器放在一个特别的目录,那么体系的加载器就无法加载,也便是终究仍是由咱们自己的加载器加载。”

            然后,阐明下上面解说中说到的一些概念

            类加载器可分为两类:一是发动类加载器(Bootstrap ClassLoadjava 能不能自己写一个类叫 java.lang.System/String 正确答案er),是C++完结的,是JVM的一部分;另一种是其它的类加载器,是Java完结的,独立于JVM,全部都承继自抽象类java.lang.ClassLoader。jdk自带了三品种加载器,分别是发动类加载器(Bootstrap ClassLoader),扩展类加载器(Extension ClassLoader),应用程序类加载器(Application ClassLoader)。后两种加载器是承继自抽象类java.lang.ClassLoader。关于这三种加载器各自的效果这儿不做具体阐明,有爱好的能够自己了解下。

            类加载器是有层次的

            一般是:自界说类加载器 >> 应用程序类加载器 >> 扩展类加载器 >> 发动类加载器

            上面的层次联系被称为双亲派遣模型(Parents Delegation Model)。除了最顶层的发动类加载器外,其他的类加载器都有对应的父类加载器。

            再简略说下双亲托付机制:假如一个类加载器收到了类加载的恳求,它首要不会自己测验去加载这个类,而是把这个恳求派遣给父类加载器,每一个层次的类加载器都是加此,因而一切的加载恳求终究抵达顶层的发动类加载器,只有当父类加载器反应自己无法完结加载恳求时(指它的查找规模没有找到所需的类),子类加载器才会测验自己去加载。

            再回去看下解说内容,我信任前面的部分咱们应该很看懂了,也没什么大问题。终究的假如部分“假如咱们自己的类加载器放在一个特别的目录,那么体系的加载器就无法加载,也便是终究仍是由咱们自己的加载器加载。” 我就不理解所以了,逻辑彻底不通。我想它的原意或许是,将自己的java.lang.System类放置在特别目录,然后体系自带的加载器无法加载,这样终究仍是由咱们自己的加载器加载(由于咱们自己的加载器知道其地点的特别目录)。这种说法如同逻辑上没有问题,那么咱们就来试验下了。

            代码验证

            测验类结构及内容如下:


            public class MyClassLoader extends ClassLoader{

            public MyClassLoader() {
            super(null);
            }

            @Override
            public Class
            try{
            String className = null;
            if(name.startsWith("java.lang")){
            className = "/" + name.replace('.', '/') + ".class";
            }else{
            classNajava 能不能自己写一个类叫 java.lang.System/String 正确答案me = name.substring(name.lastIndexOf('.') + 1) + ".class";
            }
            System.out.println(className);
            InputStream is = getClass().getResourceAsStream(className);
            System.out.println(is);
            if(is == null)
            return super.loadClass(name);

            byte[] b = new byte[is.available()];
            is.read(b);
            return defineClass(name, b, 0, b.length);
            }catch (Exception e) {
            e.printStackTrace();
            throw new ClassNotFoundException();
            }
            }
            }


            public class ClassLoaderTest {

            public static void main(String[] argsjava 能不能自己写一个类叫 java.lang.System/String 正确答案) throws ClassNotFoundException, InstantiationException, IllegalAccessException {
            ClassLoader myLoader = new MyClassLoader();
            Object obj = myLoader.loadClass("java.lang.Math").newInstance();
            System.out.println(obj);
            }

            }


            public final class Math {

            public static void main(String[] args) {
            System.out.println("hello world");
            }
            }


            public class MyMath {

            public static void main(String[] args) {
            System.out.println("hello world");
            }
            }


            上面的测验代码没用自界说java.lang.System类,由于测验代码用到了JDK自带的System类进行输出打印,会抵触,所以改用为自界说的java.lang.Math类。假如自界说的Math类能加载,那么自界说的System类相同能加载。

            咱们先直接运转下Math类,输出如下:

            提示Math类没有main办法。首要咱们要理解一个概念,当类初次自动运用时,有必要进行类的加载,这部分作业是由类加载器来完结的。依据双亲托付准则,Math类首要由发动类加载器去测验加载,很显然,它找到rt.jar中的java.lang.Math类并加载进内存(并不会加载咱们自界说的Math类),然后履行main办法时,发现不存在该办法,所以报办法不存在过错。也便是说,默许情况下JVM不会加载咱们自界说的Math类。

            再直接运转MyMath类,输出如下:

            留意赤色部分的内容。由仓库反常信息可知道,当应用程序类加载器类(AppClassLoader)测验加载MyMath类时,ClassLoader.java的479行抛出了SecurityException

            制止运用包名:java.lang。

            直接检查抽象类java.lang.Clasjava 能不能自己写一个类叫 java.lang.System/String 正确答案sLoader的preDefineClass办法代码,摘录如下:

            private ProtectionDomain preDefineClass(String name,
            ProtectionDomain protectionDomain)
            {
            if (!checkName(name))
            throw new NoClassDefFoundError("IllegalName: java 能不能自己写一个类叫 java.lang.System/String 正确答案" + name);

            if ((name != null) && name.startsWith("java.")) {
            throw new SecurityException("Prohibited package name: " +
            name.substring(0, name.lastIndexOf('.')));
            }
            if (protectionDomain == null) {
            protectionDomain = getDefaultDomain();
            }

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

            return protectionDomain;
            }


            能够看到假如加载的类全称号以“java.”最初时,将会抛出SecurityException,这也是为什么直接履行MyMath类会呈现SecurityException。

            照这样,咱们自界说的类加载器有必要承继自ClassLoader,其loadClass()办法里调用了父类的defineClass()办法,并终究调到preDefineClass()办法java 能不能自己写一个类叫 java.lang.System/String 正确答案,因而咱们自界说的类加载器也是不能加载以“java.”最初的java类的。咱们持续运转下ClassLoaderTest类,输出如下:

            赤色部分清楚标明,也是在preDefineClass办法中抛出的SecurityException。

            经过代码实例及源码剖析能够看到,关于自界说的类加载器,强行用defineClass()办法去加载一个以"java."最初的类也是会抛出反常的。

            总结

            不能自己写以"java."最初的类,其要么不能加载进内存,要么即便你用自界说的类加载器去强行加载,也会收到一个SecurityException。

            请关注微信公众号
            微信二维码
            不容错过
            Powered By Z-BlogPHP