`
T240178168
  • 浏览: 367370 次
  • 性别: Icon_minigender_1
社区版块
存档分类
最新评论

Java编译原理

    博客分类:
  • java
阅读更多
Java编译原理
1. 关于动态加载机制
学习Java比C++更容易理解OOP的思想,毕竟C++还混合了不少面向过程的成分。很多人都能背出来Java语言的特点,所谓的动态加载机制等等。当然概念往往是先记住而后消化的,可有多少人真正去体会过动态加载的机制,试图去寻找过其中的细节呢? 提供大家一个方法:在命令行窗口运行Java程序的时候,加上这个很有用的参数:
java verbose *.class
这样会清晰的打印出被加载的类文件,大部分是jdk自身运行需要的,最后几行会明显的看到自己用到的那几个类文件被加载进来的顺序。即使你声明了一个类对象,不实例化也不会加载,说明只有真正用到那个类的实例即对象的时候,才会执行加载。这样是不是大家稍微能明白一点动态加载了呢?^_^
2. 关于寻找class文件原理
建议大家在入门的时候在命令行窗口编译和运行,不要借助JCreator或者Eclipse等IDE去帮助做那些事情。尝试自己这样做:javac -classpath yourpath *.javajava -classpath yourpath *.class也许很多人都能看懂,设置classpath的目的就是告诉编译器去哪里寻找你的class文件. 不过至少笔者今日才弄懂JVM去查询类的原理,编译器加载类要依靠classloader, 而classloader有3个级别,从高到低分别是BootClassLoader(名字可能不准确) , ExtClassLoader, AppClassLoader.
这3个加载器分别对应着编译器去寻找类文件的优先级别和不同的路径:BootClassLoader对应jre/classes路径,是编译器最优先寻找class的地方。ExtClassLoader对应jre/lib/ext路径,是编译器次优先寻找class的地方,AppClassLoader对应当前路径,所以也是编译器默认找class的地方
其实大家可以自己写个程序简单的测试,对任何class,例如A, 调用new A().getClass().getClassLoader().toString() 打印出来就可以看到,把class文件放在不同的路径下再次执行,就会看到区别。特别注意的是如果打印出来是null就表示到了最高级 BootClassLoader, 因为它是C++编写的,不存在Java对应的类加载器的名字。
寻找的顺序是一种向上迂回的思想,即如果本级别找不到,就只能去本级别之上的找,不会向下寻找。不过似乎从Jdk1.4到Jdk1.6这一特点又有改变,没有找到详细资料。所以就不举例子了。告诉大家设计这种体系的是Sun公司曾经的技术核心宫力先生,一个纯种华人哦!
这样希望大家不至于迷惑为什么总报错找不到类文件,不管是自己写的还是导入的第三方的jar文件(J2ee中经常需要导入的)。
3. 关于jdk和jre
大家肯定在安装JDK的时候会有选择是否安装单独的jre,一般都会一起安装,我也建议大家这样做。因为这样更能帮助大家弄清楚它们的区别:
Jre 是java runtime environment, 是java程序的运行环境。既然是运行,当然要包含jvm,也就是大家熟悉的虚拟机啦,还有所有java类库的class文件,都在lib目录下打包成了jar。大家可以自己验证。至于在windows上的虚拟机是哪个文件呢? 学过MFC的都知道什么是dll文件吧,那么大家看看jre/bin/client里面是不是有一个jvm.dll呢?那就是虚拟机。
Jdk 是java development kit,是java的开发工具包,里面包含了各种类库和工具。当然也包括了另外一个Jre. 那么为什么要包括另外一个Jre呢?而且jdk/jre/bin同时有client和server两个文件夹下都包含一个jvm.dll。 说明是有两个虚拟机的。这一点不知道大家是否注意到了呢?
相信大家都知道jdk的bin下有各种java程序需要用到的命令,与jre的bin目录最明显的区别就是jdk下才有javac,这一点很好理解,因为 jre只是一个运行环境而已。与开发无关,正因为如此,具备开发功能的jdk自己的jre下才会同时有client性质的jvm和server性质的 jvm, 而仅仅作为运行环境的jre下只需要client性质的jvm.dll就够了。
记得在环境变量path中设置jdk/bin路径麽?这应该是大家学习Java的第一步吧, 老师会告诉大家不设置的话javac和java是用不了的。确实jdk/bin目录下包含了所有的命令。可是有没有人想过我们用的java命令并不是 jdk/bin目录下的而是jre/bin目录下的呢?不信可以做一个实验,大家可以把jdk/bin目录下的java.exe剪切到别的地方再运行 java程序,发现了什么?一切OK!
那么有人会问了?我明明没有设置jre/bin目录到环境变量中啊?
试想一下如果java为了提供给大多数人使用,他们是不需要jdk做开发的,只需要jre能让java程序跑起来就可以了,那么每个客户还需要手动去设置环境变量多麻烦啊?所以安装jre的时候安装程序自动帮你把jre的java.exe添加到了系统变量中,验证的方法很简单,大家看到了系统环境变量的 path最前面有“%SystemRoot%\system32;%SystemRoot%;”这样的配置,那么再去Windows/system32下面去看看吧,发现了什么?有一个java.exe。
如果强行能够把jdk/bin挪到system32变量前面,当然也可以迫使使用jdk/jre里面的java,不过除非有必要,我不建议大家这么做。使用单独的jre跑java程序也算是客户环境下的一种测试。
这下大家应该更清楚jdk和jre内部的一些联系和区别了吧?
鉴于上回写的一点感想大家不嫌弃,都鼓励小弟继续写下去,好不容易等到国庆黄金周,实习总算有一个休息的阶段,于是这就开始写第二篇了。希望这次写的仍然对志同道合的朋友们有所帮助。上回讲了Java动态加载机制、classLoader原理和关于jdk和jre三个问题。这次延续着讲一些具体的类库。
1. 关于集合框架类
相信学过Java的各位对这个名词并不陌生,对 java.util.*这个package肯定也不陌生。不知道大家查询API的时候怎么去审视或者分析其中的一个package,每个包最重要的两个部分就是interfaces和classes,接口代表了它能做什么,实现类则代表了它如何去做。关注实现类之前,我们应该先理解清楚它的来源接口,不管在j2se还是j2ee中,都应该是这样。那么我们先看这三个接口:List、Set、Map。
也许有些人不太熟悉这三个名字,但相信大部分人都熟悉ArrayList,LinkedList,TreeSet,HashSet,HashMap, Hashtable等实现类的名字。它们的区别也是满容易理解的,List放可以重复的对象集合,Set放不可重复的对象组合,而Map则放 这样的名值对, Key不可重复,Value可以。这里有几个容易混淆的问题:
到底Vector和ArrayList,Hashtable和HashMap有什么区别?很多面试官喜欢问这个问题,其实更专业一点应该这样问:新集合框架和旧集合框架有哪些区别?新集合框架大家可以在这些包中找since jdk1.2的,之前的如vector和Hashtable都是旧的集合框架包括的类。那么区别是?
a. 新集合框架的命名更加科学合理。例如List下的ArrayList和LinkedListb. 新集合框架下全部都是非线程安全的。建议去jdk里面包含的源代码里面自己去亲自看看vector和ArrayList的区别吧。当然如果是jdk5.0之后的会比较难看一点,因为又加入了泛型的语法,类似c++的template语法。
那么大家是否想过为什么要从旧集合框架默认全部加锁防止多线程访问更新到新集合框架全部取消锁,默认方式支持多线程?(当然需要的时候可以使用collections的静态方法加锁达到线程安全)笔者的观点是任何技术的发展都未必是遵循它们的初衷的,很多重大改变是受到客观环境的影响的。大家知道Java的初衷是为什么而开发的麽?是为嵌入式程序开发的。记得上一篇讲到classLoader机制麽?那正是为了节约嵌入式开发环境下内存而设计的。而走到今天,Java成了人们心中为互联网诞生的语言。互联网意味着什么?多线程是必然的趋势。客观环境在变,Java技术也随着飞速发展,导致越来越脱离它的初衷。据说Sun公司其实主打的是J2se,结果又是由于客观环境影响,J2se几乎遗忘,留在大家谈论焦点的一直是j2ee。
技术的细节这里就不多说了,只有用了才能真正理解。解释这些正是为了帮助大家理解正在学的和将要学的任何技术。之后讲j2ee的时候还会再讨论。
多扯句题外话:几十年前的IT巨人是IBM,Mainframe市场无人可比。微软如何打败IBM?正是由于硬件飞速发展,对个人PC的需求这个客观环境,让微软通过OS称为了第二个巨人。下一个打败微软的呢?Google。如何做到的?如果微软并不和IBM争大型机,Google借着互联网飞速发展这个客观环境作为决定性因素,避开跟微软争OS,而是走搜索引擎这条路,称为第3个巨人。那么第4个巨人是谁呢?很多专家预言将在亚洲或者中国出现, Whatever,客观环境变化趋势才是决定大方向的关键。当然笔者也希望会出现在中国。
2. 关于Java设计模式
身边的很多在看GOF的23种设计模式,似乎学习它无论在学校还是在职场,都成了一种流行风气。我不想列举解释这23种Design Pattern, 我写这些的初衷一直都是谈自己的经历和看法,希望能帮助大家理解。首先我觉得设计模式只是对一类问题的一种通用解决办法,只要是面向对象的编程预言都可以用得上这23种。理解它们最好的方法就是亲自去写每一种,哪怕是一个简单的应用就足够了。如果代码实现也记不住的话,记忆它们对应的UML图会是一个比较好的办法,当然前提是必须了解UML。
同时最好能利用Java自身的类库帮助记忆,例如比较常用的观察者模式,在java.util.*有现成的Observer接口和Observable这个实现类,看看源代码相信就足够理解观察者模式了。再比如装饰器模式,大家只要写几个关于java.io.*的程序就可以完全理解什么是装饰器模式了。有很多人觉得刚入门的时候不该接触设计模式,比如图灵设计丛书系列很出名的那本《Java设计模式》,作者: Steven John Metsker,大部分例子老实说令现在的我也很迷惑。但我仍然不同意入门跟学习设计模式有任何冲突,只是我们需要知道每种模式的概念的和典型的应用,这样我们在第一次编写 FileOutputStream、BufferedReader、PrintWriter的时候就能感觉到原来设计模式离我们如此之近,而且并不是多么神秘的东西。
另外,在学习某些模式的同时,反而更能帮助我们理解java类库的某些特点。例如当你编写原型(Prototype)模式的时候,你必须了解的是 java.lang.Cloneable这个接口和所有类的基类Object的clone()这个方法。即深copy和浅copy的区别:
Object.clone()默认实现的是浅copy,也就是复制一份对象拷贝,但如果对象包含其他对象的引用,不会复制引用,所以原对象和拷贝共用那个引用的对象。
深copy当然就是包括对象的引用都一起复制啦。这样原对象和拷贝对象,都分别拥有一份引用对象。如果要实现深copy就必须首先实现 java.lang.Cloneable接口,然后重写clone()方法。因为在Object中的clone()方法是protected签名的,而 Cloneable接口的作用就是把protected放大到public,这样clone()才能被重写。
那么又有个问题了?如果引用的对象又引用了其他对象呢?这样一直判断并复制下去,是不是显得很麻烦?曾经有位前辈告诉我的方法是重写clone方法的时候直接把原对象序列化到磁盘上再反序列化回来,这样不用判断就可以得到一个深copy的结果。如果大家不了解序列化的作法建议看一看 ObjectOutputStream和ObjectInputStream
归根结底,模式只是思想上的东西,把它当成前人总结的经验其实一点都不为过。鼓励大家动手自己去写,例如代理模式,可以简单的写一个Child类, Adult类。Child要买任何东西由Adult来代理实现。简单来说就是Adult里的buy()内部实际调用的是Child的buy(),可是暴露在main函数的却是Adult.buy()。这样一个简单的程序就足够理解代理模式的基本含义了。
分享到:
评论

相关推荐

    JAVA 编译原理 SLR(1)算法模拟器

    **JAVA编译原理SLR(1)算法模拟器** 在计算机科学中,编译原理是研究编程语言如何转换为机器可执行代码的学科。其中,SLR(1)算法是一种用于解析程序源代码的确定性有限自动机(DFA)构造方法,广泛应用于编译器的词法...

    java编译原理bo

    Java编译原理是计算机科学中的一个关键领域,它涉及到将高级编程语言,如Java,转换为机器可理解的指令的过程。这个过程分为多个阶段,包括词法分析、语法分析、语义分析以及中间代码生成。以下是对这些概念的详细...

    编译原理实验词法分析器 java语言版

    总的来说,这个实验提供了一个学习编译原理和Java语言的实践平台。通过完善词法分析器以支持带符号的常数,学生可以深入理解编译器的工作原理,增强处理文本解析和模式匹配问题的能力。对于Java开发者来说,这样的...

    编译原理java编译器

    本实验主要围绕“编译原理”展开,重点关注Java编译器的设计与实现,涵盖词法分析、语法分析、语义分析以及中间代码生成等关键步骤。 首先,我们来深入了解一下词法分析。词法分析是编译过程的第一步,它的任务是将...

    编译原理课程解释器构造Java源码

    在这个“编译原理课程解释器构造Java源码”中,我们可以推测这是一个基于Java编程语言实现的解释器项目。Java是一种广泛应用的面向对象的编程语言,它的跨平台特性使得它成为构建各种软件工具的理想选择,包括解释器...

    java实现简单的编译原理词法语法语义分析程序

    以上就是这个Java编译原理项目涉及的关键知识点,涵盖了从源代码到可执行代码转换的全过程,以及在此过程中可能出现的错误处理和恢复机制。这个项目为学习和实践编译原理提供了很好的实践平台。

    \编译原理\编译原理课程讲义\java图.

    本文将深入探讨Java编译原理,并通过一张简化的流程图来帮助理解Java代码如何从编写到最终执行的全过程。 #### 二、编译时间环境 Java程序的编译过程主要发生在开发者的计算机上。在这个阶段,开发者编写的源代码...

    编译原理 词法分析 语法分析 Java版【NFA DFA DFA最小化】[有注释版可下,请参看楼主其他分享]

    在编程和计算机科学领域,编译原理是理解计算机语言如何转化为机器可执行代码的基础。它主要涉及三个核心步骤:词法分析、语法分析和语义分析。本资源着重于词法分析和语法分析,特别是非确定性有限自动机(NFA)和...

    编译原理编辑器java

    这个过程通常分为多个阶段,包括词法分析、语法分析和语义分析,这些步骤在“编译原理编辑器java”中扮演着关键角色。 **词法分析**是编译过程的第一步,也称为扫描或标记。它负责识别源代码中的基本单元,即词法...

    编译原理实验二语法分析java代码JavaCC

    设计MiniC的上下文无关文法,利用JavaCC生成调试递归下降分析程序,以便对任意输入的符号串进行分析。本次实验的目的主要是加深对递归下降分析法的理解。 按照MiniC语言的语法规则检查词法分析输出的记号流是否符合...

    编译原理,词法分析,java

    在编程领域,编译原理是理解计算机语言处理过程的关键部分,它涉及词法分析、语法分析、语义分析以及代码生成等多个步骤。本资源主要关注的是词法分析,这一阶段的任务是从源代码文本中识别出一个个有意义的符号,即...

    Java编写的编译原理实验的程序

    通过这个Java编译原理的实验,你可以深入理解编译器如何将高级语言转化为机器可执行的指令,从而提升你的编程技能和对语言底层机制的理解。同时,掌握这些知识对于未来开发编译器、解释器或进行代码优化等高级任务都...

    编译原理课程设计(JAVA)

    本课程设计以“编译原理”为主题,采用JAVA语言进行实现,涵盖了BASIC高级语言的翻译程序设计,包括词法分析和语法分析等关键步骤。 词法分析,又称扫描器或词法生成器,是编译过程的第一步。它将源代码分解成一...

    java现代编译原理.rar_java 编译_现代编译原理_编译_编译原理_编译原理 java

    Java现代编译原理是计算机科学中的一个重要领域,它涉及到如何将高级编程语言,如Java,转换为机器可执行的指令。这个主题对于深入理解Java程序的生命周期和性能优化至关重要。以下是对这一领域的详细阐述: 首先,...

    编译原理实验(基于表达式的计算器ExprEval)

    在编程领域,编译原理是理解计算机如何处理高级语言的关键学科。这个实验“基于表达式的计算器ExprEval”旨在让学生深入理解编译器的工作原理,并通过实际操作来掌握编译技术。下面将详细介绍这个实验涉及的知识点,...

    编译原理教程

    4. **Java 编译原理**:虽然没有专门的文件名提及Java,但考虑到标签,我们可以推断教程可能包含有关Java编译器特定的细节,比如类文件结构、字节码和JVM的交互等。 5. **编译讲稿第11章zs.ppt**:这可能是一个专题...

    现代编译原理(虎书,包含c版和java版中英文,源码,全书答案)

    现代编译原理(虎书,包含c版和java版中英文,源码,全书答案) 1. 现代编译原理C语言描述_虎书 从官方网站下载的全书代码 现代编译原理课后题答案 Advanced.Compiler.Design.and.Implementation(Steven.S....

    编译原理课程设计

    在编译原理这一领域,课程设计通常涉及到构造一个简单的编译器或解释器,以便学生能够深入理解语言处理的各个方面。北华航天工业学院的这门课程设计专注于使用Java语言实现变量声明语句和赋值表达式语句,这是编程...

Global site tag (gtag.js) - Google Analytics