4二、根本Java
4第1章:Java措辞概述
41.1 Java措辞的发展历史
61.2 Java程序运行机制
71.3 运行Java程序的JVM
71.4 开拓Java的准备
81.5 第一个Java程序
81.6 Java程序的组织形式
91.7 垃圾回收机制
9第2章:理解面向工具
92.1 封装
112.2 继续
112.3 多态
122.4 Java面向工具特色
122.5类和工具
12第3章:数据类型及运算符
133.1 注释
133.2 标识符
143.3 标识符规则
143.4 Java关键字
153.5 数据类型
173.6 基本数据类型转换
183.7 运算符
21第4章:流程掌握与数组
214.1 顺序构造
224.2 分支构造
244.3 循环构造
264.4 掌握循环构造
284.5 数组类型
294.6 深入数组
344.7 数组的运用
35第5章:面向工具(上)
355.1 类和工具
405.2 Java中的方法
425.3 成员变量和局部变量
445.4 隐蔽与封装
465.5 深入布局器
485.6 类的继续
525.7 多态
545.8 继续与组合
585.9 初始化块
60第6章:面向工具(下)
606.1 Java增强的包装类
626.2 处理工具
636.3 类成员
656.4 final润色符
686.5 抽象类
716.6 接口
766.7 内部类
796.8 列举类
80第7章:与运行环境交互
807.1 与用户互动
817.2 系统干系
837.3 常用类
877.4 日期处理类
917.5 正则表达式
957.6 国际化与格式化
96第8章:Java凑集框架
968.1 凑集概述
988.2 Collection和Iterator接口
1018.3 Set凑集
1068.4 List凑集
1108.5 Queue凑集
1138.6 Map
1198.7 操作凑集的工具类Collections
125第9章:泛型
1259.1 泛型入门
127第10章:非常处理
12710.1 非常概述
12710.2 非常处理机制
131第11章:输入/输出
13211.1 File类
13311.2 Java的IO流
13411.3 InputStream和Reader
13511.4 OutputStream和Writer
13611.5 InputStreamReader和OutputStreamWriter
13611.6 BufferedReader和BufferedWriter
13711.7 PrintStream和PrintWriter
13711.8 内存流、数据流
13811.9 Object工具流
14411.10 ZipOutputStream、ZipFile、ZipInputStream
14511.11 RandomAccessFile
146第12章:AWT编程
14612.1 GUI(图形用户界面)和AWT
14812.2 AWT容器
15012.3 AWT常用组件
16012.4 布局管理器
17912.5 事宜处理
18712.6 AWT菜单
19112.7 AWT中的绘图
206Java小游戏项目
206游戏1:拼图
210游戏2:赛马
216第13章:Swing编程
21613.1 Swing简述
21613.2 MVC设计模式
21613.3 Swing组件体系
21713.4 创建基本的Swing运用程序
21813.5 Swing常用的组件
22613.6 Swing中的特色组件
26413.7 JTextPane和JFormattedTextField创建格式文本
277Swing项目总结
277第14章:MySQL数据库与JDBC编程
27814.1 JDBC根本
一、如何学习Java
1、打牢根本,切勿好高骛远
2、从根本入手、多敲多练
3、按照Java本身的学习规律、踏踏实实的学习
4、踏实的基本功是学习统统Java的关键
二、根本Java
第1章:Java措辞概述
1.1 Java措辞的发展历史
Java措辞历史十多年,已经发展成为人类打算机史上影响深远的编程措辞,从某种程度上说,它乃至超出了编程措辞的范畴,成为一种开拓平台,一种开拓规范。
Java措辞的出身具有一定的戏剧性,它并不是经由精心策划、制作而产生的划时期的产品,从某个角度来看,Java措辞的出身完备是一个误会。
在1990年末,Sun公司预见嵌入式系统将会在未来家电器领域中霸占主要地位。于是成立了由詹姆斯.高林斯(James Gosling)领导的“Green操持”,准备为下一代智能极爱单编写一个通用的掌握系统。
该团队最初考虑利用C++措辞,但是很多成员个中包括Sun的首席科学家比尔.乔伊创造C++措辞还有可用的API(Application Programming Interface,运用程序编程接口。是一些预先定义的函数,目的是供应运用程序与开拓职员基于某软件或硬件的以访问一组例程的能力,而又无需访问源码,或理解内部事情机制的细节。)在某些方面存在很大问题。而且事情小组利用的是嵌入式平台,可用的系统资源极其有限。并且C++措辞太繁芜,以至于开拓者很随意马虎出错,而且C++短缺垃圾回收机制、可移植性、分布式和多线程等功能。以是比尔.乔伊决定开拓一种新措辞,它发起在C++的根本上,开拓一种面向工具的环境。于是詹姆斯试图修正和扩展C++的功能来知足这个哀求,但是后来他放弃了,决定创造一种全新的措辞:OaK。
1992年夏天,Green操持已经完成了新平台的部分功能,包括Green操作系统、Oak的程序设计措辞、类库等,同年11月,Green操持被转化成为“FirstPerson有限公司”,一个Sun公司的全资子公司。公司致力于创建一种高度互动的设备,当时代华纳公司发布了一个关于电视机顶盒的搜聚发起书时,FirstPerson改变了他们的目标,作为对搜聚发起书的相应,提出了一个机顶盒平台的发起,但是有线电视业界以为FirstPerson的平台给与用户过多的掌握权,因此FirstPerson的投标失落败给了SGI,同时与3DO公司的其余一笔关于机顶盒的交易也没有成功。
在Green项目险些短命的情形下,1994年夏天互联网和浏览器的涌现不仅给广大互联网用户带来了福音,同时也为Oak措辞带来新的活气。詹姆斯意识到这是一个机会,于是对Oak进行了小规模的改造,到了94年秋日,小组中成员诺顿(Naughton)和乔纳森.佩恩(Jonathan Payne)完成了第一个Java措辞的网页浏览器:WebRunner。当时Oak这个牌号已被别人注册,于是Java出身了。
Sun公司在1995年年初发布了Java措辞,Sun公司直接把Java放到互联网上,免费给大家利用。乃至源代码也不保留,也放在互联网上向所有人公开。几个月后,让所有人都大吃一惊的事发生了,Java成为互联网上最热门的措辞。10多万人次访问了Sun公司的网页,下载Java措辞。然后互联网上立即就有数不清的的Java小程序,演示各种小动画、小游戏等。
在Java措辞涌现之前,互联网的网页本色上便是一张纸,不会由任何动态的内容,有了Java措辞之后,浏览器的功能被扩大了,Java程序可以直接在浏览器中运行,可以直接与远程做事器进行交互。
1995年,Sun虽然推出了Java,但这只是一种措辞,如果想开拓繁芜的运用程序,必须要有一个强大的开拓类库,因此在1996年年初发布了JDK1.0,这个版本包括两部分:运行环境(JRE)和开拓环境(JDK)。运行环境和开拓环境共同包括核心API、集成API、用户界面API、发布技能、Java虚拟机(JVM)五部分。而开拓环境还包括编译Java程序的编译器,即javac命令。
Sun在1997年2月18日发布了JDK1.1。JDK1.1增加了JIT(即时编译)编译器,JIT和传统的编译器有所不同,传统的编译器是编译一条,运行完成后将其扔掉;而JIT会将常常用到的指令保存在内存中,当下次调用时就不须要重新编译了,通过这种办法让JDK在效率上有了较大提升。一贯以来,Java紧张的运用便是网页上的Applet以及一些移动设备。到了1996年年底,Flash面世,这是一种更加大略的动画设计软件,利用Flash险些无须任何编程措辞知识,就可以作出丰富多彩的动画。随后Flash还增加ActionScript编程脚本,Flash逐渐蚕食了Java在网页上的运用。
从1995年Java的出身到1998年年底,Java措辞虽然成为了互联网上广泛利用的编程单元,但它并没有找到一个准确的定位,也没有找到它必须存在的情由:Java措辞可以编写Applet,而Flash一样可以做到,而且更快,开拓本钱更低。
直到1998年12月,Sun公司发布了Java历史上最主要的JDK版本:JDK1.2,伴随JDK1.2一同发布的还有JSP/Servlet、EJB等规范,并将Java分成了标准版(J2SE)、企业版(J2EE)和微缩版(J2ME)三个版本。
J2SE便是Java2的标准版,紧张用于桌面运用软件的编程;
J2ME紧张运用于嵌入式系统开拓,如手机和PDA的编程;
J2EE是Java2的企业版,紧张用于分布式的网络程序的开拓,如电子商务网站和ERP系统。
这标志着Java已经吹响了向企业、桌面和移动3个领域进军的号角,标志着Java已经进入了Java2时期,这个期间也是Java飞速发展的期间。
不仅如此,JDK1.2还把它的API分成了三类:
核心API:由Sun公司制订的基本的API,所有的Java平台都该当供应。这便是Java核心类库。
可选API:这是Sun公司为JDK供应的扩充的API,这些API因平台的不同而不同。
分外的API:用于知足分外哀求的API。如JCA和JCE的第三方加密类库。
2002年2月,sun公司发布了JDK历史上最为成熟的版本:JDK1.4。此时由于康柏(Compaq)、富士通(Fujitsu)、SAS、塞班(Symbian)、IBM等公司的参与,使得JDK1.4成为发展最快的一个JDK版本。到JDK1.4为止,我们已经可以利用Java实现大多数的运用了。
在此期间,Java措辞在企业运用领域大放光彩,呈现了大量基于Java措辞的开源框架:Struts、WebWork、Hibernate、Spring等,大量企业运用做事器中间件也开始呈现:WebLogic、WebSphere、Jboss等,这些都标志着Java措辞进入了飞速发展期间。
2004年10月,Sun发布了万众期待的JDK1.5,同时,Sun将JDK1.5改名为Java SE5.0,J2EE、J2ME也相应的改名为Java EE和Java ME。JDK增加了诸如泛型、增强for语句、可变数量的形参、注释、自动拆箱和装箱等功能。同时也发布了新的企业级平台规范,如通过注释等新特性来简化EJB的繁芜性,并推出了EJB3.0规范。还推出了自己的MVC框架规范:JSF,JSP规范。
2006年12月,Sun公司发布了JDK1.6,一贯以来Sun公司坚持着大约2年发布一次JDK新版本的习气。
但在2009年4月20日,Oracle公司宣告将以每股9.5美元的价格收购Sun公司,该交易总代价为74亿美元。而Oracle通过收购Sun公司得到了两项软件资产:Java和Solaris。
同年java之父詹姆斯离开了Sun公司,进入到了Google公司。
Sun倒下了,不过Java的大旗依然在树立着,2007年11月,Google宣告推出了一款基于Linux平台的开源手机操作系统:Android。Android的涌现顺应了即将涌现的移动互联网潮流,而且Android系统的用户体验非常好,因此迅速成为手机操作系统中的中坚力量。Android平台利用了Dalvik虚拟机来运行.dex文件,Dalvik虚拟机的浸染类似于JVM虚拟机,只是它并未遵照JVM规范而已。Android利用Java措辞来开拓运用程序。这也给Java措辞一个新的机会。
2011年7月28日,oracle公司如约发布了Java SE7.0版本,这次版本升级经由了将近5年韶光,Java SE7.0也是Oracle发布的第一个Java版本。JavaSE7.0虽然并未完备知足所有人的期望,不过他也加入了不少新的特性,至此Java发展进程到此结束,而我们学习的也是基于JDK1.6版本,目前大多数公司开拓也是基于JDK1.6版本进行的。
1.2 Java程序运行机制
Java措辞是一种分外的高等措辞,它既具有阐明型措辞的特性,也具有编译型措辞的特色,由于Java程序要经由先编译,后阐明两个步骤。
打算机高等措辞按程序的实行办法可以分为编译型和解释型两种。
编译型措辞是指利用专门的编译器,针对特定的平台(操作系统)将某种高等措辞源代码一次性“翻译”成可被实行的机器码,并包装成该平台所能识别的可实行性程序的格式,这个转换过程成为编译。编译天生的可实行程序可以分开开开拓环境,在特定的平台上独立运行。
举例:First.java javac.exe First.class
阐明型措辞是指利用专门的阐明器对源程序逐行阐明成特定平台的机器码并立即实行的措辞。阐明型措辞常日不会进行整体性的编译,阐明型措辞相称于把编译型措辞中编译和解释过程稠浊到一起同时完成。
1.3 运行Java程序的JVM
Java措辞比较分外,由Java措辞编写的程序须要经由编译步骤,但这个编译步骤并不会天生特定平台的机器码,而是天生一种与平台无关的字节码(.class)。这种字节码不是可实行的,必须利用Java阐明器来阐明实行。如下图所示:
Java措辞中卖力阐明实行字节码文件(.class)的是Java虚拟机,即JVM(Java Virtual Machine)。JVM是可运行Java字节码文件的虚拟打算。JVM是一个抽象的打算机,和实际的打算机一样,它具有指令集并利用不同的存储区域。它卖力实行指令,还要管理数据、内存和寄存器。
1.4 开拓Java的准备
第一步:下载并安装、配置Java程序须要的JDK(Java SE Development Kit),即Java标准版开拓包。它供应了编译、运行Java程序所须要的各种工具和资源,包括Java编译器、Java运行时环境,以及常用的Java类库。
甲骨文官方中文版:
下载JDK的地址:
第二步:配置环境变量path
环境变量path,在windows系统下path不区分大小写,在Linux系统下区分大小写,以是一样平常写成PATH。
Path: C:\Java\jdk1.6.0\bin;
1.5 第一个Java程序
利用记事本书写,保存为HelloWorld.java
public class HelloWorld{
public static void main(String args[]){
System.out.println(“My First Java Program.”);
}
}
把稳:文件名要与类名相同
利用Javac命令编译此文件: javac HelloWorld.java,会在当期目录下天生一个与此文件名相同的类文件HelloWorld.class。运行此文件:java HelloWorld
1.6 Java程序的组织形式
Java程序是一种纯粹的面向工具的程序设计措辞,因此Java程序必须以类(class)的形式存在,类是Java程序的最小程序单位。Java程序不许可可实行性语句、方法等身分独立存在。
Java程序源文件的命名不是随意的,后缀名必须是.java,在常日情形下Java程序源文件名是可以任意命的,但有一种情形例外:如果Java程序源代码中定义了一个public的类,那么该源文件名必须与该public类的类名相同,以是一个Java源文件里最多只能定义一个public类。
为了供应更好的可读性,建议一个Java源文件只定义一个类,不同的类利用不同的源文件定义;让Java源文件名与源文件中定义的public类同名。
Java措辞中是严格区分大小写的措辞。
如果须要利用Java阐明器直接运行一个Java类,那么这个Java类必须包含main方法,这个方法必须利用public和static类进行润色。
1.7 垃圾回收机制
传统的C/C++等编程措辞,须要程序员卖力回收已经分配出去的内存。显示进行垃圾回收是一件令人头疼的事情,由于程序员并不总是知道内存该当何时进行开释。如果一些分配出去的内存不能及时的回收就会引起系统运行速率低落,乃至导致程序瘫痪,这种征象称为内存透露。
与C/C++措辞不通,Java措辞不须要程序员自己去掌握内存回收,Java程序的内存分配和回收都是由JRE在后台自动进行的。JRE会卖力回收那些不再利用的内存,这种机制被称为垃圾回收机制(Garbage Collection,也被称为GC)。常日JRE会供应一个后台线程来进行检测和掌握,一样平常都是在CPU空闲或者内存不敷时自动进行垃圾回收。
Java的堆内存是一个运行时数据区,用来保存类的实例工具,Java虚拟机的堆内存中存储着正在运行运用程序所建立的所有工具,这些工具不须要程序通过代码来显示地开释。以是GC回收的是Java堆内存空间。当一个工具不再被引用的时,内存回收它盘踞的空间。
垃圾回收的潜在缺陷是它的开销影响程序性能,Java虚拟机必须跟踪程序中有用的工具,才能确定哪些工具是无用的,并终极开释这些无用的工具,这个过程须要花费处理器的韶光。
垃圾回收机制的事情目标是回收无用工具的内存空间,这些内存空间都是JVM堆内存里的内存空间。
为了更快的让垃圾回收机制回收那些不再利用的工具,可以将工具的引用变量设置为null。
垃圾回收发生的不可预知性,有可能是当CPU空闲是发生,也有可能等到内存花费涌现极限时发生。
垃圾回收的精确性紧张包括两个方面:一是垃圾回收能够精确的标记活着的工具;二是垃圾回收器能够精确的定位工具之间的引用关系。
现在的JVM有多种不同的垃圾回收实现,每种回收机制因其算法差异而表现互异。
第2章:理解面向工具
Java措辞是纯粹的面向工具的程序设计措辞,紧张表现为Java完备支持面向工具的三种基本特性:封装、继续和多态。
2.1 封装
封装:将工具的实现细节隐蔽起来,然后通过一些公用的方法来暴露该工具的功能。
举例:
package com.langsin.test;
publicclass Car {
private String name;
private String color;
private String speed;
public String getName() {
return name;
}
publicvoid setName(String name) {
this.name = name;
}
public String getColor() {
return color;
}
publicvoid setColor(String color) {
this.color = color;
}
public String getSpeed() {
return speed;
}
publicvoid setSpeed(String speed) {
this.speed = speed;
}
publicvoid run(){
System.out.println(\公众车的名字:\公众+this.getName());
System.out.println(\"大众车的颜色:\"大众+this.getColor());
System.out.println(\公众车的时速:\"大众+this.getSpeed());
}
publicstaticvoid main(String args[]){
Car car = new Car();
car.setColor(\"大众绿色\"大众);
car.setName(\"大众解放\"大众);
car.setSpeed(\公众60码/时\公众);
car.run();
}
}
输出结果:
车的名字:解放
车的颜色:绿色
车的时速:60码/时
2.2 继续
继续:继续是面向工具实现软件重用的主要手段,当子类继续父类后,子类将直接得到父类的属性和方法。
举例:
package com.langsin.test;
publicclass BmwCar extends Car {
publicstaticvoid main(String[] args) {
BmwCar car = new BmwCar();
car.setColor(\"大众玄色\"大众);
car.setName(\"大众BMW\"大众);
car.setSpeed(\公众300码/时\"大众);
car.run();
}
}
输出结果:
车的名字:BMW
车的颜色:玄色
车的时速:300码/时
2.3 多态
多态:多态指的是子类的实例工具可以直接赋给父类类型的变量,但运行时依然表示出子类的行为特色,这就意味着同一个类型的工具在实行同一个方法时,表现出多种行为特色。
存在多态的条件:
1:有继续
2:要有重写
3:父类引用指向子类工具
举例:
publicclass TestCar {
publicstaticvoid main(String[] args) {
Car carOne = new BenzCar();
carOne.setColor(\公众蓝色\公众);
carOne.setName(\"大众奔驰\"大众);
carOne.setSpeed(\"大众300码/时\"大众);
carOne.run();
System.out.println(\"大众-----------------------------\"大众);
Car carTwo = new BmwCar();
carTwo.setColor(\公众玄色\"大众);
carTwo.setName(\公众BMW\"大众);
carTwo.setSpeed(\公众300码/时\"大众);
carTwo.run();
}
}
输出结果:
车的名字:奔驰
车的颜色:蓝色
车的时速:300码/时
-----------------------------
车的名字:BMW
车的颜色:玄色
车的时速:300码/时
2.4 Java面向工具特色
在Java措辞中,除了8个基本的数据类型外(byte、short、int、long、char、boolean、float、double),统统都是工具,而工具便是面向工具程序设计的中央。
工具具有状态,一个工具用数据值来描述它的状态。工具实现了数据和操作的结合,工具把数据和对数据的操作封装成一个有机的整体。工具是Java程序的核心,以是Java里的工具具有唯一性。
2.5类和工具
具有相同或相似性子的一组工具的抽象化便是类,类是对一类事物的描述,是抽象的、观点上的定义,工具是实际存在的该类事物的个体。工具的抽象化是类,类的详细化便是工具,也可以说类的实例时工具。
Java措辞利用class关键字定义类,Java措辞利用extends关键字来表示继续关系。利用new关键字来创建指定类的详细实例工具。
举例:
Public class Car{
}
Public class BmwCar extends Car{
}
Car car = new Car();
第3章:数据类型及运算符
Java措辞是一门强类型措辞,强类型措辞包含两方面含义:1、所有的变量必须先声明后利用;2、指定类型的变量只能配置指定类型的值。
举例:Car car = null; car = new Car();
car.run();
3.1 注释
单行注释:Java措辞中利用双斜杠(//)放在要注释的内容之前。
多行注释:利用“/”和“/”将程序中须要注释的内容包括起来。
文档注释:文档注释是已“/”开始,以星号紧跟一个斜杠(/)结尾。
举例:
package com.langsin.test;
publicclass Car {
//定义String类型的变量表示车的名称
private String name;
//定义String类型的变量表示车的颜色
private String color;
/
多行注释,可进行换行,注释既可以描述代码含义
也可以注释代码块,使被注释的代码不在被实行
/
private String speed;
/
Description <br>
获取车的名称
@authorpengjianming
@version 1.0
/
public String getName() {
return name;
}
}
3.2 标识符
Java措辞里的分号(;)、花括号({})、小括号(())方括号([])、空格、圆点(.)都具有分外的分隔浸染因此被统称为分隔符。
举例1:
int age = 25; String name = “zhangsan”;
举例2:
Public void run(){
//花括号用来包含代码块,代码块在逻辑上是一个整体。
}
举例3:
privateinta[] =newint[4];//定义一个4个长度的int类型的数组工具,数组里面必须存放int类型的数值
a[0] = 1; //数组的访问因此索引值(index)开始的,也称为下标,索引(下标)因此0为起始值的。
举例4:
圆括号是一个功能丰富的分隔符,定义方法是必须利用圆括号来包含形参声明,调用方法是也必须利用圆括号来传入参数;例如:
Class类:Car
private String name;
public void setName(String name){
this.name = name;
}
public static void main(String args[]){
Car car = new Car(); //天生类的实例工具时也必须带有小括号,默认的动作是调用类的布局方法。
car.setName(“BMW”);
}
举例5:
Java措辞利用空格分隔一条语句的不同部分,如上例所示。
举例6:
圆点常日用做(类/工具)和它的成员之间的分隔符,表明调用某个类或者某个实例的指定成员。
3.3 标识符规则
标识符便是用于给程序中变量、类、方法名的命名的符号,由于Java是区分大小写的以是abc和Abc是两个不同的标识符,规则如下:
标识符可以由字母、数字、下划线(_)和美元符号($)组成,个中数字不能打头。
标识符不能是Java的关键字和保留字,可以包含关键字和保留字,例如String abcString = “abc”;
标识符不能包含空格。例如:String a bc = “123”;
标识符只能包含美元符号($)不能包含其他分外字符,如:@ #
3.4 Java关键字
Java措辞中有一些具有分外用场的单词被称为关键字,定义标识符时不要让标识符和关键字相同,否则会引起缺点。Java的关键字都是小写,Java一共包含48个关键字。
3.5 数据类型
Java措辞支持的数据类型分为两类:基本数据类型和引用类型
1、基本数据类型共8中,分为布尔类型(boolean)和数值类型,数值类型又分为整数类型和浮点类型。整数类型包括byte、short、int、long、char,浮点类型包括float(单精度浮点)和double(双精度浮点)
2、引用类型包括类、接口、和数组类型,还有一种分外null类型。引用数据类型便是对一个工具的引用,工具包括实例和数组两种。空类型(null)便是null值类型,这种类型没有名称,以是不能声明一个null类型的变量或者转换到null类型。
3.5.1 整型
byte:byte(字节)类型的整数在内存里占8位,表示的范围是:-128(-2的7次方) ~ 127 (2的7次方-1)
short:short(2个字节长度)类型整数在内存里占16位,表示范围-32768 ~ 32767
int:int(4个字节长度)类型在内存中32位,表示范围-2147483648 ~ 2147483647
long:long(8个字节长度)类型在内存中64位,表示范围-9223372036854775808 ~ 9223372036854775807
int类型是常用的整数类型,Java整数常量默认的便是int类型。利用byte或者short类型时,整数的范围不能超过类型的范围,Java直接将整数常量当成byte或者short类型。例如:
byte a = 24; short b = 1255;
但是利用几个巨大的整数常量时,Java不会自动把全体整数常量当成long类型,以是须要在整数常量后面加上L作为后缀,例如
long a = 99999999999999999L;
Java中整数常量有4种表示办法:十进制,二进制(0b或者0B开头),八进制(以0开头),十六进制(以0x或者0X开头)。
举例:int octalValue = 013; //八进制转换成十进制表示11
int hexValue1 = 0X13; //十六进制转换成十进制表示19
int hexValue2 = 0XAF; //十六进制转换成十进制表示175
int binValue1 = 0B11011; //二进制转换成十进制表示27(JDK1.7中新增特性)
3.5.2 补码、反码、原码
所有的数字在打算机底层都因此二进制形式存在,但是打算机以补码的形式保存所有的整数。
定义32位的二进制整数时,最高位实在是符号位。符号位是1表示负数,0表示正数
举例:
int a = 0B10000000000000000000000000000011; //这是一个补码表示-2147483645
原码:直接将一个数值换算成二进制数。
补码:正数的补码和原码完备相同,负数的补码是其反码加1。
反码:是对原码按位取反,只是最高符号位保持不变。
举例:
1000 0000 0000 0000 0000 0000 0000 0011 为补码,要得到它的详细指须要先获取它的反码
负数的补码是其反码+1,那么其反码便是补码-1;
1000 0000 0000 0000 0000 0000 0000 0010 为反码,原码是对反码取反
1111 1111 1111 1111 1111 1111 1111 1101 为原码,//-2147483645
3.5.3 字符型
字符型常用于表示单个字符,字符常量必须利用单引号括起来,例如:char a = ‘a’;char类型的值也可以直接作为整数类型的值来利用,是一个16位的无符号整数,范围是0 ~ 65535 表示办法如下:
直接通过单个字符来指定字符常量,例如’A’‘a’‘0’
通过转义字符表示分外字符型常量,例如:’\n’‘\t’
直策应用Unicode值来表示字符常量,例如:’\uXXXX’,XXXX表示一个十六进制的整数。
举例:
char aChar = 'a';
char enterChar = '\t';
char ch = '\u667F';
char name = '张';
int value = name;
System.out.println(aChar);
System.out.println(enterChar);
System.out.println(ch);
System.out.println(value);
3.5.4 浮点型
Java浮点类型:float和double。float占4个字节(byte)32位,double占8个字节(byte)64个长度。
float类型的常量后面必须以f或者F结尾,例如:float a = 12.55f; double类型的常量后面可以d或者D结尾,但是不逼迫追加,不写也没有问题。
分外情形:正无穷大、负无穷大、非数分别用基本数据类型对应的封装类来表示,
浮点数的表示办法分为两种:
十进制办法 float a = 12.55f;
科学计数法形式: float a = 12.5e2f;
举例:
floata = 12.555f;
doubleb = 12.55;
floata = 12.55e5f;
floatc = Float.NaN; //不是一个数
floatd = Float.NEGATIVE_INFINITY; //负无穷大
inte = Integer.MIN_VALUE; //最大值
3.5.5 布尔型
布尔型只有一个boolean类型,用于表示逻辑上的“真”或者“假”,数值只能是true或者false
举例:
boolean a = true; boolean b = false;
常用在逻辑判断上,例如:
if(a){
System.out.println(“条件为真”);
}else{
System.out.println(“条件为假”);
}
3.6 基本数据类型转换
Java程序中,不同的基本类型的值常常须要进行相互转换,Java供应了两种类型转换办法:自动类型转换和逼迫类型转换。
3.6.1、自动类型转换
将一种基本数据类型的值直接赋给另一种基本数据类型,则这种办法被称为自动类型转换。条件是把一个范围小的数值或变量直接赋值给另一个数据范围大的变量时,系统可以进行自动类型转换。
举例:
byte a = 25;
shortb = a;
longc = a;
float d = a;
System.out.println(d);
把稳:不能将数据范围大的变量或数值赋值给范围小的变量,例如:int a = 25; byte b = a; 会直接报错。
换行顺序:byte->short->int->long->float->double
char->
3.6.2、逼迫类型转换
将大范围的数据向小范围的数据进行转换则须要进行逼迫转换,语法格式为:(targetType)value;
例如:
float d = 12.5F;
inte = (int)d; //变量e的值为整数12,不会保留小数
如果大范围的数据值超过了小数据的的范围,则按位进行截取。
int a = 327775;
short b = (short)a;
System.out.println(b); //输出结果95
3.7 运算符
运算符是一种分外的符号,用以表示数据的运算、赋值和比较等。Java措辞利用运算符将一个或多个操作数据连接成实行性语句,用以实现特定功能。
算术运算符
赋值运算符
比较运算符
逻辑运算符
位运算符
类型干系运算符
3.7.1 算术运算符
加法运算(+)、减法运算(-)、乘法运算()、除法运算(/)、取余(取模)运算(%)、自加运算(++)、自减运算(--)、(+)还可以做为字符串的连接符。
举例:
int a = 12;
int b = 24;
System.out.println(\"大众加法运算:\公众+(a+b)); // 36
System.out.println(\"大众减法运算:\"大众+(a-b)); //-12
System.out.println(\公众乘法运算:\"大众+ab); //288
System.out.println(\公众除法运算:\"大众+a/b); //0
System.out.println(\公众取模运算:\"大众+a%b); //12
int c = --a;
System.out.println(c); //11
System.out.println(a); //11
c = b--;
System.out.println(c); //24
System.out.println(b); //23
3.7.2 赋值运算符
Java利用“=”作为赋值运算符,为变量指定变量值。举例:
int a = 5; String b = “abc”;
3.7.3 位运算符
Java支持的运算符有7个:按位与(&)、按位或(|)、按位非(~)、按位异或(^)、左移运算符(<<)、右移运算符(>>)、无符号右移运算符(>>>)
基本运算法则:
按位非运算,举例:
Int a = 19; System.out.println(~a); //输出结果为-20
运算事理:19的二进制表示办法为:00010011 按位非运算为:11101100 按位打算后的值为补码,(打算机都是按照补码进行表示的),根据补码获取它的反码,前面为1表示为负数,负数的反码是:补码减1,因此其反码为11101011,其原码为10010100,转换成十进制为-20。
右移运算:Java的右移运算符有两个>>和>>>,对付>>运算符,把第一个操作数的二进制码向右移动指定位数后,左边空出来的位数以原来的的符号位添补,如果是正数用0添补,如果是负数用1添补,>>>运算符移动后,只用0添补。
举例:
-5>>2
-5的原码是1000 0101,它的反码为:1111 1010,它的补码为:1111 1011,右移两位为:1111 10,前面用符号位添补为:1111 1110(补码)。将补码转换成十进制数—》先变成反码:1111 1101,其原码为:1000 0010,表示未十进制数为:-2。
-5>>>2用32表示(缘故原由:打算自动转换类型为int,int类型为32位)
-5的原码为:1000 0000 0000 0000 0000 0000 0000 0101,
其反码为:1111 1111 1111 1111 1111 1111 1111 1010
其补码为:1111 1111 1111 1111 1111 1111 1111 1011
右移后为:0011 1111 1111 1111 1111 1111 1111 1110(补码)
其原码为:0011 1111 1111 1111 1111 1111 1111 1110
转换成十进制为:2的30次方减2为:Math.pow(2,30)-2。
3.7.4 扩展后的赋值运算符
赋值运算符可以与算术运算符、位移运算符结合,扩展成功能更加强大的运算符。
+=:对付x += y,表示 x = x + y;
-=:对付 x-= y,表示 x = x-y;
=: x= y,表示 x = x y;
/= ; %=; &=; |=; ^=; <<= ; >>=; >>>=;
3.7.5 比较运算符
比较运算符用于判断两个变量或者常量的大小,比较运算的结果是一个boolean值(true或者false)
>:大于,只支持旁边两边操作数是数值类型。
>=:同上
<:同上
<=:同上
==:同上,纵然他们数据类型不相同,只要它们的值相同,也返回true,例如:97==’a’,返回true
!=:不即是,如果进行比较的两个操作数都是数值类型,只要值不同就返回true,如果比较的是引用类型,只有当两个引用变量相同类型的实例时才可以比较,只要两个引用指向不是同一个工具就返回true,
举例1:
Car car1 = new Car();
TestCar car2 = new TestCar();
boolean result = (car1 ==car2); //两个类型不同不能进行比较
举例2:
Car car1 = new Car();
Car car2 = new Car();
boolean result1 = car1 !=car2;
boolean result2 = car1 ==car2;
System.out.println(result1); //输出结果为true
System.out.println(result2); //输出结果为false
举例3:
Car car1 = new Car();
Car car2 = car1;
boolean result = car1 ==car2;
System.out.println(result); //输出结果为true
3.7.6 逻辑运算符
逻辑运算符用于操作两个布尔型的变量或常量,逻辑返回的值为boolean类型,紧张有6个,
&&:前后两个操作数都为true时,返回true,否则返回false,例如:32>24 &&“abc”==”abc”,返回true
||:前后两个操作数,有个为true就返回true,举例:32>24 || “abc”!=”abc”,返回true
&(不短路与),|(不短路或),!(非),^(异或)
3.7.7 三目运算符
三目运算符只有一个:(?:),举例:int a = 5>3 ? 6 : 7;//成立输出6不成立输出7
3.7.8 运算符的优先级
//从高到底的
第4章:流程掌握与数组
任何一门编程措辞都会供应两种基本的流程掌握构造:分支构造和循环构造。个中分支构造根据条件来选择性地实行某段代码,循环构造则用于实现根据循环条件重复实行某段代码。
Java中的分支构造语句为:if、switch
Java中的循环构造语句为:while、do while、for、foreach
Java中供应了break、continue来掌握程序的循环构造
4.1 顺序构造
顺序构培养是程序从上到下逐行的实行,中间没有任何判断和跳转。
举例1:
package com.langsin.test;
publicclass TestCar {
publicstaticvoid main(String[] args) {
int a = 3;
int b = 5;
int c = a+b;
System.out.println(\"大众输出结果:\"大众+c);
}
}
4.2 分支构造
Java措辞利用if语句和switch语句来进行分支掌握,个中if语句利用boolean表达式或boolean值来作为分支条件进行分支掌握;switch语句则用于对多个整型值进行匹配,从而实现分支。
4.2.1 if条件语句
举例1:
package com.langsin.test;
publicclass TestCar {
publicstaticvoid main(String[] args) {
boolean flag = 5>3;
//利用变量,此种办法为常用办法
if(flag){
System.out.println(\"大众条件为真实行\"大众);
}
//利用常量
if(true){
System.out.println(\公众利用常量,此代码永久会被实行\公众);
}
//利用表达式,此种办法为常见利用办法
if(5>3){
System.out.println(\"大众表达式的结果为true时,代码会被实行\"大众);
}
//完全的if分支构造
int a = 5;
int b = 8;
if(a>b){
System.out.println(\"大众a的值大于b的值\"大众);
}else{
System.out.println(\"大众a的值不大于b的值\"大众);
}
//分支的嵌套利用
if(a>b){
if(b>0){
System.out.println(\"大众a的值大于b的值,并且b的值大于0\"大众);
}
}
//此代码段等价于上面的代码
if(a>b && b>0){
System.out.println(\公众a的值大于b的值,并且b的值大于0\"大众);
}
//完全构造下的嵌套
if(a>b){
if(b>0){
System.out.println(\公众a的值大于b的值,并且b的值大于0\"大众);
}else{
System.out.println(\"大众a的值大于b的值,但是b的值不大于0\公众);
}
}else{
if(a>0){
System.out.println(\"大众a的值不大于b,并且a的值大于0\公众);
}else{
System.out.println(\公众a的值不大于b,并且a的值不大于0\"大众);
}
}
//if语句串联利用
if(a>b){
System.out.println(\"大众a的值大于b的值\"大众);
}elseif(a>0){
System.out.println(\"大众a的值不大于b的值,并且a的值大于0\公众);
}
}
}
4.2.2 switch分支语句
Switch语句由一个掌握表达式和多个case标签组成,表达式的数据类型只能是byte、short、int、char四个整数类型和列举类型。
举例1:
package com.langsin.test;
publicclass TestCar {
publicstaticvoid main(String[] args) {
int a = 5;
switch (a) {
case 1:
System.out.println(\"大众当key值为1时的运行代码段\"大众);
int x = 2;
int y = 3;
int z = x + y;
System.out.println(\公众打算加法后的结果:\公众+z);
break;
case 2:
System.out.println(\"大众当key值为2时的运行代码段\"大众);
int x1 = 2;
int y1 = 3;
int z1 = x1 - y1;
System.out.println(\公众打算减法后的结果:\"大众+z1);
break;
default:
System.out.println(\公众当key值不符合任意条件时,默认实行的代码段\公众);
break;
}
}
}
4.3 循环构造
循环语句可以在知足循环条件的情形下,反复实行某一段代码,被重复实行的代码段称为循环体,在反复实行循环体的时候,须要在得当的情形下将条件改为假,否则循环将一贯实行下去,形成恐怖的去世循环。
4.3.1 while循环语句
当while条件为真(true)时,实行循环体中的代码
举例1:
package com.langsin.test;
publicclass TestCar {
publicstaticvoid main(String[] args) {
int count = 1;
while(count<10){
System.out.println(\"大众当前值为:\公众+count);
count++;
}
}
}
4.3.2 do while 循环语句
do代码段中为循环体,先实行循环体中的代码,然后再去判断条件是否为真(true),如果为真再实行do代码段中的循环体。
举例2:
package com.langsin.test;
publicclass TestCar {
publicstaticvoid main(String[] args) {
int count = 1;
do {
System.out.println(\公众当前的数值为:\公众+count);
count++;
} while (count<10);
}
}
4.3.3 for循环
For循环体是更加简洁的循环语句,在大部分情形下for循环可以代替while循环、do while循环。
举例1:
package com.langsin.test;
publicclass TestCar {
publicstaticvoid main(String[] args) {
for(int i=0;i<10;i++){
System.out.println(\"大众当前的数值为:\"大众+i);
}
System.out.println(\公众---------------for循环结束---------------\"大众);
}
}
4.3.4 foreach循环
Foreach循环更加简洁,循环的必须是个凑集或者数组。For表达式中定义的变量实行了数组或凑集中的每一个详细的值。
举例:
package com.langsin.test;
publicclass TestCar {
publicstaticvoid main(String[] args) {
System.out.println(\公众--------------开始for循环------------\"大众);
int num[] ={11,20,33,40,55};
for(int i : num){
System.out.println(\"大众当前数值为:\公众+i);
}
System.out.println(\"大众---------------for循环结束---------------\"大众);
}
}
4.4 掌握循环构造
Java措辞供应了continue语句和break语句来掌握循环构造,除此之外还可以利用return语句来结束全体方法体。
4.4.1 break结束循环
在代码体中,一旦实行到break语句,那么就结束全体循环,跳出循环体,不在实行,纵然还没有实行完成也将不再实行。
举例1:
package com.langsin.test;
publicclass TestCar {
publicstaticvoid main(String[] args) {
for(int i=0;i<10;i++){
System.out.println(\公众当前实行第\公众+(i+1)+\"大众次\公众);
if(i==5){
break;//当实行第6次的时候跳出循环体
}
}
System.out.println(\公众循环结束\"大众);
}
}
4.4.2 continue结束本次循环
与break有点类似,差异是终止后面代码的实行,跳出本次循环,连续实行下一次循环。
举例1:
package com.langsin.test;
publicclass TestCar {
publicstaticvoid main(String[] args) {
for(int i=0;i<5;i++){
if(i==2){
continue;
}
System.out.println(\"大众当前实行第\"大众+(i+1)+\公众次\公众);
}
System.out.println(\"大众循环结束\"大众);
}
}
4.4.3 return结束方法
return关键字,并不是专门用于结束循环体的,return的功能时结束一个方法。return关键字后面还可以跟变量、常量、表达式用于对方法的返回值。
举例1:
package com.langsin.test;
publicclass TestCar {
publicstaticvoid main(String[] args) {
for(int i=0;i<5;i++){
if(i==2){
return;
}
System.out.println(\"大众当前实行第\"大众+(i+1)+\"大众次\公众);
}
System.out.println(\"大众循环结束\"大众);
}
}
举例2:
package com.langsin.test;
publicclass TestCar {
publicint getNum(int a,int b){
return a+b;
}
publicstaticvoid main(String[] args) {
TestCar test = new TestCar();
int result = test.getNum(5, 6);
System.out.println(\"大众打算后的结果为:\"大众+result);
}
}
4.5 数组类型
数组是编程措辞中最常见的一种数据构造,可以存储多个数据,每个数组元素存放一个数据,通过数组元素的索引(或者称为下标index)来访问数组元素。数组也是一种类型,它是引用类型。
4.5.1 定义数组
Java措辞支持两种语法格式来定义数组:
举例1:
int a[]; int[] a; //int类型的数组,只能放int类型的值
int a[] = newint[5] ;
a[0] = 10; //如果a[0] = 12.5f;则报错,由于12.5f是float类型的常量
System.out.println(a[0]);
基本数据类型、引用数据类型都可以定义数组,举例
bouble b[] ; Car car[];
4.5.2 数组的初始化
举例1:只初始化数组的长度,不带有默认值
int a[] = new int[10];
举例2:初始化长度,同时带有默认值
int a[] = new int[]{11,12,13,14,15};
或者 int a[] = {11,12,13,14,15};
4.5.3 利用数组
数组常用的方法便是访问数组元素,包括对数组元素进行赋值、取出数组元素的值。访问数组元素都是通过在数组引用变量后紧跟一个方括号[],方括号中是数组元素的索引值,索引值都是从0开始的。一个数组的索引值最大即是这个数组的长度减1。
举例1:int a[] = new int[10],这个int类型的数组长度为10,那么取第10个数便是a[9],如果编写代码的时候写成了a[10],编译不会出错,但是在运行时会涌现非常:java.lang.ArrayIndexOutOfBoundsException:非常,这个便是数组索引越界非常。
举例2:
package com.langsin.test;
publicclass TestCar {
publicstaticvoid main(String[] args) {
int num[] = {11,22,33,44,55} ;
for(int i=0;i<num.length;i++){
System.out.println(\"大众当前数值中的第\"大众+(i+1)+\"大众元素的值为\"大众+num[i]);
}
}
}
输出结果为:当前数值中的第1元素的值为11
当前数值中的第2元素的值为22
当前数值中的第3元素的值为33
当前数值中的第4元素的值为44
当前数值中的第5元素的值为55
举例3:利用foreach进行遍历
publicstaticvoid main(String[] args) {
int num[] = {11,22,33,44,55} ;
int i=1;
for(int n : num){
System.out.println(\"大众当前数值中的第\"大众+i+\公众元素的值为\公众+n);
i++;
}
}
4.6 深入数组
数组是一种引用数据类型,数组引用变量只是一个引用,数组元素和数组变量在内存里是分开存放的。
4.6.1 内存中的数组
数组引用变量只是一个引用,这个引用变量可以指向任何有效的内存,只有当引用指向有效内存后,才可通过该数组变量来访问数组元素。
举例1:int a[] = {1,3,5,4} a[0]的值为1, int a[] = null; a[0]则报错。
数组工具被存储在堆内存中(heap),而引用该数组工具的数组引用变量如上例中的a变量,则被存储在栈内存中(stack)。如下图:
当一个方法实行时,每个方法都会建立自己的栈内存,这个方法中定义的变量将会逐个放入这块栈内存里,随着方法的实行结束,这个方法的内存栈也就会自然销毁,因此所有在方法中定义的局部变量都是放在栈内存中的,当我们在程序中创建一个工具时,这个工具将被保存到运行时数据区中,以便反复利用,这是由于工具的创建本钱常日是比较大的,这个运行时数据区便是堆内存。堆内存中的工具不会随着方法的结束而销毁,纵然方法结束后,这个工具可能被另一个变量引用,则这个工具依然不会存在。只有当一个工具没有任何引用变量引用它时,系统的垃圾回收机制(GC)才会在得当的时候回收它,即销毁它。
为了让垃圾回收机制回收一个数组所占的内存空间,可以将该数组变量赋值为null,也就割断了数组引用变量和实际数组之间的引用关系,实际的数组也就成了垃圾信息。
举例2:
int a[] = {1,5,6,8,10,12};
System.out.println(a[0]);
int b[] = a;
a = null;//割断引用数据类型变量a与数组之间的联系,但是变量b又指向了这个数组工具,以是该数组工具不会被GC回收,仍旧在堆内存中存在。
b = null; //同上割断变量b与数组之间的联系,没有变量指向这个数组,因此GC会在得当的时候将工具回收销毁。
举例3:
publicstaticvoid main(String[] args) {
int a[] = {1,12,13,22};
int b[] = newint[5];
System.out.println(\公众数组b的长度为:\"大众+b.length);
for(int i=0;i<a.length;i++){
b[i] = a[i];
}
for(int num : b){
System.out.print(\"大众\"大众+num);
}
b = a;
System.out.println(\公众数组b的长度为:\公众+b.length);
}
举例4:定义一个引用数据类型数组
package com.langsin.test;
publicclass Person {
Person(String name,String phone,int age){
this.name = name;
this.phone = phone;
this.age = age;
}
private String name;
private String phone;
privateint age;
public String getName() {
return name;
}
publicvoid setName(String name) {
this.name = name;
}
public String getPhone() {
return phone;
}
publicvoid setPhone(String phone) {
this.phone = phone;
}
publicint getAge() {
return age;
}
publicvoid setAge(int age) {
this.age = age;
}
publicstaticvoid main(String[] args) {
Person p[] = new Person[5];
for(int i=0;i<p.length;i++){
Person person = new Person(\"大众zhangsan\公众+i,\"大众859949\公众+i,25+i);
p[i] = person;
}
for(int i=0;i<p.length;i++){
System.out.print(\"大众姓名:\公众+p[i].getName());
System.out.print(\"大众年事:\公众+p[i].getAge());
System.out.println(\"大众电话:\公众+p[i].getPhone());
System.out.println(\"大众--------------------------------------------------------\"大众);
}
}
}
基本数据类型数组与引用数据类型数组的差别:基本数据类型数组在初始化时,在堆内存中的数组工具里面已经初始化好数据值并且进行存放。引用数据类型的数组在初始化时,在堆内存中的数组工具实际存放的是引用数据类型的引用变量。
4.6.2 多维数组
Java措辞中供应了支持多维数组的语法。多维数组在实质上是有一维数组组合而成,只是外层的数组中存放的是内存数组的引用变量而已。
多维数组的初始化同一维数组相同。
举例1:
publicstaticvoid main(String[] args) {
int num[][] = {{1,3,5,7},{2,4,6,9}};
//num是二维数组,num的长度是最外层数组的长度,它存放的值为里面一层数组的引用地址
System.out.println(num.length);
int num2[][] = newint[5][6];
//给数组num里面的第一个数组工具的第一个工具值赋值
num2[0][0] = 1;
//给数组num里面的第一个数组工具的第二个工具赋值
num2[0][1] = 3;
}
如下图所示:
4.6.3 操作数组的工具类
java.lang.Arrays类,包含了一些用static润色的方法可以直接操作数组,常用的方法如下:
int binarySearch(type[] a,type value):利用二分法查询value元素值在a数组中涌现的索引位置,如果a数组不包含value元素值,则返回负数。该方法哀求数组已经按照升序进行了排列。
int binarySearch(type[] a,int fromeIndex,int toIndex,type value):与上一个方法名相同,参数不同,称为方法重载,同样哀求数组已经按照升序进行了排列。
举例1:
publicstaticvoid main(String[] args) {
int[] a = {1,3,4,6,7,2,8};
int index = Arrays.binarySearch(a,10); //输出-8
System.out.println(index);
index = Arrays.binarySearch(a,2);
System.out.println(index); //输出-2
index = Arrays.binarySearch(a,3);
System.out.println(index); //输出1
index = Arrays.binarySearch(a,1,6,3);
System.out.println(index); //输出1
index = Arrays.binarySearch(a,1,6,1);
System.out.println(index); //输出负数
}
type[] copyOf(type[] original,int newLength):这个方法会把original数组复制成一个新数组,个中newLength是新数组的长度,当newLength大于original的长度时,新数组的前面元素便是original的所有元素,后面所有元素进行补充,0(int类型),false(boolean类型)、null(引用类型)。
type[] copyOfRange(type[] original,int fromIndex,int toIndex):这个方法只复制original数值的from索引到to索引的元素。
举例2:
publicstaticvoid main(String[] args) {
int[] a = {1,3,4,6,7,2,8};
int[] b = Arrays.copyOf(a,5);
System.out.println(b[1]); //输出:3
b = Arrays.copyOfRange(a, 2, 5);
System.out.println(b.length+\"大众====\"大众+b[2]); //输出:3====7
}
boolean equals(type[] a1,type[] a2):如果数组a1与数组a2的长度相同,并且数值a1中元素值与a2中元素值相同,该方法返回true。排序值也得一样!
举例3:
publicstaticvoid main(String[] args) {
int[] a = {1,3,4,6,7,2,8};
int[] b = {1,3,4,6,7,2,8};
System.out.println(Arrays.equals(a, b)); //输出true
}
void fill(type[] a,type val):该方法对数组进行赋值,将所有元素赋值为val
void fill(type[] a,int fromIndex,int toIndex,type val):该方法仅仅对从fromIndex开始到toIndex索引的的元素进行赋值,赋值为val
举例4:
publicstaticvoid main(String[] args) {
int[] a = newint[5];
Arrays.fill(a, 12);
System.out.println(a[1]);
int[] b = newint[5];
Arrays.fill(b,1,b.length,13);
System.out.println(b[0]);
System.out.println(b[4]);
}
void sort(type[] a):该方法对数组a中的元素进行排序。
void sort(type[] a,int fromIndex,int toIndex):对数组a中的从fromIndex开始到toIndex的元素进行排序。
String toString(type[] a):该方法将一个数组转换成一个字符串。该方法顺序把多个数组元素连缀在一起,多个数组元素利用英文逗号和空格隔开。
举例5:
publicstaticvoid main(String[] args) {
int a[] = {1,6,3,7,2,8,9,10};
Arrays.sort(a);
System.out.println(Arrays.toString(a)); //输出 [1, 2, 3, 6, 7, 8, 9, 10]
}
4.7 数组的运用
将字符串形式的浮点数“1245.45”转换成大写格式 壹仟贰佰肆拾伍点肆伍
提示:从字符串中取出每个位置的值的方法:
char c = String.charAt(index);
字符型的变量也是整数类型,字符‘0’对应的整数值为48
获取字符串的长度为的方法:
Int length = String.length();
第5章:面向工具(上)
JAVA是面向工具的程序设计措辞,Java措辞供应了定义类(class)、属性(Field)、方法(method)等最基本的功能。类是一个自定义类型的数据类型。所有利用类定义的变量都是引用变量,变量都指向一个详细的类的工具。
面向工具的三大特色:封装、继续、多态。Java供应了private、protected、public三种访问掌握润色符来实现良好的封装,供应了extends关键字来实现继续关系。子类继续父类就可以继续父类的属性和方法。如果访问掌握许可,子类实例就可以直接调用父类里定义的方法。继续是实现类复用的主要手段。
布局器也称布局方法用于对类实例进行初始化,布局器支持重载,实在也便是布局方法的重载。
5.1 类和工具
Java是面向工具的程序设计措辞,类是面向工具的主要内容,可以把类当成一种自定义的数据类型,可以利用类来定义变量,这种类型的变量统称为引用变量,所有的类是引用数据类型。
5.1.1 定义类
面向工具的程序设计过程中有两个主要观点:类(class)和工具(object),个中类是某一批工具的抽象,可以把类理解成某种观点。
比如:车跟宝马便是类与工具的关系,车是类,宝马是详细的工具。
一、Java措辞里定义类的语法格式:
[润色符] class 类名{
0到多个布局方法
0到多个变量
0到多个方法
}
润色类的关键字可以是public(公共的)、final(终极的)、abstract(抽象的),或者完备省略这三个润色符。类名是一个合法的标识符即可。但这仅仅是符合Java的语法哀求,实际上从程序的可读性来说,Java的类名必须是由一个或多个故意义的单词连接而成,每个单词首字母大写,其他字母全部小写,单词与单词之间不要利用任何分隔符,例如: public class ProductService{},从类名上就能看出这是一个为产品操作供应做事的类。
对付一个类定义而言,可以包含三种最常见的成员,也称为类成员,布局器、变量、方法,三种成员都可以定义0到多个。
类里面,各成员之间的定义顺序没有任何影响,各成员之间可以相互调用,但是用static润色的成员只能访问static润色的成员。
举例1:
package com.langsin.test;
publicclass Student {
private String sex = \"大众\公众;
static String name = \公众\"大众;
publicstaticvoid main(String[] args) {
name = \"大众zhangsan\"大众;
sex = \公众man\公众; //此行代码直接报错
}
}
二、Filed(变量)用于定义该类或该类的实例所包含的状态数据,方法则用于定义该类或该类实例的行为特色或者功能实现。布局器(布局方法)用于该类的实例,Java措辞利用new关键字来调用布局器(布局方法)从而返回这个类的实例。布局器是一个类创建工具的根本,如果一个类没有布局器,那么Java就会为该类供应一个默认的布局器。
举例2:
public class Student{
private String name = null;
private int age = null;
private String gender = null;
Student(String name,int age,String gender){
this.name = name;
this.age = age;
this.gender = gender;
}
public void introduce(){
System.out.println(“My name is ”+this.name+”, age is ”+this.age);
}
}
Student st1 = new Student(“zhangsan”,25,”男”);
st1.introduce();
Student st2 = new Student(“lili”,25,”女”);
St2.introduce();
定义类变量(Field)语法格式如下:
1、润色符可以省略,也可以是public、protected、private、static、final,个中public、protected、private三个只能涌现个中一个,可以与static、final组合起来润色field
2、变量类型:可以是Java措辞中的任何数据类型:基本数据类型、引用数据类型。
3、Field名只假如一个合法的Java标识符即可,这是从语法角度来说,如果从程序可读性来说该当是每个单词首字母小写,后面每个单词首字母大写,与类名定义相似。
举例3:public static String name = “abc”;
private static age = “23”;
private final String classNo = “20130607”;
三、定义类方法(method)语法格式如下:
1、润色符:润色符可以省略,也可以是public、protected、private、static、final、abstract,个中public、protected、private、三个只能涌现一个,abstract和final最多只能涌现个中之一,可以与static组合起来。
2、方法返回值类型:返回值类型是Java措辞许可的任何类型,即:基本类型,引用类型。如果有返回类型,必须有一个有效的return语句,该语句返回一个变量或一个表达式。这个变量或表达式的类型必须与此方法声明的类型同等。
3、方法名:方法名命名规则与Field命名规则进本相同
4、形参列表:形参列表用于定义方法可以接管的参数,形参类型和形参名之间用英文空格隔开。
举例4::
public int getTotalValue(int a,int b){
int totalNum = a + b;
return totalNum;
}
Static是一个分外的关键字,它可以用于润色方法,变量(Field)等成员,static润色的成员表名它属于这个类本身,而不是该类的单个实例,常日把static润色的变量(Field)和方法(method)称为类变量,类方法。不该用static润色的普通方法、变量则属于该类的单个实例。
举例5:
publicclass Student {
private String sex = \"大众\"大众;
privatestatic String name = \"大众\"大众;
publicstaticvoid main(String[] args) {
name = \"大众zhangsan\公众;
System.out.println(name);
Student st = new Student();
st.name = \"大众lisi\"大众;
System.out.println(st.name); //实例的名称
System.out.println(name); //类的名称
st.sex = \公众男\公众;
System.out.println(st.sex);
}
}
四、布局器(布局方法)是一个分外的方法,定义布局器的语法样式与定义方法的语法格式很像,定义布局器的语法格式如下:
[润色符] 布局器名(形参列表){
//0到多个可实行语句组成的布局器实行体
}
润色符:可以省略,也可以是public、protected、private个中之一。
布局器名:必须和类名一样。
形参列表:和定义方法形参列表格式完备相同。
把稳:布局器既不能定义返回值类型,也不能利用void定义布局器没有返回值。这是Java规范定义的,实际上类的布局器是有返回值的,当利用new关键字来调用布局器时,布局器返回该类的的实例。
举例6:
package com.langsin.test;
publicclass Student {
privateintage = 29;
privatestatic String name = \"大众\公众;
privatevoid say(){
System.out.println(\公众仅供自身调用\"大众);
}
publicstaticvoid main(String[] args) {
Student st = new Student();
st.say();
}
}
5.1.2 工具、引用和指针
如上例所示:在创建Student工具时,实际创建了两个东西,一个是栈内存中的变量st,存储的是类Student工具的地址值。一个是堆内存(数据区域)中的Student工具本身。在堆内存中的工具本身中,自身的属性变量(Field)并不是存放在栈内存中的,同样也是存放在堆内存中的。对付基本数据类型的变量(Filed)来说,变量存放的是详细的值,对付引用数据类型的变量(Field)来说,存放的同样是该类型指向的详细类型的地址值。引用变量都是指向堆内存里的工具。引用变量与C措辞里的指针很像,都是存储一个地址值。
5.1.3 工具的this引用
Java供应了一个this关键字,this关键字总是指向调用该方法的工具。根据this涌现位置的不同,this作为工具的默认引用有两种情形:
布局器中引用,this指的是该布局器正在初始化的工具。
在方法中引用,this指的是调用该方法的工具。
this关键字最大的浸染便是让类中一个方法,访问该类里的另一个方法或Field。
举例1:
package com.langsin.test;
publicclass Student {
Student(){
this.sex = \公众男\公众;
}
private String sex = \"大众\公众;
privatestatic String name = \"大众\"大众;
publicvoid standUp(){
this.say();
}
privatevoid say(){
System.out.println(\"大众仅供自身调用\"大众);
}
publicstaticvoid main(String[] args) {
Student st = new Student();
System.out.println(st.sex);
st.standUp();
}
}
把稳:在默认情形下,由于调用关系都是工具本身的方法或者Field,以是this可以省略。
5.2 Java中的方法
方法是类或者工具的行为特色抽象,方法是类或者工具最主要的组成部分。Java中的方法不能独立存在,所有的方法要么属于类,要么属于工具。
5.2.1 方法的所属性
在Java措辞中,方法不能独立存在,方法必须属于类或者工具。因此如果定义方法,那么方法只能定义在类体内,不能独立定义一个方法。如果方法利用static润色,那么这个方法属于这个类,否则这个方法属于这个类的实例。因此方法的实行者要么是类或者类的实例工具。
5.2.2 方法的参数通报机制
在方法声明时如果包含了形参声明,则调用方法时必须给这些形参指定参数值,调用方法时实际通报给形参的参数值也被称为实参。Java里方法的参数通报办法只有一种:值通报。所谓的值通报便是将实际参数值的副本(复制品)传入方法内,而参数本身不会受任何影响。
举例1:
package com.langsin.test;
publicclass Test {
publicvoid getSum(int a,int b){
a = a+b;
System.out.println(\"大众参数a的值改变为:\"大众+a); // 10
}
publicstaticvoid main(String[] args) {
int a = 5;
int b = 5;
Test test = new Test();
test.getSum(a, b);
System.out.println(a); // 5
}
}
基本数据类型为参数时的通报,引用数据类型为参数时的通报,通报的同样是实际值的副本,但要把稳的是引用数据类型的值存放的是地址值,即指向实际工具的那个地址值。以是调用方法时将地址值通报给了方法,方法操作时根据地址值找到了详细的工具,将详细工具的信息发生了变革。
举例2:
Student类:
package com.langsin.test;
publicclass Student {
protected String name = \"大众zhangsan\"大众;
}
Test类:
package com.langsin.test;
publicclass Test {
privatestaticvoid changeValue(Student st){
st.name = \"大众李四\"大众;
}
publicstaticvoid main(String[] args) {
Student st = new Student();
System.out.println(st.name); //zhangsan
Test.changeValue(st);
System.out.println(st.name); //李四
}
}
5.2.3 递归方法
一个方法体内调用它自身,被称为方法递归。方法递归包含了一种隐式的循环,它会重复实行某段代码,但这种重复实行无需循环掌握。
例如1:打算1+2+3+4+…..+100的和为多少?
publicclass Test {
publicstaticint getSum(int num){
if(num>1){
return num+getSum(num-1);
}else{
return num;
}
}
publicstaticvoid main(String[] args) {
int total = Test.getSum(100);
System.out.println(total);
}
}
练习:已知有一个数列,f(0)=1,f(1)=4,f(2) =2f(1)+f(0),f(n+2) = 2f(n+1)+f(n) 3 2 1
个中n是大于即是0的整数,求f(10)的值。
5.2.4 方法重载
Java许可同一个类里定义多个同名方法,只要形式参数列表不同就行。如果同一个类中包含了两个或两个以上方法的方法名相同,但形参不同,则被称为方法重载。至于方法的其他部分,如方法返回值类型、润色符即是方法重载没有任何关系。
举例1:
publicclass Test {
publicvoid printMsg(){
System.out.println(\"大众输出打印信息\"大众);
}
public String printMsg(String msg){
System.out.println(\"大众输出打印信息:\"大众+msg);
return msg;
}
publicstaticvoid main(String[] args) {
Test test = new Test();
test.printMsg();
test.printMsg(\"大众你好\"大众);
}
}
5.3 成员变量和局部变量
在Java措辞中,根据定义变量位置的不同,可以将变量分成两大类:成员变量和局部变量。成员变量和局部变量的运行机制存在较大差异。
5.3.1 成员变量和局部变量
成员变量指的是在类范围里定义的变量,也便是先容的Field;局部变量指的是在方法里定义的变量。成员变量又分为类变量与实例变量。个中利用static润色的便是类变量,可以通过类直接访问,没有用static润色的是实例变量。类变量从这个类的准备阶段开始就存在,直到系统完备销毁这个类。实例变量从该类的实例被创建时开始存在,直到系统销毁这个类的实例。
举例1:
package com.langsin.test;
publicclass Test {
publicstatic String name = \公众zhangsan\"大众; //类变量
public String age = \"大众25\"大众; //实例变量
publicstaticvoid main(String[] args) {
Test test = new Test();
test.age = \"大众36\"大众;
test.name = \公众张三\公众;
System.out.println(test.age);
System.out.println(test.name);
Test test1 = new Test();
System.out.println(test1.age);
System.out.println(test1.name);
}
}
把稳:实例Field随着实例的存在而存在,而类Field则随着类的存在而存在。实例也可以访问类Field,同一个类的所有实例访问类Field时,实际上访问的是该类本身的同一个Field。
局部变量的分类:
形参:在定义方法名时定义的变量,形参的浸染域在全体方法内有效。
方法局部变量:在方法体内定义的局部变量,它的浸染域是从定义该变量的地方生效,到该方法结束时失落效。
代码块局部变量:由代码块中定义的局部变量,这个局部变量的浸染域从定义该变量的地方生效,到该代码块结束时失落效。
举例2:
publicvoid getSum(int a,int b){ //a,b为形参局部变量
int num = a+b; // num为方法局部变量
for(int i=0;i<5;i++){ // i 为代码块局部变量,for循环结束时,i失落效
num = num + i;
}
System.out.println(num);
}
在Java中,成员变量的浸染域是全体类内有效,一个类里不能定义两个同名的成员变量,一个方法里不能定义两个相同的成员变量,但是Java许可局部变量和成员变量同名,如果方法里的局部变量跟成员变量同名,那么在一个方法内利用成员变量时,须要利用this关键字。
举例3:
publicclass Test {
public String name = \公众zhangsan\"大众;
publicvoid printName(String name){
String result = this.name + name;
System.out.println(result);
}
publicvoid printName(){
System.out.println(this.name);
}
publicstaticvoid main(String[] args) {
Test test = new Test();
test.printName(\"大众是张三\"大众);
test.printName();
}
}
5.3.2 变量的利用规则
在Java中定义变量时,须要根据不同情形来定义变量的范围。
如果变量是用来描述类或者工具的固有信息,比如一些固定不变的值的信息,须要将变量定义成类变量。
如果在某个类中须要定义一个变量来保存该类或者实例运行时的状态信息。或者变量须要在全体类范围内有效,则定义成成员变量。
如果只须要在方法中运行,则变量须要定义成局部变量。
在程序中,该当尽可能地缩小局部变量的浸染范围,局部变量的浸染范围越小,在内存中勾留的韶光越短,程序运行性能就越好。
举例1:
publicclass Test {
publicstaticintRUN_SUCCESS = 0;
publicstaticintRUN_FAILURE = 1;
publicint runStatus(int a){
if(a>0){
return Test.RUN_SUCCESS;
}else{
return Test.RUN_FAILURE;
}
}
publicstaticvoid main(String[] args) {
Test test = new Test();
int result = test.runStatus(10);
if(result==Test.RUN_SUCCESS){
System.out.println(\"大众程序运行正常\"大众);
}else{
System.out.println(\"大众程序运行失落败\"大众);
}
}
}
5.4 隐蔽与封装
在程序中常常涌现通过某个工具的直接访问其Field的情形,这会存在一系列的问题,比如定义一个Person的工具,个中有age这样一个属性,如果将属性值赋值为1000,虽然程序不会出错,但是逻辑是缺点的,人不可能活1000岁,因此常日将成员变量定义利用private关键字进行润色,然后通过方法的办法向外供应做事
举例1:
package com.langsin.test;
publicclass Test {
privateint age = 0;
publicint getAge() {
return age;
}
publicvoid setAge(int age) {
if(age>100){
this.age = 100;
}else{
this.age = age;
}
}
publicstaticvoid main(String[] args) {
Test test = new Test();
test.setAge(125);
System.out.println(test.getAge());
}
}
5.4.1 理解封装
封装是面向工具的三大特色之一,它指的是将工具的状态信息隐蔽在工具内部,不许可外部程序直接访问工具的内部信息,而是通过该类所供应的方法来实现对内部信息的操作和访问。
封装可以实现以下目的:
隐蔽类的实现细节
利用者只能通过供应的方法来访问数据,从而可以在方法中加入掌握逻辑,限定对变量的不合理的访问。
可进行数据检讨,从而有利于担保工具信息的完全性。
便于修正,提高代码的可掩护性。
封装的实际含义便是该隐蔽的隐蔽,该暴漏的暴漏。
5.4.2 package、import
Oracle公司供应的JDK、各种软件厂商、浩瀚的开拓商,会供应成千上万、具有各种用场的类,那么类名肯定会涌现同名的这种情形,为了处理重名问题,Java引入了包(package)机制,供应了类的多层命名空间,用于办理类的命名冲突、类文件管理问题。
Java源文件中利用了pageckage语句,就意味着该源文件里定义的所有类属于这个包下。位于包中的每个类的完全类名都该当是包名和类名的组合。
举例1:
publicclass Test {
publicstaticvoid main(String[] args) {
com.langsin.vo.Page page1 = new com.langsin.vo.Page();
}
}
为了简化编程,Java引入了import关键字,import可以向某个Java文件中导入指定包层次下的某个类或全部类,import语句涌如今package语句之后,类定义之前。
举例2:
package com.langsin.test;
import com.langsin.vo.Page;
publicclass Test {
publicstaticvoid main(String[] args) {
Page page = new Page();
System.out.println(page.getLineNum());
}
}
Import语句可以简化编程,可以导入报销某个类或者全部类,导入全部类的办法用表示,
举例3:
import com.langsin.vo.;
表示导入com.langsin.vo包下的所有类。
5.4.3 Java的常用包
Java的核心类都放在java这个包以及其子包下,Java扩展的许多类都放在javax包以及其子包下,这些实用类也便是前面所说的API。
java.lang:这个包下包含了Java措辞的核心类,如String、Math、System、和Thread类等,利用这个包下的类无须利用import语句导入,系统会自动导入这个包下的所有类。
java.util:这个包下包含了Java的大量工具类/接口和凑集框架类/接口,例如Arrays和List、Set等。
java.net:这个包下包含了一些Java网络编程干系的类和接口。
java.io:这个包下包含了一些Java输入/输出编程干系的类和接口。
java.text:这个包下包含了一些Java格式化干系的类。
java.sql:这个包下包含了Java进行JDBC数据库编程的干系类和接口。
java.awt:这个包下包含了抽象窗口工具集的干系类和接口,这些类紧张用于构建图形用户界面(GUI)程序。
java.swing:这个包下包含了Swing图形用户界面编程的干系类和接口,这些类可用于构建平台无关的GUI程序。
5.5 深入布局器
布局器是一个分外的方法,这个分外方法用于创建实例时实行初始化。布局器是创建工具的主要路子,因此Java类必须包含一个或一个以上的布局器。
5.5.1 利用布局器进行初始化
布局器最大的用途便是在创建工具时实行初始化,所谓的初始化便是创建工具时,系统对这个工具的Field进行赋值处理。
举例1:
package com.langsin.test;
publicclass Test {
private String name = null;
privateint age = 0;
Test(String name,int age){
this.name = name;
this.age = age;
}
public String getName(){
returnthis.name;
}
publicvoid setName(String name){
this.name = name;
}
publicint getAge(){
returnthis.age;
}
publicvoid setAge(int age){
this.age = age;
}
publicstaticvoid main(String[] args) {
Test test = new Test(\公众张三\"大众,35);
System.out.println(test.getName());
System.out.println(test.getAge());
}
}
把稳:如果程序员供应了自定义的布局器,系统就不再供应默认的布局器,因此上例中Test类中供应告终构器因此不能再通过new Test()代码来创建实例,由于该类不再包含无参数的布局器。
5.5.2 布局看重载
同一个类里具有多个布局器,多个布局器的形参列表不同,即被称为布局看重载。布局看重载许可Java类里包含多个初始化逻辑,从而许可利用不同的布局器来初始化java工具。
举例1:
package com.langsin.test;
publicclass Test {
private String name = null;
privateint age = 0;
public Test(String name,int age){
this.name = name;
this.age = age;
}
public Test(){
}
public String getName(){
returnthis.name;
}
publicvoid setName(String name){
this.name = name;
}
publicint getAge(){
returnthis.age;
}
publicvoid setAge(int age){
this.age = age;
}
publicstaticvoid main(String[] args) {
Test test = new Test(\公众张三\"大众,35);
System.out.println(test.getName());
Test test1 = new Test();
System.out.println(test1.getName());
}
}
5.6 类的继续
继续是面向工具的又一大特色,也是实现软件复用的主要手段。Java的继续具有单继续的特点,每个子类只有一个直接父类。
5.6.1 继续的特点
Java的继续通过extends关键字来实现,实现继续的类被称为子类,被继续的类被称为父类(或者称为基类、超类)。父类和子类的关系是一种一样平常和分外的关系。子类扩展了父类,将可以得到父类全部的Filed成员变量和方法。例如车跟宝马的关系,宝马继续了车,宝马是车的子类,则宝马是一种分外的车。
由于子类是一种分外的父类,因此父类包含的范围总比子类包含的范围要大,以是可以认为父类是大类,而子类是小类。例如:车包含很多种车,宝马、陆虎、博兰基尼都是车的子类,你可以说这些都是车,但是你不能说车是宝马、陆虎、博兰基尼。
Java类只能有一个直接的父类,但是Java类可以有无限多个间接父类。例如:
public class HighGradeCar extends Car{}
public class BmwCar extends HighGradeCar{}
BmwCar类有两个父类,一个是Car,一个是HighGradeCar。
如果定义一个Java类时并未显示指定这个类的直接父类,则这个类默认扩展java.lang.Object类,因此java.lang.Object类是所有类的父类,要么是其直接父类,要么是其间接父类。
5.6.2 重写父类的方法
子类扩展了父类,子类是一个分外的父类。大部分情形下子类总是以父类为根本,额外增加新的Field和方法,但是有一种分外的情形例外:子类须要重写父类的方法。
举例1:父类Bird类
package com.langsin.test;
publicclass Bird {
publicvoid fly(){
System.out.println(\"大众可以在天空中飞行....\公众);
}
}
package com.langsin.test;
publicclass Ostrich extends Bird {
@Override
publicvoid fly() {
System.out.println(\公众只能在地上跑......\公众);
}
publicstaticvoid main(String[] args) {
Ostrich os = new Ostrich();
os.fly();
}
}
程序实行时,不再实行父类Bird中fly()方法,而是实行了自身的fly()方法,这种子类包含与父类同名方法的征象称为重写,也称为方法覆盖(Override)。方法的重写要遵照如下规则:
方法名相同、形参列表相同
子类方法返回值类型应比父类方法返回值类型相等或者更小
子类方法声明抛出的非常类该当比父类方法更小或相等。
当子类覆盖了父类方法后,子类工具将无法访问父类中被覆盖的方法,但可以在子类方法中调用父类中被覆盖的方法,须要利用super关键字。如果父类方法具有private访问权限,则该方法对其子类是隐蔽的,也就无法重写该方法。如果子类中定义了一个与父类private方法相同的方法名、相同形参列表、相同返回值类型的方法,依然不是重写,只是在子类中定义了一个新的方法而已。
举例2:
package com.langsin.test;
publicclass Bird {
publicvoid fly(){
System.out.println(\公众可以在天空中飞行....\"大众);
}
privatevoidgetFood(){
System.out.println(\公众得到小虫子\公众);
}
}
package com.langsin.test;
publicclass Ostrich extends Bird {
@Override
publicvoid fly() {
super.fly();
System.out.println(\"大众只能在地上跑......\"大众);
}
publicstaticvoid main(String[] args) {
Ostrich os = new Ostrich();
os.fly();
}
}
父类中定义的fly方法,利用super可以调用到,但是getFood()方法缺无法调用到,由于此方法是私有方法,只有父类本是可调用。利用super关键字调用fly()方法,就可以实行父类中被重写的方法。
5.6.3 super限定
Super是Java供应的关键字,super用于限定该工具调用从父类继续得到的Field成员变量或方法。如果在布局器中利用super,则super用于限定该布局器初始化的是该工具从父类继续得到的Field,而不是该类自己定义的Field。
在子类进行实例化时,会首先调用父类的布局方法,对父类中的Field成员变量或者方法进行初始化,并创建会父类工具。
举例1:
package com.langsin.test;
publicclass Bird {
Bird(){
System.out.println(\公众=========\"大众);
}
private String name = \"大众\"大众;
publicvoid setName(String name){
this.name = name;
}
public String getName(){
returnthis.name;
}
publicvoid fly(){
System.out.println(\公众可以在天空中飞行....\公众);
}
}
子类:
package com.langsin.test;
publicclass Ostrich extends Bird {
Ostrich(){
super.setName(\"大众小鸟\"大众);
}
private String name = \公众鸵鸟\"大众;
public String getName(){
returnthis.name;
}
@Override
publicvoid fly() {
System.out.println(\公众只能在地上跑\"大众);
System.out.println(super.getName());
System.out.println(this.getName());
}
publicstaticvoid main(String[] args) {
Ostrich os = new Ostrich();
os.fly();
}
}
5.6.4 调用父类布局器
子类继续父类,子类在实例化时会首先调用父类的布局方法,对父类成员进行初始化。如果父类的布局方法是隐式的,那么Java会帮我们进行自动调用。而如果父类的布局方法是显式的,那么子类就必须声明一个显示的布局方法,同时在布局器中显示的调用父类的布局器。
举例1:
package com.langsin.test;
publicclass Bird {
Bird(String name){
System.out.println(\公众=========\"大众);
}
}
package com.langsin.test;
publicclass Ostrich extends Bird {
Ostrich() {
super(\"大众小鸟\公众);
}
}
5.7 多态
Java引用变量有两个类型,一个是编译时类型,一个是运行时类型。编译时类型由声明该变量时利用的类型决定,运行时类型由实际赋给该变量的工具决定。如果编译时类型和运行时类型不一致,就可能涌现多态。所谓的多态便是同样一个东西表现出多种不同办法。
5.7.1 多态性
Java中的多态性也是由Java面向工具中继续特色导致的。由于子类是一种分外的父类,因此Java许可把一个子类工具直接赋值给父类引用变量,无须任何类型转换。或者称为向上转型,向上转型由系统自动完成。如果子类重写了父类的方法,那么利用父类引用变量指向不同的子类时,调用方法相同,但表现形式有所不同,这种征象就成为多态。
举例1:
package com.langsin.test;
publicclass BmwCar extends Car {
publicvoid run() {
System.out.println(\公众我是宝马车。。。。\公众);
}
}
=======================================================
package com.langsin.test;
publicclass BenzCar extends Car {
publicvoid run() {
System.out.println(\"大众我是兰博基尼车。。。。\"大众);
}
}
========================================================
package com.langsin.test;
publicclass Car {
publicvoid run(){
System.out.println(\"大众我是所有车的父类......\"大众);
}
publicstaticvoid main(String args[]){
//编译时类型与运行时类型完备同等,以是不存在多态
Car car = new Car();
car.run();
//编译时类型与运行时类型不一致,以是存在多态
car = new BmwCar();
car.run();
//编译时类型与运行时类型不一致,以是存在多态
car = new BenzCar();
car.run();
}
}
5.7.2 引用变量的逼迫类型转换
编写Java程序时,引用变量只能调用它编译时类型的方法,而不能调用它运行时类型的方法,纵然它实际引用的工具确实包含该方法,也无法引用到。如果须要让这个引用变量调用它运行时类型的方法,则必须把它逼迫转换成运行时类型,逼迫类型转换须要借助于类型转换运算符。
举例1:
package com.langsin.test;
publicclass BmwCar extends Car {
publicvoid run() {
System.out.println(\公众我是宝马车。。。。\公众);
}
publicvoid description(){
System.out.println(\"大众高端、大气、上档次\公众);
}
}
package com.langsin.test;
publicclass Car {
publicvoid run(){
System.out.println(\"大众我是所有车的父类......\"大众);
}
publicstaticvoid main(String args[]){
Car car = new BmwCar();
car.run(); //调用本身类所定义的方法
((BmwCar)car).description(); //进行逼迫转换后调用子类工具中的方法
}
}
逼迫类型转换不是万能的,当进行逼迫类型转换时须要把稳:
基本类型之间的转换只能在数值类型之间进行,数值类型包括整数型、字符型和浮点型。但数值类型和布尔类型之间不能进行类型转换。
引用类型之间的转换只能具有继续关系的两个类之间进行,如果两个没有任何继续关系的类型,则无法进行类型转换。如果将一个父类类型转换成子类类型,那么这个父类类型指向的实例必须是子类类型的实例才行,否则在运行时会引发类型转换非常(ClassCastException)。
举例1:
package com.langsin.test;
publicclass Test {
publicstaticvoid main(String[] args) {
double d = 13.4;
//将浮点型转换发展整型
longl = (long)d;
inta = 4;
//无法将一个整型逼迫转换成boolean型,下面这行代码编译报错
//boolean b = (boolean)a;
//由于Object是所有类的父类,以是String是它的子类
Object obj = \"大众Hello World\"大众;
//obj引用类型指向的是一个详细的String类,以是可以进行逼迫转换
String str = (String)obj;
//Integer类是int数据类型的详细类,它也是Object的子类
obj = new Integer(5);
//由于obj已经指向了一个详细的整型数据类,以是再进行逼迫转换时就报ClassCastExcetpion非常
str = (String)obj;
}
}
5.7.3 instanceof运算符
Instanceof运算符的前一个操作数常日是一个引用类型变量,后一个操作数常日是一个类(也可以是接口,接口也是类,是一种分外的类),它用于判断前面引用变量所指向的详细工具是否是后面这个类,或者后面这个类的子类、后面这个类的实现类的一个实例工具。是则返回ture,否则返回false。
举例1:
package com.langsin.test;
publicclass Test {
publicstaticvoid main(String[] args) {
Object obj = \"大众hello\公众;
//obj指向了一个详细的String类,Object是所有类的父类,String是它的子类,以是返回true
System.out.println(obj instanceof Object);
//obj为String类,是String类型的实例,所有返回true
System.out.println(obj instanceof String);
//obj为String类,Math是Object的子类,但不是String的子类,以是返回false
System.out.println(obj instanceof Math);
String a = \"大众hello\"大众;
//String既不是Math的父类也不是Math类,所有下面编译报错
System.out.println(a instanceof Math);
}
}
5.8 继续与组合
继续是实现类重用的主要手段,但是继续带来了一个最大的坏处:毁坏封装。比较之下,组合也是实现类重用的主要办法,而采取组合办法来实现类重用则能供应更好的封装。下面详细先容继续和组合之间的联系与差异。
5.8.1 利用继续的把稳点
子类扩展父类时,子类可以从父类继续得到Filed和方法。如果访问权限许可,子类可以直接访问父类的Field和方法,相称于子类可以直接复用父类的Field和方法。继续带来了高度复用的同时,也带来了一个严重的问题:那便是继续严重毁坏了父类的封装性。封装:每个类都该当访问父类的Field和方法,而只须要暴漏必要的方法给其他类利用。但是在继续关系中,子类可以直接访问父类的Field和方法,从而造成子类与父类的严重耦合。
父类的实现细节对付子类来说不再透明,子类可以访问父类的Field和方法,并可以改变父类的方法的实现细节,从而导致子类可以任意的修改父类的方法。
举例1:
package com.langsin.test;
publicclass Bird {
public String name = \"大众小鸟\"大众;
publicvoid fly(){
System.out.println(this.name+\公众可以在天空中自由飞行。。。\"大众);
}
Public void run(){
this.fily();
}
}
修改属性:
package com.langsin.test;
publicclass Ostrich extends Bird {
publicvoid test(){
this.name = \"大众大象\公众; //任意修改了父类的属性信息
this.fly();
}
publicstaticvoid main(String[] args) {
Ostrich os = new Ostrich();
os.test();
}
}
修改方法:
package com.langsin.test;
publicclass Ostrich extends Bird {
publicvoid test(){
this.fly();
}
//任意修改方法
publicvoid fly(){
System.out.println(this.name+\"大众在水中游来游去。。。\"大众);
}
publicstaticvoid main(String[] args) {
Ostrich os = new Ostrich();
os.test();
}
}
对付此种问题,基于担保父类有良好的封装,不会被子类随意改变,设计父类时常日遵照如下规则。
只管即便隐蔽父类的内部数据,只管即便把父类的所有Field都设置成private访问类型,不让子类直接访问父类的Field.
不要让子类可以随意访问、修正父类的方法。父类中作为赞助其他方法的工具方法,该当利用private访问掌握符润色,让子类无法访问该方法。如果父类中的方法须要被外部类调用,则必须以public润色,但又不肯望被子类重写该方法,可以利用final润色符来润色,表示终极的方法。如果父类的方法可以让子类重写,但是又不肯望被其他类自由访问,可以利用protected来润色该方法。
不要在父类布局方法中调用将会被子类重写的方法。由于如果方法被子类重写,那么父类初始化时,布局方法中调用的是被子类重写的方法,而不是本身的那个方法。
举例2:
package com.langsin.test;
publicclass Bird {
Bird(){
this.fly();
}
publicvoid fly(){
System.out.println(\"大众小鸟可以在天空中自由飞行。。。\公众);
}
}
package com.langsin.test;
publicclass Ostrich extends Bird {
publicvoid fly(){
System.out.println(\公众鱼儿在水中游来游去。。。\公众);
}
publicstaticvoid main(String[] args) {
Ostrich os = new Ostrich(); //在创建子类工具时,父类布局方法调用了被子类重写的方法。
}
}
把稳:如果把某些类设置成终极类,即利用final润色符润色这个类,那么这个类将不能被当成父类。例如JDK所供应的java.lang.String类,java.lang.System类,都是终极类。
5.8.2 利用组合实现复用
如果须要复用一个类,除了把这个类当成基类来继续之外,还可以把该类当成其余一个类的组成部分,从而许可新类直接复用该类的public方法。因此,不管是继续还是组合,都许可在新类中直接复用旧类的方法。
举例1:
package com.langsin.test;
publicclass Person {
private String sex;
privateint age;
private String name;
public String getSex() {
return sex;
}
publicvoid setSex(String sex) {
this.sex = sex;
}
publicint getAge() {
return age;
}
publicvoid setAge(int age) {
this.age = age;
}
public String getName() {
return name;
}
publicvoid setName(String name) {
this.name = name;
}
}
Student学生
package com.langsin.test;
publicclass Student {
private String schoolName;
private Person pseron = new Person();
publicstaticvoid main(String[] args) {
Student student = new Student();
student.schoolName = \"大众山东轻工业大学\"大众;
student.person.setAge(22);
student.person.setName(\公众张三\公众);
student.person.setSex(\"大众男\公众);
System.out.println(\"大众姓名:\公众+student.person.getName());//组合的利用
System.out.println(\"大众年事:\公众+student.person.getAge());
System.out.println(\"大众性别:\"大众+student.person.getSex());
System.out.println(\"大众学校:\公众+student.schoolName);
}
}
Worker工人类
package com.langsin.test;
publicclass Worker {
private String factoryName;
private Person person = new Person();
publicstaticvoid main(String[] args) {
Worker worker = new Worker();
worker.factoryName = \公众山东齐鲁制药厂\"大众;
worker.person.setName(\公众李四\"大众);
worker.person.setAge(25);
worker.person.setSex(\"大众男\"大众);
System.out.println(\"大众姓名:\"大众+worker.person.getName());
System.out.println(\"大众年事:\公众+worker.person.getAge());
System.out.println(\"大众性别:\公众+worker.person.getSex());
System.out.println(\"大众学校:\公众+worker.factoryName);
}
}
5.9 初始化块
Java利用布局器来对单个工具进行初始化操作,利用布局器先完玉成部Java工具的状态初始化,然后将Java工具返回给程序,从而让该Java工具的信息更加完全。与布局器浸染非常类似的是初始化块,也可以对Java工具进行初始化操作。
5.9.1 利用初始化块
初始化块是Java类里可以涌现的第四种成员,一个类里可以有多个初始化块,相同类型的的初始化块之间有顺序:前面定义的初始化块先实行,后面定义的初始化块后实行。
语法格式如下:
[润色符]{
//初始化块的可实行代码
}
初始化块的润色符只能是static,利用static润色的初始化块被称为静态初始化块。初始化块里的代码可以包含任何可实行性语句,包括定义语句变量、调用其他工具的方法,以及利用分支、循环语句等。
举例1:
package com.langsin.test;
publicclass Person {
Person(){
System.out.println(this.gender);
}
//一行代码的初始化块,先实行下面代码
private String gender = \公众女\"大众;
//初始化块
{
System.out.println(this.gender); // 女
this. gender = \"大众男\"大众;
System.out.println(this.gender); // 男
}
publicstaticvoid main(String[] args) {
Person person = new Person();
//工具创建之后,首先实行初始化块,private String gender = “女”;也是初始化块
}
}
//先处理静态的
5.9.2 初始化块和布局器
初始化块先于布局器实行,系统可以同样利用初始化块来进行工具的初始化操作。初始化块是一段固定实行的代码,它不能吸收任何参数,因此如果工具有一段初始化处理代码对所有工具都完备相同,且无须吸收任何参数,就可以把这段初始化代码提取到初始化块中。
举例1:
publicclass Person {
Person(){
this.currentCityName = \公众青岛\"大众;
System.out.println(this.nation+\公众:\"大众+this.currentCityName);
}
//如果仅仅是定义变量且初始化的代码块,则可以不放到{}中
private String nation = \公众中国\"大众;
private String currentCityName = \"大众济南\公众;
//代码块会被首先实行,如果是可实行的语句必须将代码放到代码块中,即{}中
{
System.out.println(this.nation+\"大众:\公众+this.currentCityName);
This.currentCityName = “淄博”;
System.out.println(this.nation+\"大众:\"大众+this.currentCityName);
}
publicstaticvoid main(String[] args) {
Person person = new Person();
}
}
输出信息:中国 济南
中国 淄博
中国 青岛
5.9.3 静态初始化块
定义初始化块时利用了static润色符,则这个初始化块就变成了静态初始化块,也被称为类初始化块。静态初始化块是类干系的,系统在类初始化阶段时实行静态初始化块,而不是在创建工具时才实行。因此静态初始化块总是比普通初始化块先实行。
举例1:
package com.langsin.test;
publicclass Person {
Person(){
this.currentCityName = \公众青岛\"大众;
System.out.println(this.nation+\"大众:\公众+this.currentCityName);
}
private String nation = \"大众中国\"大众;
private String currentCityName = \"大众济南\"大众;
{
System.out.println(this.nation+\"大众:\"大众+this.currentCityName);
}
privatestatic String flag = \公众success\"大众;
static{
System.out.println(Person.flag);
Person.flag = \"大众false\"大众;
System.out.println(Person.flag);
}
publicstaticvoid main(String[] args) {
Person person = new Person();
}
}
第6章:面向工具(下)
Java供应了final关键字来润色变量、方法和类,系统不许可为final变量重新赋值,子类不许可覆盖父类的final方法,final类不能派生子类。通过利用final关键字、许可Java实现不可变类,不可变类会让系统更加安全。
abstract和interface两个关键字分别用于定义抽象类和接口,抽象类和接口都是从多个子类中抽象出来的共同特色。但抽象类紧张作为多个类的模板,而接口则定义了多类该当遵守的规范。enum关键字用于创建列举类,列举类是一种不能自由创建工具的类,列举类的工具在定义类时已经固定下来。
6.1 Java增强的包装类
Java是面向工具编程措辞,但同样供应了8中基本数据类型,这8种基本数据类型不支持面向工具的编程机制,基本数据类型同样也不具备“工具”的特色:没有Field成员变量、没有方法可以被调用。8种基本数据类型带来一定的方便性,即:可以进行大略、有效的常规数据处理。但在某些时候基本数据类型会有一些制约。例如:所有的引用类型的变量都继续Object类,都可以当成Object类型变量利用,但是基本数据类型则不可以,如果某些类供应的方法须要Object类型的参数,但实际的数值确是1、2、3、4等数值,这种情形就难以处理。
为理解决8中基本数据类型的变量不能当成Object类型变量利用的问题,Java供应了包装类的观点,为8中基本数据类型分别定义了相应的引用类型,并称为基本数据类型的包装类。
举例1:如何将基本数据类型转换成对应的包装类
publicstaticvoid main(String[] args) {
int a = 5;
Integer ia = new Integer(a);
System.out.println(ia);
boolean b = true;
Boolean bl = new Boolean(b);
System.out.println(bl);
Float fl = new Float(12.5);
System.out.println(fl);
float f = 12.5f;
fl = new Float(f);
System.out.println(fl);
fl = new Float(\"大众12.5\"大众);
System.out.println(fl);
}
所有基本数据类型包装类,都供应通过向包装类布局器中传入一个字符串参数的办法来创建包装类工具。但是如果传入的字符串参数不符合基本数据类型格式,那么将引发java.lang.NumberFormatException非常。数据转换格式化非常。
例如:Integer a = new Integer(“aaa”);就会引发数据转换格式化非常。
装箱与拆箱
Java供应的基本数据类型与包装类之间的转换有点繁琐,在JDK1.5版本中供应了自动装箱与拆箱的功能。所谓的自动装箱与拆箱便是可以把一个基本类型的数据变量赋值为包装类变量,或者赋值给Object变量,子类工具可以直接赋值给父类变量便是装箱的一种表示。
自动拆箱则与之相反,许可直接把包装类工具直接赋值给一个对应的基本类型变量。
举例2:
publicstaticvoid main(String[] args) {
//自动装箱
Integer a = 5;//引用行的变量只能接管一个工具!
Object obj = new Float(\"大众12.5\"大众);
//自动拆箱
intb = new Integer(6);
}
基本数据类型与字符串之间的转换
利用包装类供应的parseXxx(String s)的静态方法,将String类型的数据转换成相应的基本数据类型
利用包装类供应的Xxx(String s)布局器
String类型供应了多个valueOf()方法,用于将基本类型变量转换成字符串。
举例3:
publicstaticvoid main(String[] args) {
int a = Integer.parseInt(\"大众125\公众);
float f = Float.parseFloat(\"大众12.5\公众);
boolean b = Boolean.parseBoolean(\"大众true\"大众);
String str = String.valueOf(a);
str = String.valueOf(f);
str = String.valueOf(b);
}
6.2 处理工具
Java工具都是Object类的实例,都可以直接调用Object类中定义的方法,这些方法供应了处理Java工具的通用方法。
6.2.1 打印工具和toString方法
创建一个工具,并将工具在掌握台打印出来。
package com.langsin.test;
publicclass Test {
publicstaticvoid main(String[] args) {
Test test = new Test();
System.out.println(test);
}
}
输出结果:com.langsin.test.Test@de6ced
System.out.println()方法只能在掌握台输出字符串,而Test是内存中的一个工具,实际上输出Test的时候默认的调用的是Test从Object工具中继续的toString()方法。等同于System.out.println(test.toString());
Object类供应的toString方法是对该工具的“自我描述”信息,该方法总是返回实现类的“类名+@+hashCode”值,这个返回值并不能真正实现“自我描述”,就必须重写Object类的toString方法。
举例2:
publicclass Test {
public String toString(){
return\"大众自我描述\公众;
}
publicstaticvoid main(String[] args) {
Test test = new Test();
System.out.println(test);
}
}
6.2.2 ==和equals方法
Java中止定两个变量是否相等有两种方法:一种是利用==运算符,另一种是利用equals方法。当利用==来判断两个变量是否相等时,如果两个变量是基本类型变量,并且是数值类型,只要两个值相等则返回true。对付引用类型,它们指向同一个工具时,“==”判断才返回true。==不可用于比较类型上没有父子关系的两个工具。
举例1:
publicstaticvoid main(String[] args) {
int a = 1;
int b = 1;
System.out.println(a==b); // true
String s1 = \"大众abc\"大众;
String s2 = \公众abc\公众;
System.out.println(s1==s2); // true
s2 = new String(\"大众abc\公众);
System.out.println(s1==s2); // false
Object obj = \公众abc\"大众;
System.out.println(s1==obj); // true
obj = new String(\公众abc\"大众);
System.out.println(s1==obj); // false
System.out.println(s2==obj); // false
Integer it = 5;
System.out.println(s2==it); //编译出错//类型
}
程序判断两个引用变量是否相等时,equals是进行一种“值相等”的判断,并不严格哀求两个引用变量指向同一个工具。例如:对付两个字符串变量,可能只是哀求它们引用字符串工具里包含的字符串序列相同即可。
举例2:String s1 = new String(“abc”); String s2 = new String(“abc”);
判断两个变量所包含的值是否相等时,就可以用equals方法来进行判断。
publicstaticvoid main(String[] args) {
String s1 = new String(\"大众abc\"大众);
String s2 = new String(\公众abc\"大众);
System.out.println(s1.equals(s2));
}
把稳:利用equals方法常用于两个字符串之间的值比较。
6.3 类成员
Static关键字润色的成员便是类成员,个中有类变量Field、类方法、静态初始化块。Static润色的类成员属于全体类,不属于单个实例。
6.3.1 理解类成员
在Java类里只能包含Field、方法、布局器、初始化块、内部类(接口、列举)5中成员,个中static可以润色Field、方法、初始化块、内部类。以static润色的成员便是类成员。类成员属于全体类,而不是属于单个工具。
类Field既可以通过类来访问,也可以通过类的工具来访问。但是通过类的工具来访问类Field时,实际上访问的并不是该工具所拥有的Field,而是类所拥有的Field。可以理解为:当通过工具来访问类Field时,系统会在底层转换为通过该类来访问类Field。
举例1:
publicclass Test {
Public static inta = 1;
publicvoid run(){
a++;
System.out.println(a);
}
publicstaticvoid main(String[] args) {
Test t1 = new Test();
t1.run(); //
Test t2 = new Test();
t2.run(); //
}
}
类方法也是类成员的一种,类方法属于类的,常日直策应用类作为调用者来调用类方法,但是可以利用工具来调用类方法,与类Field累世。
静态初始化块也是类成员的一种,静态初始化块用于实行类初始化动作,在类的初始化阶段,系统会调用该类的静态初始化来对类进行初始化。一旦该类初始化结束后,静态初始化块将永久不会得到实行的机会。
对付static关键字而言,有一条非常主要的规则:类成员不能访问实例成员。由于类成员是属于类的,类成员的浸染域比实例成员更大,完备可能涌现类成员已经初始化完成,但实例成员还未曾初始化的情形。如果许可类成员访问实例成员将会引发大量的缺点。
6.3.2 单例类
在Java中,类的布局器默认为public的权限,许可任何类自由的创建该类的工具。但是在某些情形下一些类自由的创建该类的实例工具没有任何意义,比如说:一个别系的窗口管理器、一个数据库引擎访问点,此时如果在系统中为这些类创建多个工具就没有太大的实际意义。
以是在这种情形下,可以设计一个类只能创建一个实例,则这个类被称为单例类。
创建单例类的步骤:
利用private关键字润色布局器
供应一个public的static的类方法调用布局器
创建一个static的成员变量来保存类工具,同时判断工具是否已经创建
举例1:
package com.langsin.test;
publicclass Singleton {
private Singleton(){
}
privatestatic Singleton single = null;
publicstatic Singleton getInstance(){
if(single==null){
single = new Singleton();
}
returnsingle;
}
publicstaticvoid main(String[] args) {
Singleton s1 = Singleton.getInstance();
Singleton s2 = Singleton.getInstance();
System.out.println(s1==s2);
}
}
6.4 final润色符
final关键字可用于润色类、变量和方法,用于表示它润色的类、方法和变量不可改变。final润色变量时,表示该变量一旦得到了初始值,就不可被改变,final既可以润色成员变量,也可以润色局部变量、形参。
6.4.1 final成员变量
成员变量是随着类初始化或者工具的初始化而初始化的。那么成员变量的初始值可以在定义变量时指定默认的初始值也可以在初始化块或者布局器中指定初始值。
对付final润色的成员变量而言,一旦有了初始值,就不能被重新赋值。如果没有在定义成员变量是指定初始值,也没有在初始化块、布局器中指定初始值,那么这些成员变量也就失落去了意义。因此Java语法规定:final润色的成员变量必须由开拓职员显示的指定默认值,系统不会对final成员变量进行隐式赋值。
利用final润色的成员变量初始化归纳如下:
类Field:必须在静态初始化块中或声明该Field时指定初始值。
实例Field:必须在非静态初始化块、声明该Field或布局器中指定初始值.
举例1:
package com.langsin.test;
publicclass Test {
public Test(){
s3 = \"大众abc\"大众; //变量s3在布局器中初始化
}
publicstaticfinalinta; //类变量a定义时没有初始化,但在静态化块中进行初始化
publicstaticfinalintb = 2; //类变量b在定义时进行了初始化
static{
a = 1; //在静态化块中对a进行了初始化
}
publicfinal String s1 = \"大众abc\"大众; //普通成员变量在定义时进行了初始化
publicfinal String s2; //普通成员变量在s2在初始化块中进行了初始化。
{
s2 = \公众123\"大众;
}
publicfinal String s3; //普通成员变量s3在定义时没有初始化,但是在布局器中进行了初始化。
}
6.4.2 final局部变量
系统不会对局部变量进行初始化,局部变量必须由程序员显示初始化。因此利用final润色局部变量时,既可以在定义时指定默认值,也可以不指定默认值。
如果final润色的局部变量在定义时没有指定默认值,则可以在后面代码中对该final变量赋初始值,但只能赋值一次,不能重复赋值。
举例1:
publicclass Test {
publicvoid run(){
Final int a = 1;
for(int i=0;i<5;i++){
a = i; //程序编译时报错,提示去掉final
}
System.out.println(a);
}
}
6.4.3 final润色基本类型和引用类型变量的差异
利用final润色基本类型变量时,不能对基本类型变量重新赋值,因此基本类型不能被改变。但对付引用类型变量而言,它保存的仅仅是一个引用,final只能担保这个引用类型变量所引用的地址不会改变,即一贯指向这个工具,但这个工具完备可以改变。
举例1:
package com.langsin.test;
publicclass Test {
privatefinal Student st = new Student();
publicvoid run(){
st.setAge(36);
st.setName(\"大众王二\"大众);
System.out.println(st.getAge());
System.out.println(st.getName());
}
publicstaticvoid main(String[] args) {
Test test = new Test();
test.run();
}
}
class Student{
privateint age = 25;
private String name = \"大众张三\"大众;
publicint getAge() {
return age;
}
publicvoid setAge(int age) {
this.age = age;
}
public String getName() {
return name;
}
publicvoid setName(String name) {
this.name = name;
}
}
6.4.4 final方法
Final润色的方法不可被重写,出于某些缘故原由,不肯望子类重写父类的某些方法,则可以利用final润色该方法。
Java供应的Object类里中供应的getClass()方法便是利用final进行润色的,由于Java不肯望任何类重写这个方法,以是利用final把这个方法封闭起来。但对付该类供应的toString()和equals()方法,都许可子类重写,因此没有利用final润色他们。
举例1:
package com.langsin.test;
publicclass Bird {
publicfinalvoid fly(){
System.out.println(\"大众小鸟可以在天空中自由飞行。。。\"大众);
}
}
getclass
package com.langsin.test;
publicclass Ostrich extends Bird {
publicvoidfly(){
System.out.println(\"大众鱼儿在水中游来游去。。。\"大众);
}
}
子类Ostrich在重写fly方法时编译报错。
把稳:对付利用private润色的方法,表示私有方法,只能是工具本身调用,那么子类在继续时是无法访问该方法的,以是子类无法重写该方法。如果子类中定义一个与父类private方法相同方法名、相同返回值类型、相同参数列表的方法,也不是重写,而是定义了一个新的方法。因此纵然利用final润色一个利用private访问权限的的方法,依然可以在其子类中定义一个与该方法千篇一律的方法。
package com.langsin.test;
publicclass Bird {
privatefinalvoidfly(){
System.out.println(\"大众小鸟可以在天空中自由飞行。。。\公众);
}
}
package com.langsin.test;
publicclass Ostrich extends Bird {
publicvoidfly(){
System.out.println(\公众鱼儿在水中游来游去。。。\公众);
}
}
此时,此类中定义的方法将不会编译报错。
6.4.5 final类
final润色的类不可以有子类,例如:java.lang.Math类便是一个final类,它不可以有子类。
当子类继续父类时,将可以访问到父类内部数据,并可通过重写父类的方法来改变父类方法的实现细节,这可能会导致一些不屈安的成分。为了确保某个类不被继续,则可以利用final类润色这个类。
6.4.6 不可变类
不可变类的意思是创建该类的实例后,该实例的Field是不可改变的。Java供应的8个数据类型包装类和java.lang.String类都是不可变类,当创建他们的实例后,实在例的Field不可改变。
举例:
Double d = new Double(\公众12.5\"大众);
String str = new String(\"大众abc\"大众);
创建两个工具,并传入了两个字符串作为参数,那么Double类和String类肯定须要供应实例成员变量来存放这个两个参数,但程序无法修正这两个实例成员的值。
因此,如果须要创建自定义的不可变类,可遵照如下规则:
利用private和final润色符来润色该类的Field
供应参数布局器,用于根据传入参数来初始化类里的Field
仅为该类的Field供应getter方法。
6.5 抽象类
当编写一个类时,常常会为该类定义一些方法,这些方法用于描述这个类的行为。但在某些情形下只须要定义出一些方法,而不须要详细的去实现这些行为。也便是说这些方法没有方法体,只是一些署名而已,这样的方法被称为抽象方法,包含抽象方法的类被称为抽象类。
6.5.1 抽象方法与抽象类
抽象方法与抽象类必须利用abstract关键字进行润色,有抽象方法的类必须被定义成抽象类,抽象类里面可以没有抽象方法。
抽象类与抽象方法的规则如下:
抽象类与抽象方法必须利用abstract关键字进行润色,抽象方法不能有方法体。
抽象类不能被实例化。纵然抽象类不包含抽象方法,也不能被实例化。
抽象类可以包含Field、方法、布局器、初始化块、内部类、列举类6种身分。
包含抽象方法的类,只能被定义成抽象类。
举例1:
package com.langsin.test;
publicabstractclass Test {
public String name = \"大众zhangsan\"大众;
publicabstractvoid setName();
publicabstract String getName();
publicvoid run(){
System.out.println(\"大众让类跑起来\公众);
}
}
举例2:创建一个类继续Test类
package com.langsin.test;
publicclass TestAbstract extends Test {
publicvoid setName(String name) {
this.name = name;
}
public String getName() {
returnthis.name;
}
publicstaticvoid main(String[] args) {
TestAbstract test = new TestAbstract();
System.out.println(test.getName()); //打印的是zhangsan
}
}
举例3:在上面这个类中重写name属性
package com.langsin.test;
publicclass TestAbstract extends Test {
public String name;
publicvoid setName(String name) {
this.name = name;
}
public String getName() {
returnthis.name;
}
publicvoid test(){
super.name = \公众李四\"大众;
this.name = \"大众张三\"大众;
super.run();
System.out.println(this.name);
}
publicstaticvoid main(String[] args) {
TestAbstract ta = new TestAbstract();
ta.test();
}
}
利用抽象类和抽象方法的上风,可以更好的发挥多态的上风,使得程序更加灵巧。
利用abstract润色类时,表明这个类只能被继续,当利用abstract润色方法时,表明这个方法必须由子类实现。而final润色的类不能被继续,final润色的方法不能被重写。因此final和abstract永久不能同时利用。除此之外,利用static润色一个方法时,表示此方法属于该类本身,即通过类就可以调用该方法,但是如果此方法被定义成抽象方法了,则将导致通过该类来调用该方法时涌现缺点,因此static和abstract也不能同时润色某个方法,也便是没有类抽象方法。
6.5.2 抽象类的浸染
抽象类不能创建实例,只能当成父类来被继续。抽象类可以算作是从多个详细类中抽象出来的父类,它具有更高层次的抽象。从多个具有相同特色的类中抽象出来的一个抽象类,以这个抽象类作为其子类的模板,从而避免子类设计的随意性。
抽象类的表示便是一种模板模式的设计,抽象类作为多个子类的通用模板,子类在抽象类的根本上进行扩展、改造,但子类总体上会保留抽象类的行为办法。
编写一个抽象父类,父类供应了多个子类的通用方法,并把一个或多个方法留给其子类实现,这便是一种模板模式,模板模式也是十分常见的设计模式。
举例1:
package com.langsin.test;
Public abstract class Test {
publicabstract String getColor();
}
package com.langsin.test;
publicclass TestOne extends Test {
public String getColor() {
return\公众red\"大众;
}
}
package com.langsin.test;
publicclass TestTwo extends Test {
public String getColor() {
return\公众green\"大众;
}
publicstaticvoid main(String[] args) {
TestOne one = new TestOne();
System.out.println(\"大众车的颜色是:\"大众+one.getColor());
TestTwo two = new TestTwo();
System.out.println(\"大众车的颜色是:\公众+two.getColor());
}
}
模板模式在面向工具的软件中很常用,其事理大略,实现也很大略。利用模板模式有如下规则:
抽象父类可以只定义须要利用的方法,把不能实现的部分抽象成抽象方法留给子类去实现。
6.6 接口
抽象类是从多个类中抽象出来的模板,如果将这种抽象进行得更彻底,则可以提炼出一种更加分外的“抽象类”——接口(interface)。接口里不能包含普通方法,接口里的所有方法都是抽象方法。
implement
6.6.1 接口的观点
Java中的接口是一系列方法的声明,是一些方法特色的凑集,一个接口只有方法的特色没有方法的实现,因此这些方法可以在不同的地方被不同的类实现,而这些实现可以具有不同的行为(功能)。
6.6.2 接口的定义
和类定义不同,定义接口不在利用class关键字,而是利用interface关键字。接口定义的基本语法如下:
[润色符] interface 接口名 extends 父接口1,父接口2{
零到多个常量定义
零到多个抽象方法定义
}
润色符可以是public或者protected省略,省略采取默认包权限访问掌握符
接口名应与类名采取相同的命名规则
一个接口可以有多个直接父接口,但接口只能继续接口,不能继续类
接口定义的是一种规范,因此接口里不能包含布局器和初始化块定义。接口里可以包含Field、方法、内部类定义。由于接口没有布局器与初始化块,因此系统不能为Field进行默认的初始化操作,只能由程序编写职员为Field指定默认的值,以是Field只能是常量。又由于Field只能是常量,所有系统自动为这些Field增加了static和final两个润色符。也便是说在接口中定义的Field不管是否利用了public static final润色符,接口里的Field总是默认的利用这三个润色符来进行润色。
举例1:
int MAX_SIZE = 50;
public static final int MAX_SIZE = 50;
两行代码的运行结果完备同等。
接口里定义的方法都是抽象方法,因此系统会自动为方法增加public abstract润色符。因此不管定义接口方法时是否利用了public abstract润色符,系统都会默认的利用public abstract润色符来进行润色。
举例2:
package com.langsin.test;
publicinterface TestInterface {
publicstaticfinalintWIDTH = 5; //与下行代码运行结果同等
intLENGTH = 10;
publicabstractvoid run(); //与下行代码运行结果同等
void fly();
}
6.6.3 接口的继续
接口的继续与类的继续不一样,接口完备支持多继续,即一个接口可以有多个直接父接口。和继续相似,子接口扩展父接口,将会得到父接口里定义的所有抽象方法、Field、内部类和列举定义。
一个接口继续多个父接口时,多个父接口排在extends关键字之后,多个父接口之间利用英文逗号(,)进行分隔。
举例1:
package com.langsin.test;
publicinterface InterfaceA {
publicabstractvoid testA();
}
package com.langsin.test;
publicinterface InterfaceB {
publicabstractvoid testB();
}
package com.langsin.test;
publicinterface InterfaceC extends InterfaceA, InterfaceB {
publicabstractvoid testC();
}
6.6.4 利用接口
接口不能用于创建实例,但接口可以用于声明引用类型变量。当利用接口来声明引用类型变量时,这个引类型变量必须引用到实在现类的工具。除此之外,接口的紧张用场便是被实现类进行实现。
一个类可以实现多个接口,继续利用extends关键字,而实现则利用implements关键字。
实现接口与继续类相似,一样可以得到所实现接口里定义的常量Field、抽象方法、内部类和列举类定义。
让类实现接口须要在类定义后面增加implements部分,当须要实现多个接口时,多个接口之间以英文逗号(,)隔开。一个类可以继续一个父类并同时实现多个接口,implements部分必须放在extends部分之后。
一个类实现了一个或多个接口之后,这个类必须完备实现这些接口里所定义的全部抽象方法,否则该类将保留从父接口那里继续到的抽象方法,该类也必须定义成抽象类。
举例1:
package com.langsin.test;
publicinterface Product {
publicstaticfinalintMAX_SIZE = 10;
publicabstractint getProductNum();
}
package com.langsin.test;
publicinterface OutPut {
Public abstract void out();
Public void addData(String msg);
}
package com.langsin.test;
publicclass Printer implements Product, OutPut {
private String[] printData = new String[MAX_SIZE];
privateint currentNum = 0;
publicvoid out() {
while(currentNum>0){
System.out.println(printData[--currentNum]);
}
}
publicint getProductNum() {
return 45;
}
publicvoid addData(String msg){
if(currentNum>=MAX_SIZE){
System.out.println(\公众行列步队已满,添加失落败\"大众);
}else{
printData[currentNum++] = msg;
}
}
publicstaticvoid main(String[] args) {
OutPut out = new Printer();
out.addData(\"大众浪曦云团\公众);
out.addData(\"大众浪曦算法\"大众);
out.addData(\"大众浪曦coreJava\"大众);
out.out();
Product product = new Printer();
int num = product.getProductNum();
System.out.println(num);
}
}
6.6.5 接口和抽象类差异
1、接口和抽象类都不能进行实例化,它们都位于继续树的顶端,用于被其他类实现和继续。
2、接口和抽象类都可以包含抽象方法,实现接口或继续抽象类的普通子类都必须实现这些抽象方法。
接口作为系统与外界交互的窗口,接口表示的是一种规范。对付接口的实现者而言,接口规定了实现者必须向外供应哪些做事。对付接口的调用者而言,接口规定了调用者可以调用哪些做事。当在一个程序中利用接口时,接口是多个模块间的耦合标准,当在多个运用程序之间利用接口时,接口是多个程序之间的通信标准。
接口类似于系统的总纲,一旦接口发生变革,对付全体系统是辐射式的,所有实现这个接口的普通类都要进行改写。
抽象类则不一样,抽象类作为系统中多个子类的共同父类,它所表示的是一种模版式设计。抽象类作为多个子类的抽象父类,可以被当成系统实现过程中的中间产品。这个中间产品已经实现了系统的部分功能,但这个类不能称为终极产品,必须有更进一步的完善,这种完善可能有几种不同的办法来实现。
接口与抽象类在用法上也存在如下差异:
接口里只能包含抽象方法,不包含已经供应实现的方法,抽象类则完备可以包含普通方法。
接口里不能定义静态方法,抽象类里可以定义静态方法。
接口里只能定义静态常量Field,不能定义普通的Field,抽象类里则都可以
接口里不包含布局器,抽象类里可以包含布局器,抽象类里的布局器并不是用来创建工具,而是让其子类调用这些布局器完成属于抽象类的初始化操作。
接口里不能包含初始化块,但抽象类则完备可以包含初始化块。
一个类最多只有一个父类,包括抽象类,但是一个类可以实现多个接口。
6.6.6 面向接口编程
接口表示的是一种规范和实现分离的设计模式,充分利用接口可以很好降落程序各模块之间的耦合,从而提高系统的可扩展性和可掩护性。
基于这种原则,软件架构设计理论都倡导“面向接口”编程,而不是面向实现类编程,希望通过面向接口编程来降落程序的耦合。下面两种常用场景来示范面向接口编程的上风。
大略工厂模式
假设我们在系统中有个Computer类须要一个输出类Printer类,那么普通的情形下是我们在Computer类中new一个Printer类这个工具就可以,但是如果往后我们的系统进行重构,让BetterPrinter类来代替原有的Printer类,那么我们就须要打开Computer类进行源码的修正,如果系统中只有一个Computer类用到了Printer类还好,如果有10个、100个、1000个Computer类用到了Printer类,那么这将是一个非常弘大的事情量。
如果利用面向接口的办法来处理这种问题,将会变的非常大略。
例如:我们创建输出接口Out,让我们的Printer类来实现这接口,我们利用工厂模式来创建返回的结果。在我们的Computer类中利用工厂来进行创建,实现Computer类与Printer类的一个分离,对Computer类屏蔽到Printer类的实现细节。
package com.langsin.test;
publicinterface Out {
publicabstract Out printer ();
}
=======================================================================
package com.langsin.test;
publicclass Printer implements Out {
publicvoid printer() {
System.out.println(\"大众普通打印机\"大众);
}
}
=======================================================================
package com.langsin.test;
publicclass BetterPrinter implements Out {
publicvoid printer() {
System.out.println(\"大众高等打印机\"大众);
}
}
=======================================================================
package com.langsin.test;
publicclass PrinterFactory {
publicstatic Out getInstance(){
returnnew BetterPrinter();
//returnnew Printer();
}
}
========================================================================
package com.langsin.test;
publicclass Computer {
publicstaticvoid main(String[] args) {
Out out = PrinterFactory.getInstance();
out.printer();
}
}
在进行重构时,我们只须要将工厂源码打开,将返回工具进行修正,所有调用这个方法的类得到的将不再是Printer类工具,而是新的BetterPrinter类工具。
6.7 内部类
在定义类的时候,我们一样平常把类定义成一个独立的程序单元。但是在某些情形下,我们会把一个类放在另一个类的内部定义,这个定义在其他类内部的类就被称为内部类,也可以称为嵌套类。包含内部类的类也被称为外部类,也可以称为宿主类。Java从JDK1.1开始引入内部类,内部类的紧张浸染如下:
内部类供应了更好的封装,可以把内部类隐蔽在外部类之内,不许可同一个包中其他类访问该类。
内部类成员可以直接访问外部类的私有数据,由于内部类被当成外部类的成员,同一个类成员之间可以相互访问。但外部类不能访问内部类的实现细节,例如内部类的成员变量。
匿名内部类适宜用于创建那些仅须要一次利用的类。
有工具存在了就可以访问一些方法了
举例1:
package com.langsin.test;
publicclassStudent {
private String name = \公众zhangsan\公众;
publicint age = 25;
//============内部类开始=======================
class Action{
//没有什么分外意义,便是一个内部类的成员变量
public String flag = \"大众abc\公众;
publicvoid change(){
Student.this.name = \公众lisi\"大众;
Student.this.age = 35;
}
}
//=============内部类结束========================
publicvoid run(){
Action action = new Action();
action.change();
System.out.println(this.name);
System.out.println(this.age);
}
publicstaticvoid main(String[] args) {
Studentsty = newStudent ();
stu.run();
}
}
6.7.1 非静态内部类
定义内部类非常大略,只要把一个类放在另一个类内部定义即可。此处的“内部类”包括类中的任何位置,乃至在方法中也可以定义内部类,在方法中定义的内部类叫做局部内部类。
常日情形下,内部类都被作为成员内部类定义,而不是作为局部内部类。成员内部类是一种与Field、方法、布局器和初始化块相似的类成员。
成员内部类分为:静态内部类和非静态内部类两种,利用static润色的成员内部类便是静态内部类,没有利用static润色的成员内部类就是非静态内部类。
由于内部类作为其外部类的成员,以是可以利用任意访问掌握符:private、protected、public润色的Field成员。
如上例所示:不能包含静态的方法
6.7.2 静态内部类
利用static润色符来润色内部类,则这个内部类就属于外部类本身,而不属于外部类的某个工具。因此利用static润色的内部类被称为静态内部类。
静态内部类可以包含静态成员,也可以包含非静态成员。根据静态成员不能访问非静态成员的规则,静态内部类不能访问外部类的实例成员,只能访问外部类的类成员。纵然是静态内部类的实例方法也不能访问外部类的实例成员,只能访问外部类的静态成员。
举例1:
package com.langsin.test;
publicclass Car {
privatestatic String name = \公众zhangsan\公众;
publicint age = 25;
staticclass Action{
publicstatic String flag = \"大众abc\"大众;
public String gender = \公众1\"大众;
publicvoid change(){
Car.name = \公众lisi\公众;
//下面这行代码编译报错
Car.this.age = 34;
}
}
publicvoid run(){
Action action = new Action();
action.change();
System.out.println(name);
System.out.println(this.age);
System.out.println(Action.flag);
}
publicstaticvoid main(String[] args) {
Car car = new Car();
car.run();
}
}
外部类不能直接访问静态内部类的成员,但可以利用静态内部类的类名作为调用者来访问静态内部类的类成员,也可以利用静态内部类工具作为调用者来访问静态内部类的实例成员。
举例2:
package com.langsin.test;
publicclass Test {
staticclass InnerTest{
publicstaticintnum = 1;
publicint num2 = 5;
}
publicvoid run(){
InnerTest.num = 4;
System.out.println(InnerTest.num); //4
System.out.println(new InnerTest().num); // 4
}
}
6.7.3 局部内部类
如果把一个内部类定义在方法里面定义,则这个内部类便是一个局部内部类。还是可以定义在
初始化模块中,浸染是随着方法运行利用的结束自动结束!
举例1:
package com.langsin.test;
publicclass Test {
publicint aa = 12;
publicvoid run(){
class InnerTest{
publicint num2 = 5;
publicvoid run(){
System.out.println(num2);
}
}
InnerTest it = new InnerTest();
it.run();//把稳创建工具
}
publicstaticvoid main(String[] args) {
Test te = new Test();
te.run();
}
}
6.7.4 匿名内部类
匿名内部类的语法有些特殊,创建匿名内部类时会立即创建一个该类的实例,这个类定义立即消逝,匿名内部类不能重复利用。因此匿名内部类适宜创建那种只须要一次利用的类。
匿名内部类的格式如下:
new 父类布局器|实现接口(){
//匿名内部类的类体部分
}
匿名内部类必须继续一个父类,或实现一个接口,但最多只能继续一个父类,实现一个接口。
匿名内部类不能是抽象类,由于系统在创建匿名内部类时,会立即创建匿名内部类的工具。
匿名内部类不能定义布局器,由于匿名内部类没有类名,也就无法定义布局器,但是匿名内部类可以定义实例初始化块,通过初始化块来完成初始化操作。
举例1:
package com.langsin.test;
publicclass Test {
publicint aa = 12;
publicvoid run(InnerTest it){
System.out.println(it.num2);
it.run();
}
publicstaticvoid main(String[] args) {
Test te = new Test();
te.run(new InnerTest(){
{
System.out.println(\"大众飞起来。。。\"大众);
}
});
}
}
class InnerTest{
publicint num2 = 5;
publicvoid run(){
System.out.println(num2);
}
}
6.8 列举类
一个类的工具是有限而且固定的,比如时令,只有四个工具;比如行星,只有8个工具。这种实例有限而且固定的类,在Java里被称为列举类。
6.8.1 列举类定义
package com.langsin.test;
publicenum Planet {用num定义num类
MERCURY,
VENUS,
EARTH,
MARS,
JUPITER,
SATURN,
URANUS,
NEPTUNE,
}
利用办法:
package com.langsin.test;
publicclass Test {
publicstaticvoid main(String[] args) {
System.out.println(Planet.EARTH); // Planet.EARTH返回的是工具,工具的值为列举值
Planet jupiter = Planet.JUPITER;
System.out.println(jupiter);
}
}
第7章:与运行环境交互
Java供应了丰富的根本类库,Java7供应了4000多个根本类,通过这些根本类可以提高开拓效率,降落开拓难度,对付一个合格程序员来说,至少要熟习Java SE大部分的类的功能。
7.1 与用户互动
如果一个程序总是按照既定的流程运行,无序处理用户动作,这个程序总是比较大略的。实际上,绝大部分程序都须要处理用户的动作,包括吸收用户的键盘输入、鼠标动作等。后面会讲到图形用户接口(GUI)编程便是基于图形面板输入框的程序编程,本章紧张讲解如何得到键盘的输入。
7.1.1 运行Java程序的参数
main函数详解:
Public润色符:Java类由JVM调用,为了让JVM可以自由的调用这个main方法,以是利用public润色符把这个方法给暴漏出来。
Static润色符:JVM调用这个方法时,不会先创建该主类的工具,然后通过工具来调用该方法。而是直接通过该类来调用主理法,因此利用static润色该方法。
Void返回值:由于主理法被JVM调用,该方法的返回值将返回给JVM,这没有任何意义,因此main方法没有返回值。
举例1:
publicclass Test {
publicstaticvoid main(String[] args) {
System.out.println(args.length);
}
}
利用java命令来调用该类,JVM会默认实行该类的main方法。 java Test
在后面没有追加参数的情形下,打印长度为0
如果在调用该方法时传入参数,办法如下: java Test hello word ,在类名后面追加字符串参数,用空格隔开。
这时打印长度为2.
7.1.2 利用Scanner获取键盘输入
利用Scanner类可以很方便的获取用户的键盘输入,Scanner是一个基于正则表达式的文本扫描器,它可以从文件、输入流、字符串中解析出基本类型值和字符串值。
Scanner紧张供应了两个方法来扫描输入。
hasNextXxx():是否还有下一个输入项,个中Xxx可以是Int、Long等代表基本数据类型的字符串。如果须要判断是否包含下一个字符串,可以省略Xxx。
nextXxx():获取下一个输入项。Xxx的含义与前一个方法中的Xxx相同。
举例1:
publicstaticvoid main(String[] args) {
Scanner sc = new Scanner(System.in); //表示标准键盘输入
while(sc.hasNext()){
System.out.println(sc.next());
}
}
利用ctrl+Z命令表示不再输入,即sc.hasNext()返回false。
举例2:读取当前文件,将文件输入到掌握台
import java.util.Scanner;
import java.io.File;
public class Test{
public static void main(String args[]) throws Exception{
Scanner sn = new Scanner(new File(\公众./Test.java\公众));
while(sn.hasNextLine()){
System.out.println(sn.nextLine());
}
}
}
7.2 系统干系
Java程序在不同操作系统上运行时,可能须要取得平台干系的属性,或者调用平台命令来完成特定的功能,Java供应了System类和Runtime类来与程序的运行平台进行交互。
7.2.1 System类
System类代表当前Java程序的运行平台,程序不能创建System类的工具,System类供应了一些类变量、类方法,许可直接通过System类来调用这些Field和方法。
static Map<String,String>getenv():返回一个不能修正确当前系统环境的字符串映射视图。
static String getenv(String name):获取指定的环境变量值。
static Properties getProperties():确定当前的系统属性。
static String getProperty(String key):获取指定键指示的系统属性。
static long currentTimeMillis():返回以毫秒为单位确当前韶光。
举例1:
publicstaticvoid main(String[] args) throws Exception{
Map<String,String> map = System.getenv();
for(String name : map.keySet()){
System.out.println(name+\公众:\"大众+map.get(name));
}
System.out.println(\"大众=====================\"大众);
System.out.println(System.getenv(\"大众JAVA_HOME\"大众));
System.out.println(System.getenv(\"大众CLASSPATH\"大众));
System.out.println(\公众=====================\"大众);
Properties prop = System.getProperties();
System.out.println(prop.toString());
System.out.println(prop.getProperty(\"大众sun.boot.library.path\"大众));
prop.store(new FileOutputStream(\"大众./props.properties\公众), \"大众System properties\"大众);
}
举例2:
publicstaticvoid main(String[] args) throws Exception{
long begin = System.currentTimeMillis();
Map<String,String> map = System.getenv();
for(String name : map.keySet()){
System.out.println(name+\公众:\公众+map.get(name));
}
long end = System.currentTimeMillis();
System.out.println(\公众共耗时:\公众+(end-begin));
}
7.2.2 Runtime类
Runtime类代表Java程序的运行时环境,每个Java程序都有一个与之对应的Runtime实例,运用程序通过该工具与其运行时环境相连。运用程序不能创建自己的Runtime实例,但可以通过getRuntime()方法获取与之关联的Runtime工具。
举例1:
publicstaticvoid main(String[] args) throws Exception{
Runtime rt = Runtime.getRuntime();
System.out.println(\"大众处理器数量:\"大众+rt.availableProcessors());
System.out.println(\"大众空闲内存数:\公众+rt.freeMemory());
System.out.println(\公众总内存数:\"大众+rt.totalMemory());
System.out.println(\"大众可用最大内存数:\"大众+rt.maxMemory());
}
7.3 常用类
String、Math、BigDecimal、Random等的用法
7.3.1 Object类
Object类是所有类、数组、列举类的父类,也便是说,Java许可把任何类型的工具赋给Object类型的变量,当定义一个类时没有利用extends关键字为它显示指定父类,则该类默认继续Object类。可以说所有的Java类都是Object的子类,以是任何Java工具都可以调用Object类的方法。
常用方法:
boolean equals(Object obj):判断指定工具与该工具是否相等。
protected void finalize():当系统中没有引用变量指向该工具时,垃圾回收器调用此方法来清理该工具占用的资源。
Class<?> getClass():返回该工具的运行时类。
int hashCode():返回该工具的hashCode值。在默认情形下该方法根据此工具的的地址来打算。
String toString():返回该工具的字符串表示,Object类的toString()方法返回“运行时类名@十六进制hashCode值”格式的字符串。
举例1:
publicstaticvoid main(String[] args) throws Exception{
Object obj = new Object();
System.out.println(obj.toString()); // java.lang.Object@de6ced
System.out.println(obj); // java.lang.Object@de6ced
System.out.println(\公众======================\公众);
System.out.println(obj.getClass()); // class java.lang.Object
Object obj2 = new Integer(12);
System.out.println(obj2.getClass()); // class java.lang.Integer
System.out.println(\公众======================\"大众);
System.out.println(obj.hashCode()); //14576877
System.out.println(obj2.hashCode()); //12
}
7.3.2 String、StringBuffer和StringBuilder类
字符串便是持续串的字符序列,Java供应了String和StringBuffer两个类来封装字符串,并供应了一系列方法来操作字符串工具。
String类是不可变类,即一旦一个String工具被创建后,包含在这个工具中的字符序列是不可改变的,直至这个工具的销毁。
StringBuffer工具则代表一个字符序列可变的字符串,当一个StringBuffer被创建往后,通过StringBuffer供应的append()、insert()、reverse()、setCharAt()、setLength()等方法可以改变这个字符串工具的字符序列。一旦通过StringBuffer天生了终极想要的字符串,就可以调用它的toString()方法将其转换为一个String工具。
StringBuilder类,也代表了字符串工具。StringBuilder和StringBuffer基本相似,两个类的布局器和方法也基本相同。不同的是StringBuffer是线程安全的,StringBuilder没有实现线程安全。因此在常日情形下优先考虑利用StringBuffer。
String类的布局器:
String():创建一个包含0个字符串序列的String工具。
String(byte[] bytes,Charset charset):利用指定的字符集将指定的byte[]数组解码成一个新的String工具。
String(byte[] bytes,int offset,int length):利用平台的默认字符集将从指定的byte[]数组的offset开始,长度为length的子数组成一个新的String工具。
String(byte[] bytes,int offset,int length,String charsetName):利用指定的字符集将指定的byte[]数组从offset开始,长度为length的子数组解码成一个新的String工具。
String(byte[] bytes,String charsetName):利用指定的字符集将指定的byte[]数组解码成一个新的String工具。
String(char[] value,int offset,int count):将指定的字符数组从offset开始,长度为count的字符元素连接成一个字符串。
String(String original):根据字符串常量来创建一个String工具。也便是说新创建的String工具是该参数字符串的副本。
String(StringBuffer buffer):根据StringBuffer工具来创建一个String工具
String(StringBuilder builder):根据StringBuilder工具来创建一个String工具。
String类供应大量方法来操作字符串工具:
char charAt(int index):获取字符串中指定位置的字符。
int compareTo(String anotherString):比较两个字符串大小,如果两个字符串的字符序列相等,则返回0,不相等时,从两个字符串第0个字符开始比较,返回第一个不相等的字符差。如果较长的字符串的前面部分与较短的字符串一样,则返回他们的长度差。
举例1:
String s1 = “abcdef”;
String s2 = “abcdefjhi”;
String s3 = “abcdefk”;
System.out.println(s2.compareTo(s1)); //返回3
System.out.println(s2.compareTo(s3)); //返回 -1
String concat(String str):将该String工具与str连接在一起。与Java供应的字符串连接运算符“+”相同。
boolean contentEquals(StringBuffer sb):将该String工具与StringBuffer工具sb进行比较,当他们包含的字符序列相同时返回true。
static String copyValueOf(char[] data):将字符数组组成一个字符串,与布局器String(char[] content)功能相同。
static String copyValueOf(char[] data,int offset,int count):将char数组的子数组中的元素连缀成字符串,与String(char[] value,int offset,int count)布局器功能相同。
boolean endsWith(String str):返回String工具是否以str字符串结尾。
boolean equals(Object anObject):将该字符串与指定工具进行比较,如果二者包含序列相等则返回true,否则返回false。
boolean equalsIgnoreCase(String str):将字符串与指定的工具进行比较,二者包含序列相同则返回true,否则返回false。只是该方法忽略大小写。
byte[] getBytes():将该String工具转换成byte数组。
String str = \"大众abcd\公众;
byte[] data = str.getBytes();
System.out.println(data.length); //4
System.out.println((char)data[0]); //a
void getChars(int srcBegin,int srcEnd,char[] dst,int dstBegin):该方法将字符串中从srcBegin开始到srcEnd结束的字符复制到dst字符数组中,个中dstBegin为目标字符数组的要拷贝的起始位置。
public static void main(String[] args) throws Exception{
char[] c1 = {'我','爱','北','京'};
String str = \"大众济南\"大众;
str.getChars(0, 2, c1, 2);
System.out.println(c1);
}
int indexOf(int ch):找出ch字符在该字符串中第一次涌现的位置。
int indexOf(int ch,int fromIndex):找出ch字符在该字符串中从fromIndex索引后面第一次涌现的位置。
public static void main(String[] args) throws Exception{
String str = \"大众你好,我好,他也好\"大众;
System.out.println(str.indexOf('好'));
System.out.println(str.indexOf('好', 3));
}
int indexOf(String str):找出str子字符串在该字符中第一次涌现的位置。
int indexOf(String str,int fromIndex):找出str子字符串在该字符串中从fromIndex索引后第一次涌现的位置。
public static void main(String[] args) throws Exception{
String str = \"大众中华民族是一个56个民族的总称!
\"大众;
System.out.println(str.indexOf(\"大众民族\公众));
System.out.println(str.indexOf(\公众民族\"大众, 3));
}
int lastIndexOf(int ch):找出ch字符在该字符串中末了一次涌现的位置。
int lastIndexOf(int ch,int fromIndex):找出ch字符在该字符串中从fromIndex开始末了一次涌现的位置。
public static void main(String[] args) throws Exception{
String str = \公众中华民族是一个56个民族的总称!
\"大众;
System.out.println(str.lastIndexOf('民'));
System.out.println(str.lastIndexOf('民', 3));
}
int lastIndexOf(String str):找出str字符串在该字符串中末了一次涌现的位置。
int lastIndexOf(String str,int formIndex):找出str字符串在该字符串中从fromIndex索引开始后末了一次涌现的位置。
int length():返回当前字符串的长度。
public static void main(String[] args) throws Exception{
String str = \"大众中华民族是一个56个民族的总称!
\"大众;
int length = str.length();
System.out.println(length);
}
String replace(String oldChar,String newChar):将字符串中的所有的oldChar更换成newChar。
String replaceAll(String regex, String replacement):利用给定的 replacement 更换此字符串所有匹配给定的正则表达式regex的子字符串。
publicstaticvoid main(String[] args) throws Exception{
String msg = \公众你好,我也好,大家好才是真的好\公众;
String oldChar = \公众你好\"大众;
String newChar = \"大众伱好\"大众;
msg = msg.replace(oldChar, newChar);
System.out.println(msg);
oldChar = \公众好\"大众;
newChar = \"大众坏\"大众;
msg = msg.replaceAll(oldChar, newChar);
System.out.println(msg);
}
char[] toCharArray():将该字符串工具转换成字符数组。
String toLowerCase():将字符串转换成小写。
String toUpperCase():将字符串转换成大写。
String[] split(String reg):将字符串按照指定的正则表达式进行拆分。
String subString(int index):从指定的索引的位置开始直到字符串结束位置,将其作为字符串进行返回。
String subString(int beginIndex,int endIndex)
7.3.3 Math类
Java供应了最大略加、减、乘、除、取模等基本运算。同时还供应了Math类来进行更繁芜的数学运算。
static abs(Xxx xx):将基本数据类型转换成其绝对值返回。
static max(Xxx a,Xxx b):返回两个值中较大的一个
static min(Xxx a,Xxx b):返回两个值中较小的一个
static pow(double a,double b):返回第一个参数的第二个参数次幂的值。
static double random():返回带正号的 double 值,该值大于即是 0.0 且小于 1.0。
publicstaticvoid main(String[] args) throws Exception{
//取某一个范围内的随机数
for(int i=0;i<5;i++){
System.out.println((int)(Math.random()100));
}
}
7.3.4 Random类
Random类专门用于天生一个随机数。紧张方法为:nextXxx(Xxx xxx)
static Xxx nextXxx(Xxx xxx):返回该类型的一个随机数。
7.3.5 BigDecimal类
double、float浮点数在进行数据基本运算时会发生数据丢失征象,这种情形不仅仅是在Java措辞中,在其他措辞中同样存在。例如:
public static void main(String[] args) throws Exception{
System.out.println(0.05+0.01);
System.out.println(1.0-0.42);
System.out.println(4.015100);
System.out.println(123.3/100);
}
Java供应了BigDecimal类,用于处理进行基本运算发生的数据丢失问题。
利用BigDecimal布局器创建工具时,建议优先利用String类型工具作为参数传入进行初始化。
举例: BigDecimal decimal = new BigDecimal(“12.5”);
BigDecimal类供应了add()、subtract()、multiply()、divide()、pow()、等方法瞄准确浮点数进行常规算术运算。
举例1:
publicstaticvoid main(String[] args) throws Exception{
BigDecimal b1 = new BigDecimal(\"大众0.05\"大众);
BigDecimal b2 = new BigDecimal(\公众0.01\"大众);
System.out.println(b1.add(b2).floatValue());
b1 = new BigDecimal(\"大众1.0\"大众);
b2 = new BigDecimal(\公众0.42\"大众);
System.out.println(b1.subtract(b2).floatValue());
b1 = new BigDecimal(\公众4.015\"大众);
b2 = new BigDecimal(\"大众100\公众);
System.out.println(b1.multiply(b2).floatValue());
b1 = new BigDecimal(\"大众123.3\"大众);
b2 = new BigDecimal(\"大众100\"大众);
System.out.println(b1.divide(b2).floatValue());
}
7.4 日期处理类
Java供应了一系列用于处理日期、韶光的类,包括创建日期、韶光工具,获取系统当前日期、韶光等操作。
7.4.1 Date类
Java供应了Date类来处理日期、韶光,Date类既包含日期,也包含韶光。Date类从JDK1.0版本就开始存在,存在韶光久远,供应的6个布局器中,已有4个建议放弃利用,目前利用的为:
Date():天生一个以系统当前韶光日期为准的Date工具。
Date(long date):根据指定的long整型数来天生一个Date工具。
boolean after(Date when):判断日期是否在指定的日期when之后
boolean before(Date when):判断日期是否在指定的日期when之前。
int compareTo(Date antherDate):比较两个日期大小,后面韶光大于前面韶光返回-1,否则返回1.
Boolean equals(Object obj):两个韶光表示同一韶光是返回true
long getTiem():返回该工具对应long型整数
void setTime(long time):设置该工具的韶光。
publicstaticvoid main(String[] args) throws Exception{
//创建一个当前系统韶光工具
Date date1 = new Date();
//将当前哨程休眠4秒钟
Thread.sleep(4000);
//休眠4秒钟后,创建date2韶光工具
Date date2 = new Date();
//
System.out.println(date1.before(date2));
System.out.println(date1.after(date2));
System.out.println(date1.compareTo(date2));
date2.setTime(date1.getTime());
System.out.println(date1.equals(date2));
}
7.4.2 Calendar类
Calendar是一个抽象类,用于表示日历。由于Date类在设计上存在一些毛病,以是Java供应Calendar类来更好的处理日期和韶光。
Calendar类不能直接创建,可以通过类方法来创建一个Calendar的子类,Java本身供应了GregorianCalendar子类,通过getInstance()方法返回默认时区和措辞环境得到一个日历。返回的实例便是Java供应的默认子类
举例1:
publicstaticvoid main(String[] args) throws Exception{
Calendar cal = Calendar.getInstance();
System.out.println(cal.getClass()); //class java.util.GregorianCalendar
}
Calendar与Date都是表示日期的工具类,他们之间可以相互转换。
举例2:
publicstaticvoid main(String[] args) throws Exception{
Calendar cal = Calendar.getInstance();
Date date = cal.getTime();
System.out.println(date);
Calendar cale = Calendar.getInstance();
cale.setTime(date);
}
Calendar类供应的常用方法:
void add(int field,int amount):根据日历的规则,为给定的日历字段添加或减去指定的韶光量。
int get(int field):返回指定日历字段的值。
int getActualMaximum(int field):返回指定日历字段的可能拥有的最大值。
int getActualMinimum(int field):返回指定日历字段的可能拥有的最小值。
void roll(int field,int amout):与add方法相似,差异在于超过该字段的最大范围时,也不会向上一个字段进位。
void set(int field,int value):将给定的日历字段设置为给定值。
void set(int year,int month,int date):设置Calendar工具的年、月、日3个字段值。
void set(int year,int month,int date,int hourOfDay,int minute,int second):设置Calendar工具的年、月、日、时、分、秒6个字段的值。
publicstaticvoid main(String[] args) throws Exception{
Calendar cal = Calendar.getInstance();
System.out.println(cal.get(Calendar.YEAR)); //2014
cal.add(Calendar.MONTH, 12);
System.out.println(cal.get(Calendar.YEAR)); //2015
System.out.println(\公众==================================\公众);
cal = Calendar.getInstance();
System.out.println(cal.get(Calendar.YEAR)); //2014
cal.roll(Calendar.MONTH, 12);
System.out.println(cal.get(Calendar.YEAR)); //2014
System.out.println(\公众==================================\"大众);
System.out.println(cal.getActualMaximum(Calendar.MONTH)); //11
System.out.println(cal.getActualMinimum(Calendar.MONTH)); //0
}
7.4.3 利用DateFormat格式化日期
DateFormat是一个抽象类,它也供应了几个工厂方法用于获取DateFormat工具。返回的都是DateFormat工具的子类实例,是同一个类型的实例。
举例1:
publicstaticvoid main(String[] args) throws Exception{
DateFormat format = DateFormat.getInstance();
System.out.println(format.getClass());
format = DateFormat.getDateInstance();
System.out.println(format.getClass());
format = DateFormat.getTimeInstance();
System.out.println(format.getClass());
}
输出信息:class java.text.SimpleDateFormat
虽然返回的都是同一个工具类型的实例,但是根据不同的工厂方法,返回的工具在格式化韶光工具时,处理不同部分的信息。
getDateInstance():返回一个日期格式器,只对日期进行格式化。
getTimeInstance():返回一个韶光格式器,只对韶光进行格式化。
getDateTimeInstance():返回一个日期、韶光格式器,既对韶光又对日期进行格式化。
getInstance():返回一个默认的系统干系的日期、韶光格式器。
publicstaticvoid main(String[] args) throws Exception{
Date date = new Date();
//默认为中国常用格式
DateFormat format = DateFormat.getInstance();
System.out.println(format.format(date));
//返回日期、韶光格式器国际统一标准
format = DateFormat.getDateTimeInstance();
System.out.println(format.format(date));
//返回日期格式器,同时指定格式类型,为简洁型,指定要显示哪个国家的类型
format = DateFormat.getDateInstance(DateFormat.SHORT, Locale.CHINA);
System.out.println(format.format(date));
//返回日期格式器,同时指定格式类型,为中等型,指定要显示哪个国家的类型
format = DateFormat.getDateInstance(DateFormat.MEDIUM, Locale.CHINA);
System.out.println(format.format(date));
//返回日期格式器,同时指定格式类型,为完全型,指定要显示哪个国家的类型
format = DateFormat.getDateInstance(DateFormat.LONG, Locale.CHINA);
System.out.println(format.format(date));
//返回日期格式器,同时指定格式类型,为繁芜型,指定要显示哪个国家的类型
format = DateFormat.getDateInstance(DateFormat.FULL, Locale.CHINA);
System.out.println(format.format(date));
}
7.4.4 利用SimpleDateFormat格式化日期
SimpleDateFormat是DateFormat的子类,是一种更大略的日期格式,以为我们指定的格式对日期进行格式化。
举例1:
publicstaticvoid main(String[] args) throws Exception{
Date date = new Date();
SimpleDateFormat simple = new SimpleDateFormat(\"大众yyyy年MM月dd日 HH:mm:ss\"大众);
System.out.println(simple.format(date));
simple = new SimpleDateFormat(\"大众yyyy/MM/dd\"大众);
System.out.println(simple.format(date));
}
7.5 正则表达式
正则表达式是一个强大的字符串处理工具,可以对字符串进行查找、提取、分割更换等操作。String类供应的关于正则表达式的处理方法:
boolean matches(String regex):判断该字符串是否匹配指定的正则表达式。
String replaceFirst(String regex,String replacement):将该字符串中第一个匹配regex的子串更换成replacement。
String[] split(String regex):将regex作为分隔符将字符串拆分字符数组。
7.5.1 创建正则表达式
正则表达式便是一个用于匹配字符串的模板,可以匹配一批字符串,以是创建正则表达式便是创建一个分外的字符串。
正则表达式的分外字符及含义 :
举例1:
“”匹配a
“\?\[” 匹配 ?[
预定义字符
方括号表达式
花括号表达式
举例1:
1.验证用户名和密码:(\"大众^[a-zA-Z]\w{5,15}$\"大众)精确格式:\"大众[A-Z][a-z]_[0-9]\"大众组成,并且第一个字必须为字母6~16位;
2.验证电话号码:(\公众^(\d{3,4}-)\d{7,8}$\"大众)精确格式:xxx/xxxx-xxxxxxx/xxxxxxxx;
3.验证身份证号(15位或18位数字):(\"大众^[1-9]\d{14}|[1-9]\d{16}(\d|X|x)$\"大众);
4.验证Email地址:(\"大众^\w+([-+.]\w+)@\w+([-.]\w+)\.\w+([-.]\w+)$\"大众);
5.只能输入由数字和26个英笔墨母组成的字符串:(\"大众^[A-Za-z0-9]+$\"大众) ;
6.整数或者小数:^[0-9]+\.{0,1}[0-9]{0,2}$
7.只能输入数字:\"大众^[0-9]$\"大众。
8.只能输入n位的数字:\"大众^\d{n}$\"大众。
9.只能输入至少n位的数字:\"大众^\d{n,}$\"大众。
10.只能输入m~n位的数字:。\公众^\d{m,n}$\"大众
11.只能输入零和非零开头的数字:\"大众^(0|[1-9][0-9])$\"大众。
12.只能输入有两位小数的正实数:\"大众^[0-9]+(.[0-9]{2})?$\"大众。
13.只能输入有1~3位小数的正实数:\"大众^[0-9]+(.[0-9]{1,3})?$\"大众。
14.只能输入非零的正整数:\"大众^+?[1-9][0-9]$\"大众。
15.只能输入非零的负整数:\"大众^-[1-9][]0-9\公众$。
16.只能输入长度为3的字符:\"大众^.{3}$\"大众。
17.只能输入由26个英笔墨母组成的字符串:\"大众^[A-z]+$\"大众。
18.只能输入由26个大写英笔墨母组成的字符串:\"大众^[A-Z]+$\"大众。
19.只能输入由26个小写英笔墨母组成的字符串:\"大众^[a-z]+$\"大众。
20.验证是否含有^%&',;=?$\\公众等字符:\公众[^%&',;=?$\x22]+\"大众。
21.只能输入汉字:\公众^[\u4e00-\u9fa5]{0,}$\"大众
22.验证URL:\"大众^http://([\w-]+\.)+[\w-]+(/[\w-./?%&=])?$\"大众。
23.验证一年的12个月:\"大众^(0?[1-9]|1[0-2])$\"大众精确格式为:\"大众01\公众~\公众09\"大众和\"大众1\"大众~\公众12\"大众。
24.验证一个月的31天:\"大众^((0?[1-9])|((1|2)[0-9])|30|31)$\"大众精确格式为;\"大众01\公众~\公众09\公众和\"大众1\"大众~\"大众31\公众。
25.获取日期正则表达式:\d{4}[年|\-|\.]\d{\1-\12}[月|\-|\.]\d{\1-\31}日?
7.5.2 利用正则表达式
在程序中利用了正则表达式,就可以利用Java供应的Pattern和Matcher类来利用正则表达式。
Pattern工具是正则表达式编译后在内存中的表示形式,因此正则表达式字符串必须先被编译为Pattern工具,然后再利用该Pattern工具创建对应的Matcher工具。实行匹配所涉及的状态保留在Matcher工具中,多个Matcher工具可共享同一个Pattern工具。
举例1:
publicstaticvoid main(String[] args) throws Exception{
Pattern pattern = Pattern.compile(\"大众^-[1-9][0-9]$\"大众);
Matcher m = pattern.matcher(\公众12\公众);
System.out.println(m.matches());
}
如果某个正则表达式仅须要一次利用,则可直策应用Pattern类的静态matches方法,此方法自动把指定字符串编译成匿名的Pattern工具,并实行匹配
举例2:
publicstaticvoid main(String[] args) throws Exception{
boolean flag = Pattern.matches(\"大众^+?[1-9][0-9]$\"大众, \"大众12\"大众);
System.out.println(flag);
}
Pattern同String一样,也是不可变类,可供应多个并发线程安全利用。
Matcher类供应的常用方法:
find():返回目标字符串是否包含于Pattern匹配的子串。
matches():返回全体目标字符串与Pattern是否匹配。
reset(String newStr):将现有的Matcher工具重新运用于一个新的newStr工具。
lookingAt():返回目标字符串是否以Pattern开头。
举例3:
publicstaticvoid main(String[] args) throws Exception{
String[] mails = {\"大众zhangsan@163.com\"大众,\"大众lisi@csdn.net\公众,\公众wangwu@google.org\"大众};
Pattern pattern = Pattern.compile(\"大众\\w{3,20}@\\w+\\.com|net|org|gov)\"大众);
Matcher matcher = null;
for(String mail : mails){
if(matcher==null){
matcher = pattern.matcher(mail);
}else{
matcher.reset(mail);
}
System.out.println(mail+(matcher.matches()?\"大众是\"大众:\"大众不是\"大众)+\公众一个有效的邮件地址!
\"大众);
}
}
练习:1、写一个手机验证 130 131 132 133 134 135 136 137 138 139 150 151 152 155 158 159 180 181 182 183
2、写一个浮点数的正则表达式 0.12 10.11 123.34
7.6 国际化与格式化
国际化是指运用程序运行时,可根据客户端要求来自的国家/地区、措辞的不同而显示不同的界面。例如,如果要求来自中文操作系统的客户端,则运用程序中的各个提示信息和帮助等都利用中文笔墨;如果客户端利用英文操作系统,则运用程序能自动识别,并做出英文的相应。
7.6.1 Java国际化的思路
Java程序的国际化思路是将程序中的标签、提示等信息放在资源文件中,程序须要支持哪些国家、措辞环境,就对应供应相应的资源文件。
Java程序的国际化紧张通过三个类来完成:
java.util.ResourceBundle:用于加载国家、措辞资源包
java.util.Locale:用于封装特定的国家/区域、措辞环境。
java.text.MessageFormat:用于格式化带占位符的字符串。
为了实现程序的国际化,必须先供应程序所需的资源文件。资源文件的内容时很多key-value对,个中key是程序利用的部分,而value则是程序界面的显示字符串。
资源文件的命名可以有如下三种形式:
baseName_language_country.properties
baseName_language.properties
baseName.properties
个中baseName是资源文件的基本名,可随意指定,而language和country都不可以随意变革而必须是Java所支持的措辞和国家。
7.6.2 Java支持的国家和措辞
Java支持绝大部分的国家和措辞,如果须要获取Java所支持的国家和措辞,则可调用Locale类的getAvailableLocales()方法,该方法返回个Locale数组,该数组包含了Java所支持的国家和措辞。
举例1:
publicstaticvoid main(String[] args) throws Exception{
Locale[] locales = Locale.getAvailableLocales();
for(int i=0;i<locales.length;i++){
System.out.println(locales[i].getDisplayCountry()+\公众:\"大众+locales[i].getCountry()+\"大众\"大众+locales[i].getDisplayLanguage()+\"大众:\"大众+locales[i].getLanguage());
}
}
获取系统默认的国家/措辞环境
Locale.getDefaule()
举例2:
publicstaticvoid main(String[] args) throws Exception{
Locale china = Locale.getDefault();
System.out.println(china.getLanguage()+\公众_\"大众+china.getCountry());
}
7.6.3 完成程序国际化
对下面程序完成国际化
publicstaticvoid main(String[] args) throws Exception{
System.out.println(\公众Hello world\公众);
}
为上面程序供应如下两个文件
1、mess.propterites
文件内容为:
Hello world = Hello,world!
2、mess_ch_CN.propterties,此文件由native2ascii工具来天生,此工具的浸染是将资源文件中的编码转换成系统利用Unicode字符编码。
文件内容为:
Hello world = 天下,你好!
命令格式如下:native2ascii mess.properties mess_zh_CN.properties
在MyEclipse中创建属性文件时,编辑工具已经供应了此功能,因此可以直接写资源文件,而略过第一步
此文件放置在源码文件src下。
3、程序修正如下:
publicstaticvoid main(String[] args) throws Exception{
Locale china = Locale.getDefault();
ResourceBundle bundle = ResourceBundle.getBundle(\"大众mess\"大众,china);
System.out.println(bundle.getString(\"大众HelloWorld\"大众));
}
讲解:ResourceBundle.getBundle(\"大众mess\公众,china);当不指定系统默认的措辞环境时,即利用ResourceBundle.getBundle(\"大众mess\"大众);系统会默认查找当前措辞环境下的资源文件,例如当前措辞环境时中国,则会查找mess_zh_CN.properties文件,在系统中查找不到此文件时,才会找mess.properties属性文件。
第8章:Java凑集框架
Java凑集类是一种特殊有用的工具类,可以用于存储数量不等的多个工具,并可以实现常用的数据构造,如栈、行列步队等。除此之外,Java凑集还可以用于保存具有映射关系的关联数组。Java凑集分为:Set、List和Map三种体系,个中Set代表无序、不可重复的凑集;List代表有序、可重复的凑集;Map则代表具有映射关系的凑集。
8.1 凑集概述
在编程时,常常须要集中存放多个数据,起初我们利用数组来保存多个工具,但数组长度不可变革,一旦在初始化数组时指定了长度,那么这个数组长度便是不可变的。其余如果我们要保存具有映射关系的的数据,例如:成绩表:语文—79,数学—80,数组就有点不能胜任。
为了保存数量不愿定的数据,以及保存具有映射关系的数据。Java供应了凑集类。凑集类紧张卖力保存、艳服其他数据,因此凑集类也被称为容器类。所有的凑集类都位于java.util包下。
凑集类与数组不一样,数组元素可以是基本类型的数据,也可以是工具,而凑集里只能保存工具。
Java的凑集类紧张由两个接口派生而来:Collection和Map。Collection和Map是Java凑集框架的根接口,这两个接口有包含了一些子接口或实现类。
上图显示了Collection体系里的凑集,个中Set和List接口都是Collection接口派生出的两个子接口,他们分别代表了无序凑集和有序凑集;Queue是Java供应的行列步队实现。
上图为Map体系构造示意图,所有的Map实现类用于保存具有映射关系的数据。Map保存的每项数据都是key-value两个值组成。Map中的key值是不可重复的,key用于标识凑集里的每项数据。
对付Java的所有凑集分类,可以分为三大类,
set凑集:类似于一个罐子,将工具存放在Set凑集时,Set凑集无法记住这个元素的顺序,以是Set里的元素不能重复。
List凑集:非常类似于数组,它可以记住每次添加的元素的顺序,不同于数组的是List的长度是可变的。
Map凑集:类似于中药橱柜,每个橱柜上的抽屉都带有标签,标签相称于key,抽屉相称于工具。可以根据key来找到工具。
对付Set、List、Queue和Map四种凑集,最常用的类为:HashSet、TreeSet、ArrayList、ArrayDeque、LinkedList、HashMap、TreeMap。
8.2 Collection和Iterator接口
Collection接口是List、Set、Queue接口的父接口,该接口里定义的方法可用于操作Set凑集、List凑集、Queue凑集。个中定义的操作凑集的常用方法如下:
boolean add(Object obj):该方法用于向凑集里添加一个元素。如果凑集工具被添加操作改变了,则返回true。
boolean addAll(Collection c):该方法把凑集C里的所有元素添加到指定凑集里。如果凑集工具被添加操作改变了,则返回true。
void clear():打消凑集里的所有元素,将凑集长度变为0。
boolean contains(Object o):返回凑集里是否包含指定元素。
boolean containsAll(Collection c):返回凑集里是否包含凑集c里的所有元素。
boolean isEmpty():返回凑集是否为空。当长度为0时返回true,否则返回false。
Iterator iterator():返回一个Iterator工具,用于遍历凑集里的元素。
boolean remove(Object o):删除凑集中的指定元素o,当凑集中包含了一个或多个元素o时,这些元素将被删除,该方法返回true。
boolean removeAll(Collection c):从凑集中删除凑集c里包含的所有元素,如果删除一个或一个以上 的元素,则该方法返回true。
boolean retainAll(Collection c):从凑集中删除凑集c里不包含的元素,如果该操作改变了调用该方法的凑集,则该方法返回true。
int size():返回凑集里元素的个数。
Object[] toArray():该方法把凑集转换成一个数组。
举例1:
publicstaticvoid main(String[] args) throws Exception{
Collection c = newArrayList();
c.add(\"大众abc\"大众);
c.add(1);
System.out.println(\公众凑集C的长度\公众+c.size()); 2
c.remove(1);
System.out.println(\"大众凑集C的长度\"大众+c.size()); 1
System.out.println(\公众凑集c中是否包含abc\公众+c.contains(\"大众abc\"大众));
Collection c1 = newHashSet();
c1.add(\"大众abc\"大众);
c1.add(\"大众abc\"大众);
c1.add(1);
System.out.println(\公众凑集C1的长度\"大众+c1.size()); 2
System.out.println(\"大众凑集C是否包含C1凑集:\"大众+c.containsAll(c1));
c.removeAll(c1);
System.out.println(\"大众凑集C的长度\"大众+c.size()); // 0
c.clear();
System.out.println(\"大众凑集C的长度\"大众+c.size()); //0
c1.retainAll(c);
System.out.println(\"大众凑集C1的长度\公众+c1.size()); //0
}
8.2.1 利用Iterator接口遍历凑集元素
Iterator接口也是Java凑集框架的成员,但它与Collection、Map凑集不一样。Collection、Map凑集紧张用来艳服工具,而Iterator则紧张用来遍历(迭代访问)Collection凑集中的元素,Iterator工具也被称为迭代器。
Iterator接口隐蔽了各种Collection实现类的底层细节,向运用程序供应了遍历Collection凑集元素的统一编程接口。
boolean hasNext():如果被迭代的凑集元素还没有被遍历,则返回true。
Object next():返回凑集里的下一个元素。
Void remove():删除凑集里上一次next方法返回的元素。
举例1:
publicstaticvoid main(String[] args) throws Exception{
Set set = newHashSet();
set.add(\"大众张三\"大众);
set.add(\公众李四\公众);
set.add(\公众王五\"大众);
Iterator iterator = set.iterator();
while(iterator.hasNext()){
if(\公众张三\"大众.equals(iterator.next())){
iterator.remove();
}
}
System.out.println(set);
}
当利用Iterator迭代访问Collection凑集元素时,Collection凑集里的元素不能被改变,只能通过Iterator的remove方法删除上一次next方法返回的凑集元素才可以,否则将会引发并发修正非常:java.util.ConcurrentModificationException。
举例2:
publicstaticvoid main(String[] args) throws Exception{
Set set = newHashSet();
set.add(\公众张三\"大众);
set.add(\"大众李四\"大众);
set.add(\"大众王五\"大众);
Iterator iterator = set.iterator();
while(iterator.hasNext()){
if(\"大众张三\公众.equals(iterator.next())){
set.remove(\"大众张三\公众);
}
}
System.out.println(set);
}
这一点类似于windows系统中,当我们打开一个文件时,又对这个文件实行了删除操作。Windows总会提示我们文件正在被利用,不能删除一个道理。
8.2.2 利用foreach循环遍历凑集元素
除了利用Iterator接口迭代访问Collection凑集里的元素之外,还可以利用foreach循环迭代访问凑集元素更加便捷。
举例1:
publicstaticvoid main(String[] args) throws Exception{
Set set = newHashSet();
set.add(\"大众张三\"大众);
set.add(\公众李四\"大众);
set.add(\"大众王五\"大众);
for(Object obj : set){
System.out.println(obj);
}
}
把稳:利用foreach循环来遍历Collection凑集时,与Iterator接口一样,迭代工具并不是元素工具本身,而是系统依次把凑集元素工具的值赋给了迭代变量而已。
8.3 Set凑集
Set凑集是Collection凑集的子类,与Collection基本上完备一样,它没有供应额外的方法,只是在行为上略有不同。
Set凑集不许可包含相同的元素,如果把两个相同的元素加入到同一个Set凑集中去,则添加操作失落败,add方法返回false,且新元素不会被加入。
Set判断两个工具相同不是利用==运算符,而是利用equals方法。也便是说,只要两个工具equals方法比较返回true,Set就不会接管这两个工具;反之,则可以。
举例1:
publicstaticvoid main(String[] args) throws Exception{
Set set = newHashSet();
set.add(\公众zhangsan\"大众);
set.add(\公众zhangsan\公众);
System.out.println(set.size()); //1
set.add(new String(\"大众zhangsan\"大众));
set.add(new String(\"大众zhangsan\"大众));
System.out.println(set.size()); //2
}
由于:String工具利用equals比较是相同以是,只添加了一个。
publicstaticvoid main(String[] args) throws Exception{
Car car1 = new Car();
Car car2 = new Car();
Set set = newHashSet();
set.add(car1);
set.add(car2);
System.out.println(set.size()); //2
}
car1与car2分别指向了两个不同的工具,因此利用equals比较时返回false,以是set添加了两个工具。
详细来看下HashSet、TreeSet和EnumSet三个实现类。
8.3.1 HashSet类
HashSet是Set接口的范例实现,大多数时候利用Set凑集时便是利用这个实现类。HashSet按Hash算法来存储凑集中的元素,因此具有很好的存取和查找性能。
HashSet具有以下特点:
不能担保元素的排列顺序,排列顺序可能与添加顺序不同。
HashSet不是同步的,如果多个线程同时访问一个HashSet时,假设有一个或多个线程同时修正了HashSet凑集时,则必须通过代码块来担保其同步。
凑集元素可以是null。
当向HashSet凑集中存入一个元素时,HashSet会调用该工具的hashCode()方法来得到该工具的值,然后根据该HashCode()值决定该工具在HashSet中的存储位置。如果两个元素通过equals()方法比较返回true,而他们的hashCode()方法返回值不同,HashSet会将他们存储在不同的位置,依然添加成功。这就与Set凑集的规则有些出入了。
publicclass TestOne {
privateint num = 1;
public TestOne(int num){
this.num = num;
}
publicboolean equals(Object obj) {
returntrue;
}
publicint hashCode() {
returnthis.num;
}
}
publicstaticvoid main(String[] args) throws Exception{
TestOne one = new TestOne(1);
TestOne two = new TestOne(2);
System.out.println(one.equals(two));
Set set = newHashSet();
set.add(one);
set.add(two);
System.out.println(set.size()); // 1
}
把稳:如果通过equals方法比较返回true,同时根据hashCode()方法获取的返回值也相同,则只能存储一个工具。
当把一个工具放入到HashSet中时,如果重写了这个工具的equals方法,那么也必须重写这个工具的hashCode方法。其规则便是如果equals方法返回true,那么这两个工具的hashCode的值也该当相同。
如果两个工具通过equals方法比较返回false,而hashCode值返回一样,这就有点违背了HashSet的设计规则,本来通过Hash算法我们可以打算工具的存储位置,现在却成了在同一个位置上存储了两个工具。从而减低了HashSet快速查找工具的功能。
8.3.2 LinkedHashSet类
LinkedHashSet是HashSet的子类,LinkedHashSet同样是根据元素的hashCode值来决定元素的存储位置,但与HashSet不同的是,LinkedHashSet在存储工具时同时利用链表掩护了元素的次序,即:当遍历LinkedHashSet凑集里的元素时,LinkedHashSet将会按照元素的添加顺序来访问凑集里的元素。
举例1:
publicstaticvoid main(String[] args) throws Exception{
Set set = newLinkedHashSet();
set.add(\"大众张三\"大众);
set.add(\"大众李四\公众);
set.add(\"大众王五\"大众);
System.out.println(set);
}
输出结果:[张三, 李四, 王五]
8.3.3 TreeSet类
TreeSet是SortedSet接口的实现类,TreeSet可以确保凑集元素处于排序状态。与HashSet比较,TreeSet还供应了额外方法:
Comparator comparator():如果TreeSet采取了定制排序,则该方法返回定制排序所利用的Comparator,如果TreeSet采取了自然排序,则返回null。
Object first():返回凑集中的第一个元素。
Object last():返回凑集中的末了一个元素。
Object lower(Object obj):返回凑集中位于指定元素之前的元素。
Object higher(Object obj):返回凑集中位于指定元素之后的元素。
SortedSet subSet(fromElement,toElement):返回此Set的子凑集,范围从fromElement(包含)到toElement(不包含)。
SortedSet headSet(toElement):返回Set的子集,由小于toElement的元素组成。
SortedSet tailSet(fromElement):返回Set的子集,由大于或即是fromElement的元素组成。
举例1:
publicstaticvoid main(String[] args) throws Exception{
TreeSet set = newTreeSet();
set.add(12);
set.add(3);
set.add(6);
set.add(8);
System.out.println(set);
System.out.println(set.first());//3
System.out.println(set.last()); //12
System.out.println(set.headSet(8)); // 6 3
System.out.println(set.tailSet(6)); //6 8 12
System.out.println(set.subSet(3, 8)); // 3 6
}
HashSet凑集采取hash算法来决定元素的存储位置,TreeSet采取红黑树的数据构造来存储凑集元素。TreeSet支持两种排序方法:自然排序和定制排序。
自然排序
TreeSet会调用凑集元素的compareTo(Object obj):方法来比较元素之间的大小关系,然后将凑集元素按升序排列,这种办法便是自然排序。
Java中供应了一个Comparable接口,此接口中定义了一个方法compareTo(Object obj),该方法返回一个整数值,实现了该接口的类的工具就可以比较大小。由于在向TreeSet凑集中存放数据时,TreeSet会调用该元素工具的compareTo方法,因此往TreeSet凑集中存放是元素工具必须实现了该方法。
大部分类在实现compareTo方法时,都须要将被比较工具obj逼迫转换成相同类型,由于只有相同类型的实例才能比较大小。因此TreeSet凑集中存放的元素必须是同一类型的实例。
否则将会抛出ClassCastException(逼迫类型转换非常)
举例1:
package com.langsin.test;
publicclass A {
}
package com.langsin.test;
publicclass B {
}
publicstaticvoid main(String[] args) throws Exception{
TreeSet set = newTreeSet();
set.add(new A());
set.add(new B());
System.out.println(set);
}
举例2:将A类与B继续接口Compareable,存储时不会报错
package com.langsin.test;
publicclass A implementsComparable{
publicint compareTo(Object o) {
return 1;
}
}
package com.langsin.test;
publicclass B implementsComparable{
publicint compareTo(Object o) {
return 1;
}
}
publicstaticvoid main(String[] args) throws Exception{
TreeSet set = newTreeSet();
set.add(new A());
set.add(new B());
System.out.println(set);
}
举例3:
package com.langsin.test;
publicclass Student implements Comparable<Student>{
public Student(String classNo){
this.classNo = classNo;
}
private String classNo=null;
publicint compareTo(Student st){
returnthis.classNo.compareTo(st.classNo);
}
public String getClassNo(){
returnthis.classNo;
}
}
publicstaticvoid main(String[] args) throws Exception{
Student st1 = new Student(\"大众20140701\"大众);
Student st2 = new Student(\"大众20140702\公众);
Student st3 = new Student(\"大众20140703\公众);
TreeSet<Student> set = new TreeSet<Student>();
set.add(st3);
set.add(st1);
set.add(st2);
System.out.println(set.first().getClassNo());
}
定制排序
TreeSet的自然排序是根据凑集元素的大小,TreeSet将它们以升序排序。如果实现定制排序,比如降序,须要通过Comparator接口来实现。在创建TreeSet实例的时候,不在利用TreeSet默认的比较,通过Comparator接口实现自己的比较器实例,将比较器的实例作为参数通过TreeSet的布局器通报给凑集,那么在往凑集元素中存放数据的时候就会按照我们的指定顺序进行排序。实现Comparator接口的int compare(T t1,T t2)方法,此方法在往凑集元素中添加元素工具时被调用,该方法返回一个int类型值,返回正整数,表示t1大于t2,返回负整数,表示t1小于t2,返回0表示,t1即是t2.
举例1:
publicstaticvoid main(String[] args) throws Exception{
Comparator<Integer> comparator = new Comparator<Integer>(){
publicint compare(Integer num1, Integer num2) {
if(num1>num2){
return -1;
}elseif(num1<num2){
return 1;
}else{
return 0;
}
} ///梅花2 黑桃2 红桃5 黑桃5 方块6 黑桃 红桃 梅花 方块
};
TreeSet set = new TreeSet(comparator);
set.add(1);
set.add(12);
set.add(5);
System.out.println(set);
}
8.3.4 EnumSet类
EnumSet类是列举凑集类,凑集中存放的元素都必须是指定列举类型的列举值,该值在创建EnumSet时显示或隐式地指定。
EnumSet类没有供应公有属性的布局器来创建该类的实例,程序该当通过EnumSet供应是static方法来创建EnumSet工具。常用的方法如下:
Static EnumSet allOf(Class elementType):创建一个包含了列举类中所有列举值的EnumSet凑集。
Static EnumSet complementOf(EnumSet s):创建一个其元素类型与指定的EnumSet里元素类型相同的EnumSet凑集,新的EnumSet凑集中包含了原EnumSet凑集中所不包含的,剩下的所有列举值。
Static EnumSet copyOf(Collection c):利用一个普通凑集来创建一个EnumSet凑集。普通凑集Collection参数不能为空,里面必须含有元素工具。否则抛出java.lang.IllegalArgumentException(参数不合理非常)。
Static EnumSet copyOf(EnumSet s):创建一个与指定的EnumSet具有相同元素类型、相同凑集元素的EnumSet凑集。完全的copy一份。
Static EnumSet noneOf(Class elementType):创建一个元素类型为指定列举类型的空EnumSet。
Static EnumSet range(E from,E to):创建一个包含了从from开始到to结束的范围内所有的列举值凑集。
举例1:
列举类
package com.langsin.test;
publicenum Planet {
MERCURY,
VENUS,
EARTH,
MARS,
JUPITER,
SATURN,
URANUS,
NEPTUNE,
PLUTO
}
测试类:
publicstaticvoid main(String[] args) throws Exception{
EnumSet<Planet> set = EnumSet.allOf(Planet.class);
System.out.println(set.add(Planet.EARTH));
System.out.println(set.size());
Collection<Planet> collection = new HashSet<Planet>();
collection.add(Planet.MARS);
EnumSet<Planet> set1 = EnumSet.copyOf(collection);
System.out.println(set1.size());
EnumSet<Planet> set2 = EnumSet.noneOf(Planet.class);
System.out.println(set2.size());
EnumSet<Planet> set3 = EnumSet.range(Planet.MERCURY, Planet.EARTH);
System.out.println(set3.size());
}
8.4 List凑集
List凑集代表一个元素有序、可重复的凑集,凑集中每个元素都有其对应的顺序索引。List凑集许可利用重复元素,可以通过索引来访问指定位置的凑集元素。List凑集默认按元素的添加顺序设置元素的索引。
8.4.1 List接口和ListIterator接口
List作为Collection接口的子接口,可以利用Collection接口里的全部方法。由于List又是一个有序的凑集,以是List凑集中又增加了一些根据索引来操作凑集元素的方法。
Void add(int index,Object element):将元素element插入到List凑集的index处。如果当前索引位置有元素工具,则将此元素工具及后面所有元素工具都向后移动一个索引位置。
Boolean addAll(int index,Collection c):将凑集c所包含的所有元素都插入到List凑集中的index索引位置。
Object get(int index):返回凑集index索引位置的元素。
Int indexOf(Object o):返回工具o在List凑集中第一次涌现的位置索引。
Int lastIndexOf(Object o):返回工具o在List凑集中末了一次涌现的位置索引。
Object remove(int index):删除index索引位置的元素,并将此工具返回。同时此元素后面的所有元素索引向前提高一位。
Object set(int index,Object element):将index索引处的元素更换成element工具,并将被更换的元素返回。
List subList(int fromIndex,int toIndex):返回从元素索引fromIndex到索引toIndex处所有凑集元素组成的子凑集。
举例1:
publicstaticvoid main(String[] args) throws Exception{
List list = newArrayList();
list.add(\"大众123\"大众);
list.add(\"大众456\公众);
list.add(1, \"大众789\"大众);
System.out.println(list.get(1));
System.out.println(list.get(2));
System.out.println(\"大众=================\"大众);
System.out.println(list.indexOf(\公众456\"大众));
System.out.println(\"大众=================\公众);
Object obj = list.remove(1);
System.out.println(obj);
System.out.println(list.size());
System.out.println(\"大众=================\"大众);
obj = list.set(1,\"大众abc\"大众);
System.out.println(list.get(1));
List list1 = list.subList(0, 2);
System.out.println(list1.size());
}
ListIterator接口:List供应了一个listIterator()方法,该方法返回一个ListIterator工具,ListIterator接口继续了Iterator接口,还供应了专门操作List的方法。方法如下:
Boolean hasPrevious():返回该迭代器关联的凑集是否含有上一个元素。
Object previous():返回迭代器的上一个元素。
void add():在指定位置插入一个元素。
ListIterator与普通的Iterator进行比拟,ListIterator增加向前迭代的功能,而且还通过add方法向List凑集中添加元素。
举例1:
publicstaticvoid main(String[] args) throws Exception{
List list = newArrayList();
list.add(\公众123\"大众);
list.add(\公众456\公众);
list.add(\公众789\公众);
ListIterator iter = list.listIterator();
while(iter.hasNext()){
System.out.println(iter.next());
iter.add(\"大众abc\"大众);
}
System.out.println(\"大众===================\"大众);
while(iter.hasPrevious()){
System.out.println(iter.previous());
}
}
8.4.2 ArrayList和Vector实现类
ArrayList和Vector是List接口的范例实现,都是基于数组实现的List类。ArrayList和Vector都封装了一个动态的许可再分配的Object[]数组。
ArrayList和Vector的用法险些完备一样,但是Vector与ArrayList比较较而言是属于古董级别,在JDK1.0时就已经存在。那时Java还没有供应系统的凑集框架,Vector中供应了很多方法名很长的方法。从JDK1.2往后,Java提出系统凑集框架之后,将Vector改为实现List接口,作为List的实现类之一,从而导致了Vector中存在了一些功能重复的方法。
因此只管即便少用Vector,由于能用Vector的地方就能用ArrayList来代替。除此之外,ArrayList与Vector的显著差异是:ArrayList是线程不屈安的,Vector是线程安全,以是Vector的性能要比ArrayList要低一些。纵然是为了担保List凑集的线程安全,同样不推举利用Vector实现类,后面会先容Collections工具类,它会是ArrayList变成线程安全的。
举例1:
package com.langsin.test;
publicclass Product {
//商品名称
private String p_name;
//商品编码
private String p_code;
//商品名称
private String p_price;
/
@return商品名称
/
public String getP_name() {
return p_name;
}
/
@param商品名称
/
publicvoid setP_name(String p_name) {
this.p_name = p_name;
}
/
@return商品编码
/
public String getP_code() {
return p_code;
}
/
@param商品编码
/
publicvoid setP_code(String p_code) {
this.p_code = p_code;
}
/
@return商品价格
/
public String getP_price() {
return p_price;
}
/
@param商品价格
/
publicvoid setP_price(String p_price) {
this.p_price = p_price;
}
}
publicstaticvoid main(String[] args) throws Exception{
List<Product> list = new ArrayList<Product>();
Product p1 = new Product();
p1.setP_code(\"大众JD001\"大众);
p1.setP_name(\"大众康佳32吋\"大众);
p1.setP_price(\"大众1900\公众);
list.add(p1);
Product p2 = new Product();
p2.setP_code(\"大众JD002\"大众);
p2.setP_name(\"大众康佳32吋\"大众);
p2.setP_price(\"大众1900\公众);
list.add(p2);
Product p3 = new Product();
p3.setP_code(\"大众JD003\公众);
p3.setP_name(\"大众康佳32吋\公众);
p3.setP_price(\"大众1900\"大众);
list.add(p3);
System.out.println(\"大众============================\"大众);
System.out.println(\公众| 商品名称 | 商品编码 | 商品价格 |\公众);
System.out.println(\"大众============================\"大众);
for(Product pt : list){
System.out.println(\公众| \"大众+pt.getP_name()+\公众 | \"大众+pt.getP_code()+\公众 | \公众+pt.getP_price()+\"大众 |\公众);
System.out.println(\公众============================\"大众);
}
}
Vector还供应了一个Stack子类,用于仿照“栈”数据构造。“栈”也是一种容器,遵照前辈后出,后进先出的规范。供应了如下常用方法:
Object peek():返回“栈”的第一个元素,单并不将元素弹出“栈”,仍在“栈”中存放。
Object pop():返回“栈”的第一个元素,同时将元素工具弹出“栈”。
Void push(Object item):将元素工具加入到“栈”中。
举例1:
publicstaticvoid main(String[] args) throws Exception{
Stack stack = newStack();
stack.push(\公众123\"大众);
stack.push(\公众456\"大众);
stack.push(\公众789\公众);
Object obj = stack.peek(); //返回末了一个工具,工具仍旧保存在栈中
System.out.println(obj);
System.out.println(stack.size()); //以是长度不发生变革
obj = stack.pop(); //返回末了一个工具,并将工具在栈中剔除
System.out.println(obj);
System.out.println(stack.size());//以是长度减一
}
8.5 Queue凑集
Queue用于仿照行列步队数据构造,行列步队是遵照“前辈先出”,“后进后出”的存储规范。第一个存放的元素工具存放在队列队首位置,后进入的元素插入到队尾的位置,行列步队不许可随机访问行列步队中元素。
Queue接口定义的方法:
Void add(Object obj):将指定元素加入此行列步队的尾部。
Object element():获取行列步队头部的元素,但不删除该元素。
Boolean offer(Object obj):将指定元素加入此行列步队的尾部,当利用有容量限定的行列步队时,此方法比add()方法更好。
Object peek():获取行列步队头部的元素,但不删除该元素。如果此行列步队为空,返回null。
Object poll():获取行列步队头部的元素,并删除该元素,如果此行列步队为空,返回Null。
Object remove():获取行列步队头部的元素,并删除该元素。
8.5.1 PriorityQueue实现类
PriorityQueue是一个比较标准的Queue实现类,而不是绝对标准的行列步队实现,是由于PriorityQueue保存行列步队元素的顺序并不是按照加入行列步队的顺序进行保存。而是按照行列步队元素的大小进行重新一次排序。因此利用peek()或者poll()方法获取元素队列位置时,并不一定便是首先存入的元素工具,而是行列步队中最小的元素。
举例1:
publicstaticvoid main(String[] args) throws Exception{
PriorityQueue pq = newPriorityQueue();
pq.offer(6);
pq.offer(-3);
pq.offer(3);
pq.offer(9);
System.out.println(pq.toString()); //
while(pq.size()>0){
System.out.print(pq.poll() + \公众\"大众); // -3 3 6 9
}
}
把稳:PriorityQueue不许可插入null值,它须要对行列步队元素进行排序,PriorityQueue的元素排序分两种情形,自然排序和定制排序,参照TreeSet。
8.5.2 Deque接口与ArrayDeque实现类
Deque接口是Queue接口的子接口,它代表一个双端行列步队,Deque接口里定义了一些双端行列步队的方法,这些方法许可从两端来操作行列步队元素。
Void addFirst(Object obj):将指定元素插入到该行列步队的首部。
Void addlast(Object obj):将指定元素插入到该行列步队的尾部。
Iterator desceningIterator():返回该双端行列步队对应的迭代器,该迭代器将以逆向顺序来迭代行列步队中的元素。
Object getFirst():获取双端行列步队的第一个元素。
Object getLast():获取双端行列步队的末了一个元素。
Boolean offerFirst(Object obj):将指定元素插入到双端行列步队的开头。
Boolean offLast(Object obj):将指定元素插入到双端行列步队的末端。
Object peekFrist():获取但不删除双端行列步队的第一个元素。
Object peekLast():获取但不删除双端行列步队的末了一个元素。
Object pollFrist():获取并删除双端行列步队的第一个元素。
Object pollLast():获取并删除双端行列步队的末了一个元素。
Object pop():获取并删除该双端行列步队的第一个元素。
Void push(Object obj):将一个元素插入到该双端行列步队的队首位置,相称于addFrist()
Object removeFirst():获取并删除该双端行列步队的第一个元素。
Object removeLast():获取并删除该双端行列步队的末了一个元素。
举例1:
publicstaticvoid main(String[] args) throws Exception{
Deque deque = newArrayDeque();
deque.offerFirst(\"大众123\"大众);
deque.offer(\"大众456\"大众);//相称于offerLast()
deque.offerLast(\"大众789\公众);
System.out.println(deque);
deque.push(\"大众abc\"大众); //相称于offerFirst()
System.out.println(deque);
System.out.println(deque.size());
Object obj = deque.peek(); //相称于peekFirst()
System.out.println(obj);
System.out.println(deque.size());
obj = deque.poll();//相称于pollFist()
System.out.println(obj);
System.out.println(deque.size());
}
8.5.3 LinkedList实现类
LinkedList类是List接口的实现类,因此可根据索引来随机访问凑集中元素。LinkedList还实现了Deque接口,因此可被当做双端行列步队来利用,同样也可以被当做“栈”来利用。
举例1:
publicstaticvoid main(String[] args) throws Exception{
LinkedList list = newLinkedList();
list.add(\公众123\"大众); abc 789 123 456
list.offer(\"大众456\"大众);
//System.out.println(list);
list.offerFirst(\"大众789\"大众);
//System.out.println(list);
list.push(\公众abc\"大众);
System.out.println(list);
Object obj = list.pop();
System.out.println(obj);
System.out.println(list.size());
}
LinkedList与ArrayList、ArrayDeque的实现机制不同,ArrayList和ArrayDeque内部以数组的形式来保存凑集中元素,因此随机方位凑集元素时有较好的性能。而LinkedList内部以链表的形式来保存凑集中的元素,因此随机访问凑集元素时性能不如ArrayList和ArrayDeque。而插入、删除元素时性能非常出色,只须要改变指针所指向的地址即可。
8.6 Map
Map用于保存具有映射关系的数据,因此Map凑集里保存着两组值,一组用于保存Map里的key,其余一组用于保存Map里的value,key和value都可以是任何引用类型的数据。Map的key不许可重复,即同一个Map工具的任何两个key通过equals方法比较总是返回false。
Key和value是逐一对应的关系,即通过指定的key,总能找到唯一的value工具。Map里的key放在一可以算作一个Set凑集,实际上Map中包含了一个keySet()方法,用于返回Map里所有key组成的Set凑集。
Map中的所有value放在一起可以算作一个list凑集,元素与元素之间可以重复,每个元素可以根据索引来查找。只是Map中的索引不再利用整数值,而因此其余一个工具作为索引。如果须要从Map中取出元素,则须要供应该元素的key索引。
Map接口中定义了如下常用方法:
Void clear():删除Map工具中所有的key-value对。
Boolean containsKey(Object key):查询Map中是否包含指定的key,如果有则返回true。
Boolean containsValue(Object value):查询Map中是否包含一个或多个Value,如果有返回true。
Set entrySet():返回Map中包含的key-value对所组成的set凑集,每个凑集元素都是Map.Entry(Entry是Map的内部类)工具。
Object get(Object key):返回指定key所对应的value,如果此Map中不包含该key,返回null。
Boolean isEmpty():查询Map是否为空,如果为空返回true。
Set keySet():返回该Map中所有的key组成的Set凑集。
Object put(Object key,Object value):添加一个key-value对,如果当前Map中已有一个与该key相称的key-value对,则新的key-value对会覆盖原来的key-value对。
void putAll(Map m):将Map的实例工具m中的key-value对复制到本Map中。
Object remove(Object key):删除指定key-value对,返回被删除key所关联的value,如果该key不存在,返回null。
Int size():返回该Map里key-value对的个数。
Collections values():返回该Map中所有value组成的Collection。
Map中包含一个内部类Entry,该类封装了一个key-value对。Entry包含了如下三个方法:
Object getKey():返回Entry里包含的key值。
Object getValue():返回Entry里包含的value值。
Object setValue(V value):设置该Entry里包含的value值,并返回新的value值。
举例1:
publicstaticvoid main(String[] args) throws Exception{
Map<String,String> map = new HashMap<String,String>();
//首先往map中存放数据
map.put(\"大众one\"大众,\"大众zhangsan\"大众);
map.put(\公众two\"大众, \"大众lisi\"大众);
map.put(\"大众three\"大众,\公众wangwu\"大众);
//取得map中key-value的数量
System.out.println(map.size());
//判断map中是否存在value为lisi的工具
System.out.println(map.containsValue(\"大众lisi\公众));
//判断map中是否存在key为one的工具
System.out.println(map.containsKey(\"大众one\公众));
//判断当前map工具是否是空工具,即不含任何元素工具
System.out.println(map.isEmpty());
//创建一个新的Map工具m2将m2中的key-value复制到map中去
Map<String,String> m2 = new HashMap<String,String>();
m2.put(\"大众four\公众,\"大众zhaoliu\"大众);
m2.put(\"大众five\公众, \"大众qianqi\"大众);
map.putAll(m2);
//重新获取map的key-value的个数
System.out.println(map.size());
//删除指定key的key-value对
String one = map.remove(\"大众one\"大众);
System.out.println(one);
System.out.println(map.size());
//遍历map
//常用的办法1,此种遍历完备
for(Map.Entry<String, String> entry : map.entrySet()){
System.out.println(entry.getKey()+\公众====\"大众+entry.getValue());
}
//常用的办法2,根据key值进行遍历
Iterator<String> iter = map.keySet().iterator();
while(iter.hasNext()){
System.out.println(iter.next());
}
}
8.6.1 HashMap和Hashtable实现类
HashMap和Hashtable都是Map的范例实现类,两者之间的关系完备类似于ArrayList和Vector。除此之外两者之间的范例差异:
Hashtable是一个线程安全的Map实现,但HashMap是线程不屈安。以是HashMap比Hashtable性能更高一点。
Hashtable不许可利用null作为key和value,而HashMap则可以。
举例1:
publicstaticvoid main(String[] args) throws Exception{
Map map = newHashMap();
map.put(null, null);
System.out.println(map.size());
Map m2 = newHashtable();
m2.put(null, null);
System.out.println(m2.size());
}
HashMap正常实行,而Hashtable则报空指针非常缺点。
把稳:只管即便不要利用可变工具作为HashMap的key,如果利用了可变工具作为了map的key,则在程序中只管即便不要去修正变量。
举例2:
publicstaticvoid main(String[] args) throws Exception{
String str = \公众abc\"大众;
Map map = newHashMap();
map.put(str, \公众zhangsan\"大众);
str = \"大众123\"大众;
System.out.println(map.get(str)); //输出null
System.out.println(map.get(\"大众abc\公众)); //输出zhangsan
}
8.6.2 LinkedHashMap实现类
LinkedHashMap是HashMap的子类,同LinkedHashSet一样,LinkedHashMap在存储数据元素时同样利用了链表来掩护key-value对的存放顺序,该链表卖力掩护Map的迭代顺序,迭代顺序与key-value对的插入顺序保持同等。
举例1:
publicstaticvoid main(String[] args) throws Exception{
Map<String,String> map = new HashMap<String,String>();
map.put(\公众1\"大众, \"大众zhangsan1\"大众);
map.put(\"大众2\"大众, \"大众zhangsan2\"大众);
map.put(\公众3\"大众, \"大众zhangsan3\"大众);
map.put(\"大众10\"大众, \"大众zhangsan1\公众);
map.put(\"大众20\"大众, \公众zhangsan20\"大众);
map.put(\"大众30\"大众, \公众zhangsan30\"大众);
for(Map.Entry<String,String> entry : map.entrySet()){
System.out.println(entry.getKey()+\"大众=====\"大众+entry.getValue());
}
}
输出结果:
3=====zhangsan3
20=====zhangsan20
2=====zhangsan2
10=====zhangsan1
1=====zhangsan1
30=====zhangsan30
举例2:
更换上例程序的中第一行代码
LinkedHashMap<String,String> map = new LinkedHashMap<String,list<String>();
输出结果:
1=====zhangsan1
2=====zhangsan2
3=====zhangsan3
10=====zhangsan1
20=====zhangsan20
30=====zhangsan30
8.6.3 Properties属性类
Properties类是Hashtable类的子类,该工具在处理属性文件时非常方便。Properties类可以把Map工具和属性文件关联起来,从而可以把Map工具中的key-value对写入到属性文件中,也可以把属性文件中的“属性名=属性值”加载到Map工具中。由于属性文件里的属性名、属性值只能是字符串类型,所有Properties里的key、value都是字符串类型。该类的常用方法如下
String getProperty(String key):获取Properties中指定属性名对应的属性值。
String getProperty(String key,String defaultValue):方法重载,获取Properties中指定属性名对应的属性值,如果此属性名不存在时,返回默认的defaultValue值。
Object setProperty(String key,String value):设置属性值,类似于Map的put()方法。
void load(InputStream inStream):从属性文件中加载key-value对。
void store(OutputStream out,String comments):将Properties中的key-value对输入到指定的属性文件中。
属性文件格式:在windows系统下属性文件常以.ini进行结尾,在Java中属性文件以.properties结尾
举例1:
publicstaticvoid main(String[] args) throws Exception{
Properties prop = new Properties();
prop.setProperty(\"大众name\"大众,\"大众zhangsan\"大众);
prop.put(\公众age\"大众,\"大众24\公众);
prop.store(new FileOutputStream(\"大众./test.ini\"大众), \公众注释内容\"大众);
Properties prop2 = new Properties();
//FileInputStream文件输入流,利用prop的load()方法进行加载文件
prop2.load(new FileInputStream(\"大众./test.ini\公众));
prop2.setProperty(\公众gender\公众, \公众male\"大众);
System.out.println(prop2.get(\"大众age\公众));
System.out.println(prop2.getProperty(\"大众name\"大众));
//FileOutputStream文件输出流,利用prop的store()方法将porp工具的信息保存到指定的文件中
prop2.store(new FileOutputStream(\"大众./test.properties\"大众), \"大众属性文件\"大众);
}
bankCode = 62202 1602 0131 34567
bankPass = 123456
userName = zhangsan
userAge = 24
8.6.4 SortedMap接口与TreeMap实现类
犹如Set接口派生出SortedSet子接口,SortedSet接口有一个实现类TreeSet一样,Map接口也有一个SortedMap接口,SortedMap接口也有一个实现类TreeMap。TreeMap便是一个红黑树数据构造,每个key-value对即作为红黑树的一个节点。TreeMap存储key-value对时,须要根据key对节点进行排序。TreeMap担保所有的key-value对都处于有序的状态。
TreeMap的两种排序办法:
自然排序:TreeMap的所有key必须实现Comparable接口,而且所有的key该当是同一个类的工具,否则抛出ClassCastException(类型转换非常)。
定制排序:创建TreeMap工具时,传入一个Comparator工具,该工具卖力对TreeMap中的所有key进行排序。采取定制排序时不须要key实现Comparable接口。
TreeMap供应的常用方法如下:
Map.Entry firstEntry():返回该Map中最小key所对应的key-value对,如果Map为空,则返回null。
Object firstKey():返回该Map中最小key值,如果该Map为空,则返回null。
Map.Entry lastEntry():返回Map中最大key所对应的key-value对,如果Map为空,则返回null。
Object lastKey():返回该Map中最大key值,如果该Map为空,则返回null。
Map.Entry higherEntry(Object key):返回该Map中位于key后一位的key-value对。如果后面不存在则返回为null。
Object higherKey(Object key):返回该Map中位于key后一位的key值,如果后面不存在则返回为null。
Map.Entry lowerEntry(Object key):返回该Map中位于key前一位的key-value对。如果前面不存在则返回为null。
Object lowerKey(Object key):返回该Map中位于key前一位的key值。如果前面不存在则返回为null。
SortedMap subMap(Object fromKey,Object toKey):返回该Map的子Map,其key的范围是从fromKey(包括)到toKey(不包括)。
SortedMap tailMap(Object fromKey):返回该Map的子Map,其key的范围是大于fromkey(包括)的所有key。
SortedMap headMap(Object toKey):返回该Map的子Map,其key的范围是小于toKey(不包括)的所有key。
举例1:
package com.langsin.test;
import java.util.Comparator;
import java.util.TreeMap;
class MyTest implements Comparable<Object>{
int count;
public MyTest(int count){
this.count = count;
}
publicint compareTo(Object obj) {
MyTest te = (MyTest)obj;
return count>te.count?1:count<te.count?-1:0;
}
}
publicclass TestTreeMap {
publicstaticvoid main(String[] args) {
Comparator<MyTest> comp = new Comparator<MyTest>(){
publicint compare(MyTest m1, MyTest m2) {
if(m1.count>m2.count){
return-1;
}
if(m1.count<m2.count){
return1;
}
return 0;
}
};
//首先实现treeMap的定制排序
TreeMap<MyTest,String> map = new TreeMap<MyTest,String>(comp);
map.put(new MyTest(-3), \"大众123\公众);
map.put(new MyTest(1), \"大众456\"大众);
map.put(new MyTest(3), \公众789\"大众);
System.out.println(map);
System.out.println(map.firstEntry());
}
}
8.6.5 WeakHashMap实现类
WeakHashMap与HashMap的用法基本相似,差异在于HashMap的key保留了对实际工具的强引用。即:只要HashMap不被销毁,该HashMap的所有key所引用的工具就不会被垃圾回收,HashMap也不会自动删除这些key所对应key-value对。WeakHashMap的key只保留了对实际工具的弱引用,即:WeakHashMap的工具的key所引用的工具没有被其他强引用变量所引用,则这些key所引用的工具可能被垃圾回收,WeakHashMap也可能自动删除这些key所对应的key-value对。
对付WeakHashMap,大家仅作理解,知道与HashMap的差异即可。
举例1:
publicstaticvoid main(String[] args) throws Exception{
WeakHashMap map = newWeakHashMap();
map.put(new String(\公众123\公众), \公众123\"大众);
String str = newString(\"大众456\公众);
map.put(str, \"大众456\"大众);
map.put(\"大众456\"大众, \"大众abc\"大众);
System.out.println(map); //输出内容
System.gc();//垃圾回收机制
System.out.println(map);
}
8.6.7 EnumMap实现类
EnumMap是一个与列举类一起利用的Map实现,EnumMap中所有的key都必须是单个列举类的列举值。创建EnumMap时必须显示或隐式指定它对应的列举类。
EnumMap根据key的自然顺序,即在列举类中的定义顺序来掩护key-value对的顺序。调用Map的方法keySet()、entrySet()、values()遍历EnumMap时可以看到这种顺序。
EnumMap不许可利用null作为key,但许可利用null作为value。
创建EnumMap时必须指定一个列举类,从而与使EnumMap和指定列举类关联起来。
举例1:
publicstaticvoid main(String[] args) throws Exception{
Map map = new EnumMap(Planet.class);
map.put(Planet.EARTH, \公众地球\"大众);
map.put(Planet.MARS, \公众火星\"大众);
map.put(Planet.PLUTO, \公众冥王星\"大众);
map.put(Planet.VENUS, \"大众金星\公众);
map.put(Planet.SATURN, \"大众土星\"大众);
map.put(Planet.JUPITER, \公众木星\"大众);
map.put(Planet.MERCURY, \"大众水星\"大众);
map.put(Planet.NEPTUNE, \"大众海王星\公众);
map.put(Planet.URANUS, \"大众天王星\"大众);
System.out.println(map);
}
8.7 操作凑集的工具类Collections
Java供应了一个操作Set、List和Map等凑集的工具类:Collections,该工具类里供应了大量方法对凑集元素进行排序、查询和修正等操作,还供应了将凑集工具设置为不可变,对凑集工具实现同步掌握等方法。
8.7.1 排序操作
Collections供应了如下几个方法用于对List凑集元素进行排序。
Static void reverse(List list):反转指定List凑集中元素的顺序。
Static void shuffle(List list):对List凑集元素进行随机排序。
Static void sort(List list):根据元素的自然顺序对指定list凑集的元素按升序进行排序。
Static void sort(List list,Comparator comp):根据指定Comperator产生的顺序对List凑集元素进行排序。
Static void swap(List list,int i,int j):将指定List凑集中的i处元素和j处元素进行交流。
Static void rotate(List list,int distance):当distance为正数时,将list凑集的后distance个元素“整体”移动到前面,当distance为负数时,将list凑集的前distance个元素“整体”移动到后面。
package com.langsin.product;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.TreeSet;
public class ShowHand {
//该游戏支持的最多玩家数量
private final int PALY_NUM = 5;
//该游戏实际参与的玩家数量
private int factNum = 0;
//定义所有扑克的花色和数值
private String[] types = {\"大众♠\"大众,\"大众♥\公众,\"大众♣\"大众,\"大众♦\公众};
private String[] values = {\"大众8\"大众,\"大众9\"大众,\公众10\"大众,\公众J\"大众,\"大众Q\公众,\"大众K\"大众,\"大众A\"大众};
//在一局中所有牌的数量
private List<String> cards = new ArrayList<String>();
//定义所有的玩家
private String[] players = new String[PALY_NUM];
//定义所有玩家手上的扑克牌
private Map<String,Set<String>> playerCards = new HashMap<String,Set<String>>();
/
初始化扑克牌,并将其随机排序,相称于洗牌
/
public void initCards(){
//首先将牌放到凑集中去
for(String type : types){
for(String value : values){
this.cards.add(type+value);
}
}
Collections.shuffle(cards);
}
/
初始化玩家
/
public boolean initPlays(String... names){
if(names.length>this.PALY_NUM || names.length<2){
System.out.println(\"大众玩家数量禁绝确\公众);
return false;
}else{
//初始化玩家
for(int i=0;i<names.length;i++){
this.players[i] = names[i];
playerCards.put(names[i], this.getSortSet());
}
this.factNum = names.length;
return true;
}
}
/
创建一个自定义的Set凑集,用于存放扑克牌,按照我们定制的顺序排放
/
private Set<String> getSortSet(){
//自定义排序器,让扑克牌按照我们的办法进行排放
Comparator<String> comp = new Comparator<String>(){
/
扑克牌的大小及排放规则,花色按照黑、红、花、片,排序,大小8、9、10、J、Q、K、A
/
public int compare(String s1, String s2) {
int num1 = this.getSize(s1.charAt(1));
int num2 = this.getSize(s2.charAt(1));
if(num1>num2){
return 1;
}else if(num1<num2){
return -1;
}else{
int type1 = this.getType(s1.charAt(0));
int type2 = this.getType(s2.charAt(0));
if(type1>type2){
return -1;
}else{
return 1;
}
}
}
/
判断牌的点数大小
/
private int getSize(char c){
switch (c) {
case '8':
return 8;
case '9':
return 9;
case 'J':
return 11;
case 'Q':
return 12;
case 'K':
return 13;
case 'A':
return 14;
default:
return 10;
}
}
/
判断牌的花色
/
private int getType(char c){
switch (c) {
case '♦':
return 1;
case '♣':
return 2;
case '♥':
return 3;
default:
return 4;
}
}
};
Set<String> set = new TreeSet<String>(comp);
return set;
}
/
为每个玩家初始化扑克牌
/
public void deliverCard(){
for(int i=0;i<5;i++){
for(int j=0;j<factNum;j++){
playerCards.get(this.players[j]).add(cards.get(0));
cards.remove(0);
}
}
}
/
测试每个人手中的牌
/
public void print(){
for(int i=0;i<this.factNum;i++){
System.out.println(this.playerCards.get(this.players[i]));
}
}
public static void main(String[] args) {
ShowHand test = new ShowHand();
test.initCards();
test.initPlays(\公众张三\公众,\"大众李四\"大众,\"大众王五\"大众);
test.deliverCard();
test.print();
}
}
8.7.2 查找、更换操作
Collections还供应了如下用于查找、更换凑集元素的常用方法。
Static int binarySearch(List list,Object key):利用二分法搜索指定的List凑集,用来得到指定工具key在List凑集中的索引。如果要使该方法可以正常事情,则必须担保List中的元素已经处于有序的状态。
Static Object max(Collection coll):根据元素的自然顺序,返回给定凑集中的最大元素。
Static Object max(Collection coll,Comparator comp):根据Comparator指定的顺序,返回给凑集中的最大的元素。
Static Object min(Collection coll):根据元素的自然顺序,返回给凑集中的最小元素。
Static Object min(Collection coll,Comparator comp):根据Comparator指定的顺序,返回给凑集中的最小的元素。
Static void fill(List list,Object obj):利用指定元素obj更换指定List凑集中的所有元素。
Static int frequency(Collection c,Object o):返回指定凑集中指定元素的涌现次数。
Static int indexOfSubList(List source,List target):返回子List工具在父List工具中第一次涌现的位置索引;如果父List中没有涌现这样的子List,则返回-1。
Static int lastIndexOfSubList(List source,List target):返回子List工具在父List工具中末了一次涌现的位置索引,如果父List中没有涌现这样的子List,则返回-1。
Static boolean replaceAll(List list,Object oldVal,Object newVal):利用一个新值newVal更换List工具的所有旧值oldVal。
举例1:
publicstaticvoid main(String[] args) throws Exception{
List list = newArrayList();
list.add(2);
list.add(-3);
list.add(5);
list.add(1);
System.out.println(list);
System.out.println(Collections.max(list));
System.out.println(Collections.min(list));
Collections.replaceAll(list, 1, 6);
System.out.println(list);
System.out.println(Collections.frequency(list, 5));
Collections.sort(list);
System.out.println(list);
System.out.println(Collections.binarySearch(list, 6));
}
8.7.3 同步掌握
Collections类中供应了多个synchronizedXxx()方法,该方法可以将指定的凑集包装成线程同步的凑集,从而可以办理多线程并发访问凑集时的多线程安全问题。
Java中常用的凑集框架中的实现类,HashSet、TreeSet、ArrayList、ArrayDeque、LinkedList、HashMap、和TreeMap都是线程不屈安的。如果有多个线程访问它们,而且有超过一个的线程试图修正它们,则可能会涌现缺点。Collections供应了多个静态方法可以把它们包装成线程同步的凑集。
举例1:
publicstaticvoid main(String[] args) throws Exception{
Collectioncoll = Collections.synchronizedCollection(new ArrayList());
Listlist = Collections.synchronizedList(new ArrayList());
Setset = Collections.synchronizedSet(new HashSet());
Mapmap = Collections.synchronizedMap(new HashMap());
}
通过synchronizedXxx()方法,就可以直接获取List、Set、Map的线程安全实现版本。
8.7.4 设置不可变凑集
Collections供应如下三个类方法来返回一个不可变的凑集。
emptyXxx():返回一个空的,不可变的结合工具,此处的凑集即可以是List,也可以是Set,还可以是Map。
singletonXxx():返回一个包含指定工具的,不可变的凑集工具,此处的凑集即可以是List,也可以是Set,还可以是Map。
unmodifiableXxx():返回指定凑集工具的不可变视图,此处的凑集既可以是List,也可以是Set,还可以是Map。
举例1:
publicstaticvoid main(String[] args) {
//创建一个空的,不可变的Set工具
Setset = Collections.emptySet();
//创建一个只包含特定工具的List凑集
List<String>list = Collections.singletonList(\公众abc\"大众);
//创建一个普通的Map凑集,将Map凑集转变为一个不能在变动的Map工具
Map map = newHashMap();
map.put(\"大众123\公众, \公众abc\"大众);
map.put(\"大众456\"大众, \公众def\公众);
MapunmodifiableMap = Collections.unmodifiableMap(map);
}
第9章:泛型
在Java发布的JDK1.5版本中增加了泛型支持,所谓的泛型便是为了让凑集在很大程度上记住器元素的数据类型。在没有利用泛型之前,一旦把工具存放进Java凑集中,凑集只会将元素作为Object工具进行处理。当从凑集中取出工具时就须要进行逼迫类型转换。如果转换缺点,则将会引起ClassCastException非常(类型转换非常)。
增加泛型支持后的凑集,则可以让凑集记住元素的类型,并在编译时检讨凑集中元素的类型,如果往凑集中添加不知足类型哀求的工具,编译器则会提示缺点。增加泛型后的凑集,可以让代码更加简洁,程序更加健壮。
9.1 泛型入门
Java凑集之以是被设计成以存放Object工具为根本的类,是由于设计之初,程序员并不知道我们要用凑集来存放什么类型的工具,以是把凑集设计成能保存任何数据类型的工具,只哀求有很好的通用性。因此而导致了下面两个问题:
凑集对元素类型没有任何限定,只假如Object类型就都可以存放。
把工具存放进凑集时,凑集丢失了工具的状态信息,凑集只知道存放的是Object,因此取出时还须要对工具进行一个逼迫类型转换,增加了编程的繁芜度,还有可能会引发ClassCastException非常。
举例1:
publicstaticvoid main(String[] args) {
List list = newArrayList();
list.add(\"大众abc\"大众);
list.add(\公众def\"大众);
list.add(5);
for(int i=0;i<list.size();i++){
String s = (String)list.get(i);
System.out.println(s);
}
}
9.1.1 利用泛型
publicstaticvoid main(String[] args) {
List<String> list = new ArrayList<String>();
list.add(\公众abc\公众);
list.add(\公众def\"大众);
list.add(5); //编译报错
for(int i=0;i<list.size();i++){
String s = list.get(i); //无需进行逼迫类型转换
System.out.println(s);
}
}
上面程序创建了一个分外的List凑集,这个List凑集只能保存字符串工具,不能保存其他类型的工具。创建这种分外凑集的方法是:在凑集接口、类后面增加“<>”尖括号,尖括号中写入一个数据类型,即表明这个凑集接口、凑集类只能保存这种特定类型的工具。
9.1.2 定义泛型接口、类
所谓的泛型便是许可在定义类、接口、方法时利用类型形参,这个类型形参将在声明变量、创建工具、调用方法时动态的指定。
举例1:
publicinterface MyInterface<T>{
public T getType();
publicvoid setType(T t);
}
publicclass MyClass implements MyInterface<String> {
public String getType() {
returnnull;
}
publicvoid setType(String t) {
}
}
当创建了带有泛声明的接口、父类之后,可以为该接口创建实现类,或者从该父类派生子类,但是把稳一点:当利用这些接口、父类是不能再包含类型形参,而是必须指出详细的实际类型。如上例所示。
9.1.3 不存在泛型类
在程序中我们为一个ArrayList<String>指定了泛型后,可以把这个ArrayList<String>算作ArrayList的子类,这个类只能存储String类型的元素,但是实际上,系统并没有为ArrayList<String>天生新的class文件,也不会把ArrayList<String>当成新类,由于并不存在这种泛型类。
第10章:非常处理
Java的非常机制紧张依赖于try、catch、finally(始终都会被运行)、throw和throws五个关键字,个中try关键字后面紧随着一个花括号括起来的代码块,它里面放置可能会引发非常的代码块。Catch后面对应非常类型和一个代码块,用于表明该catch块用于处理这种类型的代码块,多个catch块后面还可以跟一个finally块,用于回收在try块里打开的物理资源,非常机制会担保finally块总会被实行。throws关键字紧张在方法署名中利用,用于声明该方法可能抛出的非常;而throw用于抛出一个实际的非常,throw可以单独作为语句利用,抛出一个详细的非常工具。
10.1 非常概述
非常处理已经成为衡量一门措辞是否成熟的标准之一,目前的主流编程措辞如C++,C#,Ruby等大都供应了非常处理机制。增加非常处理机制后的程序有更好的容错性,更加健壮。
举例1:
publicstaticvoid main(String[] args) {
List<String> list = new ArrayList<String>();
list.add(\"大众abc\公众);
list.add(\"大众def\"大众);
try {
for(int i=0;i<4;i++){
System.out.println(list.get(i));
}
} catch (IndexOutOfBoundsException e) {
System.out.println(\公众已经超出了凑集的范围\"大众);
}
}
10.2 非常处理机制
Java的非常处理机制可以让程序具有极好的容错性,让程序更加健壮。当程序涌现意外环境时,系统会自动天生一个Exception工具来关照程序,从而实现将“业务功能实当代码”和“缺点处理代码”分离,供应更好的可读性。
10.2.1 利用try…catch捕获非常
在Java中提出了一种假设:如果程序可以顺利完成,那就“统统OK”,把系统的业务实当代码放在try块中定义,所有的非常处理逻辑放在catch块中进行处理。下面是Java非常处理机制的语法规则。
try{
//业务实当代码
}catch(ExceptionClass1 e1){
//缺点处理代码
}catch(ExceptionClass2 e2){
//缺点处理代码
}finally{
//始终会实行的代码
}
Try块后可以有多个catch块,这是为了针对不同的非常类供应不同的非常处理办法。当系统发生不同的意外情形时,系统会天生不同的非常工具,Java运行时就会根据该非常工具所属的非常类来决定利用哪个catch块来处理。
举例1:
publicstaticvoid main(String[] args) {
List<String> list = new ArrayList<String>();
list.add(\"大众abc\公众);
list.add(\"大众def\"大众);
list.add(null);
try {
for(int i=0;i<4;i++){
list.get(i).equals(\公众abc\"大众);
System.out.println(list.get(i));
}
} catch (IndexOutOfBoundsException e) {
System.out.println(\公众索引值越界非常\公众); 2
}catch(NullPointerException e){
System.out.println(\公众空指针非常处理\"大众); 1
}finally{
System.out.println(\"大众始终会被实行的代码块\"大众); 3
}
}
10.2.2 非常类的继续体系
Java供应了丰富的非常类,这些非常类之间有严格的继续关系,如下图所示:
在Java中把所有的非正常情形分为两种:非常(Exception)和缺点(Error),他们都继续Throwable父类。Error缺点,一样平常是指与虚拟机干系的问题,如系统崩溃、虚拟机缺点、动态链接失落败等,这种缺点无法规复或不能捕获,将导致运用程序中断。常日运用程序无法处理这些缺点,因此运用程序不能试图利用catch块来捕获Error工具,在定义方法时也无须其throws子句中声明该方法可能抛出Error及其任何子类。
10.2.3 访问非常信息
如果程序须要在catch块中访问非常工具的干系信息,则可以通过访问catch块后的非常形参来得到。当Java运行时决定调用某个catch块来处理该非常工具时,会将非常工具赋给catch块后的非常参数,程序即可通过该参数来得到非常的干系信息。
所有非常工具都包含了如下几个常用方法。
getMessage():返回该非常的详细描述字符串。
printStackTrace():将该非常的跟踪栈信息输出到标准缺点输出。
printStackTrace(PrintStream s):将该非常的跟踪栈信息输出到指定输出流中。
getStackTrace():返回该非常的跟踪栈信息。
举例1:
publicstaticvoid main(String[] args) {
List<String> list = new ArrayList<String>();
list.add(\"大众abc\"大众);
list.add(\"大众def\公众);
list.add(null);
try {
for(int i=0;i<4;i++){
list.get(i).equals(\公众abc\"大众);
System.out.println(list.get(i));
}
} catch (IndexOutOfBoundsException e) {
System.out.println(\公众已经超出了凑集的范围\公众);
}catch(NullPointerException e){
e.printStackTrace();
System.out.println(e.getMessage());
System.out.println(\"大众空指针非常处理\"大众);
}finally{
System.out.println(\"大众始终会被实行的代码块\公众);
}
}
输出信息:
10.2.4 利用finally回收资源
程序在try块里打开了一些物理资源,比如:数据库连接、网络连接、和磁盘文件等,这些物理资源都必须显示回收。
如果在try块的某条语句引起了非常,该语句后的其他语句常日不会得到实行的机会,这将导致该语句之后的资源回收语句得不到实行。如果在catch块里进行资源回收,但catch块完备有可能得不到实行,这将导致不能及时回收这些物理资源。
为了担保一定能回收try块中打开的物理资源,非常处理机制供应了finally块。不管try块中的代码是否涌现非常,也不管哪一个catch块被实行,乃至在try块或者catch块中实行了return语句,finally块总会被实行。因此回收资源实行语句该当在finally块中实行。
举例1:
publicstaticvoid main(String[] args) {
FileInputStream fis = null;
try {
fis = new FileInputStream(\"大众./a.txt\"大众);
} catch (Exception e) {
e.printStackTrace();
return;
}finally{
try {
fis.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
10.2.5 利用throws声明抛出非常
利用throws声明抛出非常的思路是,当前方法不知道如何处理这种类型的非常,该非常该当由上一级调用者处理;如果main方法也不知道如何处理这种类型的非常,也可以利用throws声明抛出非常,该非常将交给JVM处理。JVM对非常的处理方法是,打印非常的跟踪栈信息,并终止程序实行。
举例1:
publicvoid dealFile() throws Exception{
FileInputStream fis = null;
try {
fis = new FileInputStream(\公众./a.txt\"大众);
} catch (Exception e) {
fis.close();
e.printStackTrace();
}
}
publicstaticvoid main(String[] args) throws Exception {
Test test = new Test();
test.dealFile();
}
10.2.6 利用throw抛出非常
如果须要在程序中自主的抛出非常,则该当利用throw语句,throw语句可以单独利用,throw语句抛出的不是非常类,而是一个非常实例,而且每次只能抛出一个非常实例。
举例1:
publicstaticvoid main(String[] args){
for(int num=5;num>0;num--){
try {
if(num<2){
thrownew Exception(\"大众数字的值小于2了,停滞运行\"大众);
}
} catch (Exception e) {
System.out.println(\"大众======\公众);
System.out.println(e.getMessage());
}
}
System.out.println(\"大众终极实行完成\"大众);
}
第11章:输入/输出
IO(输入/输出)是所有程序都必须的部分。输入机制:许可程序读取外部数据(包括来自磁盘、光盘等存储设备的数据)、用户输入数据;输出机制:许可程序记录运行状态,将程序数据输出到磁盘、光盘等存储设备中。
Java的IO通过java.io包下的类和接口来支持,在java.io包下紧张包括输入、输出两种IO流,每种输入、输出流又可分为字节流和字符流两大类。个中字节流以字节为单位来处理输入、输出操作,而字符流则以字符来处理输入、输出操作。
11.1 File类
File是java.io包下代表与平台无关的文件和目录,则程序中操作文件和目录,都可以通过File类来完成。File能新建、删除、重命名文件和目录。File不能访问文件内容本身,如果访问文件内容本身,则须要利用输入/输出流。
11.1.1 访问文件和目录
File类可以利用文件路径字符串来创建File实例,该文件路径字符串既可以是绝对路径,也可以是相对路径。在默认情形下,系统总是依据用户的事情路径来阐明相对路径。
创建File工具后,可以调用File工具的方法来访问。常用的方法如下:
1、访问文件名干系的方法
String getName():返回此文件工具所表示的文件名或路径名。
String getPath():返回此File工具所对应的路径名。
File getAbsoluteFile():返回此File工具所对应的绝对路径指向的File工具。
String getAbsolutePath():返回此File工具所对应的绝对路径。
String getParent():返回此File工具所对应的目录的父目录,以事情路径为准,如果已经在事情路径的根目录下,则返回null,否则返回父目录。
boolean renameTo(File newName):重命名此File工具所对应的文件或目录,成功返回true,否则返回false。
2、文件检测干系的方法
boolean exists():判断File工具所对应的文件或目录是否存在。
boolean canWrite():判断File工具所对应的文件和目录是否可写。
boolean canRead():判断File工具所对应的文件和目录是否可读。
boolean isFile():判断File工具所对应的是否是文件。
boolean isDirectory():判断File工具所对应的是否是目录。
boolean isAbsolute():判断File工具所对应的文件或目录是否绝对路径。例如:如果在Unix/Linux等系统上,如果路径名的开头是/,则表明File工具对应一个绝对路径,在Windows等系统上,如果路径开头是盘符,则解释它是一个绝对路径。
获取常规文件信息
long lastModified():返回文件的末了修正韶光。
long length():返回文件内容的长度。
文件操作干系的方法
boolean createNewFile():当此File工具对应的文件不存在时,创建一个该File工具所对应的文件,创建成功返回true,否则返回false。
boolean delete():删除File工具所在的文件或路径。
目录操作干系的方法
boolean mkdir():创建一个File工具所对应的目录,创建的是目录而不是文件。
boolean mkdirs():创建一个File工具所对应的所有目录,如果上次目录不存在,会同时将上级目录创建出来。
File[] listFile():列出File工具的所有子文件和路径,返回File数组。
Static File[] listRoots():列出系统所有根路径。
举例1:
publicstaticvoid main(String[] args) throws Exception {
File file = new File(\"大众./abc/aaa\"大众);
//返回文件的文件名或路径名
System.out.println(file.getName());
//返回文件所在的相对目录
System.out.println(file.getPath());
//返回文件所在的绝对目录
System.out.println(file.getAbsolutePath());
//返回文件工具的父目录
System.out.println(file.getParent());
//判断文件是否存在
if(!file.exists()){
//连同不存在的父级目录一同创建出来
file.mkdirs();
}
System.out.println(file.canWrite());
System.out.println(file.canRead());
System.out.println(file.isDirectory());
System.out.println(file.isFile());
file = new File(\"大众./abc/aa.txt\"大众);
if(!file.exists()){
file.createNewFile();
}
//判断文件是否是绝对路径
System.out.println(file.isAbsolute());
file = new File(file.getParent());
File[] files = file.listFiles();
for(File fi : files){
System.out.println(fi.getName());
}
}
11.2 Java的IO流
Java的IO流是实现输入/输出的根本,它可以方便的实现数据的输入/输出操作,Java把所有传统的流类型都放在java.io包中,用以实现输入/输出功能。
11.2.1 流的分类
输入流和输出流
按照流向来分,可以分为输入流和输出流
输入流:只能从中读取数据,而不能向其写入数据;基本上是从磁盘文件到系统内存。
输出流:只能向其写入数据,而不能从中读取数据;基本上是从系统内存到磁盘文件。
Java的输入流紧张由InputStream和Reader作为基类,而输出流则紧张由OutputStream和Writer作为基类。他们都是一些抽象基类,能直接创建实例工具。
2、字节流与字符流
字节流和字符流的用法险些一样,差异在于字节流和字符流所操作的数据单元不同,字节流操作的数据单元是8位的字节,而字符流操作的数据单元是16位的字符。
英笔墨母代表一个字符代表一个字节,一个汉字字符是2个字节
一个字节即是8位
字节流紧张由InputStream和OutStream作为基类,字符流紧张由Reader和Writer作为基类。
11.3 InputStream和Reader
InputStream和Reader是所有输入流的抽象基类,本身并不能创建实例来实行输入,它们是所有输入流的模板,它们的方法是所有输入流都可以利用的方法。
在InputStream里包含如下方法:
int read():从输入流中读取单个字节,返回所读取的字节数据。
int read(byte[] b):从输入流中最多读取b.length个字节的数据,并将其存储在字节数组b中,返回实际读取的字节数。
int read(byte[] b,int off,int len):从输入流中最多读取len个字节的数据,并将其存储在数据组b中,放入数组b中时,并不是从数组出发点开始,而是从off位置开始,返回实际读取的字节数。
aa.txt文件中的数据为:测试数据信息
举例1:
publicstaticvoid main(String[] args) throws Exception {
InputStream is = new FileInputStream(new File(\"大众./abc/aa.txt\公众));
byte[] b = newbyte[1024];
int size = 0;
while((size=is.read(b))>0){
System.out.println(new String(b,0,size));
}
//末了不要忘却关闭流
is.close();
}
举例2:
publicstaticvoid main(String[] args) throws Exception {
InputStream is = new FileInputStream(new File(\公众./abc/aa.txt\"大众));
byte[] b = newbyte[1024];
int size = 0;
//从输入流中读取数据放入到字节数组中,从2位置开始放,从输入流中读取6个长度
while((size=is.read(b,2,6))>0){
System.out.println(new String(b,2,size));
}
//末了不要忘却关闭流
is.close();
}
在Reader里包含如下方法:
int read():从输入流中读取单个字符,返回所读取的字符数据
int read(char[] ch):从输入流中最多读取ch.length个字符的数据,并将其存储在字符数组ch中,返回实际读取的字符数。
int read(char[] ch,int off,int len):从输入流中最多读取len个字符的数据,并将其存储在字符数组ch中,放入数组时,从数组的off位置开始,返回实际读取的字符数。
举例3:
publicstaticvoid main(String[] args) throws Exception {
Reader rd = new FileReader(new File(\公众./abc/aa.txt\公众));
char[] ch = newchar[1024];
int size = 0;
while((size=rd.read(ch))>0){
System.out.println(new String(ch,0,size));
}
//末了不要忘却关闭流
rd.close();
}
举例4:
publicstaticvoid main(String[] args) throws Exception {
Reader rd = new FileReader(new File(\"大众./abc/aa.txt\"大众));
char[] ch = newchar[1024];
int size = 0;
while((size=rd.read(ch,2,4))>0){
System.out.println(new String(ch,2,size));
}
//末了不要忘却关闭流
rd.close();
}
11.4 OutputStream和Writer
OutputStream和Writer也非常相似,两个流都供应了如下方法进行输出:
void write(int c):将指定的字节/字符输出到输出流中,个中c既可以表示字节也可以表示字符。
void write(byte[]/char[] buf):将字节数组/字符数组中的数据输出到指定输出流中。
void write(byte[]/char[] buf,int off,int len):将字节数组/字符数组中从off位置开始,长度为len的字节/字符输出到输出流中。
由于字符流直接以字符作为操作单位,所有Writer可以用字符串来代替字符数组,即以String工具作为参数。Writer里还包含了如下两个方法。
void write(String str):将str字符串里包含的字符输出到指定输出流中。
void write(String str,int off,int len):将字符串从off位置开始,长度为len的字符输出到指定输出流中。
举例1:将会覆盖原有的文件内容从开始位置写入
publicstaticvoid main(String[] args) throws Exception {
OutputStream os = new FileOutputStream(new File(\"大众./abc/aa.txt\公众));
byte[] b = {55,56,57,58};
os.write(b);
os.close();
}
举例2:
publicstaticvoid main(String[] args) throws Exception {
Writer writer = new FileWriter(new File(\"大众./abc/aa.txt\"大众));
char[] ch = {'你','们','都','是','很','棒','的'};
writer.write(ch);
writer.write(Arrays.toString(ch));
writer.close();
}
11.5 InputStreamReader和OutputStreamWriter
输出/输出体系中供应了两个转换流InputStreamReader和OutputStreamWriter,这两个转换流用于实现将字节流转换成字符流,个中InputStreamReader将字节输入流转换成字符输入流,OutputStreamWriter将字节输出流转换成字符输出流。此类用律例子详见:11.6
11.6 BufferedReader和BufferedWriter
BufferedReader和java.io.BufferedWriter类各拥有8192字符的缓冲区。当BufferedReader在读取文本文件时,会先只管即便从文件中读入字符数据并置入缓冲区,而之后若利用read()方法,会先从缓冲区中进行读取。如果缓冲区数据不敷,才会再从文件中读取,利用BufferedWriter时,写入的数据并不会先输出到目的地,而是先存储至缓冲区中。如果缓冲区中的数据满了,才会一次对目的地进行写出。如果要在缓冲区中数据未满的情形下将数据写入到目的地,须要利用flush()方法,将数据刷新一下。
举例1:
publicstaticvoid main(String[] args) throws Exception {
//System.in返回的是一个字节流的是工具,将字节流转换成一个字符流
InputStreamReader isr = new InputStreamReader(System.in);
//是否还有一种更好的流来处理字符流内,答案是肯定的:缓冲流
BufferedReader br = new BufferedReader(isr);
//缓冲流可以将文本中的字符信息按一行来进行处理,即读取一行,写入一行,
//而不在须要定义个数组来存放读取内容,读取内容时以换行符为标志,如果没有读取到换行符则程序
//壅塞,一贯读取到换行符为止。
String line = null;
//将所有信息写入到文件中去
BufferedWriter writer = new BufferedWriter(new FileWriter(new File(\"大众./abc/aa.txt\"大众),true));
while((line=br.readLine()) != null){
if(\公众exit\"大众.equals(line)){
//停滞写入,退出
System.exit(1);
}
writer.write(line);
writer.newLine();
//将内容从缓存中刷新出去,写入到目的地
writer.flush();
}
writer.close();
br.close();
}
11.7 PrintStream和PrintWriter
PrintStream的布局函数:
public PrintStream(File file)
创建具有指定文件新打印流。
public void print(Object obj)
这个方法功能是非常强大的,它可以输出任何工具,而不必另加解释。此外print()方法有许多重载形式,即有多种参数。它们是字符串(String)、字符数组(char[])、字符(char)、整数(int)、长整数(long)、浮点数(float)、双精度浮点数(double)、布尔值(boolean)。
public void println(Object obj)
此方法同上,差异在于打印之后追加一个换行符。
举例1:
publicstaticvoid main(String[] args) throws Exception {
//如果文件不存在,则将文件直接创建
PrintStream ps = new PrintStream(new File(\"大众./abc/bb.txt\"大众));
ps.print(\公众你好\"大众);
ps.close();
}
PrintWriter是与字节流相对应的字符流。PrintWriter用于大多数输出,比PrintStream更为得当。建议新开拓的代码利用PrintWriter类。 PrintWriter类与PrintStream类的方法是对应的。
举例2:
publicstaticvoid main(String[] args) throws Exception {
PrintWriter writer = new PrintWriter(new File(\公众./abc/bb.txt\"大众));
writer.print(\"大众新的内容\"大众);
writer.close();
}
11.8 内存流、数据流
ByteArrayInputStream和ByteArrayOutputStream为内存流或者称为数组流。
ByteArrayInputStream 包含一个内部缓冲区,该缓冲区包含从流中读取的字节。内部计数器跟踪read()方法要供应的下一个字节。ByteArrayOutputStream类实现了一个输出流,个中的数据被写入一个 byte 数组。缓冲区会随着数据的不断写入而自动增长。可利用 toByteArray() 和 toString() 获取数据。
ByteArrayInputStream和ByteArrayOutputStream,用于以IO流的办法来完成对字节数组内容的读写,来支持类似内存虚拟文件或者内存映射文件的功能。
DataInputStream和DataOutputStream数据流,用来处理基本数据的IO流。
举例1:
客户端和做事器端交互,当连接建立之后,如果只是根据协议用DataInputStream的readInt() 或者readByte() 等固定方法一个一个的读,那是相称花费资源的,如果一次将所须要的数据读取完毕,然后剩下的便是本地解析,那就省了不少交互资源
做事器端处理完毕须要往客户端返回数据,如果利用DataOutputStream的writeInt(int v)或者writeByte(int v)等方法一个一个的写,那么和读取的场景性子就一样了:交互资源是相称花费的;因此如果现在本地把数据组织完毕之后,进行一次传输。
publicstaticvoid main(String[] args) throws Exception {
//创建一个字节流或者内存流,将内容写入到这个流中
ByteArrayOutputStream baos = new ByteArrayOutputStream();
//Date数据流写入的内容被存储在内存流baos中
DataOutputStream dos = new DataOutputStream(baos);
dos.writeFloat(13.5f);
dos.writeDouble(12.50);
dos.writeFloat(14.6f);
//写完之后可以将baos流包装好进行传输
//客户端吸收到做事器端返回的字节流,进行一次吸收,然后进行处理
DataInputStream dis = new DataInputStream(new ByteArrayInputStream(baos.toByteArray()));
//读取字节流的时候,必须按照写入的办法进行读取,例如:第一个写入了float数据,那么读取的时
//候必须先读取Float,第二写入的是Double,那么读取第二数据的时候必须读入Double。
System.out.println(dis.readFloat());
System.out.println(dis.readDouble());
System.out.println(dis.readFloat());
}
11.9 Object工具流
工具序列化:工具序列化可以将工具保存在磁盘中,或者将工具在网络中进行传输。序列化的机制是可以将工具分开程序的运行而独立存在。如果让一个类的工具支持序列化机制,则须要让这个类实现Serializable接口就可以了。该接口无须实现任何方法,它只是表明该类的实例是可序列化的。
利用工具流ObjectInputStream和ObjectOutputStream将工具保存到磁盘上或者通过网络进行传输。
举例1:
publicstaticvoid main(String[] args) throws Exception {
//创建一个person工具,此工具已经支持序列化
Person person = new Person();
person.setAge(25);
person.setName(\"大众张三\公众);
//创建一个Object工具输出流,将此工具写入到文件中去
ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream(new File(\公众./abc/person.txt\"大众)));
oos.writeObject(person);
//创建一个Object工具输入流,将工具从文件中读取出来
ObjectInputStream ois = new ObjectInputStream(new FileInputStream(new File(\公众./abc/person.txt\"大众)));
Person ps = (Person)ois.readObject();
System.out.println(ps.getName());
System.out.println(ps.getAge());
}
举例2:将工具写入到内存流中
publicstaticvoid main(String[] args) throws Exception {
//创建一个person工具,此工具已经支持序列化
Person person = new Person();
person.setAge(25);
person.setName(\"大众张三\公众);
//创建一个Object工具输出流,将此工具写入到内存流中去
ByteArrayOutputStream baos =new ByteArrayOutputStream();
ObjectOutputStream oos = new ObjectOutputStream(baos);
oos.writeObject(person);
//创建一个内存输入流,将工具从内存输出流中获取出来
ByteArrayInputStream bais = new ByteArrayInputStream(baos.toByteArray());
//创建一个Object工具输入流,将工具从内存输入中读取出来
ObjectInputStream ois = new ObjectInputStream(bais);
Person ps = (Person)ois.readObject();
System.out.println(ps.getName());
System.out.println(ps.getAge());
}
11.9.1 浅克隆与深克隆
1、什么是克隆
Object工具clone()方法,此方法将会产生此工具的一个副本返回,类似于拷贝了一份当前的工具,clone方法是protected进行润色的(受保护的),如果要想使我们自己的类来实现的这个方法,首先要实现Cloneable这个接口,然后重写Object工具的这个方法,所谓的重写便是在本类中调用父类的方法。这是由于:如果在没有实现 Cloneable 接口的实例上调用 Object 的 clone 方法,则会导致抛出 CloneNotSupportedException 非常。
2、浅克隆
假如有两个类,一个是A类,一个是B类,A类中包含了B类的这样一个引用,例如class B{} ,
class A{
B b=null;
}
在调用A类的clone方法时,返回一个此类的工具副本。需把稳的是对付A类中引用类型变量b跟副本中的引用类型b,他们指向了同一个工具。因此无论是通过A类中的引用变量b还是副本中的引用变量b来操作B工具实际上是对同一个工具进行操作,这种不完备的克隆,称为浅克隆。
举例1:
//学生的课程分数类
package com.langsin.item;
publicclass Course {
Course(String chinese,String english,String math){
this.chinese = chinese;
this.english = english;
this.math = math;
}
private String chinese;
private String english;
private String math;
public String getChinese() {
return chinese;
}
publicvoid setChinese(String chinese) {
this.chinese = chinese;
}
public String getEnglish() {
return english;
}
publicvoid setEnglish(String english) {
this.english = english;
}
public String getMath() {
return math;
}
publicvoid setMath(String math) {
this.math = math;
}
}
// 学生的信息类
package com.langsin.item;
publicclass Student implements Cloneable{
Student(String name,String age,Course cour){
this.name = name;
this.age = age;
this.cour = cour;
}
private String name;
private String age;
private Course cour;
public String getName() {
return name;
}
publicvoid setName(String name) {
this.name = name;
}
public String getAge() {
return age;
}
publicvoid setAge(String age) {
this.age = age;
}
public Course getCour() {
return cour;
}
publicvoid setCour(Course cour) {
this.cour = cour;
}
@Override
protected Object clone() throws CloneNotSupportedException {
return super.clone();
}
}
// 测试方法
publicstaticvoid main(String[] args) throws Exception{
Student st1 = new Student(\"大众张三\"大众,\公众24\"大众,new Course(\公众85\"大众,\公众85\"大众,\"大众85\"大众));
System.out.println(st1.getName()); // 张三
System.out.println(st1.getCour().getChinese()); //85
Student st2 = (Student)st1.clone();
st2.setName(\"大众李四\"大众);
System.out.println(st2.getName()); // 李四
System.out.println(st2.getCour().getChinese()); //85
System.out.println(\"大众====================\"大众);
st1.getCour().setChinese(\公众36\公众);
System.out.println(st1.getCour().getChinese()); //36
System.out.println(st2.getCour().getChinese()); //36
st2.getCour().setEnglish(\"大众88\公众);
System.out.println(st1.getCour().getEnglish()); // 88
System.out.println(st2.getCour().getEnglish()); //88
}
2、深克隆
对付IO流中的工具流ObjectInputStrean、ObjectOutputStream来说,当把工具从内存中写入到文件中时,写入的工具保持了工具当时的一个状态。同样如果有两个类,一个A类,一个B类,A类中包含了对B类的一个引用,如果把A类型的工具a1写入到文件中时,由于要保存状态,因此会把a1中的引用类型的B工具也写入到文件中去,当我们把a1工具读取出来时, 此时这个工具因此完备独立的办法存在,与a1没有什么关系了,这时此工具可以成为a1的副本工具a2。通过a1操作它的引用类型b时,a2中的引用类型并不发生变革。这种克隆成为深克隆。
举例2:
// 学生课程类
package com.langsin.item;
import java.io.Serializable;
publicclass Course implements Serializable{
Course(String chinese,String english,String math){
this.chinese = chinese;
this.english = english;
this.math = math;
}
private String chinese;
private String english;
private String math;
public String getChinese() {
return chinese;
}
publicvoid setChinese(String chinese) {
this.chinese = chinese;
}
public String getEnglish() {
return english;
}
publicvoid setEnglish(String english) {
this.english = english;
}
public String getMath() {
return math;
}
publicvoid setMath(String math) {
this.math = math;
}
}
//学生信息类
package com.langsin.item;
import java.io.Serializable;
publicclass Student implements Serializable{
Student(String name,String age,Course cour){
this.name = name;
this.age = age;
this.cour = cour;
}
private String name;
private String age;
private Course cour;
public String getName() {
return name;
}
publicvoid setName(String name) {
this.name = name;
}
public String getAge() {
return age;
}
publicvoid setAge(String age) {
this.age = age;
}
public Course getCour() {
return cour;
}
publicvoid setCour(Course cour) {
this.cour = cour;
}
}
// 测试方法
publicstaticvoid main(String[] args) throws Exception{
Student st1 = new Student(\"大众张三\公众,\"大众24\公众,new Course(\"大众85\公众,\"大众85\"大众,\"大众85\公众));
ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream(new File(\"大众./abc/aa.txt\"大众)));
oos.writeObject(st1);
oos.close();
ObjectInputStream ois = new ObjectInputStream(new FileInputStream(new File(\"大众./abc/aa.txt\"大众)));
Student st2 = (Student)ois.readObject();
System.out.println(\公众=====================\公众);
System.out.println(st1.getName()); // 张三
System.out.println(st2.getName()); // 张三
st2.setName(\"大众李四\"大众);
System.out.println(st1.getName()); // 张三
System.out.println(st2.getName()); // 李四
System.out.println(\公众=============================\"大众);
st1.getCour().setChinese(\"大众78\"大众);
System.out.println(st1.getCour().getChinese()); //78
System.out.println(st2.getCour().getChinese()); // 85
st2.getCour().setEnglish(\"大众99\"大众);
System.out.println(st1.getCour().getEnglish()); // 85
System.out.println(st2.getCour().getEnglish()); //99
}
11.10 ZipOutputStream、ZipFile、ZipInputStream
在软件开拓中我们会常常处理一些文件的传送问题,如果文件内容较多,那么文件就比较大,在传送过程中就会花费较多的韶光去等待文件的传送完毕,如果我们将文件先一步进行压缩为一个较小的文件,那么将会大大缩小文件通报所花费的韶光。
在日常中我们常见的压缩文件格式为:zip、jar、GZ
在java中同样可以实现对文件的压缩,zip是一种常见的压缩文件,java中实现zip的压缩须要导入java.util.zip包,可以用此包下的ZipFile、ZipOutputStream、ZipInputStream、ZipEntry来实现压缩。
ZipEntry代表的是压缩包中的一个文件实体。
举例1:将一个文件压缩为一个新的压缩文件
publicstaticvoid main(String[] args) throws Exception {
// 创建一个文件实例工具
File file = new File(\"大众./abc/aa.txt\"大众);
// 创建一个压缩文件的实例工具
File zipFile = new File(\公众./abc/one.zip\"大众);
// 将要压缩的文件首先读入到输入流中
InputStream is = new FileInputStream(file);
// 创建一个压缩流工具
ZipOutputStream zipOut = new ZipOutputStream(new FileOutputStream(zipFile));
zipOut.putNextEntry(new ZipEntry(file.getName()));
int temp = 0;
while((temp=is.read())!=-1){
zipOut.write(temp);
}
is.close();
zipOut.close();
}
举例2:将一个文件夹压缩为一个压缩文件
publicstaticvoid main(String[] args) throws Exception {
// 创建一个文件实例工具
File file = new File(\"大众./abc/bb\"大众);
// 创建一个压缩文件的实例工具
File zipFile = new File(\"大众./abc/bb.zip\"大众);
// 创建一个压缩流工具
ZipOutputStream zipOut = new ZipOutputStream(new FileOutputStream(zipFile));
// 如果要压缩的文件是一个文件夹,只须要创建一个ZipEntity的实例即可
zipOut.putNextEntry(new ZipEntry(new ZipEntry(file.getName()+\"大众/\公众)));
// 创建完成后不须要写入,由于文件夹是空文件,
// 因此既不须要读入文件也不须要写入文件,关闭即可
zipOut.close();
}
举例3:将一个含有文件、文件夹、文件夹中含有文件的繁芜文件夹压缩为一个文件
publicstaticvoid main(String[] args) throws Exception {
// 创建一个要压缩的文件目录的实例工具
File file = new File(\公众./abc\公众);
// 创建一个末了要天生的压缩文件的实例工具
File zipFile = new File(\"大众./abc.zip\"大众);
// 创建一个压缩流工具,所有的信息都要放到此这个流中
ZipOutputStream zos = new ZipOutputStream(new FileOutputStream(zipFile));
// 调用一个对文件目录或文件进行压缩的的处理方法
dealFile(zos,file,\"大众\"大众);
// 压缩流要在方法调用完成之后关闭,由于在方法利用了递归处理,
// 并不能确定压缩流在何时要处理完成
zos.close();
}
publicstaticvoid dealFile(ZipOutputStream zos,File file,String filePath) throws Exception{
// 首先判断要处理的是个文件还是个文件夹
if(file.isDirectory()){
//如果是个文件夹,则添加文件夹的zipEntity工具即可,然后再处理文件夹下的文件
zos.putNextEntry(new ZipEntry(filePath+file.getName()+\公众/\公众));
File[] fileList = file.listFiles();
for(int i=0;i<fileList.length;i++){
dealFile(zos,fileList[i],filePath+file.getName()+\"大众/\公众);
}
}else{
// 对付文件的处理,首先要将文件读取出来,然后写入到压缩文件中去
InputStream is = new FileInputStream(file);
zos.putNextEntry(new ZipEntry(filePath+file.getName()));
int temp = 0;
while((temp=is.read())!=-1){
zos.write(temp);
}
is.close();
}
}
11.11 RandomAccessFile
RandomAccessFile的唯一父类是Object,与其他流父类不同。是用来访问那些保存数据记录的文件的,这样你就可以用seek( )方法来访问记录,并进行读写了。这些记录的大小不必相同;但是其大小和位置必须是可知的。
RandomAccessFile竟然会是不属于InputStream和OutputStream类系的。实际上,除了实现DataInput和DataOutput接口之外(DataInputStream和DataOutputStream也实现了这两个接口),它和这两个类系绝不相关,乃至都没有用InputStream和OutputStream已经准备好的功能;它是一个完备独立的类,所有方法(绝大多数都只属于它自己)都是从零开始写的。这可能是由于RandomAccessFile能在文件里面前后移动,以是它的行为与其它的I/O类有些根本性的不同。总而言之,它是一个直接继续Object的,独立的类。
基本上,RandomAccessFile的事情办法是,把DataInputStream和DataOutputStream粘起来,再加上它自己的一些方法,比如定位用的getFilePointer( ),在文件里移动用的seek( ),以及判断文件大小的length( )。此外,它的还要一个表示以只读办法(\"大众r\"大众),还是以读写办法(\公众rw\"大众)打开文件的参数 (和C的fopen( )千篇一律)。它不支持只写文件,从这一点上看,如果RandomAccessFile继续了DataInputStream,它大概会干得更好。
举例1:
publicstaticvoid main(String[] args) throws Exception {
// 创建一个RandomAccessFile类,根据布局方法,传入一个要操作的文件
// 同时解释对此文件是读写操作,\"大众r\"大众表示对文件只读
RandomAccessFile file = new RandomAccessFile(new File(\"大众./abc/aa.txt\"大众), \"大众rw\"大众);
// 往文件中写时可以指定从文件中那个位置开始写入,即跨过多少个字符开始写
file.seek(10);
// 如果输入中文时,须要将中文转换成字节数组进行写入防止乱码
file.write(\公众你好\"大众.getBytes());
file.close();
}
把稳:如果写入的文件信息跨行,须要在上一行的长度根本上+1个长度,即(\r)回车符,在文件中一个中笔墨符代表2个长度,普通英笔墨符代表一个长度。
IO作业:附件—掌握台下操作学生管理信息系统解释书
第12章:AWT编程
当代的编程已经分开了单调的黑窗体,即Dos环境下运行程序。当代的用户也早已经习气了GUI(Graphics User Interface)图形化用户界面。
Java利用AWT和Swing类完成图形用户界面编程,个中AWT的全称是抽象窗口工具集(Abstract Window Toolkit),它是Sun最早供应的GUI(Graphics User Interface图形化用户界面)库,这个GUI库供应了一些基本功能,但这个GUI库的功能比较有限,所有后来有供应了Swing库。通过利用AWT和Swing供应的图形界面组件库,Java的图形用户界面编程非常大略,程序只须要依次创建所须要的图形组件,并以得当的办法将这些组件组织在一起,就可以开拓出非常都雅的用户界面。
要创建GUI程序,可以大概的分为以下几步:
创建顶层窗口
创建组件、如:文本框、标签、按钮
确定窗口中各组件的排列办法
将组件添加到窗口
12.1 GUI(图形用户界面)和AWT
JDK1.0发布时,Sun供应了一套基本的GUI类库,这个GUI类库能够在所有平台下都运行,这套基本类库被称为“抽象窗口工具集”,它为Java运用程序供应了基本的图形组件。AWT是窗口框架,它从不同的窗口系统中抽取出共同组件,当程序运行时,将这些组件的创建和动作委托给程序所在的运行平台。AWT编写图形界面运用时,程序仅指定了界面组件的位置和行为,并未供应真正的实现,JVM调用操作系统本地的图形界面来创建和平台同等的对等体。
利用AWT创建的图形界面运用和所在的运行平台有相同的界面风格,比如在Windows操作系统,它就表现出Windows风格,在Unix操作系统上,就表现出Unix风格。
但是在实际运用中,AWT涌现了几个如下问题:
利用AWT做出的图形用户界面在所有的平台上都显得很丑陋,功能也非常有限。
AWT为了迎合所有主流操作系统的界面设计,AWT组件只能利用这些操作系统上图形界面组件的交集,以是不能利用特定操作系统上繁芜的图形界面组件。
AWT用的是非常笨拙的、非面向工具的编程模式。
1996年,网景公司开拓了一套事情办法完备不同的GUI库,简称IFC(Internet Foundation Classes),这套GUI库的所有图形界面组件,例如文本框、按钮等都是在空缺窗口上的,之后窗口本身借助于操作系统的窗口实现。IFC真正实现了各种平台上的界面同等性。
之后,Sun公司和网景公司互助完善了这种方法,并创建了一套新的用户界面库:Swing。AWT、Swing、赞助功能API、2DAPI以及拖放API共同组成JFC(Java Foundation Classes),个中Swing组件全面代替了AWT组件,保留了AWT组件的事宜模型。总体上,AWT是图形用户界面编程的根本,Swing组件替代了绝大部分AWT组件,对AWT图形用户界面编程有极好的补充和加强。
所有的和AWT编程干系的类都放在java.awt包以及它的子包中,AWT编程中有两个基类:Component和MenuComponent。
在java.awt包中供应了两种基类表示图形界面元素:Component(普通组件)和MenuComponent(菜单干系的组件),个中Component代表了一个能以图形化办法显示出来,并可与用户交互的工具,例如Button代表了一个按钮,TextField代表一个文本框等;而MenuComponent则代表图形界面的菜单组件,包括MenuBar菜单条,MenuItem菜单项等子类。
除此之外,AWT图形用户界面编程里还有两个主要的观点:Container和LayoutManager,个中Container是一种分外的Component,它代表一种容器,可以艳服普通的Component;而LayoutManager则是容器管理其他组件布局的办法。
12.2 AWT容器
任何窗口都可被分解成一个空的容器,容器里艳服了大量的基本组件,通过设置这些基本组件的大小、位置等属性,就可以将该空的容器和基本组件组成一个整体的窗口。图形界面编程非常大略,类似于拼图游戏,容器类相称于“模版”,而普通组件则类似于拼图的图块。创建图形用户界面的过程便是完成拼图的过程。
容器(Container)是Component的子类,因此容器工具本身也是一个组件,具有组件的所有性子,可以调用Component类的所有方法。Component类供应了如下几个常用方法来设置组件的大小、位置和可见性等。
setLocation(int x,int y):设置组件的位置。
setSize(int width;int height):设置组件的大小。
setBounds(int x,int y,int width,int height):同时设置组件的位置、大小。
setVisible(Boolean b):设置该组件是否可见。
容器还可以艳服其他组件,容器类(Container)供应了如下几个常用方法来访问容器里的组件:
Component add(Component comp):向容器中添加其他组件,并返回被添加的组件。
Component getComponent(int x,int y):返回指定点的组件。
int getComponentCount():返回该容器组件内的数量
Component[] getComponent():返回该容器内的所有组件。
AWT紧张供应了如下两种紧张的容器类型。
Window:可独立存在的顶级窗口。
Panel:可作为容器容纳其他组件,单不能独立存在,必须被添加到其他容器中(如:window、Panel或Applet等)
AWT容器之间的继续关系如下图所示:
12.2.1 框架(Frame)
Frame代表常见的窗体,它是Window类的子类,具有如下几个特点
Frame工具有标题,许可通过拖沓来改变窗口的位置、大小。
初始化时不可见,可以利用setVisible(true)使其显示出来。
默认利用BorderLayout作为其布局管理器。
举例1:
package com.langsin.awt;
import java.awt.Frame;
publicclass MyFrame {
publicstaticvoid main(String[] args) {
Frame myFrame = new Frame(\"大众我的第一个窗口\公众);
// setBounds()方法,移动组件并设置其大小,可以用来处理组件的显示位置以及设置组件大小
myFrame.setBounds(50,50,500,300);
myFrame.setVisible(true);
}
}
12.2.2 面板(Panel)
Panel是AWT组件中的其余一个范例的容器,它代表不能独立存在、必须放在其他容器中的容器。Panel的外在表现为一个矩形区域,该区域内可艳服其他组件。Panel容器存在的意义在于为其他组件供应空间,Panel容用具有如下特点:
可作为容器来艳服其他组件,为放置组件供应空间。
不能单独存在,必须放置到其他容器中。
默认利用FlowLayout作为其布局管理器。
举例2:
package com.langsin.awt;
import java.awt.Button;
import java.awt.Frame;
import java.awt.Panel;
import java.awt.TextField;
publicclass MyFrame {
publicstaticvoid main(String[] args) {
//创建一个窗体,布局函数吸收的是窗体的名称
Frame myFrame = new Frame(\"大众第一个窗口\"大众);
//设置窗体的初始坐标位置以及宽度,高度
myFrame.setBounds(50,50,500,300);
//创建一个Panel面板组件
Panel panel = new Panel();
//在Panel中添加个文本域
panel.add(new TextField(20));
//在Panel中添加给按钮
panel.add(new Button(\"大众点击\公众));
//将Panel工具加入到Frame窗体中,由于Panel不能独立存在
myFrame.add(panel);
//让窗体可见
myFrame.setVisible(true);
}
}
ScrollPane是一个带有滚动条的容器,它也不能独立存在,必须被添加到其他容器中。ScrollPane容用具有如下特点:
可作为容器来艳服其他组件,当组件占用空间过大时,ScrollPane自动产生滚动条。当然也可以通过布局器参数来指定默认具有滚动条。
不能独立存在,必须放置在其他容器中。
默认利用BorderLayout作为其布局管理器。ScrollPane常日用于艳服其他容器,以是常日不许可改变ScrollPane的布局管理器。
举例3:
package com.langsin.awt;
import java.awt.Button;
import java.awt.Frame;
import java.awt.ScrollPane;
import java.awt.TextField;
publicclass MyFrame {
publicstaticvoid main(String[] args) {
//创建一个窗体,布局函数吸收的是窗体的名称
Frame myFrame = new Frame(\"大众第一个窗口\"大众);
//设置窗体的初始坐标位置以及宽度,高度
myFrame.setBounds(50,50,500,300);
//创建一个Panel面板组件
ScrollPane panel = new ScrollPane(ScrollPane.SCROLLBARS_ALWAYS);
//在Panel中添加个文本域
panel.add(new TextField(20));
//在Panel中添加给按钮
panel.add(new Button(\"大众点击\公众));
//将Panel工具加入到Frame窗体中,由于Panel不能独立存在
myFrame.add(panel);
//让窗体可见
myFrame.setVisible(true);
}
}
实行结果我们只能看到一个按钮,而看不到文本框,这是由于布局管理器的缘故,BorderLayout导致了该容器中只有一个组件被显示出来。
12.3 AWT常用组件
AWT组件须要调用运行平台的图形界面来创建和平台同等的对等体,因此AWT只能利用所有平台都支持的公共组件,以是AWT只供应了一些常用的GUI组件。
12.3.1 基本组件
AWT供应的基本组件:
Button:按钮,可以吸收单击事宜
Canvas:用于绘图的画布
CheckBox:复选框组件(也可变成单选框组件)
CheckBoxGroup:用于将多个CheckBox组件组合成一组,一组Checkbox组件只有一个可以当选中,即全部变成单选框组件。
Choice:下拉选择框组件
Frame:窗口,在GUI程序里通过该类创建一个窗口。
Label:标签类,用于放置提示性文本
List:列表框组件,可以添加多项条款
Panel:不能单独存在的基本容器类,必须放到其他容器中去
Scrollbar:滑动条组件,如果须要用户输入位于某个范围的值,可以利用滑动条组件。当创建一个滑动条时,必须制订它的方向,初始值、滑块的大小、最小值和最大值
ScrollPane:带水平及垂直滚动条的容器组件。
TextArea:多行文本域
TextField:单行文本框
12.3.2 Button(按钮)
常用的布局方法:
Button():创建一个按钮,按钮上的标签没有任何内容
Button():创建一个按钮,自定义按钮标签上的内容
常用的方法:
setBackground(Color color):设置按钮的背景颜色
setEnable(boolean b):设置按钮是否可用
setFont(Font f):设置按钮标签的字体
setForeground(Color color):设置按钮的前景色
setLabel(String text):设置按钮标签的内容
setVisible(boolean b):设置按钮是否可见
举例1:
publicstaticvoid main(String[] args) {
Frame frame = new Frame(\"大众我的窗体\公众);
Button bt1 = new Button(\"大众苹果\"大众);
bt1.setBackground(Color.GREEN);
bt1.setForeground(Color.BLUE);
frame.add(bt1,BorderLayout.NORTH);
Button bt2 = new Button(\公众喷鼻香蕉\"大众);
bt2.setBackground(Color.YELLOW);
Font font = new Font(\公众微软雅黑\"大众, Font.PLAIN, 15);
bt2.setFont(font);
frame.add(bt2);
frame.setSize(500, 500);
frame.setLocation(100, 100);
frame.setVisible(true);
}
12.3.3 Label(标签)
常用的布局方法:
Label():创建一个标签,标签上没有任何笔墨
Label(String text):创建一个标签,并且自定义标签上的笔墨。
Label(String text,int alignment):创建一个标签,并且自定义标签上的笔墨及对齐办法。
常用方法:
setAlignment(int alignment):设置标签文本的对齐办法
setBackground(Color color):设置标签的背景色
setEnable(boolean b):设置标签是否可用
setFont(Font font):设置标签文本的字体
setForeground(Color color):设置标签的前景色
setText(String text):设置标签的内容
setVisible(boolean b):设置标签是否可见
举例1:
package com.langsin.awt;
import java.awt.Frame;
import java.awt.GridLayout;
import java.awt.Label;
publicclass LabelDemo extends Frame {
Label lab1 = new Label();
Label lab2 = new Label(\"大众Second\"大众,Label.LEFT);
Label lab3 = new Label(\"大众Third\公众,Label.RIGHT);
Label lab4 = new Label();
LabelDemo(){
this.setLayout(new GridLayout(2,2));
this.lab4.setText(\"大众Fourth\"大众);
this.lab4.setAlignment(Label.RIGHT);
this.add(lab1);
this.add(lab2);
this.add(lab3);
this.add(lab4);
this.setSize(300,200);
this.setVisible(true);
}
publicstaticvoid main(String[] args) {
new LabelDemo();
}
}
12.3.4 TextField(文本域)
常用的布局方法:
TextField():创建一个文本域
TextField(String text):创建一个文本域,并且有初始值
TextField(String text,int columns):创建一个文本域,有初始值,并且设置列数
TextField(int columns):创建一个文本域,没有初始内容,可设置列数。
常用方法:
requestFocus():为文本域要求焦点
setBackground(Color color):设置标签的背景色
setColumns(int columns):设置文本域的列数
setEditable(boolean b):设置文本域是否可编辑
setEnable(boolean b):设置文本是否可用
setFont(Font f):设置文本域笔墨的字体
setForeground(Color color):设置文本域的前景色
setText(String text):设置文本域的文本内容
setVisible(boolean b):设置文本域是否可见
举例1:
package com.langsin.awt;
import java.awt.FlowLayout;
import java.awt.Frame;
import java.awt.TextField;
publicclass TextFieldDemo extends Frame {
TextField textField1 = new TextField();
TextField textField2 = new TextField(\"大众second\"大众);
TextField textField3 = new TextField(\"大众Third\公众,10);
TextField textField4 = new TextField();
TextFieldDemo(){
this.setLayout(new FlowLayout());
this.textField1.setEnabled(false);
this.textField2.setEditable(false);
this.textField4.setText(\"大众Fourth\"大众);
this.add(textField1);
this.add(textField2);
this.add(textField3);
this.add(textField4);
this.setSize(300, 400);
this.setLocation(100, 200);
this.setVisible(true);
}
publicstaticvoid main(String[] args) {
new TextFieldDemo();
}
}
12.3.5 TextArea(多行文本域/文本区)
常用的布局方法
TextArea():创建一个默认大小的空文本区
TextArea(String text):创建一个默认大小的文本区,并初始其内容
TextArea(String text,int rows,int columns):创建一个含有初始内容的文本区域,并设定文本区域的行数跟列数。
TextArea(String text,int rows,int columns,int scrollbars):创建一个文本区,并且自定义文本内容,设定文本区域的内容,设定文本区的行数跟列数,设置滚动条的状态
TextArea(int rows,int columns):创建一个文本区,并且自定义文本区的行数跟列数。
常用的方法:
append(String text):在文本结尾追加自定义的文本。
insert(String text,int begin):在指定的位置插入自定义文本
replaceRange(String text,int begin,int end):将指定例模内的文本更换为自定义的文本
setRows(int rows):设置文本的行数
setColumns(int columns):设置文本的列数
举例1:
package com.langsin.awt;
import java.awt.FlowLayout;
import java.awt.Frame;
import java.awt.TextArea;
publicclass TextAreaDemo extends Frame {
TextArea textArea1 = new TextArea();
TextArea textArea2 = new TextArea(\"大众Second\公众, 3 , 15);
TextArea textArea3 = new TextArea(\"大众Third\"大众,2 , 10);
TextArea textArea4 = new TextArea(\公众Fourth\"大众,2 , 10 ,TextArea.SCROLLBARS_BOTH);
TextAreaDemo(){
this.setLayout(new FlowLayout());
this.textArea2.replaceRange(\公众Hello World\公众, 0, 5);
this.textArea4.insert(\公众你好\公众, 6);
this.add(textArea1);
this.add(textArea2);
this.add(textArea3);
this.add(textArea4);
this.setSize(400, 400);
this.setLocation(100, 200);
this.setVisible(true);
}
publicstaticvoid main(String[] args) {
new TextAreaDemo();
}
}
12.3.6 Checkbox(复选框/单选按钮)
常用的布局方法:
Checkbox():创建一个复选框
Checkbox(String text):创建一个复选框,并自定义标签
Checkbox(String text,CheckboxGroup group,boolean state):创建一个复选框,并将其加入到一个复选框组中,设置复选框是否是当选中,加入到复选框组中的复选框将变成单选。
Checkbox(String text,boolean state):创建一个复选框,并设置其是否当选中
常用的方法:
setCheckboxGroup(CheckboxGroup group):将一个复选框加入大一个组中去,将其变为一个单选
setLabel(String label):为复选框添加一个文本标签
setState(boolean b):设置浮选框的状态,是否当选中。
举例1:
package com.langsin.awt;
import java.awt.Checkbox;
import java.awt.CheckboxGroup;
import java.awt.Frame;
import java.awt.GridLayout;
publicclass CheckboxDemo extends Frame {
CheckboxGroup group = new CheckboxGroup();
Checkbox box1 = new Checkbox(\"大众First\公众, group, false);
Checkbox box2 = new Checkbox(\"大众Second\"大众,group, false);
Checkbox box3 = new Checkbox(\"大众Third\"大众,group, false);
Checkbox box4 = new Checkbox(\公众Fourth\"大众, false);
Checkbox box5 = new Checkbox(\"大众Fifth\"大众, false);
CheckboxDemo(){
this.setLayout(new GridLayout(3,2));
this.box3.setCheckboxGroup(null);
this.box4.setLabel(\公众第四个\公众);
this.box5.setState(true);
this.add(box1);
this.add(box2);
this.add(box3);
this.add(box4);
this.add(box5);
this.setSize(300,200);
this.setVisible(true);
}
publicstaticvoid main(String[] args) {
new CheckboxDemo();
}
}
12.3.7 List(列表框)
常用的布局函数:
List():创建一个空的列表框
List(int rows):创建一个空的列表框,并设置其行数
List(int rows,boolean multipleModal):创建一个空的列表框,并设置其是否利用多选模式。
常用的方法:
add(String item):为列表框追加项目
add(String item,int index):在列表框的index位置添加项目,如果此位置上已有项目,则已有的项目以及项目后面的内容相应的向后移动一个位置。
clear():清楚列表框的所有项目
countItems():返回列表框的项目总数
delItem(int index):在列表框的index位置处,删除项目
delItem(int start,int end):删除从列表框的start位置开始到end结束的所有项目
deselect(int index):打消已选中项目的index位置上的项目
getSelectedItem():返回String值,返回一个选中的项目
getSelectedItems():返回String[]数组,返回所有当选中的项目
10、removeAll():打消列表框的所有项目
11、select(int index):选中列表框index位置上的项目
12、setMultipleMode(boolean b):设置是否采取多行选择模式
举例1:
package com.langsin.awt;
import java.awt.FlowLayout;
import java.awt.Frame;
import java.awt.List;
publicclass ListDemo extends Frame {
private List list = new List(10,true);
private List list2 = new List(6);
ListDemo(){
this.list.add(\公众apple\"大众);
this.list.add(\公众orange\"大众);
this.list.add(\公众banana\"大众,1);
this.list.setMultipleMode(false);
this.list2.add(\公众1111\"大众);
this.list2.add(\"大众2222\公众);
this.setLayout(new FlowLayout());
this.add(this.list);
this.add(this.list2);
this.setSize(400, 400);
this.setLocation(100, 100);
this.setVisible(true);
}
publicstaticvoid main(String[] args) {
new ListDemo();
}
}
12.3.8 Choice(下拉框)
常用的布局方法:
Choice():创建一个下拉框
常用的方法:
addItem(String item):为选择框添加一个项目
getItem(int index):返回下拉框中index位置上的项目的文本标签
getItemCount():返回下拉框中所有的项目总数。
getSelectedItem():返回以选中的项目的文本标签
insert(String item,int index):在index位置插入文本标签为item的项目
remove(int index):删除index位置上的项目
removeAll():删除所有项目
select(int index):选中index位置上的项目
举例1:
package com.langsin.awt;
import java.awt.Choice;
import java.awt.FlowLayout;
import java.awt.Frame;
publicclass ChoiceDemo extends Frame {
private Choice ch1 = new Choice();
ChoiceDemo(){
this.ch1.getSelectedItem();
this.ch1.add(\公众1111\"大众);
this.ch1.add(\"大众2222\公众);
this.ch1.add(\"大众3333\"大众);
this.ch1.add(\"大众4444\"大众);
this.setLayout(new FlowLayout());
this.add(this.ch1);
this.setSize(300, 300);
this.setLocation(100, 200);
this.setVisible(true);
}
publicstaticvoid main(String[] args) {
new ChoiceDemo();
}
}
12.3.9 Dialog(对话框)
Dialog是Windows类的子类,是一个容器类,属于分外组件。对话框是可以独立存在的顶级窗口,用法与普通窗口没什么差异。利用对话框时需把稳以下两点:
对话框常日依赖于其他窗口,即含有一个父窗口(parent)
对话框有非模式(non-modal)和模式(modal)两种,当某个模式对话框被打开之后,该模式对话框总是位于parent之上;模式对话框被关闭之前,它的依赖窗口无法得到焦点。
Dialog对话框有多个重载的布局器,参数如下:
owner:指定该对话框所依赖的窗口,即可以是窗口,有可以是对话框。
title:指定该对话框的窗口标题
modal:指定该对话框是否是模式的,是Boolean值,true表示模式,false表示非模式。
举例1:
package com.langsin.awt;
import java.awt.BorderLayout;
import java.awt.Button;
import java.awt.Dialog;
import java.awt.Frame;
import java.awt.TextField;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
publicclass Test {
// 创建一个父窗体
static Frame frame = new Frame(\公众测试窗口\"大众);
// 创建两个Dialog对话框,一个为模式,一个为非模式
static Dialog d1 = new Dialog(frame, \"大众模式对话框\"大众, true);
static Dialog d2 = new Dialog(frame, \"大众非模式对话框\"大众, false);
publicstaticvoid main(String[] args) {
frame.setBounds(100, 100, 400, 400);
d1.setBounds(200, 200, 100, 100);
d2.setBounds(300, 300, 100, 100);
// 创建两个按钮,通过按钮事宜将窗体显示出来
Button b1 = new Button(\"大众模式对话框\公众);
Button b2 = new Button(\公众非模式对话框\公众);
// 为了区分模式与非模式的差异,添加一个文本域进行验证
TextField text = new TextField(40);
// 为按钮加上事宜,通过事宜将模式对话框调用出来
b1.addActionListener(new ActionListener() {
publicvoid actionPerformed(ActionEvent e) {
d1.setVisible(true);
}
});
b2.addActionListener(new ActionListener() {
publicvoid actionPerformed(ActionEvent e) {
d2.setVisible(true);
}
});
frame.add(text,BorderLayout.NORTH);
frame.add(b1,BorderLayout.EAST);
frame.add(b2,BorderLayout.WEST);
frame.pack();`
frame.setVisible(true);
}
}
12.3.10 FileDialog(文件对话框)
FileDialog是一个文件对话框,它是Dialog的子类,用于打开或者保存文件。FileDialog供应了几个布局器,分别支持parent、title、mode三个布局参数,个中parent、title指定文件对话框的所属父窗口和标题;mode指定该窗口用于打开文件或保存文件,此参数支持两个值:FileDialog.LOAD、FileDialog.SAVE。
FileDialog供应了两个方法来获取被打开/保存文件的路径。
getDirectory():获取FileDialog被打开/保存文件的绝对路径。
getFile():获取FileDialog被打开/保存文件的文件名。
举例1:
publicclass Test {
// 创建一个父窗体
static Frame frame = new Frame(\"大众测试窗口\公众);
// 创建两个FileDialog对话框,一个为模式,一个为非模式
static FileDialog d1 = new FileDialog(frame, \"大众选择须要打开的文件\"大众, FileDialog.LOAD);
static FileDialog d2 = new FileDialog(frame, \"大众选择须要保存的文件\"大众, FileDialog.SAVE);
publicstaticvoid main(String[] args) {
frame.setBounds(100, 100, 400, 400);
d1.setBounds(200, 200, 100, 100);
d2.setBounds(300, 300, 100, 100);
// 创建两个按钮,通过按钮事宜将FileDialog显示出来
Button b1 = new Button(\"大众打开文件\公众);
Button b2 = new Button(\"大众保存文件\公众);
// 为按钮加上事宜,通过事宜将文件对话框调用出来
b1.addActionListener(new ActionListener() {
publicvoid actionPerformed(ActionEvent e) {
d1.setVisible(true);
// 打印要保存的文件的路径,以及文件的名称
System.out.println(d1.getDirectory()+\公众=========\公众+d1.getFile());
}
});
b2.addActionListener(new ActionListener() {
publicvoid actionPerformed(ActionEvent e) {
d2.setVisible(true);
// 打印要保存的文件的路径,以及文件的名称
System.out.println(d1.getDirectory()+\"大众=========\"大众+d1.getFile());
}
});
frame.add(b1,BorderLayout.EAST);
frame.add(b2,BorderLayout.WEST);
frame.pack();
frame.setVisible(true);
}
}
12.4 布局管理器
为了使天生的图形用户界面具有良好外不雅观与运行平台没有任何关系,Java供应告终构管理器这个工具类来管理组件在容器中的布局,而不该用直接设置组件位置和大小的办法。
例如:Lable lable = new Lable(“Hello World”);如果让lable标签能够刚好容纳Hello World字符串,也便是实现该标签的最佳大小,即:在Windows平台中可能该当设置长100px,高20px;而在Unix系统上须要设置长120px;高24px;如果让程序员去手动掌握每个组件的大小、位置,这将给编程带来巨大的困难,为理解决这个问题,Java供应了LayoutManager布局管理器类,LayoutManager可以根据运行平台来调度组件的大小,程序员要做的是便是为容器选择得当的布局管理器。
所有的AWT容器都有默认的布局管理器,如果没有为容器指定布局管理器,则该容器利用默认的布局管理器。为容器指定布局管理器通过调用容器的setLayout(LayoutManager lm)方法来完成。
AWT供应了FlowLayout、BorderLayout、GridLayout、GridBagLayout、CardLayout5个常用的布局管理器,Swing还供应了一个BoxLayout布局管理器。
12.4.1 FlowLayout布局管理器
在FlowLayout(浮动布局管理器)布局管理器中,组件像水流一样向某方向流动(排列),碰着障碍(边界)就折回,重头开始排列。在默认情形下,FlowLayout布局管理器从左向右排列所有组件,碰着边界就会折回下一行重新开始。
FlowLayout有3个常用的布局方法:默认是居中
FlowLayout():利用默认的对齐办法及默认的垂直间距、水平间距创建FlowLayout布局管理器。
FlowLayout(int align):利用指定的对齐办法及默认的垂直间距、水平间距创建FlowLayout布局管理器。
FlowLayout(int align,int hgap,int vgap):利用指定的对齐办法以及指定的垂直间距、水平间距创建一个FlowLayout布局管理器。
在Panel(面板)和Applet(Java小运用程序)中默认为利用FlowLayout布局管理器,Frame默认利用BorderLayout布局管理器,下面将利用FlowLayout布局管理器来管理Frame容器中的组件。
举例1:
publicstaticvoid main(String[] args) {
//创建一个窗口
Frame frame = new Frame(\"大众测试窗体\"大众);
frame.setLayout(new FlowLayout(FlowLayout.LEFT, 20, 10));
for(int i=0;i<5;i++){
frame.add(new Button(\"大众按钮\"大众+(i+1)+\"大众号\公众));
}
//设置窗体的最佳大小,如果子组件未显示开,则适当的将包含组件的容器加宽或加高
frame.pack();
//将窗体显示出来
frame.setVisible(true);
}
举例2:
publicstaticvoid main(String[] args) {
// 创建一个窗口
Frame frame = new Frame(\"大众测试窗口\"大众);
// 创建一个浮动布局管理器,并且指定容器中的组件的排列办法是居中排列,同时
// 组件之间的水平间隔与垂直间隔为10个像素
FlowLayout fl = new FlowLayout(FlowLayout.CENTER, 10, 10);
// 为窗体设置浮动布局管理器
frame.setLayout(fl);
// 添加按钮组件
frame.add(new Button(\"大众button1\公众));
frame.add(new Button(\公众button2\"大众));
frame.add(new Button(\"大众button3\公众));
frame.add(new Button(\"大众button4\"大众));
frame.add(new Button(\"大众button5\公众));
frame.add(new Button(\公众button6\公众));
// 设置窗体的显示位置,以及窗体容器的宽度与高度
frame.setBounds(40, 40, 400, 400);
frame.setVisible(true);
}
12.4.2 BorderLayout布局管理器
BorderLayout(边界布局管理器)将容器分为EAST、SOUTH、WEST、NORTH、CENTER5个区域,普通组件可以被放置在这个5个区域的任意一个里面。
改变BorderLayout的容器大小时,NORTH、SOUTH会在水平方向上调度,而EAST、WEST在垂直方向上调度,CENTER会根据调度在水平、垂直方向上都进行调度。利用BorderLayout布局管理器时需把稳以下两点:
1、向利用BorderLayout布局管理器的容器中添加组件时,须要指定要添加到哪个区域中。如果没有指定添加哪个区域中,则默认添加到中间区域中。
2、如果向同一个区域中添加多个组件时,后放入的组件会覆盖先放入的组件。
Frame、Dialog、ScrollPane默认利用BorderLayout布局管理器,BorderLayout有如下两个布局器。
BorderLayout():利用默认的水平间距、垂直间距创建BorderLayout布局管理器。
BorderLayout(int hgap,int vgap):利用指定的水平间距、垂直间距创建BorderLayout布局管理器。
利用BorderLayout布局管理器时,该当利用BorderLayout类的几个静态常量来指定组件添加到哪个区域内。对应的常量为:EAST、SOUTH、WEST、NORTH、CENTER。
举例1:
publicstaticvoid main(String[] args) {
//创建一个窗口
Frame frame = new Frame(\"大众测试窗体\公众);
//为窗体创建一个边界布局管理器,同时指定边界的水平方向上的组件之间的间距
//与垂直方向上组件之间的间距
frame.setLayout(new BorderLayout(5, 5));
//向北面的边界中添加一个按钮组件
frame.add(new Button(\"大众北面\"大众), BorderLayout.NORTH);
//向西面的边界中添加一个按钮组件
frame.add(new Button(\"大众西面\"大众), BorderLayout.WEST);
//向中间的区域内添加一个按钮组件
frame.add(new Button(\公众中心\"大众), BorderLayout.CENTER);
//向东面的区域内添加一个按钮组件
frame.add(new Button(\"大众东面\公众), BorderLayout.EAST);
//向南面的区域内添加一个按钮组件
frame.add(new Button(\"大众南面\"大众), BorderLayout.SOUTH);
//将窗体变得更得当一点
frame.pack();
frame.setVisible(true);
}
利用BorderLayout布局管理器时,每个区域的组件都会尽可能大的去霸占全体区域,BorderLayout最多只能放置5个组件,但可以放置少于5个组件,如果某个区域没有放置组件,该区域并不会涌现空缺,阁下的组件会自动霸占该区域,从而担保窗口有较好的外不雅观。
其余,虽然BorderLayout布局管理器最多只能放5个组件,但由于容器也是一个组件,以是我们可以先把组件放到一个容器内,在把容器放到BorderLayout布局管理器中。
举例2:
publicstaticvoid main(String[] args) {
//创建一个窗口
Frame frame = new Frame(\"大众测试窗体\公众);
//为窗体创建一个边界布局管理器,同时指定边界的水平方向上的组件之间的间距与
//垂直方向上组件之间的间距
frame.setLayout(new BorderLayout(5, 3));
//创建一个面板容器
Panel panel = new Panel();
//在面板中添加一个文本框
panel.add(new TextField(30));
//将面板添加到窗体中
frame.add(panel,BorderLayout.NORTH);
//再创建一个面板,添加按钮
Panel butPanel = new Panel();
//设置面板的宽度与高度
butPanel.setSize(5, 20);
String[] names = {\公众0\"大众,\"大众1\"大众,\"大众2\"大众,\公众3\公众,\公众4\"大众,\公众5\"大众,\"大众6\"大众,\"大众7\公众,\"大众8\"大众,\"大众9\公众,\公众+\"大众,\公众-\"大众,\"大众\公众,\"大众/\"大众,\公众=\公众};
for(String flag : names){
butPanel.add(new Button(\"大众\"大众+flag+\"大众\公众));
}
//将按钮面板添加到窗体中去
frame.add(butPanel,BorderLayout.CENTER);
frame.pack();
frame.setVisible(true);
}
12.4.3 GridLayout网格布局管理器
GridLayout(网格布局管理器)布局管理器将容器分割成纵横分隔的网格,每个网格所占的区域大小相同,当向利用GridLayout布局管理器的容器中添加组件时,默认为从左向右,从上向下依次添加到每个网格中,与FlowLayout不同的是,放置在GridLayout布局管理器中的各个组件的大小由组件所处的区域来决定。
GridLayout有如下两个布局器:
GridLayout(int rows,int cols):采取指定的行数与列数,以及默认的横向间距、纵向间距将容器分割成多个网格。
GridLayout(int rows,int cols,int hgap,int vgap):采取指定的行数、列数,以及指定的水平间距,垂直间距将容器分割成多个网格。
举例1:
publicstaticvoid main(String[] args) {
//创建一个窗口
Frame frame = new Frame(\"大众打算器\"大众);
//创建一个面板容器
Panel panel = new Panel();
//在面板中添加一个文本框
panel.add(new TextField(30));
//将面板添加到窗体中
frame.add(panel,BorderLayout.NORTH);
//再创建一个面板,添加按钮
Panel butPanel = new Panel(new GridLayout(3,5,4,4));
//设置面板的宽度与高度
butPanel.setSize(5, 20);
String[] names = {\公众0\公众,\"大众1\公众,\"大众2\"大众,\"大众3\公众,\公众4\"大众,\"大众5\"大众,\"大众6\"大众,\公众7\"大众,\公众8\"大众,\"大众9\"大众,\公众+\"大众,\公众-\"大众,\"大众\"大众,\公众/\"大众,\"大众=\"大众};
for(String flag : names){
butPanel.add(new Button(\"大众\"大众+flag+\公众\公众));
}
//将按钮面板添加到窗体中去
frame.add(butPanel);
frame.pack();
frame.setVisible(true);
}
12.4.4 GridBagLayout网格包布局管理器比较繁芜
GridBagLayout(网格包布局管理器)布局管理器的功能最强大,同时也最繁芜,与GridLayout布局管理器不同的是,在GridBagLayout布局管理器中,一个组件可以跨一个或多个网格,并可以设置各个网格的大小互不相同,从而增加告终构的灵巧性。当窗体的大小发生变革时,GridBagLayout布局管理器也可以准确的掌握窗口各部分的拉伸。
为了处理GridBagLayout中组件的大小,超过性,Java供应了GridBagConstraints工具,该工具与特定的组件关联,用于掌握该GUI组件的大小、超过性。
GridBagLayout布局管理器的利用办法如下:
创建GridBagLayout布局管理器工具,并指定容器利用该布局管理器。
GridBagLayout gridBagLayout = new GridBagLayout();
container.setLayout(gridBagLayout);
创建GridBagConstrains工具,并设置该工具的干系属性,此工具用于掌握要添加的GUI组件的大小及超过性。
GridBagConstraints gbc = new GridBagConstraints();
gbc.gridx = 2; //设置受该工具掌握的GUI组件位于网格中横向索引的位置
gbc.gridy = 1; //设置受该工具掌握的GUI组件位于网格中纵向索引的位置
gbc.gridwidth = 2; //设置受该工具掌握的GUI组件横向超过多少个网格
gbc.gridhight = 1; //设置受该工具掌握的GUI组件纵向超过多少个网格
调用GridBagLayout工具的方法来建立GridBagConstraints工具和受控组件之间的关联。
container.setConstraints(comp,gbc);
添加组件,与普通布局管理器添加组件的方法完备同等。
container.add(comp);
把稳:如果须要向一个容器中添加多个GUI组件,则须要重复实行2-4的步骤,GridBagConstraints工具可以重复利用,因此在程序中只须要创建此类的一个实例工具即可。每次添加GUI组件时,重新修正GridBagConstraints工具的属性即可。
利用GridBagLayout布局管理器,重点在于GridBagConstraints工具,它能精确掌握每个GUI组件与容器之间的布局关系,该类具有如下属性:
gridx、gridy:设置受该工具掌握的GUI组件从左上角开始在网格的横向索引、纵向索引。这两个值还可以是GridBagConstraints.RELATIVE(默认值),表示当前组件紧跟随在上一个组件之后。
gridwidth、gridheight:设置受该工具掌握的GUI组件横向、纵向超过多少个网格,两个属性值默认都是1,表示不进行超过。如果设置这两个的属性值为:GridBagConstraints.REMAINDER,表示受该工具掌握的GUI组件是横向、纵向上的末了一个组件。
fill:设置受该工具掌握的GUI组件如何霸占空缺区域。
GridBagConstraints.NONE:表示组件不进行扩大。
GridBagConstraints.HORIZONTAL:GUI组件水平扩大霸占空缺区域
GridBagConstraints.VERTICAL:GUI组件垂直扩大霸占空缺区域
GridBagConstraints.BOTH:GUI组件水平、垂直扩大霸占空缺区域
ipadx、ipady:设置GUI组件在区域内横向、纵向的大小。如果设置了这两个属性,则组件会在默认的宽度和高度的根本上增加,最小宽度+ipdax2个像素,最小高度+ipady2个像素。
insets:设置受该工具掌握的GUI组件的外部添补的大小,即该组件边界和显示区域边间之间的间隔。
anchor:设置受该工具掌握的GUI组件在其显示区域的布局办法。
GridBagConstraints.CENTER:居中显示
GridBagConstraints.NORTH:上中显示(即:北面)
GridBagConstraints.NORTHWEST:左上显示(西北角)
GridBagConstraints.NORTHEAST:右上显示(东北角)
GridBagConstraints.SOUTH:下中显示(南面)
GridBagConstraints.SOUTHWEST:左下显示(西南角)
GridBagConstraints.SOUTHEAST:右下显示(东南角)
GridBagConstraints.WEST:左中显示(西面)
GridBagConstraints.EAST:右中显示(东面)
weightx、weighty:用来设置窗口变大时,各组件随着变大的比例,当数字越大,表示组件能到更多的空间,默认值为0。
举例1:
publicstaticvoid main(String[] args) {
//创建一个窗口
Frame frame = new Frame(\"大众测试窗口\"大众);
//创建一个网个包布局管理器
GridBagLayout gb = new GridBagLayout();
frame.setLayout(gb);
//创建一个网格包布局管理器的约束工具
GridBagConstraints gbc = new GridBagConstraints();
//设置所有的组件都可以随着窗口的扩大而扩大
gbc.fill = GridBagConstraints.BOTH;
//设置组件在水平位置上的扩展权重
gbc.weightx = 1;
//创建一个组件,并将组件与约束工具建立管理,末了将组件加入到容器中
for(int i=0;i<4;i++){
Button button = new Button(\"大众按钮\公众+i);
gb.setConstraints(button, gbc);
frame.add(button);
}
//设置下一个组件为容器中横向位置上的末了一个组件
Button button = new Button(\公众按钮4\"大众);
gbc.gridwidth = GridBagConstraints.REMAINDER;
gb.setConstraints(button, gbc);
frame.add(button);
//创建一个新的组件,设置此组件在水平位置上不会进行扩展,此组件为新的一行的开始位置
button = new Button(\公众按钮5\"大众);
gbc.weightx = 0;
gb.setConstraints(button, gbc);
frame.add(button);
//设置下一个组件,此组件霸占后面以为网格
button = new Button(\公众按钮6\"大众);
gbc.gridwidth = 2;
gbc.gridheight = 2;
gb.setConstraints(button, gbc);
frame.add(button);
//设置下一个组件,此组件霸占后面以为网格
button = new Button(\"大众按钮7\"大众);
//gbc.gridwidth = 3;
gbc.gridheight = 2;
gbc.gridwidth = GridBagConstraints.REMAINDER;
gb.setConstraints(button, gbc);
frame.add(button);
//创建一个新的按钮放置在第三行
button = new Button(\公众按钮8\"大众);
gbc.gridwidth = 1;
//设置此行的组件跨两行
gbc.gridheight = 2;
gbc.weighty = 1;
gb.setConstraints(button, gbc);
frame.add(button);
gbc.weighty = 0;
gbc.gridwidth = GridBagConstraints.REMAINDER;
//设置此行的组件重新跨一行
gbc.gridheight = 1;
button = new Button(\"大众按钮9\公众);
gb.setConstraints(button, gbc);
frame.add(button);
button = new Button(\公众按钮10\"大众);
gb.setConstraints(button, gbc);
frame.add(button);
frame.pack();
frame.setVisible(true);
}
12.4.5 CardLayout布局管理器
CardLayout(卡片布局管理器)布局管理器以韶光来管理它里面的组件,它将加入到容器中的组件看做一叠卡片,每次只能看到最上面的那个容器。CardLayout供应了两个布局器:
CardLayout():创建一个默认的CardLayout布局管理器。
CardLayout(int hgap,int vgap):通过指定卡片与容器旁边边界的间距(hgap)、高下边界(vgap)的间距来创建CardLayout布局管理器。
CardLayout用于掌握组件可见的5个常用方法:
first(Container target):显示容器target中的第一张卡片
last(Container target):显示容器target中的末了一张卡片
previous(Container target):显示容器target中的前一张卡片
next(Container target):显示容器target中的下一张卡片
show(Container target,String name):显示容器target中指定名称的卡
举例1:
publicstaticvoid main(String[] args) {
// 创建一个窗口
Frame frame = new Frame(\"大众测试窗口\"大众);
// 创建一个卡片布局管理器
final CardLayout cl = new CardLayout();
// 创建一个panel面板利用卡片布局管理器
final Panel panel1 = new Panel();
panel1.setLayout(cl);
// 往面板中加入几个按钮
for (int i = 0; i < 5; i++) {
panel1.add(\公众按钮\"大众 + (i + 1), new Button(\公众按钮\"大众 + (i + 1)));
}
// 将此面板加入到窗体中
frame.add(panel1);
// 再创建一个面板,加几个按钮,同时对按钮添加事宜机制
Panel panel2 = new Panel();
Button button = new Button(\公众上一张\"大众);
button.addActionListener(new ActionListener() {
publicvoid actionPerformed(ActionEvent e) {
cl.previous(panel1);
}
});
panel2.add(button);
// 在面板中添加第二个按钮
button = new Button(\"大众下一张\"大众);
button.addActionListener(new ActionListener() {
publicvoid actionPerformed(ActionEvent e) {
cl.next(panel1);
}
});
panel2.add(button);
// 在面板中添加第三个按钮
button = new Button(\"大众第一张\"大众);
button.addActionListener(new ActionListener() {
publicvoid actionPerformed(ActionEvent e) {
cl.first(panel1);
}
});
panel2.add(button);
// 在面板中添加第四个按钮
button = new Button(\"大众末了张\"大众);
button.addActionListener(new ActionListener() {
publicvoid actionPerformed(ActionEvent e) {
cl.last(panel1);
}
});
panel2.add(button);
// 在面板中添加第五个按钮
button = new Button(\"大众第三张\公众);
button.addActionListener(new ActionListener() {
publicvoid actionPerformed(ActionEvent e) {
cl.show(panel1,\"大众按钮3\"大众);
}
});
panel2.add(button);
//在往窗体中加入第二个组件及之后的组件必须制订位置,不然会将之前的组件覆盖掉
frame.add(panel2,BorderLayout.SOUTH);
frame.pack();
frame.setVisible(true);
}
12.4.6 绝对定位
Java也可以对GUI组件进行绝对定位,在Java容器中采取绝对定位的步骤如下:
将Container的布局管理器设置为null:container.setLayout(null)
向容器中添加组件时,先调用setBounds()或setSize()方法来设置组件的大小、位置,或者直接创建GUI组件时通过布局参数指定该组件的大小、位置,然后将该组件添加到容器中。
举例1:
publicstaticvoid main(String[] args) {
// 创建一个窗口
Frame frame = new Frame(\"大众测试窗口\"大众);
//设置窗体不该用布局管理器
frame.setLayout(null);
//创建一个按钮,同时指定它的绝对位置,在X坐标上的值为40,Y坐标上的值为40
//按钮的宽度为50,高度为20,
Button button1 = new Button(\公众按钮1\"大众);
button1.setBounds(40, 40, 50, 20);
frame.add(button1);
//创建一个按钮2,同时指定它的绝对位置,将按钮放置在第一个按钮的下面
//则X坐标保持同等,Y坐标在原来的根本上加上第一个按钮的高度
Button button2 = new Button(\"大众按钮2\"大众);
button2.setBounds(40, 60, 50, 20);
frame.add(button2);
//设置窗体的涌现位置,以及窗体的宽度,高度
frame.setBounds(40, 40, 600, 600);
frame.setVisible(true);
}