`

java底层学习

 
阅读更多

下面文字来自《疯狂java讲义》:

1.类的加载、连接和初始化

当系统主动使用某个类,如果该类还未加载到内存中,系统会加载、连接、初始化三个步骤。
1.类的加载将类的Class文件读入内存中,并为之创建一个java.lang.Class对象。
Class文件的来源:
(1)从本地加载class文件
(2)从jar包中加载(系统api)
(3)从网络加载
2.类的连接:
连接阶段负责将类的二进制数据合并到JRE中。
3.类的初始化
类的初始化时机:
(1)创建类的实例:new操作符、反射创建实例、通过反序列化;
(2)调用某个类的静态方法;
(3)访问某个类的静态属性(final属性除外)

2.new操作符和newInstance()方法的区别

http://lvqingboy-163-com.iteye.com/blog/657599

在初始化一个类,生成一个实例的时候,newInstance()方法和new关键字除了一个是方法,一个是关键字外,最主要有什么区别?它们的区别在于创建对象的方式不一样,前者是使用类加载机制,后者是创建一个新类。那么为什么会有两种创建对象方式?这主要考虑到软件的可伸缩、可扩展和可重用等软件设计思想。

    Java中工厂模式经常使用newInstance()方法来创建对象,因此从为什么要使用工厂模式上可以找到具体答案。 例如:
    class c = Class.forName(“Example”);
    factory = (ExampleInterface)c.newInstance();

    其中ExampleInterface是Example的接口,可以写成如下形式:
    String className = "Example";
    class c = Class.forName(className);
    factory = (ExampleInterface)c.newInstance();

    进一步可以写成如下形式:
    String className = readfromXMlConfig;//从xml 配置文件中获得字符串
    class c = Class.forName(className);
    factory = (ExampleInterface)c.newInstance();

    上面代码已经不存在Example的类名称,它的优点是,无论Example类怎么变化,上述代码不变,甚至可以更换Example的兄弟类Example2 , Example3 , Example4……,只要他们继承ExampleInterface就可以。

    从JVM的角度看,我们使用关键字new创建一个类的时候,这个类可以没有被加载。但是使用newInstance()方法的时候,就必须保证:1、这个类已经加载;2、这个类已经连接了。而完成上面两个步骤的正是Class的静态方法forName()所完成的,这个静态方法调用了启动类加载器,即加载java API的那个加载器。

    现在可以看出,newInstance()实际上是把new这个方式分解为两步,即首先调用Class加载方法加载某个类,然后实例化。 这样分步的好处是显而易见的。我们可以在调用class的静态加载方法forName时获得更好的灵活性,提供给了一种降耦的手段。

    最后用最简单的描述来区分new关键字和newInstance()方法的区别:
    newInstance: 弱类型。低效率。只能调用无参构造。
    new: 强类型。相对高效。能调用任何public构造。

我的理解:

其实,newInstance()方法是显式加载

Class 类的 forName (String s)方法把自定义类 TestClass 加载进来,并通过 newInstance ()方法把实例初始化

new操作符是隐式加载:JRE在执行到 new 关键字的时候就会把对应的实例类加载进入内存。

3.深入讨论java的类加载器机制

 

http://www.blogjava.net/William/archive/2006/08/25/65804.html

Java 语言是一种具有动态性的解释型编程语言,当指定程序运行的时候, Java 虚拟机就将编译生成的 . class 文件按照需求和一定的规则加载进内存,并组织成为一个完整的 Java 应用程序。 Java 语言把每个单独的类 Class 和接口 Implements 编译成单独的一个 . class 文件,这些文件对于 Java 运行环境来说就是一个个可以动态加载的单元。正是因为 Java 的这种特性,我们可以在不重新编译其它代码的情况下,只编译需要修改的单元,并把修改文件编译后的 . class 文件放到 Java 的路径当中,等到下次该 Java 虚拟机器重新激活时,这个逻辑上的 Java 应用程序就会因为加载了新修改的 .class 文件,自己的功能也做了更新,这就是 Java 的动态性。

下面用一个简单的例子让大家对 Java 的动态加载有一个基本的认识:

[java] view plaincopy
 
  1. class TestClassA{  
  2.          publicvoid method(){  
  3.                    System.out.println("LoadingClassA");  
  4.          }  
  5.   
  6. }  
  7. public class ClassLoaderTest {  
  8.          publicstatic void main(String args[]){  
  9.                    TestClassAtestClassA = new TestClassA();  
  10.                    testClassA.method();  
  11.          }  
  12.   
  13. }   



编译后输入命令: java -verbose:class ClassLoaderTest ,执行文件。 (java-verbose:class:查看class的加载情况)

输出结构如图 (1)

图( 1 )

从运行结果我们可以看到, JRE ( JavaRuntime Environment )首先加载 ClassLoaderTest文件,然后再加载 TestClassA 文件,从而实现了动态加载。

 

1. 预先加载与依需求加载

Java 运行环境为了优化系统,提高程序的执行速度,在 JRE 运行的开始会将 Java 运行所需要的基本类采用预先加载( pre-loading )的方法全部加载要内存当中,因为这些单元在 Java 程序运行的过程当中经常要使用的,主要包括 JRE 的 rt.jar 文件里面所有的 .class 文件。

当 java.exe 虚拟机开始运行以后,它会找到安装在机器上的 JRE 环境,然后把控制权交给 JRE , JRE 的类加载器会将 lib 目录下的 rt.jar 基础类别文件库加载进内存,这些文件是 Java 程序执行所必须的,所以系统在开始就将这些文件加载,避免以后的多次 IO 操作,从而提高程序执行效率。

图( 2 )我们可以看到多个基础类被加载, java.lang.Object,java.io.Serializable 等等。

图( 2 )

相对于预先加载,我们在程序中需要使用自己定义的类的时候就要使用依需求加载方法( load-on-demand ),就是在 Java 程序需要用到的时候再加载,以减少内存的消耗,因为 Java 语言的设计初衷就是面向嵌入式领域的。

在这里还有一点需要说明的是, JRE 的依需求加载究竟是在什么时候把类加载进入内部的呢?

我们在定义一个类实例的时候,比如 TestClassA testClassA ,这个时候 testClassA 的值为 null ,也就是说还没有初始化,没有调用 TestClassA 的构造函数,只有当执行 testClassA = new TestClassA() 以后, JRE 才正真把TestClassA 加载进来。

 

2.隐式加载和显式加载

隐式加载:使用new操作符;

显示加载:使用forname()方法:Class 类的 forName (String s) 方法把自定义类 TestClass 加载进来,并通过 newInstance ()方法把实例初始化

Java 的加载方式分为隐式加载( implicit)和显示加载( explicit ),上面的例子中就是用的隐式加载的方式。所谓隐式加载就是我们在程序中用 new 关键字来定义一个实例变量, JRE 在执行到 new 关键字的时候就会把对应的实例类加载进入内存。隐式加载的方法很常见,用的也很多, JRE 系统在后台自动的帮助用户加载,减少了用户的工作量,也增加了系统的安全性和程序的可读性。

相对于隐式加载的就是我们不经常用到的显示加载。所谓显示加载就是有程序员自己写程序把需要的类加载到内存当中,下面我们看一段程序:

[java] view plaincopy
 
  1. class TestClass{  
  2.          publicvoid method(){  
  3.                    System.out.println("TestClass-method");  
  4.          }  
  5. }  
  6.   
  7.    
  8.   
  9. public class CLTest {  
  10.          publicstatic void main(String args[]) {  
  11.                   try{  
  12.                             Classc = Class.forName("TestClass");  
  13.                             TestClassobject = (TestClass)c.newInstance();  
  14.                             object.method();  
  15.                    }catch(Exceptione){  
  16.   
  17.                             e.printStackTrace();  
  18.                    }  
  19.   
  20.          }  
  21.   
  22. }   



我们通过 Class 类的 forName (String s) 方法把自定义类 TestClass 加载进来,并通过 newInstance ()方法把实例初始化。事实上 Class 类还很多的功能,这里就不细讲了,有兴趣的可以参考 JDK 文档。

Class 的 forName() 方法还有另外一种形式:Class forName(String s, boolean flag, ClassLoader classloader) , s 表示需要加载类的名称,flag 表示在调用该函数加载类的时候是否初始化静态区, classloader 表示加载该类所需的加载器。

forName (String s) 是默认通过ClassLoader.getCallerClassLoader() 调用类加载器的,但是该方法是私有方法,我们无法调用,如果我们想使用 Class forName(String s, boolean flag, ClassLoader classloader) 来加载类的话,就必须要指定类加载器,可以通过如下的方式来实现:

Test test = new Test();//Test 类为自定义的一个测试类;

ClassLoader cl = test.getClass().getClassLoader();

                                                                           //获取 test 的类装载器;

Class c =Class.forName("TestClass", true, cl);

因为一个类要加载就必需要有加载器,这里我们是通过获取加载 Test 类的加载器 cl 当作加载 TestClass 的类加载器来实现加载的。

 

3. 自定义类加载机制

之前我们都是调用系统的类加载器来实现加载的,其实我们是可以自己定义类加载器的。利用 Java 提供的 java.net.URLClassLoader 类就可以实现。下面我们看一段范例:

                 

[java] view plaincopy
 
  1. try{  
  2.   
  3.                             URLurl = new URL("file:/d:/test/lib/");  
  4.   
  5.                             URLClassLoaderurlCL = new URLClassLoader(new URL[]{url});  
  6.   
  7.                             Classc = urlCL.loadClass("TestClassA");  
  8.   
  9.                             TestClassAobject = (TestClassA)c.newInstance();  
  10.   
  11.                             object.method();  
  12.   
  13.                    }catch(Exceptione){  
  14.   
  15.                             e.printStackTrace();  
  16.   
  17.                    }  



 

我们通过自定义的类加载器实现了 TestClassA 类的加载并调用 method ()方法。分析一下这个程序:首先定义 URL 指定类加载器从何处加载类, URL 可以指向网际网络上的任何位置,也可以指向我们计算机里的文件系统 ( 包含 JAR 文件 ) 。上述范例当中我们从 file:/d:/test/lib/ 处寻找类;然后定义 URLClassLoader 来加载所需的类,最后即可使用该实例了。

 

4. 类加载器的阶层体系

讨论了这么多以后,接下来我们仔细研究一下 Java 的类加载器的工作原理:

当执行 java ***.class 的时候, java.exe 会帮助我们找到 JRE ,接着找到位于 JRE 内部的 jvm.dll ,这才是真正的 Java 虚拟机器 , 最后加载动态库,激活 Java 虚拟机器。虚拟机器激活以后,会先做一些初始化的动作,比如说读取系统参数等。一旦初始化动作完成之后,就会产生第一个类加载器―― Bootstrap Loader , Bootstrap Loader 是由 C++ 所撰写而成,这个 Bootstrap Loader 所做的初始工作中,除了一些基本的初始化动作之外,最重要的就是加载 Launcher.java 之中的 ExtClassLoader ,并设定其 Parent 为 null ,代表其父加载器为 BootstrapLoader 。然后 Bootstrap Loader 再要求加载 Launcher.java 之中的 AppClassLoader ,并设定其 Parent 为之前产生的 ExtClassLoader 实体。这两个加载器都是以静态类的形式存在的。这里要请大家注意的是, Launcher$ExtClassLoader.class 与Launcher$AppClassLoader.class 都是由 Bootstrap Loader 所加载,所以 Parent 和由哪个类加载器加载没有关系。

下面的图形可以表示三者之间的关系:

父类

父类

载入

载入

BootstrapLoader

       PARENT

AppClassLoader

PARENT

ExtClassLoader

这三个加载器就构成我们的 Java 类加载体系。他们分别从以下的路径寻找程序所需要的类:

BootstrapLoader :      sun.boot.class.path

ExtClassLoader:                java.ext.dirs

AppClassLoader:               java.class.path

这三个系统参量可以通过 System.getProperty() 函数得到具体对应的路径。大家可以自己编程实现查看具体的路径。

 

5. 总结

了解 Java 的类加载机制对我们熟练灵活运用 Java 语言,提高程序的运行效率有着非常重要的作用,知其然也要知其所以然,这样才能从整体提高程序的质量。

 

4.深入java底层

http://bigwhite.blogbus.com/logs/579744.html

 

在一个朋友的书架上发现王森著的《Java深度历险》一书,看了书的前言了解该书是关于Java底层技术内幕的。怀着好奇心浏览了一下,谈不上有太多收获,但也记下了一些自认为有益的两点。

Java xxx

我们在命令行下敲入:“java xxx”后会发生什么呢?

流程如下:

 

1.        找到JRE;

 

2.        找到JVM.dll;

 

3.        启动JVM,并进行初始化;

 

4.        产生Bootstrap Loader;

 

5.        载入ExtClassLoader;(Ext – Extended)

 

6.        载入AppClassLoader;

 

7.        加载xxx类。

 

书中提到Bootstrap Loader、ExtClassLoader和AppClassLoader构成了Java的“类加载器继承体系--class loader hierarchy”,其中BootstrapLoader是由C++编写的,其他两个是由Java写的。之所以成为“继承体系”是因为这三个loader之间是有联系的。Bootstrap Loader负责加载ExtClassLoader,后者ExtClassLoader就将其parent置为Bootstrap Loader。AppClassLoader较为特殊,虽然由Bootstrap载入,但是其parent却置为ExtClassLoader。其原因是为了实现“委托模型”。简述“委托模型”就是当类加载器有加载类的需求时,会先请求其parent使用其搜索路径帮助加载,如果其parent找不到,才使用自己的搜索路径进行加载。如上述所说当ExtClassLoader想载入AppClassLoader类时它首先请求其parent “Bootstrap Loader”帮忙,Bootstrap Loader将AppClassLoader载入后,由于这个载入是ExtClassLoader请求的,所以AppClassLoader的parent还是置为ExtClassLoader而不是Bootstrap Loader。

类的加载流程

类加载的时候遵循一个原则:“类加载器会依类的继承体系从上至下依次加载”。举个例子:“如果C继承了B并实现了接口I,而B有继承自A”,则类加载器在加载C时,加载的次序会是A-> B->I->C,(注:interface会如同class一样被Java编译器编译为独立的.class文件)

其实我对底层的东西并未给与太多的关注,如果在哪个项目中需要我去了解底层的话,我会去很好的学习。

 

额,顺便看看什么事DLL

http://baike.baidu.com/view/887.htm

动态链接库英文为DLL,是DynamicLink Library 的缩写形式,DLL是一个包含可由多个程序同时使用的代码和数据的库,DLL不是可执行文件。动态链接提供了一种方法,使进程可以调用不属于其可执行代码的函数。函数的可执行代码位于一个 DLL 中,该 DLL 包含一个或多个已被编译、链接并与使用它们的进程分开存储的函数。DLL 还有助于共享数据和资源。多个应用程序可同时访问内存中单个DLL 副本的内容。DLL 是一个包含可由多个程序同时使用的代码和数据的库。

分享到:
评论

相关推荐

    spring底层的学习之路

    本资料包"Spring学习之路"深入浅出地介绍了Spring的底层原理以及如何搭建一个完整的Spring MVC项目,对于初学者来说是极好的学习资源。 首先,我们要了解Spring的核心概念——IoC(Inversion of Control)和DI...

    java的底层开发工具

    Java的底层开发主要涉及到与操作系统直接交互,以实现更高效、更低级别的功能,这通常包括系统调用、原生接口(Native Interface)等技术。在Java中,JNI(Java Native Interface)是Java平台标准的一部分,它允许Java...

    java底层控件编程(绝无仅有,错过了别后悔)

    Java底层控件编程是Java GUI(图形用户界面)开发中的一个重要方面,它涉及到对Java Swing、JavaFX等库的深入理解和自定义组件的创建。在Java中,我们并不像其他语言那样有直接的“控件”概念,而是通过组件...

    java底层实现类 不用任何框架 值得新手学习和借鉴

    对于新手来说,深入学习Java底层实现不仅能够提升编程能力,还能帮助理解程序执行的本质。本资料集合着重于Java的基础和核心概念,不依赖任何框架,旨在提供一个纯净的学习环境。 在Java中,类是对象的蓝图,定义了...

    java相关底层源码

    总的来说,深入学习Java底层源码是提升编程技能和问题解决能力的有效途径。它不仅能够帮助我们理解Java平台的工作原理,还能让我们掌握如何利用这些知识来优化性能、调试问题和设计更高质量的代码。通过阅读和理解...

    java底层核心rt包源代码

    Java的rt.jar是Java运行时环境(Runtime Environment)的核心库...总之,研究Java底层核心rt包的源代码,是提高Java技术水平的重要途径,它能帮助开发者更高效地编写、调试和优化Java应用程序,提升软件开发的专业性。

    25本java高手合集 各种底层分析各种精华

    这份“25本Java高手合集”无疑是Java开发者们的一份宝贵资源,它涵盖了各种底层分析和精华知识点,旨在帮助读者深入理解Java的核心原理,提升编程技能。 在Java的世界里,JDBC(Java Database Connectivity)是连接...

    Java零基础学习指南java帮助文档 Java课件等学习资料.zip

    Java零基础学习指南java帮助文档 Java课件等...还包括了学习过程中可能需要用到的帮助文档,全方面满足嵌入式开发人员,Java底层驱动初学者以及Java应用程序开发爱好者的需要。 内容包括: java帮助文档 java程序设计

    java各类学习网站及论坛

    - **推荐理由**: 适合那些希望深入了解Java底层原理和技术细节的研究人员或高级开发者。 #### HuiHoo - **网址**: - **特点**: HuiHoo 是一个致力于推广开源软件和技术的组织,尤其是Java相关的项目和技术。 - **...

    Java jdk源码

    Java JDK源码是Java开发人员深入...总的来说,研究Java JDK源码是一次深入学习之旅,它可以帮助开发者从底层理解Java的工作方式,提升编程技艺,解决复杂问题,并且更好地利用Java的特性来设计高效、可靠的软件系统。

    深入Java集合学习系列

    这个学习系列将深入探讨Java集合框架的几个关键组件,包括ArrayList、HashMap以及LinkedHashMap。以下是对这些主题的详细解释: 首先,我们来看ArrayList。ArrayList是Java集合框架中的一种线性数据结构,属于List...

    79程序员练级攻略(2018):Java底层知识1

    【Java底层知识详解】 在Java开发领域,深入理解底层机制是提升编程技能的关键步骤。本文将探讨Java字节码编程、Java Agent以及JVM的相关知识,帮助Java程序员提升到更高的技术水平。 **Java字节码编程** Java字节...

    深入学习Java同步机制中的底层实现

    总结起来,Java的同步机制底层实现主要依赖于`AbstractQueuedSynchronizer`,它为多线程同步提供了灵活且高效的框架。`ReentrantLock`和`CountDownLatch`是基于AQS的典型应用,通过它们我们可以深入理解Java并发编程...

    JAVA学习资源推荐

    - **知识点**: 这个网站提供了丰富的Java研究资料,适合那些希望深入了解Java底层原理和技术细节的学习者。 - **特点**: 包含了大量的技术文章、研究报告和代码示例。 - **适用人群**: 高级开发者、研究人员以及对...

    java语言学习六大要点

    Java语言学习涵盖了许多关键点,对于想要进入Java开发领域的初学者来说,理解并掌握这些要点至关重要。以下是Java语言学习的六大要点的详细说明: 1. 掌握静态方法和属性: 静态方法和属性是Java中类的一个重要特性...

    Java学习文档.doc

    - **编程语言**:编程语言是人与计算机交流的工具,Java作为高级编程语言,简化了底层细节,使得程序员可以专注于应用程序的逻辑。 - **Java的特点**:Java有四大特性:简单性、面向对象、健壮性和安全性。它简化...

    java 3D 学习电子书

    在学习这些书籍时,读者可能会接触到OpenGL和Java Bindings for OpenGL (JOGL)的相关知识,因为Java 3D底层依赖于这些库来实现高性能的3D图形渲染。同时,理解基本的线性代数和向量几何也是学习3D编程的基础,因为...

    java的native关键字学习

    Java的`native`关键字在Java编程中扮演着特殊的角色,它是Java语言与底层操作系统交互的重要桥梁。本资源包是针对Java中的`native`关键字的学习资料,对于想要深入了解Java本地接口(JNI,Java Native Interface)的...

Global site tag (gtag.js) - Google Analytics