关于Java的诞生和发展网上比较多,在此就再也不赘述了,能够参考http://i.cnblogs.com/EditArticles.aspx?postid=4050233。html
1995年,Sun虽然推出了Java,但这只是一种语言,若是想开发复杂的应用程序,必需要有一个强大的开发类库。所以,Sun在1996年初发布了JDK 1.0。这是Sun公司发布的初版JDK,这个版本包括两部分:java
JRE 运行环境(Java Runtime Environment):包括核心API、集成API,用户界面API、发布技术、Java虚拟机(JVM)。
JDK 开发环境(Java Development Kit):开发环境包括编译Java程序的编译器(即javac命令)。linux
接着,Sun在1997年2月18日发布了JDK 1.1。JDK 1.1增长了JIT(即时编译)编译器。JIT和传统的编译器不一样,传统的编译器是编译一条,运行完后将其扔掉。而JIT会将常常用到的指令保存在内存中,当下次调用时就不须要从新编译了,经过这种方式让JDK在效率上有了较大提高。程序员
到1998年12月,Sun发布了Java历史上最重要的JDK版本:JDK l.2。伴随JDK l.2一同发布的还有jsp/servlet3、EJB4(Enterprise JavaBean)等规范,并将Java分红了J2EE、J2SE和J2ME三个版本。
J2EE 企业版(Java 2 Platform,Enterprise Edition):Java技术中应用最普遍的部分,J2EE提供了企业应用开发相关的完整解决方案。
J2SE 标准版(Java 2 Platform, Simple Edition):整个Java技术的核心和基础,它是J2ME和J2EE编程的基础。
J2ME 微缩版(Java Platform,Micro Edition): 主要用于控制移动设备和信息家电等有限存储的设备。
这标志着Java已经吹响了向企业、桌面和移动3个领域进军的号角,标志着Java已经进入Java 2时代,这个时期也是Java飞速发展的时期。在Java 2中,Java发生了不少革命性的变化,而这些革命性的变化一直沿用到如今,对Java的发展造成了深远的影响。直到今天,咱们还常常看到J2EE、J2ME等名称。
不只如此,JDK 1.2还把它的API分红了三大类:正则表达式
核心API:由Sun公司制定的基本的API,全部的Java平台都应该提供。这就是咱们日常所说的Java核心类库。算法
可选API:这是Sun为JDK提供的扩充API,这些API因平台的不一样而不一样。shell
特殊API:用于知足特殊要求的API。如用于JCA相JCE的第三方加密类库。apache
2002年2月,Sun发布了JDK历史上最为成熟的版本:JDK l.4.此时因为Compaq、Fujitsu、SAS、Symbian、IBM等公司的参与,使JDK 1.4成为发展最快的一个JDK版本。到JDK l.4为止,咱们已经可使用Java实现大多数的应用了。
在此期间.Java语言在企业应用领域大放异彩,涌现出大量基于Java语言的开源框架:Struts、WebWork、Hibemate、Spring等;大量企业应用服务器也开始涌现:WebLogic、WebSphere、JBoss等,这些都标志着Java语言进入了飞速发展时期。编程
2004年10月,Sun发布了万众期待的JDK 1.5,同时,Sun将JDK 1.5更名为Java SE 5.0。J2EE、J2ME也相应地更名Java EE和Java ME。JDK1.5增长了诸如泛型、加强的for语句、可变数量的形参、注释(Annotations)、自动拆箱和装箱等功能;同时,也发布了新的企业级平台规范如经过注释等新特性来简化EJB的复杂性,并推出了EJB3.0规范。还推出了本身的MVC框架规范:JSF,JSF规范相似于ASP.NET的服务器端控件,经过它能够快速地构建复杂的JSP界面。小程序
2006年l2月.Sun公司发布手JDK l.6(也被称为Java SE 6)。一直以来,Sun公司维持着大约2年发布一次JDK新版本盼习惯。但在2009年4月20日,Oracle宣布将以每股9.5美圆韵价格收购Sun。该交易的总价值约为74亿美圆。而Orack经过收购Sun公司得到了两项软件资产Java和Solaris。因而曾经表明一个时代的公面:Sun终于被“雨打风吹’’去,“江湖”上再也没有了Sun的身影。
Sun倒下了,不过Java的大旗依然“猎猎"做响。2007年11月,Google宣布推出一款基于Linux平台的开源手机操做系统:Android。Android的出现顺应了即将出现的移动互联网潮流,并且Android系统的用户体验很是好,所以迅速成为手机操做系统的中坚力量。
Ancfioid平台使用了Dalvik虚拟机来运行.dex文件。
Dalvik虚拟机的做用相似于JVM虚拟机,只是它并未遵照JVM规范而已。
Android使用Java语言来开发应用程序,这也给了Java语言一个新的机会。在过去的岁月中Java语言做为服务器端编程语言,已经取得了极大盼成劢;而Android平台的流行,则让Java谣衰得到了在客户端程序上大展拳脚的机会。
2011年7月28,Oracle公司终于如约一发布了Java SE 7此次版本。升级通过了将近5年时间。Java SE 7也是Oracle发布的第一个Java版本。Javat.SE 7虽然并未彻底知足所存人的指望,不过它也加入了很多新特性。
Java语言目前是最流行的面向对象编裎语言,与Java相似的程序设计语言还有C#、Ruby和Python等,它们在某些方面有本身的独特优点,所以都是Java语言有力的竞争者。
当年Microsoft也一度加入到Java语言阵营中,Microsoft曾经在Visual Studio中提供了Visual J++。正当Microsoft尽力在Visual J++基础上拓展Java功能,并使之与Windows操做系统紧密结合在一块儿时.Sun公司对Nticrosoft提出法律诉讼,称其违反了Java许可证协议中的条款,最终的结果是微软公司不得不中止Visual J++-产品的开发。
1998年10月以来,Microsoft就再也不发布新的Visual J++版本,并且致使Microsoft一直站在Java阵营的对立面,甚至在Windows XP系统中再也不提供Java运行时环境的支持。接下来,Microson推出了.NET平台,并发布了C#语言,不管从哪一个角度来看,C#程序设计语言都是Microsoft对Java语言的反击。自C#诞生之日起,关于C#与Java之间的论战便此起彼伏,至今不辍。
相同点:
(1) 从技术的角度来看
C#与Java是对传统面向对象程序设计在组件化软件时代的革新成果,可谓异曲同工,两种编程语言甚至有90%的重叠。Java和C撑都对传统C++-艰深、晦涩的语法和语义进行了改进。
(2) 在语法方面
二者都摒弃了C++中函数及其参数的const修饰、宏代换、全局变量和全局函数等华而不实的地方;
(3) 在继承方面
二者都采用了更易于理解的单继承和多接口的实现方案;
(4) 在源代码组织方面
都提出了声明与实现于虽体的逻辑封装。
不一样点:
C#也有其独特的优点:Microsoft提供的Visual Studio开发平台能够极好地提升C#程序的开发效率,并且Microsoft要比Java更善于利用Windows平台,当使用C#建立Windows服务、记录Windows事件日志、访问Windows注册表时,.NET确实更方便。Microsof提供了Windows任务相关的大量基类,容许程序员经过向导、拖放等操做来快速开发应用所以比较容易使用。
Java的设计宗旨独立于任何平台,天然不会提供太多的Windows特性。但这也正是Java语言的优点:跨平台。对于一个企业应用而言,永远没法肯定这个应用须要在怎样的平台上运行,若是你一旦选择了c撑语言,那么你的应用就只能局限在Windows平台上。所以,对于一个开放式的企业应用而言,一般会选择Java做为开发语言,而不是选择C#。
Ruby语言由日本人松本行弘于1993年起开始着手研发,经历2年时间,发布了Ruby语言的第一个版本:0.95版。据松本行弘的描述:他一直想发明一种语言,这种语言既能进行高效开发,又能让开发人员享受编程的快乐。
事实上,Ruby确实是一种很是简洁的解释型语言1,一种纯粹的面向对象编程语言。甚至比Java更纯粹(在Java语言里,还有基本数据类型等不是对象的变量,但在Ruby语言里,一切都是对象)。除此以外,Ruby还提供了许多额外的便捷功能,好比闭包、迭代和集合等,这些都是为了达到Ruby语言刨始人的梦想:让Ruby开发者能享受编程的快乐。
Ruby语言最大的特征就是简洁:
首先,它是一种弱类型的语言,变量无须声明,变量没有类型,所以Ruby的变量能够保存任何类型的数据:
其次,它还提供了强大的正则表达式支持,并支持运算符重载;
除此,Ruby也提供了许多额外的便捷功能,好比闭包、代码块、迭代器和集合等。
Ruby语言还有一个重要的优势:它也是彻底跨平台的,能够在任何操做系统上解释执行。
2004年,Ruby语言阵营里出现了一个优秀的MVC框架:Ruby On Rails,这个开发框架被宣传成现有企业框架的一个替代品。Ruby On Rails框架是一个真正意义上的敏捷开发框架,它提供了大量代码生成器,经过使用这些代码生成器能够极好地提升应用的开发效率。
相对于Java领域的众多开发框架而言。Ruby on Rails提供了一个“一站式”的解决方案.Ruby On Rails框架提供了Web层的MVC框架、持久层的ORM等解决方案。借助于Ruby这种动态语言的优点,整个应用的代码至关简洁,于是使得Ruby On Rails应用的开发很是快速。关于Rails框架和Java EE平台,算实是各有优点的。
Python由Guido于1989年年末开发,Python语言是基于ABC教学语言2的。ABC这种语言很是优美和强大,是专门为非专业程序员设计的.可是.ABC语言并无得到普遍的应用,Guido认为是非开放形成的。
Guido决心在Python中避免这一错误,所以Guido增强了Python和其余语言如C、C#和Java的结合性。同时,他还实现了许多ABC中闪现过但不曾实现的东西。Python的第一个实现是基于Mac机的。Python由ABC语言发展而来,主要受到了Modula-3(另外一种至关优美且强大的语言,为小型团体所设计)的影响,而且结合了UNIX shell和C的习惯。
Python是一种面向对象的解释型编程语言,也是一种功能强大而完善的通用型语言,已经具备十多年的发展历史,成熟且稳定。Python具备脚本语言中最丰富和强大的类库,足以支持绝大多很多天常应用。Python语言具备简洁而清晰的语法特色,适合完成各类高层任务,几乎能够在全部的主流操做系统上运行。
虽然Python也是一种解释型的脚本语言,但一些大规模的软件开发计划,好比Zope、Mnet、BitTorrent和Google都普遍地使用了该语言,而Python的支持者喜欢称它为高级动态编程语言,所以Python绝非JavaScript等只能处理简单任务的脚本语言所能比拟的。
Python的两大特点是可扩展性和清晰的语法。Python新的内置模块(module)能够用C或C++写成,也可为现成的模块加上Python-的接口。Python的设计者在设计它的时候认为:对于一个特定的一问题,只要有一种最好的方法来解决就行了。所以.Python甚至不是一种格式自由的语言.例如.它要求if语句的下一行必须向右缩进,不然不能经过编译。
Python在编程领域的占有率一直处于稳步上升之中根据最新的数据,Python排名第七。前六名分别是Java、C、VB、C++、PHP和Perl。最近,微软也将Python入.NET平台,相信Python盼将来会更好。
Java语言是一种特殊的高级语言,它既具备解释型语言的特征,也具备编译型语言的特征,由于Java程序要通过先编译,后解释两个步骤。
计算机高级语言接程序的执行方式能够分为编译型和解释型两种。
(1) 编译型语言
编译型语言是指使用专门的编译器,针对特定平台(操做系统)将某种高级语言源代码一次性“翻译”成可被该平台硬件执行的机器码(包括机器指令和操做数),并包装成该平台所能识别的可执行性程序的格式,这个转换过程称为编译( Compile)。编译生成的可执行性程序能够脱离开发环境,在特定的平台上独立运行.
有些程序编译结束后,还可能须要对其余编译好的目标代码进行连接,即组装两个以上的目标代码模块生成最终的可执行性程序,经过这种方式实现低层次的代码复用。由于编译型语言是—次性地编译成机器码,因此能够脱离开发环境独立运行,并且一般运行效率较高。但由于编译型语言的程序被编译成特定平台上的机器码,所以编译生成的可执行性程序一般没法移植到其余平台上运行;若是须要移植,则必须将源代码复制到特定平台上,针对特定平台进行修改,至少也须要采用特定平台上的编译器从新编译。现有的C、C++、FORTRAN、Pascal等高级语言都属于编译型语言。
(2) 解释型语言
解释型语言是指使用专门的解释器对源程序逐行解释成特定平台的机器码并当即执行的语言。解释型语言一般不会进行总体性的编译和连接处理,解释型语言至关于把编译型语言中的编译和解释过程混合到一块儿同时完成。能够认为:每次执行解释型语言的程序都须要进行一次编译,所以解释型语言的程序运行效率一般较低,并且不能脱离解释器独立运行。但解释型语言有一个优点:跨平台比较容易,只需提供特定平合的解释器便可,每一个特定平台上的解释器负责将源程序解释成特定平台的机器指令便可。解释型语言能够方便地实现源程序级的移植,但这是以牺牲程序执行效率为代价的。
现有的Ruby、Python等语言都属于解释型语言。
除此以外,还有一种伪编译型语言,如Visual Basic,它属于半编译型语言,并非真正的编译型语言。它首先被编译成P-代码,并将解释引擎封装在可执行性程序内,当运行程序时P-代码会被解析成真正的二进制代码。表面上看起来,Visual Basic能够编译生成可执行性的EXE文件,并且这个EXE文件也能够脱离开发环境,在特定平台上运行,很是像编译型语言。实际上,在这个EXE文件中,既有程序的启动代码,也有连接解释程序的代码,而这部分代码负责启动Visual Basic解释程序,再对Visual Basic代码进行解释并执行。
Java语言比较特殊,由Java语言编写的程序须要通过编译步骤,但这个编译步骤并不会生成特定平台的机器码,而是生成一种与平台无关的字节码(也就是.class文件)。固然,这种字节码不是可执行性的,必须使用Java解释器来解释挟行。所以,咱们能够认为:Java语言既是编译型语言,也是解释型语言。或者说,Java语言既不是纯粹的编译型语言,也不是纯粹的解释型语言Java程序的执行过程必须通过先编译,后解释两个步骤,如图所示。
Java语言里负责解释执行字节码文件的是Java虚拟机,即JVM(Java Virtual Machine)。JVM是可运行Java字节码文件的虚拟计算机。全部平台上的JVM向编译器提供相同的编程接口,而编译器只须要面向虚拟机,生成虚拟机能理解的代码,而后由虚拟机来解释执行。在一些虚拟机的实现中,还会将虚拟机代码转换成特定系统的机器码执行,从而提升执行效率。
当使用Java编译器编译Java程序时,生成的是与平台无关的字节码,这些字节码不面向任何具体平台,只面向JVM。不一样平台上的JVM都是不一样的,但它们都提供了相同的接口。JVM是Java程序跨平台的关键部分,只要为不一样平台实现了相应的虚拟机,编译后的Java字节码就能够在该平台上运行。显然,相同的字节码程序须要在不一样的平台上运行,这几乎是“不可能的”,只有经过中间的转换器才能够实现,JVM就是这个转换器。
JVM是一个抽象的计算机,和实际的计算机同样,它具备指令集并使用不一样的存储区域。它负责执行指令,还要管理数据、内存和寄存器。
注意: JVM的做用很容易理解,就像咱们有两支不一样的笔,但须要把同一个笔帽套在两支不一样的笔上,这就须要为这两支笔分别提供一个转换器。这个转换器: |
Sun公司制定的Java虚拟机规范,在技术上规定了JVM的统一标准,具体定义了JVM的以下细节:
Sun公司制定这些规范的目的是为了提供统一的标准,最终实现Java程序的平台无关性。
在开发Java程序以前,必须先完成一些准备工做,也就是在计算机上安装并配置Java开发环境,开发Java程序必须配置安装JDK。
JDK的全称是Java SE Development Kit,即Java 标准版开发包,是Sun提供的一套用于开发Java应用程序的开发包。它提供了编译、运行Java程序所需的各类工具和资源,包括Java编译器、Java行时环境以及经常使用的Java类库等。
JRE:Java运行时环境,它的全称是Java Runtime Environment,所以也被称为JRE它是运行Java程序的必需条件。
注意: 简单的说,JRE包含JVM。JVM是运行Java程序的核心虚拟机,而运行Java程序不只须要核心虚拟机,还须要其余的类加载器、字节码校验器以及大量的基础类库。JRE除了包含JVM以外,还须要包含运行Java程序的其余环境的支持。 |
通常而言,若是只是运行Java程序,咱们只安装JRE,无需安装JDk。若是要开发Java程序,则应选择安装JDK;固然,安装了JDK以后,就包 含了JRE,也能够运行Java程序。但若是只是运行Java程序,则须要在计算机上安装JRE。仅安装JVM是不够的。实际上,Sun网站上提供的就是 JRE的下载,并不提供单独的JVM下载。 |
Sun把Java分为Java SE、Java EE和Java ME三个部分,并且为Java SE和Java EE分别提供了JDK和Java EE SDK(Software Development Kit)两个开发包若是你只须要学习Java SE的编程知识,则能够下载标准的JDK;若是你还须要学习Java EE的相关内容也能够选择下载Java EE SDK,有一个Java EE SDK版本里已经包含了最新版的JDK,安装Java EE SDK就包含了JDK。
下载和安装步骤以下:
(1) 登录 http://www.oracle.com/technetwork/java/javase/downloads/index.html页面,下载Java SE Development Kit的最新版本
(2) 在该页面中咱们能够看到JDK不一样的版本,目前咱们能够看到,当前的最新版本是JDK 8,点击以下图2.1所示的页面连接,进入JDK 8的下载界面,如图2.2所示,在该页面中咱们能够看到两种类型的JDK版本,一个是带“java example”源码,一个是不带“java example”源码的。而且每种类型,针对不一样操做系统平台有对应不一样的JDK版本:
图 2.1
图 2.2
(3) 下载完成后:
(4) Linux的安装方式比较简单,用tar命令将JDK包解压,而后配置环境变量便可,不在赘述,能够参考http://www.cnblogs.com/sunddenly/p/3977809.html。
Windows平台上安装JDK的步骤:
1. 双击安装包EXE文件,开始安装后,第一个对话框提问是否赞成Java的许可协议,单机“接受”按钮,进入如图2.3所示的组件界面。
图 2.3
下面介绍一下JDK中的这些组件:
公共JRE:是一个独立的JRE系统,会单独安装在系统的其余路径下。公用JRE会向Internet Explore浏览器和系统中注册Java运行时环境。经过这种方式,系统中任何应用程序均可以使用公用JRE。但大部分时候,并不须要安装全部组件,在图2.3中我选择安装了两个组件,没有安装公共JRE。因为如今在网页上执行Applet的机会愈来愈少了,并且彻底可使用JDK目录下的JRE来运行Java程序,所以,没有太大必要安装公用JRE
Java开发工具:这是JDK的核心,包括编译java程序的必需命令工具。实际上,这个选项里已经包含了运行Java程序的JRE了,这个JRE会安装在JDK目录的子目录里这也是我不安装公共jre的缘由。
源代码:安装这个选项将会安装java全部核心类库的源代码。
(5) 选择安装路径,安装完成后可在JDK安装路径下看到以下文件路径。
图 2.4
注意: 用于编译java程序所使用的javac.exe命令也是用java写的,这个类就是lib目录下tool.jar文件中sun\tools\javac路径下的Main类JDK的bin目录下的java.exe文件实际上仅仅是包装了这个java类。不只如此,bin目录下的绝大部分命令都包装了tool.jar文件里的工具类。 |
path环境变量的值是一系列指令的路径:
在Windows操做系统中,当咱们执行一条命令时,Windows会根据Path环境变量来查找这个命令。若是能找到这个命令,则该命令可执行。不然将出现“‘xxxx’不是内部或外部命令,也不是可运行的程序或批处理文件”的提示。
在Linux操做系统中,Linux也会根据PATH环境变量来查找命令。
由于Windows操做系统不区分大小写 ,设置path和PATH并无区别;而Linux区分大小写,设置path和PATH是有区别的,所以只须要设置PATH环境变量便可。
Windows配置方式:
在windows中的配置方式以下图所示:
(1) 打开计算机,点击系统属性。
(2) 点击高级系统设置
(3) 点击环境变量
(4) 环境变量有两种类型,系统变量和用户变量,我选择系统变量,在系统变量里已经有一个Path变量,咱们双击它。
(5) 在该窗口的,变量值选项的最后加入:;%JAVA_HOME%\bin;%JAVA_HOME%\jre\bin
注意: 路径中'%--%'表示引用操做,JAVA_HOME表示一个系统变量,'%JAVA_HOME%',表示对该变量的引用,但该变量未设置,下面咱们将对其进行设置。 |
(6) 在系统变量栏,点击新建,新建一个JAVA_HOME变量,变量的值为jdk的安装路径。
(7) 设置CLASSPATH,设置变量值为:.;%JAVA_HOME%\lib;%JAVA_HOME%\lib\tools.jar,下面会介绍。
注意: 用户变量和系统变量没有太大的区别,只是用户变量只对当前用户有效,而系统变量对全部用户有效。为了减小本身的操做对他人的影响。对于当 前用户而言,设置用户变量和系统变量效果大体相同,只是系统变量在用户变量以前。可能出现这一种状况:若是Path系统变量的路径里包含了java命令而 PATH用户变量的路径里也包含了java命令,则优先执行Path系统变量路径里包含的java命令。 |
Linux配置方式:
在 linux 中环境变量的设置方法有如下三种(以PATH为例):
(1) 直接使用 export 命令
[root@hadoop ~]# export PATH=$PATH:/usr/local/jdk/bin
在Linux中,变量之间的分隔符是“:”Windows中是";",查看是否已经设置好,可使用命令 export 命令来查看,也能够直接$变量名来查看
[root@hadoop ~]# $PATH
-bash: .:/usr/local/hadoop/bin:/usr/local/zk/bin:/usr/local/zk/conf:/usr/local/jdk/bin:/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin:/root/bin:
[root@hadoop ~]#
注意: 直接使用 export 设置的变量,都是临时变量,也就是说退出当前的 shell ,为该变量定义的值便不会生效了。如何能让咱们定义的变量永久生效呢,那就看咱们的第二种定义的方式。 |
(2) 修改 /etc/profile
[root@hadoop ~]# vi /etc/profile
export PATH=$PATH:/usr/local/jdk/bin # 在配置文件中加入此行配置
须要注意的是:修改完这个文件必需要使用 如下命令在不用重启系统的状况下使修改的内容生效
[root@hadoop ~]# source /etc/profile 或者是:[root@hadoop ~]# . /etc/profile
查看设置是否生效
[root@hadoop ~]# echo $PATH
.:/usr/local/hadoop/bin:/usr/local/zk/bin:/usr/local/zk/conf:/usr/local/jdk/bin:/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin:/root/bin
[root@hadoop ~]#
配置已经生效
(3) 修改 .bashrc 文件(在当前用户 shell 下生效)
# vi /root/.bashrc?在里面加入:
export PATH=$PATH:/usr/local/jdk/bin
修改这个文件以后一样也须要使用 source 或者是 . 使配置文件生效。再来使用 echo $PATH看下变量是否生效
[root@hadoop ~]# echo $PATH
.:/usr/local/hadoop/bin:/usr/local/zk/bin:/usr/local/zk/conf:/usr/local/jdk/bin:/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin:/root/bin
[root@hadoop ~]#
export命令参数 功能:设置或显示环境变量,export的效力仅及于该此登录操做。 语法:export [-fnp][变量名称]=[变量设置值] 参数: -f 表明[变量名称]中为函数名称。 -n 删除指定的变量。变量实际上并未删除,只是不会输出到后续指令的执行环境中。 -p 列出全部的shell赋予程序的环境变量。 补充:在shell中执行程序时,shell会提供一组环境变量。 export可新增,修改或删除环境变量,供后续执行的程序使用。 一个变量建立时,它不会自动地为在它以后建立的shell进程所知。而命令export能够向后面的shell传递变量的值。当一个shell脚本调用并执行时,它不会自动获得原为脚本(调用者)里定义的变量的访问权,除非这些变量已经被显式地设置为可用。export命令能够用于传递一个或多个变量的值到任何后继脚本 |
咱们知道,编译和运行java程序必须通过两个步骤。
(1) 将源文件编译成字节码。
(2) 解释执行平台无关字节码。
上面的两个步骤分别须要使用java和javac两个命令。当咱们在操做系统的命令窗口,输入java和 javac命令,将看到以下提示:
‘java’不是内部或外部命令,也不是可运行的程序或批处理文件
‘javac’不是内部或外部命令,也不是可运行的程序或批处理文件
则说明咱们JDK的Path环境变量没有配置,须要按照上面的步骤进行配置。
设置完Path环境变量,咱们就可使用这两个命令来编译和执行咱们的java程序了。下面在Linux上,以运行一个小程序来分析javac和java的做用
步骤下所示:
[root@hadoop code]# pwd
/usr/code
[root@hadoop code]# vi HelloWorld.java
public class HelloWorld{
public static void main(String args[]){
System.out.println("HelloWorld");
}
}
[root@hadoop code]# javac HelloWorld.java
[root@hadoop code]# ls
HelloWorld.class HelloWorld.java
[root@hadoop code]# java HelloWorld
HelloWorld
由上面的操做可知,咱们的当前路径是/usr/code,在该路径下新建一个".java"源文件,编辑文件内容输入程序代码。而后通过javac编译生成".class"平台无关字节码,默认名称为其中类名,最后由“java 类名”命令来执行该字节码,输出最终结果“HelloWorld”。下面咱们输入javac命令,看一下它的参数:
注意:
当代码中含有包名的时候,编译以后,再次是“java 类名”,就会出现错误,我新建了一个带有包名的源文件以下:
[root@hadoop code]# vi PackageTest.java
package build.classes;
public class HelloWorld{
public static void main(String args[]){
System.out.println("HelloWorld");
}
}
[root@hadoop code]# ls
HelloWorld.class HelloWorld.java PackageTest.java
[root@hadoop code]# javac PackageTest.java
[root@hadoop code]# java PackageTest.java
Exception in thread "main" java.lang.NoClassDefFoundError: PackageTest/java
Caused by: java.lang.ClassNotFoundException: PackageTest.java
………………
Could not find the main class: PackageTest.java. Program will exit.
从上面的错误提示信息,咱们能够知道错误缘由是找不到PackageTest,其实者这不难理解,既然在代码中加入了“package build.classes;”这行代码,就表示了PackageTest这个源文件,是在build/classes路径下,但是并无该路径,因此会找不到,并且此时执行的时候不能用“java 类名”而应该是“java 包名.类名”。
因此一种解决方案以下:
[root@hadoop code]# javac -d ./ PackageTest.java
[root@hadoop code]# ls
build HelloWorld.class HelloWorld.java jar.jar PackageTest.class PackageTest.java
[root@hadoop code]# java build.classes.PackageTest
HelloWorld
咱们能够发现,在执行 javac -d ./ PackageTest.java时会在指定目录生成相应包名。
另外一种解决方案:感受最简单,直接把包名删除,在当前路径执行javac、java。
关于java和javac的详细介绍,可参考:
http://www.cnblogs.com/pengxl/archive/2010/12/10/1902082.html
http://www.cnblogs.com/JeffChen/archive/2008/01/16/1041783.html
总结: |
由下图javac的命令参数可知,classpath选项,主要用来指定用户类文件。那么由此可知,环境变量“CLASSPATH”也是用来定位类的,当咱们执行“java 类名时”JRE默认从当前位置搜索“.class”文件,当咱们在系统中设置了CLSSPATH时,就会从CLASSPATH路径查找“.class”字节码文件。
所以,只要在咱们的CLASSPATH对应的路径中有咱们的字节码文件时,那么就能够在任何路径下经过java命令来执行咱们的“.class”字节码文件。以下图所示,在/usr目录下有一个子目录,code中有一个子目录classes,code中存放的是".java"源码,classes中存放的是“.class”字节码,这样咱们就能够将字节码目录的路径设置为CLASSPATH,当咱们在任意路径上,经过“java 类名”来运行java程序。目录结构以下图所示,个人CLASSPATH设置的路径为:“/usr/code/classess”
|---usr
|---code
|---".java"
|---classes
|---".class"
我以,含有包名“build.classes”的PackageTest.java源码为例,对上述进行测试,步骤以下:
[root@hadoop code]#vi PackageTest.java
package build.classes;
public class PackageTest{
public static void main(String args[]){
System.out.println("HelloWorld");
}
}
[root@hadoop code]# ls
PackageTest.java
[root@hadoop code]# javac -d ./classes PackageTest.java
[root@hadoop code]# java build.classes.PackageTest
HelloWorld
我在学习ZooKeeper编程时,打算在Linux系统中,经过javac和java命令来执行一段程序,代码以下:
package org.zk; import java.io.IOException; import java.util.concurrent.CountDownLatch; import org.apache.zookeeper.CreateMode; import org.apache.zookeeper.KeeperException; import org.apache.zookeeper.WatchedEvent; import org.apache.zookeeper.Watcher; import org.apache.zookeeper.Watcher.Event.KeeperState; import org.apache.zookeeper.ZooDefs.Ids; import org.apache.zookeeper.ZooKeeper; public class CreateGroup implements Watcher{ private static final int SESSION_TIMEOUT=5000; private ZooKeeper zk; private CountDownLatch connectedSignal=new CountDownLatch(1); @Override public void process(WatchedEvent event) { if(event.getState()==KeeperState.SyncConnected){ connectedSignal.countDown(); } } public static void main(String[] args) throws IOException, InterruptedException, KeeperException { CreateGroup createGroup = new CreateGroup(); createGroup.connect("10.1.14.24:2181"); createGroup.create("zoo"); createGroup.close(); } private void close() throws InterruptedException { zk.close(); } private void create(String groupName) throws KeeperException, InterruptedException { String path="/"+groupName; if(zk.exists(path, false)== null){ zk.create(path, null/*data*/, Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT); } System.out.println("Created:"+path); } private void connect(String hosts) throws IOException, InterruptedException { zk = new ZooKeeper(hosts, SESSION_TIMEOUT, this); connectedSignal.await(); } }
须要注意的有两处:
(1) 程序中须要导入“.jar"包,以下图所示。
(2) 使用main函数的args参数,以下图所示。
对应的处理有两处:
(1) 将ZooKeeper的全部jar包,加入到CLASSPATH,以下图所示。
(2) 执行“java 类名”时,后面加入对应的参数,即主机号和节点名称,以下所示。
java org.zk.CreateGroup localhost:2181 zoo1
运行结果:
[root@hadoop code]# ls
build classes CreateGroup.java HelloWorld.java jar.jar PackageTest.java zookeeper.out
[root@hadoop code]# javac -d ./classes CreateGroup.java
[root@hadoop code]# java org.zk.CreateGroup localhost:2181 zoo1
2014-10-28 18:00:26,154 [myid:] - INFO [main:Environment@100] - Client environment:zookeeper.version=3.4.5-1392090, built on 09/30/2012
2014-10-28 18:00:26,157 [myid:] - INFO [main:Environment@100] - Client environment:host.name=hadoop
2014-10-28 18:00:26,157 [myid:] - INFO [main:Environment@100] - Client environment:java.version=1.6.0_24
2014-10-28 18:00:26,157 [myid:] - INFO [main:Environment@100] - Client environment:java.vendor=Sun Microsystems Inc.
2014-10-28 18:00:26,158 [myid:] - INFO [main:Environment@100] - Client environment:java.home=/usr/local/jdk/jre
2014-10-28 18:00:26,158 [myid:] - INFO [main:Environment@100] - Client environment:java.class.path=.:/usr/local/jdk/lib:……
……
Created:/zoo1
2014-10-28 18:00:26,236 [myid:] - INFO [main:ZooKeeper@684] - Session: 0x4956f7f1d70005 closed
2014-10-28 18:00:26,237 [myid:] - INFO [main-EventThread:ClientCnxn$EventThread@509] - EventThread shut down
[root@hadoop code]#
CLASSPATH环境变量经常设置为:.;%JAVA_HOME%\lib\dt.jar;%JAVA_HOME%\lib\tools.jar, 咱们知道CLASSPATH做用是,在经过“java 类名”解释执行java程序时,JRE会去搜索类文件,而CLASSPATH就为JRE提供了搜索路径。下面,我对上面的CLASSPATH环境变量作一下解释:
(1) 引用符和分隔符
在Windows上,分隔符:“;”
引用符:“%……%”
在Linux上, 分隔符:“:”
引用符:“$”
(2) 变量的意义
上面有三个路径,用两个分号隔开,它们的意义以下:
1.“.”:
‘点’也表示路径,他表示的是当前路径。由于在默认状况下,咱们会在当前路径下生成类文件,因此须要把该路径添加到CLASSPATH环境变量里
2.“%JAVA_HOME%\lib\dt.jar;%JAVA_HOME%\lib\tools.jar”:
编译和运行Java程序还须要JDK的lib路径下的dt.jar和tool.jar文件中的Java类,因此还须要把这两个文件添加到CLASSPATH环境变量里。
实际上,若是使用1.5以上版本的JDK,JRE会自动搜索当前路径下的类文件,并且使用Java编译和运行工具时系统能够自动加载dt.jar和tools.jar文件中的Java类,所以即便不设置CLASSPATH环境变量,也能运行java程序。但1.4之前版本的JDK都没这个功能,这意味着即便当前路径已经包含了HeIloWorld.class并在当前路径下执行“java HeIIoWorld",系统将同样提示找不到HeIIoWorld类。
若是使用更早版本的JDK,一般须要设置CLASSPATH环境变量。若是想在运行Java程序时临时指定JRE搜索Javtr类的路径,则可使用-classpath选项,即按以下格式来运行java命令:
java -classpath dirl;dir2,dir3……;dirN Java类
classpath选项的值能够是一系列的路径,多个路径之间在Windows平台上以分号";"隔开,在LinUX平台上财以冒号":"隔开。
若是在运行Java程序时指定了-classpath选项的值,JRE将严格按-classpath选项所指定的路径来搜索Java类,即不会在当前路径下搜索Java类,CLASSPATH环境变量所指定的搜索路径也再也不有效。
若是想使CLASSPATH环境变量指定的搜索路径有效,并且还会在当前路径下搜索Java类,则能够按以下格式来运行Java程序:
java -classpath %CLASSPATH%;.;dir1;dir2;dir3……;dirN java类
上面命令经过%CLASSPATH%来引用CLASSPATH环境变量的值,并在classpath选项的值里添加了一点,强制JRE在当前路径下搜索Java类。
传统的C/C++等编程语言,须要程序员负责回收已经分配的内存。显式进行垃圾回收是一件比较困难的事情,由于程序员并不老是知道内存应该什么时候被释放。若是一些分配出去的内存得不到及时回收,就会引发系统运行速度降低,甚至致使程序瘫痪,这种现象被称为内存泄漏。整体而言,显式进行垃圾回收主要有以下两个缺点。
(1) 程序忘记及时回收无用内存,从而致使内存泄漏,下降系统性能。
(2) 程序错误地回收程序核心类库的内存,从而致使系统崩溃。
与C/C++程序不一样,Java语言不须要程序员直接控制内存回收,Java程序的内存分配和回收都是由JRE在后台自动进行的。JRE会负责回收那些再也不使用的内存,这种机制被称为垃圾回收(GarbageCollection,也被称为GC)。一般JRE会提供一个后台线程来进行检测和控制,通常都是在CPU空闲或内存不足时自动进行垃圾回收,而程序员没法精确控制垃圾回收的时间相顺序等。
Java的堆内存是一个运行时数据区,用以保存类的实例(对象),Java虚拟机的堆内存中存储着正在运行的应用程序所创建的全部对象,这些对象不须要程序经过代码来显式地释放。通常来讲,堆内存的回收由垃圾回收来负责,全部的JVM实现都有一个由垃圾回收器管理的堆内存。垃圾回收是一种动态存储管理技术,它自动地释放再也不被程序引用的对象,按照特定的垃圾回收算法来实现内存资源的自动回收功能。
在C/C++中,对象所占的内存在程序结束运行以前一直被占用,被明确释放以前不能分配给其余对象;在Java中,当没有对象引用指向原先分配给某个对象的内存时,该内存便成为垃圾。JVM的一个超级线程会自动释放该内存区。垃圾回收意味着程序再也不须要的对象是“垃圾信息”,这些信息将被丢弃。
当一个对象再也不被引用时,内存回收它占领的空间,以便空间被后来的新对象使用。事实上,除了释放没用的对象外,垃圾回收也能够清除内存记录碎片。因为建立对象和垃圾回收器释放丢弃对象所占的内存空间,内存会出现碎片。碎片是分配给对象的内存块之间的空闲内存区,碎片整理将所占用的堆内存移到堆的一端,JVM将整理出的内存分配给新的对象。
优势:
垃圾回收能自动稃放内存空间,减轻编程的负担。这使Java虚拟机具备两个显著的优势。
(1) 垃圾回收机制能够很好地提升编程效率。
在没有垃圾回收机制时,可能要花许多时间来解决一个难懂的存储器问题。在用Java语言编程时,依靠垃圾回收机制可大大缩短期。
(2) 垃圾回收机制保护程序的完整性,垃圾回收是Java语言安全性策略的一个重要部分。
缺点:
垃圾回收的一个潜在缺点是它的开销影响程序性能。
(1) Java虚拟机必须跟踪程序中有用的对象,才能够肯定哪些对象是无用的对象,并最终释放这些无用的对象。这个过程须要花费处理器的时间。
(2) 垃圾回收算法的不完备性,早先采用的某些垃圾回收算法就不能保证100%收集到全部的废弃内存。
固然,随着垃圾回收算法的不断改进,以及软硬件运行效率的不断提高,这些问题均可以迎刃而解。
若是,您认为阅读这篇博客让您有些收获,不妨点击一下右下角的【推荐】。
若是,您但愿更容易地发现个人新博客,不妨点击一下左下角的【关注我】。
若是,您对个人博客所讲述的内容有兴趣,请继续关注个人后续博客,我是【Sunddenly】。本文版权归做者和博客园共有,欢迎转载,但未经做者赞成必须保留此段声明,且在文章页面明显位置给出原文链接,不然保留追究法律责任的权利。