Java基础学习(一)---Java初识

一、Java介绍

关于Java的诞生和发展网上比较多,在此就不再赘述了,可以参考http://i.cnblogs.com/EditArticles.aspx?postid=4050233

1.1 Java的开发平台JDK

1.1.1 JDK 1.0----JRE+JDK

1995年,Sun虽然推出了Java,但这只是一种语言,如果想开发复杂的应用程序,必须要有一个强大的开发类库。因此,Sun在1996年初发布了JDK 1.0。这是Sun公司发布的第一版JDK,这个版本包括两部分:

  JRE 运行环境Java Runtime Environment):包括核心API、集成API,用户界面API、发布技术、Java虚拟机(JVM)。
  JDK
开发环境Java Development Kit):开发环境包括编译Java程序的编译器(即javac命令)。

1.1.2 JDK 1.1----+JIT

接着,Sun在1997年2月18日发布了JDK 1.1。JDK 1.1增加了JIT即时编译编译器。JIT和传统的编译器不同,传统的编译器是编译一条,运行完后将其扔掉。而JIT会将经常用到的指令保存在内存中,当下次调用时就不需要重新编译了,通过这种方式让JDK在效率上有了较大提升。

1.1.3 JDK 1.2----jsp/serverlet+EJB+Java版本

1998年12月,Sun发布了Java历史上最重要的JDK版本:JDK l.2。伴随JDK l.2一同发布的还有jsp/servlet3EJB4(Enterprise JavaBean)等规范,并将Java分成了J2EE、J2SEJ2ME三个版本。
  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因平台的不同而不同。

特殊API:用于满足特殊要求的API。如用于JCA相JCE的第三方加密类库。

1.1.4 JDK 1.4

2002年2月,Sun发布了JDK历史上最为成熟的版本:JDK l.4.此时由于Compaq、Fujitsu、SAS、Symbian、IBM等公司的参与,使JDK 1.4成为发展最快的一个JDK版本。到JDK l.4为止,我们已经可以使用Java实现大多数的应用了。
在此期间.Java语言在企业应用领域大放异彩,涌现出大量基于Java语言的开源框架StrutsWebWorkHibemateSpring等;大量企业应用服务器也开始涌现:WebLogic、WebSphere、JBoss等,这些都标志着Java语言进入了飞速发展时期。

1.1.4 JDK 1.5

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界面。

1.1.4 JDK 1.6

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谣衰获得了在客户端程序上大展拳脚的机会。

1.1.4 JDK 1.7

2011年7月28,Oracle公司终于如约一发布了Java SE 7这次版本。升级经过了将近5年时间。Java SE 7也是Oracle发布的第一个Java版本。Javat.SE 7虽然并未完全满足所存人的期望,不过它也加入了不少新特性。

1.2 Java的竞争对手及各自优势

Java语言目前是最流行的面向对象编裎语言,与Java类似的程序设计语言还有C#、Ruby和Python等,它们在某些方面有自己的独特优势,因此都是Java语言有力的竞争者。

1.2.1 C#简介和优势

当年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#。

1.2.2 Ruby简介和优势

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平台,算实是各有优势的。

  • Rails平台的简洁性、易用性会在中小型应用上发挥出更大的吸引力。
  • Java EE平台则提供了更多的选择,适合对技术有精准把握的开发者,用于解决有复杂需求的大型企业级应用。

1.2.3 Python简介和优势

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盼未来会更好。

1.3  Java程序运行机制

Java语言是一种特殊的高级语言,它既具有解释型语言的特征,也具有编译型语言的特征,因为Java程序要经过先编译,后解释两个步骤。

1.3.1  高级语言的运行机制

计算机高级语言接程序的执行方式可以分为编译型解释型两种。
(1) 编译型语言

编译型语言是指使用专门的编译器,针对特定平台(操作系统)将某种高级语言源代码一次性翻译成可被该平台硬件执行的机器码(包括机器指令和操作数),并包装成该平台所能识别的可执行性程序的格式,这个转换过程称为编译( Compile)。编译生成的可执行性程序可以脱离开发环境,在特定的平台上独立运行.

有些程序编译结束后,还可能需要对其他编译好的目标代码进行链接,即组装两个以上的目标代码模块生成最终的可执行性程序,通过这种方式实现低层次的代码复用。因为编译型语言是—次性地编译成机器码,所以可以脱离开发环境独立运行,而且通常运行效率较高。但因为编译型语言的程序编译成特定平台上的机器码,因此编译生成的可执行性程序通常无法移植到其他平台上运行;如果需要移植,则必须将源代码复制到特定平台上,针对特定平台进行修改,至少也需要采用特定平台上的编译器重新编译。现有的CC++FORTRANPascal等高级语言都属于编译型语言。
(2) 解释型语言

解释型语言是指使用专门的解释器对源程序逐行解释成特定平台的机器码立即执行的语言。解释型语言通常不会进行整体性的编译和链接处理,解释型语言相当于把编译型语言中的编译和解释过程混合到一起同时完成。可以认为:每次执行解释型语言的程序都需要进行一次编译,因此解释型语言的程序运行效率通常较低,而且不能脱离解释器独立运行。但解释型语言有一个优势:跨平台比较容易,只需提供特定平合的解释器即可,每个特定平台上的解释器负责将源程序解释成特定平台的机器指令即可。解释型语言可以方便地实现源程序级的移植,但这是以牺牲程序执行效率为代价的。

现有的RubyPython等语言都属于解释型语言。

除此之外,还有一种伪编译型语言,如Visual Basic,它属于半编译型语言,并不是真正的编译型语言。它首先被编译成P-代码,并将解释引擎封装在可执行性程序内,当运行程序时P-代码会被解析成真正的二进制代码。表面上看起来,Visual Basic可以编译生成可执行性的EXE文件,而且这个EXE文件也可以脱离开发环境,在特定平台上运行,非常像编译型语言。实际上,在这个EXE文件中,既有程序的启动代码,也有链接解释程序的代码,而这部分代码负责启动Visual Basic解释程序,再对Visual Basic代码进行解释并执行。

1.3.2 Java程序的运行机制和JVM

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的作用很容易理解,就像我们有两支不同的笔,但需要把同一个笔帽套在两支不同的笔上,这就需要为这两支笔分别提供一个转换器。这个转换器:
    向上的接口相同,用于适应同一个笔帽;
    向下的接口不同,用于适应两支不同的笔.
  在这个类比中,我们可以近似的理解两支不同的笔就是不同的操作系统,而同一个笔帽就是Java字节码程序,转换器角色则对应JVM.类似地,我们也可以认为JVM分为向上和向下两个部分,所有平台上的JVM
    向上提供给Java字节码程序的接口完全相同
    向下适应不同平台的接口则互不相同。 

Sun公司制定的Java虚拟机规范,在技术上规定了JVM的统一标准,具体定义了JVM的如下细节:

  • 指今集
  • 寄存器
  • 类文件的格式
  • 存储区

Sun公司制定这些规范的目的是为了提供统一的标准,最终实现Java程序的平台无关性。

二、 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分别提供了JDKJava EE SDKSoftware Development Kit)两个开发包如果你只需要学习Java SE的编程知识,则可以下载标准的JDK;如果你还需要学习Java EE的相关内容也可以选择下载Java EE SDK,有一个Java EE SDK版本里已经包含了最新版的JDK,安装Java EE SDK就包含了JDK。

2.1 下载安装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版本:

  • 对于Windows平台,可以选择Windows x86或Windows X64版本。
  • 对于Linux平台,可以选择Linux平台的JDK。

图 2.1

图 2.2


(3) 下载完成后:

  • 对于Windows版本,会获得一个EXE文件,可以通过双击来完成安装。
  • 对于Linux平台,会获得一个BIN文件,只需为该文件添加执行属性,然后执行该安装文件即可。

(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安装路径下看到如下文件路径。

  • bin:该路径下存放了JDK的各种工具命令,常用的javac和java等命令就存放在该路径下。
  • db:该路径是安装javaDB的路径。
  • demo:该路径存放了一些java示例代码供初学者参考。
  • jre:该路径下安装的就是运行java程序所必需的JRE环境。
  • lib:该路径下存放的就是JDK工具命令的实际执行程序,如果使用WinRAR打开lib目录下的tool.jar文件,将看到如图2.4所示的目录结构。
  • src.zip:该压缩文件了存放的就是java所有核心类库的源代码。
  • README和LICENSE:是说明性文档。
  • 在上面的路径中,bin路径是一个非常有用的路径,这个路径下包含了编译和运行java程序的javac和java两个命令。除此之外还包括了appletviewer.jar等大量工具。

图 2.4

注意:
  用于编译java程序所使用的javac.exe命令也是用java写的,这个类就是lib目录下tool.jar文件中sun\tools\javac路径下的Main类JDK的bin目录下的java.exe文件实际上仅仅是包装了这个java类。不仅如此,bin目录下的绝大部分命令都包装了tool.jar文件里的工具类。

 三、环境变量

2.1 Path

2.1.1 变量的意义

path环境变量的值是一系列指令的路径

在Windows操作系统中,当我们执行一条命令时,Windows会根据Path环境变量来查找这个命令。如果能找到这个命令,则该命令可执行。否则将出现“xxxx’不是内部或外部命令,也不是可运行的程序或批处理文件”的提示。

在Linux操作系统中,Linux也会根据PATH环境变量来查找命令。

因为Windows操作系统不区分大小写 ,设置path和PATH并没有区别;而Linux区分大小写,设置path和PATH是有区别的,因此只需要设置PATH环境变量即可。

2.1.2 配置方式

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命令可以用于传递一个或多个变量的值到任何后继脚本

2.1.3 运行java程序

我们知道,编译和运行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

总结:
   使用如下命令对此类进行编译,编译的前提是安装过JDK ,并且配置了环境变量。
   javac: 对类文件进行编译 javac 类.java
   java: 对类文件进行解析 java  类
   如果有包就需要javac -d . 类.java(为了反映包的目录结构)

2.2  CLASSPATH

2.2.1 变量意义(一)---定位字节码

由下图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

2.2 变量意义(二)---定位“jar”包

我在学习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();
    }
}
View Code

需要注意的有两处:
(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]#

 2.3 环境变量CLASSPATH和classpath选项

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类。

三、垃圾回收机制

3.1 不同内存分配的方式的比较

传统的C/C++等编程语言,需要程序员负责回收已经分配的内存。显式进行垃圾回收是一件比较困难的事情,因为程序员并不总是知道内存应该何时被释放。如果一些分配出去的内存得不到及时回收,就会引起系统运行速度下降,甚至导致程序瘫痪,这种现象被称为内存泄漏。总体而言,显式进行垃圾回收主要有如下两个缺点

(1) 程序忘记及时回收无用内存,从而导致内存泄漏,降低系统性能。
(2) 程序错误地回收程序核心类库的内存,从而导致系统崩溃

与C/C++程序不同,Java语言不需要程序员直接控制内存回收,Java程序的内存分配和回收都是由JRE在后台自动进行的。JRE会负责回收那些不再使用的内存,这种机制被称为垃圾回收GarbageCollection,也被称为GC。通常JRE会提供一个后台线程来进行检测和控制,一般都是在CPU空闲或内存不足时自动进行垃圾回收,而程序员无法精确控制垃圾回收的时间相顺序等。

Java的堆内存是一个运行时数据区,用以保存类的实例(对象),Java虚拟机的堆内存中存储着正在运行的应用程序所建立的所有对象,这些对象不需要程序通过代码来显式地释放。一般来说,堆内存的回收由垃圾回收来负责,所有的JVM实现都有一个由垃圾回收器管理的堆内存。垃圾回收是一种动态存储管理技术,它自动地释放不再被程序引用的对象,按照特定的垃圾回收算法来实现内存资源的自动回收功能。

在C/C++中,对象所占的内存在程序结束运行之前一直被占用,被明确释放之前不能分配给其他对象;在Java中,当没有对象引用指向原先分配给某个对象的内存时,该内存便成为垃圾。JVM的一个超级线程会自动释放该内存区。垃圾回收意味着程序不再需要的对象是“垃圾信息”,这些信息将被丢弃。

当一个对象不再被引用时,内存回收它占领的空间,以便空间被后来的新对象使用。事实上,除了释放没用的对象外,垃圾回收也可以清除内存记录碎片。由于创建对象垃圾回收器释放丢弃对象所占的内存空间内存会出现碎片碎片是分配给对象的内存块之间的空闲内存区,碎片整理将所占用的堆内存移到堆的一端,JVM将整理出的内存分配给新的对象。

3.2 java垃圾回收机制的优缺点

优点:

垃圾回收能自动稃放内存空间,减轻编程的负担。这使Java虚拟机具有两个显著的优点
(1) 垃圾回收机制可以很好地提高编程效率

在没有垃圾回收机制时,可能要花许多时间来解决一个难懂的存储器问题。在用Java语言编程时,依靠垃圾回收机制可大大缩短时间。

(2) 垃圾回收机制保护程序的完整性,垃圾回收是Java语言安全性策略的一个重要部分。

缺点:

垃圾回收的一个潜在缺点是它的开销影响程序性能

(1) Java虚拟机必须跟踪程序中有用的对象,才可以确定哪些对象是无用的对象,并最终释放这些无用的对象。这个过程需要花费处理器的时间。

(2) 垃圾回收算法的不完备性,早先采用的某些垃圾回收算法就不能保证100%收集到所有的废弃内存。

当然,随着垃圾回收算法的不断改进,以及软硬件运行效率的不断提升,这些问题都可以迎刃而解。

如果,您认为阅读这篇博客让您有些收获,不妨点击一下右下角的【推荐】。
如果,您希望更容易地发现我的新博客,不妨点击一下左下角的【关注我】。
如果,您对我的博客所讲述的内容有兴趣,请继续关注我的后续博客,我是【Sunddenly】。

本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利。

posted @ 2015-03-04 10:02  sunddenly  阅读(5072)  评论(3编辑  收藏