一、问题

请在Eclipse中新建如下类,并运行它:

1 package java.lang;
2
3 public class Long {
4 public static void main(String[] args) {
5 System.out.println("Hi, i am here");
6 }
7 }

你能猜到它的运行如果吗? 不错,就是如下这个样子!

错误: 在类 java.lang.Long 中找不到 main 方法, 请将 main 方法定义为:
public static void main(String[] args)
否则 JavaFX 应用程序类必须扩展javafx.application.Application

为什么呢,明明我在Long方法类中定义了main方法,为什么说main方法没有定义呢?

本文将解决以上问题出现的原因。

二、ClassLoader的作用

我们都知道java程序写好以后是以.java(文本文件)的文件存在磁盘上,然后,我们通过(bin/javac.exe)编译命令把.java文件编译成.class文件(字节码文件),并存在磁盘上。但是程序要运行,首先一定要把.class文件加载到JVM内存中才能使用的,我们所讲的classLoader,就是负责把磁盘上的.class文件加载到JVM内存中,如下图所示:

你可以认为每一个Class对象拥有磁盘上的那个.class字节码内容,每一个class对象都有一个getClassLoader()方法,得到是谁把我从.class文件加载到内存中变成Class对象的。

三、ClassLoader层次结构

请执行如下程序:

 1 public class Test {
2 public static void main(String[] args) {
3 ClassLoader classLoader = Test.class.getClassLoader();
4 System.out.println(classLoader);
5
6 ClassLoader classLoader1 = classLoader.getParent();
7 System.out.println(classLoader1);
8
9 ClassLoader classLoader2 = classLoader1.getParent();
10 System.out.println(classLoader2);
11 }
12 }

它的输出是:

sun.misc.Launcher$AppClassLoader@2a139a55
sun.misc.Launcher$ExtClassLoader@7852e922
null

得到了 classLoader2就是null值了。这里其实有三个类加载器:

(1): 根类加载器(null)

它是由本地代码(c/c++)实现的,你根本拿不到他的引用,但是他实际存在,并且加载一些重要的类,它加载(%JAVA_HOME%\jre\lib),如rt.jar(runtime)、i18n.jar等,这些是Java的核心类。

(2): 扩展类加载器(ExtClassLoader)

虽说能拿到,但是我们在实践中很少用到它,它主要加载扩展目录下的jar包, %JAVA_HOME%\lib\ext

(3): 应用类加载器(AppClassLoader)

它主要加载我们应用程序中的类,如Test,或者用到的第三方包,如jdbc驱动包等。

这里的父类加载器与类中继承概念要区分,它们在class定义上是没有父子关系的。

四、Class加载时调用类加载器的顺序

当一个类要被加载时,有一个启动类加载器和实际类加载器的概念,这个概念请看如下分析

如上面的Test.class要进行加载时,它将会启动应用类加载器进行加载Test类,但是这个应用类加载器不会真正去加载他,而是会调用看是否有父加载器,结果有,是扩展类加载器,扩展类加载器也不会直接去加载,它看自己是否有父加载器没,结果它还是有的,是根类加载器。

所以这个时候根类加载器就去加载这个类,可在%JAVA_HOME%\jre\lib下,它找不到com.wangmeng.Test这个类,所以他告诉他的子类加载器,我找不到,你去加载吧,子类扩展类加载器去%JAVA_HOME%\lib\ext去找,也找不着,它告诉它的子类加载器 AppClassLoader,我找不到这个类,你去加载吧,结果AppClassLoader找到了,就加到内存中,并生成Class对象。
这个时间时候启动类加载器(应用类加载器)和实际类加载器(应用类加载器)是同一个.

这就是Java中著名的委托加载机制,看如下图:

我们再来看一下 java.lang.Long的加载,按上面分析,应该是由根类加载器加载得到的,此时启动类加载器是应用类加载器,但实际类加载器是根类加载器。

所以回到我们最开始那个问题,没有main方法是因为执行的根本不是我们自己写的类,执行的是java核心中的那个Long类,当然没有main方法了。 这样就防止我们应用中写的类覆盖掉java核心类。

Java中ClassLoader浅析.的更多相关文章

  1. [Java类加载器]Java中classLoader浅析.

    本文为在公司内部TD上写的一篇小文, 主要讲解java中classLoader基础知识, 现在拿来这里分享一下. 一.问题 请在Eclipse中新建如下类,并运行它: 1 package java.l ...

  2. 对java中classloader使用的一点理解(转)

    先简单介绍下java的classloader,网上资料很多,就说点关键的. Java 中的类加载器大致可以分成两类,一类是系统提供的,另外一类则是由 Java 应用开发人员编写的.系统提供的类加载器主 ...

  3. 浅析java中ClassLoader如何加载Class

    我的博客地址:https://blog.csdn.net/qq_41907991 ClassLoader是一个经常出现又让很多人望而却步的词.本文试图以最浅显易懂的方式来讲解ClassLoader,希 ...

  4. Java基础—ClassLoader的理解

    ##默认的三个类加载器 Java默认是有三个ClassLoader,按层次关系从上到下依次是: - Bootstrap ClassLoader - Ext ClassLoader - System C ...

  5. Java基础—ClassLoader的理解(转)

    默认的三个类加载器 Java默认是有三个ClassLoader,按层次关系从上到下依次是: Bootstrap ClassLoader Ext ClassLoader System ClassLoad ...

  6. Java中的Unsafe在安全领域的一些应用总结和复现

    目录 0 前言 1 基本使用 1.1 内存级别修改值 1.2 创建对象 1.3 创建VM Anonymous Class 2 利用姿势 2.1 修改值以关闭RASP等防御措施 2.2 创建Native ...

  7. 通过源码浅析Java中的资源加载

    前提 最近在做一个基础组件项目刚好需要用到JDK中的资源加载,这里说到的资源包括类文件和其他静态资源,刚好需要重新补充一下类加载器和资源加载的相关知识,整理成一篇文章. 理解类的工作原理 这一节主要分 ...

  8. 浅析Java中的final关键字

    浅析Java中的final关键字 谈到final关键字,想必很多人都不陌生,在使用匿名内部类的时候可能会经常用到final关键字.另外,Java中的String类就是一个final类,那么今天我们就来 ...

  9. 浅析Java中的访问权限控制

    浅析Java中的访问权限控制 今天我们来一起了解一下Java语言中的访问权限控制.在讨论访问权限控制之前,先来讨论一下为何需要访问权限控制.考虑两个场景: 场景1:工程师A编写了一个类ClassA,但 ...

随机推荐

  1. python 爬虫实例(四)

    环境: OS:Window10 python:3.7 爬取链家地产上面的数据,两个画面上的数据的爬取 效果,下面的两个网页中的数据取出来 代码 import datetime import threa ...

  2. mysql 转换NULL数据方法

    mysql 转换NULL数据方法<pre>SELECT info1,info2, IFNULL(info3,0) as info3 FROM `info1`;</pre>< ...

  3. ROS安装,配置

    ROS最好安装在Ubuntu系统,因为ROS目前在其他的系统中都是试验性的 ! <Learning ROS for Robotics Programming-- second Edition&g ...

  4. [转帖]进程上下文频繁切换导致load average过高

    进程上下文频繁切换导致load average过高 2016年6月26日admin发表评论阅读评论 http://www.361way.com/linux-context-switch/5131.ht ...

  5. MySQL 索引最佳实践

    原文请关注 这里 这是 文章 的翻译,在翻译过程中,会对其中涉及到的语句加上一些个人理解以及 SQL 语句的执行,并进行特别的标注. 1. 你做了一个很棒的选择,因为: 对于普通开发者和 DBA,理解 ...

  6. 剑指offer13:数组[奇数,偶数],奇数偶数相对位置不变。

    1. 题目描述 输入一个整数数组,实现一个函数来调整该数组中数字的顺序,使得所有的奇数位于数组的前半部分,所有的偶数位于数组的后半部分,并保证奇数和奇数,偶数和偶数之间的相对位置不变. 2. 思路和方 ...

  7. Java常用函数式接口--Supplier接口使用案例

    使用案例:

  8. .NET Core 使用swagger进行分组显示

    其实,和swagger版本管理类似;只是平时接口太多;不好供前端人员进行筛选. 下面进入主题: 首先: //注册Swagger生成器,定义一个和多个Swagger 文档 services.AddSwa ...

  9. interface Part2(定义接口)

    一. 在 C# 语言中,类之间的继承关系仅支持单重继承,而接口是为了实现多重继承关系设计的. 二. 一个类能同时实现多个接口,还能在实现接口的同时再继承其他类,并且接口之间也可以继承. 三. 无论是表 ...

  10. 编写Postgres扩展之五:代码组织和版本控制

    原文:http://big-elephants.com/2015-11/writing-postgres-extensions-part-v/ 编译:Tacey Wong 在关于编写Postgres扩 ...