为什么不能自定义java.lang.String

如果直接写一个java.lang.String类,并写一个main方法,即

package java.lang;

public class String {

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

}


运行之后会抛一个异常:

错误: 在类 java.lang.String 中找不到主方法, 请将主方法定义为:
   public static void main(String[] args)


这是什么原因呢?

答案先给出:Java类加载机制为代理模式,先交给其父加载器去加载,如果父加载器加载不了,则由自己加载。我们自定义的类是由系统类加载器进行加载,而它的父加载器为扩展类加载器,扩展类加载器为引导类加载器。我们定义的java.lang.String最先由引导加载器加载,而它负责加载Java核心库,但java.lang.String正是系统中的类,已经被引导加载器记载过了,所以不再加载自定义的java.lang.String。但是系统的java.lang.String没有main方法,所以出现了上面的这个异常。

另外,自定义包不能以java.xxx.xxx开头,这是一种安全机制,,如果以java开头,系统直接抛异常。


再来看以下两段代码:

片段1:


片段1执行结果:




片段2:



对于代码片段1,虽然能加载自定义的com.test.String类,但是main方法中的String对象也是自定义的,不符合main方法的定义方式,故系统抛找不到mian方法。

对于代码片段2,在main方法的定义中把String类的路径写全了,明确了,故能正常执行。



原因

这里必须要提到java在加载类的过程。Java在加载类时,采用的是代理模式,即,类加载器在尝试自己去查找某个类的字节代码并定义它时,会先代理给其父类加载器,由父类加载器先去尝试加载这个类,以此类推。在说明代理模式背后的原因之前,首先需要说明一下Java虚拟机是如何判定两个java类是相同的。Java虚拟机不仅要看类的全名是否相同,还要看加载此类的类加载器是否一样。只有两者都相同,才认为两个类时相同的。即便是同样的字节代码,被不同的类加载器加载之后所得到的类,也是不同的,如果此时试图对这两个类的对象进行相互赋值,会抛出运行时异常ClassCastException。

了解到这一点,就可以理解代理模式的设计动机了。代理模式是为了保证Java核心库的类型安全,所有的Java应用都至少需要引用java.lang.Object类,也就是说在运行时,java.lang.Object这个类需要被加载到Java虚拟机中。如果这个过程由Java应用自己的类加载器来完成的话,很可能就存在多个版本的java.lang.Object类,可是这些类之间是不兼容的。通过代理模式,对于Java核心库的类的加载工作由引导类加载器统一完成,保证了Java应用所使用的都是同一个版本的Java核心库的类,是相互兼容的。


类加载器的树状组织结构

Java中的类加载器大致可以分为两类,一类是系统提供的,另外一类则是由Java应用开发人员编写的。系统提供的类加载器主要有下面三个:

  • 引导类加载器 (bootstrap class loader):它用来加载Java的核心库,是用原生代码实现的,并不继承自java.lang.ClassLoader。
  • 扩展类加载器 (extensions class loader):它用来加载Java的扩展库。Java虚拟机的实现会提供一个扩展库目录。该类加载器在此目录里面查找并加载Java类。
  • 系统类加载器 (system class loader):它根据Java应用的类路径(CLASSPATH)来加载Java类。一般来说,Java应用的类都是由它来完成加载的。可以通过ClassLoader.getSystemClassLoader()来或其它。

除了系统提供的类加载器以外,开发人员可以通过继承java.lang.ClassLoader类的方式实现自己的类加载器。

除了引导类加载器以外,所有的类加载器都有一个父类加载器。对于系统提供的类加载器来说,系统类加载器的父类加载器是扩展类加载器,而扩展类加载器的父类是引导类加载器。一般来说,开发人员编写的类加载器的父类加载器是系统类加载器。



  • 6
    点赞
  • 13
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值