java从入门到精通
2023-12-19 12:07:56 21 举报
AI智能生成
java入门
作者其他创作
大纲/内容
一、初识java
1.1 java简介
1.1.1 什么是java语言
面向对象的程序设计语言
1.1.2 java单独应用领域
桌面应用开发系统
嵌入式开发系统
电子商务应用
企业级应用开发
交互式系统开发
多媒体系统开发
分布式系统开发
WEB应用开发
移动端应用开发
1.1.3 java的版本
Javase和javaee
jdk1.0~jdk15
openjdk的特点
所有代码都是开源代码。在Oracle jdk中但凡有产权的代码都被替换掉了,不存在知识产权纠纷,所以完全免费,任何人都可以随意下载
虽然都是代码开源的,但功能不完整,只包含了jdk中最精简的功能
不包含orcaljdk的deployment(部署)功能
不能使用java的咖啡杯商标
性能不如orcaljdk高
1.1.4 怎样学好java
明确目标,基础学习,了解模式
1.2 java语言的特性
简单
面向对象
分布性
可移植性
解释型
安全性
健壮性
多线程
高性能
动态
1.3 搭建java环境
jdk下载
在Windows10系统下搭建jdk环境
二、熟悉Eclipse开发工具
2.1 熟悉Eclipse
它基于java语言编写,是目前最流行的java集成开发工具之一。
下载Eclipse:浏览器输入网址
https://www.eclipse.org/downloads/
https://www.eclipse.org/downloads/
2.2 使用Eclipse
2.2.1 创建java项目
2.2.2 创建java类文件
2.2.3 使用编译器编写程序代码
1、打开编译器
2、编写代码
2.3 程序调试
1、断点
设置断点是程序调试中必不可少的手段,java调试器每次遇到程序断点时都会将单前线程挂起,即暂时当前程序的运行。
2、以调试方式运行java程序
要在Eclipse中调试HelloJava程序,可以在“包资源管理器”视图中的Hellojava文件处右击,在弹出的快捷菜单中选择“调试方式”命令
3、程序调试
程序执行到断点被暂停后,可以通过“调试”视图工具栏上的按钮执行相应的调试操作。
三、java语言基础
3.1 java主类结构
java程序的基本组成单元是类,类体中又包括属性和方法两部分。每一个应用程序都必须包含一个main()方法,含有main()方法的类称为主类
1、包声明:一个JAVA应用程序是由若干个类组成的.在例题3.1中就是一个类名为Frist的类,语句package Number为声明该类所在的包,package为包的关键字。
2、声明成员变量和局部变量:通常将类的属性称为类的全局变量(成员变量),将方法中的属性称为局部变量。全局变量声明在类体中,局部变量声明在方法体中。全局变量和局部变量都有各自的应用范围。在例题3.1中,s1是成员变量,s2是局部变量。
3、编写主方法:main()方法是类体中的主方法。该方法从“{”开始,至“}”结束。public、static和void分别是main()方法的权限修饰符、静态修饰符和返回值修饰符,Java程序中的main()方法必须声明为public static void。String[]args是一个字符串类型的·数组,它是main()方法的参数。main()方法是程序开始执行的位置。
4、导入API类库:在java语言中可以通过import关键字导入相关的类。在·JDK的API中(应用程序接口)提供了130多个包,如java.awt、java.io等。可以通过JDK的API文档来查看这些包中的类,把握类的继承结构、类的应用、成员变量表。构造方法表等,并对每个变量的使用目的进行了解,API文档是程序开发人员不可或缺的工具。
代码中的所有标点符号都是英文字符。不要在中文输入法状态下输入标点符号,还要注意大小写。
3.2 基本数据类型
3.2.1 整数类型
整数类型简称整型,用来存储整数数值,即没有小数部分的数值。可以是正数,也可以是负数。整型数据根据它所占内存大小的不同,可分为byte、short、int、和long4种类型。它们具有不同的取值范围,如下图所示。
3.2.2 浮点类型
浮点类型简称浮点型,用来存储含有小数部分的数值。JAVA语言中浮点类型分为单精度浮点类型(float)和双精度浮点类型(double),它们具有不同的取值范围,如下图所示。
3.2.3 字符类型
(1)char型:字符类型(char)用于存储单个字符,占用16(两个字节)的内存空间。在定义字符型变量时,要以单引号表示,如's'表示一个字符。但是“s”则表示一个字符串,虽然只有一个字符,但由于使用双引号,它仍然表示字符串,而不是字符。
(2)转义字符:转义字符是一种特殊的字行变量,它以反斜杠“\”开头,后跟一个或多个字符。转义字符具有特定的含义,不同于字符原有的意义,故称“转义”。例如,printf的数的格式串中用到的“\n”就是一个转义字符,意恩是“回车换行”。Java 中的转义字符如下表所示:
3.2.4 布尔类型
布尔类型又称逻辑类型,简称布尔型,通过关键字boolean来定义布尔类型变量。布尔类型只有true和false两个值,分别代表布尔逻辑中的“真”和“假”。布尔值不能与整数类型进行转换。布尔类型通常被用在流程控制中,作为判断条件。
3.3 变量与常量
3.3.1 标识符和关键字
1、标识符:标识符可以简单地理解为一个名字,是用来标识类名、变量名、方法名、数组名、文件名的有效字符序列。Java语言规定标识符由任意顺序的字母、下划线(___)、美元符号($)和数字组成,并且第一个字符不能是数字。标识符不能是Java中的关键字(保留字)。
2、关键字:关键字又称保留字,是Java语言中已经被赋予特定意义的一些单词,不可以把这些单词作为标识符来使用。
3.3.2 声明变量
声明变量:变量的使用是程序设计中一个十分重要的环节。声明变量就是告诉编译器这个变量的数据类型,这样编译器才知道需要配置多少空间给它,以及它能存放什么样的数据。在程序运行过程中,空间内的值是变化的,这个内存空间就称为变量。为了便于操作,给这个空间取个名字,称为变量名。变量的命名必须是合法的标识符。内存空间内的值就是变量值。在声明变量时可以是没有赋值,也可以直接赋给初值。
对于变量的命名不是随意的,应遵循以下几条规则:1、变量名必须是一个有效的标识符。2、变量名不可以使用java中的关键字。 3、变量名不能重复。 4、应选择有意义的单词作为变量名。
3.3.3 声明常量
在程序运行过程中一直不会改变的量称为常量(constant),通常也被称为“final变量”。常量在整个程序中只能被赋值一次。在为所有的对象共享值时,常量是非常有用的。
3.3.4 变量的有效范围
由于变量被定义出来后只是暂存在内存中,等到程序执行到某一个点,该变量会被释放掉,也就是说变量有它的生命周期。因此,变量的有效范围是指程序代码能够访问该变量的区域,若超出该区域,则在编译器会出现错误。在程序中,一般会根据变量的“有效范围”将变量分为“成员变量”和“局部变量”。
1、成员变量
在类体中所声明的变量被称为成员变量,成员变量在整个类中都有效。类的成员变量又可分为两种,即静态变量和实例变量。
2、局部变量
在类的方法体中声明的变量(方法内部定义,“{”与“}”之间的代码中声明的变量)称为局部变量。局部变量只在当前代码块中有效,也就是只能在“{”与“}”之内使用。在类的方法中声明的变量,包括方法的参数,都属于局部变量。局部变量只在当前定义的方法内有效,不能用于类的其他方法中。局部变量的生命周期取决于方法,当方法被调用时,java虚拟机会为方法中的局部变量分配内存空间,当该方法的调用结束后,则会释放方法中局部变量占用的内存空间,局部变量也会被销毁。
3.4 运算符
3.4.1 赋值运算符
赋值运算符以符号“=”表示,它是一个二元运算符(对两个操作数作处理),其功能是将右方操作所含的值赋给左方的操作数。(从右往左运行)
3.4.2 算术运算符
Java中的算术运算符主要有+(加)、-(减)、*(乘)、/(除)、%(求余),它们都是二元运算符。
3.4.3 自增和自减运算符
自增、自减运算符是单目运算符,可以放在操作元之前,也可以放在操作元之后。操作元必须是一个整形或浮点型变量。自增、自减运算符的作用是使变量的值增1或减1。放在操作元前面的自增、自减运算符,会先将变量的值加1(减1),然后再使该变量参与表达式的运算。放在操作元后面的自增、自减运算符,会先使变量参与表达式的运算,然后再将该变量加1(减1)。(符号在前先运算再使用,符号再后先试用再运算。)
3.4.4 比较运算符
比较运算符属于二元运算符,用于程序中的变量之间、变量和自变量之间以及其他类型的信息之间比较。比较运算符的运算结果是boolean型。当运算符对应的关系成立时,运算结果为true,否则为false。所有比较运算符通常作为判断的依据用在条件语句。比较运算符共有6个,如下图所示。
3.4.5 逻辑运算符
返回类型为布尔型的表达式,如比较运算符,可以被组合在一起构成一个更复杂的表达式。这是通过逻辑运算符来实现的。逻辑运算符包括&(&&)(逻辑与)、||(逻辑或)、!(逻辑非)。逻辑运算符的操作元必须是boolean型数据。在逻辑运算符中,除了“!”是一元运算符,其他都是二元运算符。下表给出了逻辑运算符的用法和含义。
结果为boolean型的变量或表达式可以通过逻辑运算符组合为逻辑表达式。用逻辑运算符进行逻辑运算是如下图所示:
3.4.6 位运算符
位运算符除“按位与”和“按位或”运算符外,其他只能用于处理整数的操作数,包括byte、short、char、int和long等数据类型。
(1)“按位与”运算(两者都为1,结果才是1)如图所示。
(2)“按位或”运算(只要有一者为1,结果就是1)如图所示。
(3)“按位取反”运算(0变1,1变0)如图所示
(4)“按位异或”运算(两者相同即为0,不同为1)如图所示
(5)移位操作:除了上述运算符,还可以对数据按二进制位进行移位操作。Java中的移位运算符有一下3种:<<:左移(整体左移,空位补零,溢出去掉),>>:右移(整体右移,正数补零,负数补一,溢出去掉),>>>:无符号右移。(整体右移,空位补零,溢出去掉)。如图所示。
3.4.7 三元运算符
三元运算符的使用格式为:条件式 ? 值1:值2 运算规则为:若条件式的值为true,则整个表达式取值1,否则取值2.
3.4.8 运算符优先级
通常,优先级由高到低的顺序依次是:增量和减量运算——>算术运算——>比较运算——>逻辑运算——>赋值运算
3.5 数据类型转换
3.5.1 隐式类型转换(自动转换类型,一定不会丢失数据)
从低级类型向高级类型的转换,系统将自动执行,程序员无须进行任何操作。这些类型按精度从低到高的顺序为byte<short<int<long<float<double。
3.5.2 显示类型转换(强制类型转换,有可能会丢失数据)
当把高精度的变量的值赋给低精度的变量时,必须使用显式类型转换运算,语法为:(类型名)要转换的值 除boolean类型外,其他基本类型都能以显式类型转换的方法实现转换。
3.6 代码注释与编码规范
3,.6.1 代码注释
1、单倍注释:“//”为单行注释标记,从符号“//”开始直到换行为止的所有内容均作为注释而被编译器忽略。语法为://注释内容
2、多行注释:”/* */“为多行注释标记,符号”/*“与符号”*/"之间的所有内容均为注释内容。注释的内容可以换行。语法为:/* 注释内容 注释内容 …… */
3、文档注释:“/** */“为文档注释标记。符号”/**“与”*/“之间的内容均为文档注释内容。
四、流程控制
4.1 复合语句
Java语言的复合语句是以整个块区为单位的语句。所以又称块语句。符合语句由开括号“{”开始,闭括号“}”结束。
4.2 条件语句
4.2.1 if条件语句 if条件语句是一个重要的编程语句,用于告诉程序在某个条件成立的情况下执行某段语句,而在另一种情况下执行另外的语句。
1.简单的if条件语句语法:if(布尔表达式){ 语句序列 } ·布尔表达式:必要参数,表示最后返回的结果必须是一个布尔值。它可以是一个单纯的布尔变量或常量,也可以是使用关系或布尔运算符的表达式。
语句序列:可选参数。可以是一条或多条语句,当表达式的值为true时执行这些语句。若语句序列中仅有一条语句,则可以省略条件语句中的“{}”。
语句序列:可选参数。可以是一条或多条语句,当表达式的值为true时执行这些语句。若语句序列中仅有一条语句,则可以省略条件语句中的“{}”。
2、if…else语句
if……else语句是条件语句中最常用的一种形式,它会针对某种条件有选择地做出处理。通常表现为“如果满足某种条件,就进行某种处理,否则就进行另一种处理”。语法为:if(条件表达式){语句序列1}else{语句序列2} if后面“()”内的表达式的值必须是boolean型的。如果表达式的值为true,则执行紧跟if语句的复合语句;如果表达式的值为false,则执行else后面的复合语句。同简单的if条件语句一样,如果if……else语句的语句序列中只有一条语句(不包括注释),则可以省略该语句序列外面的“{}”。有时为了编程的需要,else或if后面的“{}”中可以没有语句。
3、if…else if多分支语句
if……else if多分支语句用于针对某一事件的多种情况进行处理。通常表现为“如果满足某种条件,就进行某种处理,否则如果满足另一种条件则执行另一种处理”。语法为:if(条件表达式1){
语句序列1
}else if(条件表达式2){
语句序列2
}
……
else if(条件表达式n){
语句序列n
} 条件表达式1~条件表达式n:必要参数。可以由多个表达式组成,但最后返回的结果一定要为boolean类型。
·语句序列:可以是一条或多条语句,当条件表达式1的值为true时,执行语句序列1;当条件表达式2的值为true时,执行语句序列2,以此类推。当省略任意一组语句序列时,可以保留其外面的“{}”,也可以将“{}”替换为“;”。
语句序列1
}else if(条件表达式2){
语句序列2
}
……
else if(条件表达式n){
语句序列n
} 条件表达式1~条件表达式n:必要参数。可以由多个表达式组成,但最后返回的结果一定要为boolean类型。
·语句序列:可以是一条或多条语句,当条件表达式1的值为true时,执行语句序列1;当条件表达式2的值为true时,执行语句序列2,以此类推。当省略任意一组语句序列时,可以保留其外面的“{}”,也可以将“{}”替换为“;”。
4、switch多分支语句
在编程中,一个常见的问题就是检测一个变量是否符合某个条件,如果不符合,再用另一个值来检测,以此类推。在Java中,可以用Switch语句将动作组织起来,以一个较简单明了的方式来实现“多选一”的选择。语法如下:switch(表达式){
case 常量值1:
语句块1
[break]
……
case 常量值n:
语句块n
[break]
default:
语句块n+1
[break]
} switch语句中表达式的值必须是整型、字符型、字符串类型或枚举类型,常量值1~n的数据类型必须与表达式的值的类型相同。
switch语句首先计算表达式的值,如果表达式的计算结果和某个case后面的常量值相同,则执行该case语句后的若干个语句直到遇到break语句为止。
同一个 switch语句,case的常量值必须互不相同。在 switch语句中,case语句后常量表达式的值可以为整数,但绝不可以是非整数的实数。
case 常量值1:
语句块1
[break]
……
case 常量值n:
语句块n
[break]
default:
语句块n+1
[break]
} switch语句中表达式的值必须是整型、字符型、字符串类型或枚举类型,常量值1~n的数据类型必须与表达式的值的类型相同。
switch语句首先计算表达式的值,如果表达式的计算结果和某个case后面的常量值相同,则执行该case语句后的若干个语句直到遇到break语句为止。
同一个 switch语句,case的常量值必须互不相同。在 switch语句中,case语句后常量表达式的值可以为整数,但绝不可以是非整数的实数。
4.3 循环语句
4.3.1 while循环语句
while语句也称条件判断语句,它的循环方式为利用一个条件来控制是否要继续反复执行这个语句。语法如下:while(条件表达式){
语句序列
} 当条件表达式的返回值为真时,则执行“{}”中的语句,当执行完“{}”中的语句后,重新判断条件表达式的返回值,直到表达式返回的结果为假时,退出循环。
语句序列
} 当条件表达式的返回值为真时,则执行“{}”中的语句,当执行完“{}”中的语句后,重新判断条件表达式的返回值,直到表达式返回的结果为假时,退出循环。
4.3.2 do……while循环语句
do……while循环语句与while循环语句类似,它们之间的区别是while语句为先判断条件是否成立,再执行循环体,而do……while循环语句则先执行一次循环后,再判断条件成立。也就是说,do……while循环语句“{}”中的程序段至少要被执行一次。语法如下:do{
语句序列
}while(条件表达式) do……while语句与while语句的一个明显的区别是,do……while语句在结尾处多了一个分号。
语句序列
}while(条件表达式) do……while语句与while语句的一个明显的区别是,do……while语句在结尾处多了一个分号。
4.3.3 for循环语句
for循环是Java程序设计中最有用的循环语句之一。一个for循环可以用来重复执行某条语句,直到某个条件得到满足。for循环有两种语句,一种是传统的for语句,一种是foreach语句
1、for语句
传统的for语句中有3个表达式,其语法如下:
for(表达式1;表达式2;表达式3){
语句序列
} 表达式1:初始化表达式,负责完成变量的初始化。
表达式2:循环条件表达式,值为Boolean型的表达式,指定循环条件。等同于while循环里的表达式。
表达式3:每次循环结束后执行的语句,通常用来改变循环条件
在执行for循环时,首先执行表达式1,完成某一变量的初始化工作;下一步判断表达式2的值,若表达式的值为true,则进入循环体;在执行完循环体后紧接着计算表达式3,这部分通常是增加或减少循环控制变量的一个表达式。这样一轮循环就结束了。第2轮循环从计算表达式2开始,若表达式2返回true,则继续循环,否则跳出整个for语句。
for(表达式1;表达式2;表达式3){
语句序列
} 表达式1:初始化表达式,负责完成变量的初始化。
表达式2:循环条件表达式,值为Boolean型的表达式,指定循环条件。等同于while循环里的表达式。
表达式3:每次循环结束后执行的语句,通常用来改变循环条件
在执行for循环时,首先执行表达式1,完成某一变量的初始化工作;下一步判断表达式2的值,若表达式的值为true,则进入循环体;在执行完循环体后紧接着计算表达式3,这部分通常是增加或减少循环控制变量的一个表达式。这样一轮循环就结束了。第2轮循环从计算表达式2开始,若表达式2返回true,则继续循环,否则跳出整个for语句。
2. foreach语句
foreach语句是for语句的特殊简化版本,不能完全取代for语句,但任何foreach语句都可以改写为for语句版本。 foreach并不是一个关键字,习惯上将这种特殊的for语句格式称为 foreach语句。语法如下:
for(元素类型 x:遍历对象obj){
引用了x的Java语句;} foreach语句中的元素变量x,不必对其进行初始化。
for(元素类型 x:遍历对象obj){
引用了x的Java语句;} foreach语句中的元素变量x,不必对其进行初始化。
4.4 循环控制
4.4.1 break语句
使用 break语句可以跳出Switch结构。在循环结构中,同样也可以 break语句跳出当前语句结束循环体。从而中断当前循环。循环嵌套情况下,break语句将只会使程序流程跳出包含它的最内层的循环结构,即只跳出一层循环。
如果想让break跳出外层循环,Java提供了“标签”的功能,语法如下:标签名:循环体{
break标签名;
} 标签名:任意表示符
循环体:任意循环语句
break标签名:break跳出指定的循环体,此循环体的标签名必须与break的标签名一致。带有标签的break可以指定跳出的循环,这个循环可以是内层循环,也可以是外层循环。
如果想让break跳出外层循环,Java提供了“标签”的功能,语法如下:标签名:循环体{
break标签名;
} 标签名:任意表示符
循环体:任意循环语句
break标签名:break跳出指定的循环体,此循环体的标签名必须与break的标签名一致。带有标签的break可以指定跳出的循环,这个循环可以是内层循环,也可以是外层循环。
4.4.2 continue语句
continue语句是针对break语句的补充。 continue不是立即跳出循环体,而是跳过本次循环,回到循环的条件测试部分,重新开始执行循环。在for循环语句中遇到 continue后,首先执行循环的增量部分,然后进行条件测试。与break语句一样,continue也支持标签功能,语法如下: 标签名:循环体{
continue标签名
} 标签名:任意标识符
循环体:任意循环语句
continue标签名:continue跳出指定的循环体,此循环体的标签名必须与continue的标签名一致。
continue标签名
} 标签名:任意标识符
循环体:任意循环语句
continue标签名:continue跳出指定的循环体,此循环体的标签名必须与continue的标签名一致。
五、数组
5.1 数组概述
数组是最常见的一种数据结构,是同类型的用一个标识符封装到一起的基本类型数据序列或对象序列。可以用一个统一的数组名和下标来唯一确定数组中的元素。实质上,数组是一个简单的线性序列,因此访问速度很快。
数组是具有相同数据类型的一组数据的集合。在程序设计中,可以将这些集合称为数组。数组中的每一个元素具有相同的数据类型。在Java中同样将数组看作一个对象,虽然基本数据类型不是对象,但由基本数据类型组成的数据确是对象。
数组是具有相同数据类型的一组数据的集合。在程序设计中,可以将这些集合称为数组。数组中的每一个元素具有相同的数据类型。在Java中同样将数组看作一个对象,虽然基本数据类型不是对象,但由基本数据类型组成的数据确是对象。
5.2 一维数组
一维数组实质上是一组相同类型数据的线性集合,当在程序中需要处理一组数据,或者传递一组数据时,可以应用这种类型的数组。
5.2.1 创建一维数组
数组作为对象允许使用new关键字进行内层分配。在使用数组之前,必须首先定义数组变量所属的类型。一维数组的创建有两种形式。
1.先声明,再用new关键字进行内存分配
声明一维数组有下列两种方式:
(1)数组元素类型 数组名字[];
(2)数组元素类型[]数组名字;
数组元素类型决定了数组的数据类型,它可以是Java中任意的数据类型,包括简单类型数据,包括简单类型和组合类型。数组名字为一个合法的标识符,符号“【】”指明该变量是一个数组类型变量。单个“[]”表示要创建的数组是一个一维数组。声明一维数组,代码为:int arr[]; //声明int型数组,数组中每一个元素都是int型数值 声明数组后,还不能立即访问它的任何元素,因为声明数组只是给出了数组名字和元素的数据类型,要想真正使用数组,还要为它分配内存空间。在为数组分配内存空间时必须指明数组长度。为数组分配内存空间的语法格式如下:
数组名字=new数组元素的类型[数组元素的个数];
数组名称:被连接到数组变量名称。
数组元素的个数:指定数组中变量的个数,即数组的长度。
通过上面的语法可知,使用new关键字为数组分配内存时,必须指定数组元素的类型和数组元素的类型和数组元素的个数,即数组长度。
为数组分配内存,代码为:arr=new int[5]; 以上代码表示要创建一个含有5个元素的整形数组,并且将创建的数组对象赋给引用变量arr,即通过引用变量arr来引用这个数组,如右图所示:
声明一维数组有下列两种方式:
(1)数组元素类型 数组名字[];
(2)数组元素类型[]数组名字;
数组元素类型决定了数组的数据类型,它可以是Java中任意的数据类型,包括简单类型数据,包括简单类型和组合类型。数组名字为一个合法的标识符,符号“【】”指明该变量是一个数组类型变量。单个“[]”表示要创建的数组是一个一维数组。声明一维数组,代码为:int arr[]; //声明int型数组,数组中每一个元素都是int型数值 声明数组后,还不能立即访问它的任何元素,因为声明数组只是给出了数组名字和元素的数据类型,要想真正使用数组,还要为它分配内存空间。在为数组分配内存空间时必须指明数组长度。为数组分配内存空间的语法格式如下:
数组名字=new数组元素的类型[数组元素的个数];
数组名称:被连接到数组变量名称。
数组元素的个数:指定数组中变量的个数,即数组的长度。
通过上面的语法可知,使用new关键字为数组分配内存时,必须指定数组元素的类型和数组元素的类型和数组元素的个数,即数组长度。
为数组分配内存,代码为:arr=new int[5]; 以上代码表示要创建一个含有5个元素的整形数组,并且将创建的数组对象赋给引用变量arr,即通过引用变量arr来引用这个数组,如右图所示:
在上图中,arr为数组名称,方括号“[]”中的值为数组下标。数组通过下标来区分数组中不同的元素。数组下标是从0开始。由于创建的数组aar中有5个元素,因此数组中元素下标为0~4.
2.声明的同时为数组分配内存 这种创建数组的方法是将数组的声明和分配合在一起执行。语法如下:
数组元素的类型 数组名 =new数组元素的类型[数组元素的个数];
声明并为数组分配内存,代码为:int month[]=new int[12] 上面的代码创建数组month,并指定了数组长度为12的。这种创建数组的方法也是Java程序编写过程中普遍的做法。
数组元素的类型 数组名 =new数组元素的类型[数组元素的个数];
声明并为数组分配内存,代码为:int month[]=new int[12] 上面的代码创建数组month,并指定了数组长度为12的。这种创建数组的方法也是Java程序编写过程中普遍的做法。
5.2.2 初始化一维数组
数组与基本数据类型一样可以进行初始化操作。数组的初始化可分别初始化数组中的每个元素。数组的初始化有以下两种方式: int arr[]=new int[]{1,2,3,5,25};
int arr2[]={34,23,12,6}; 从中可以看出,数组的初始化就是包括在大括号之内用逗号分开的表达式列表。用逗号(,)分割数组中的各个元素,系统自动为数组分配一定的空间。用第一种初始化方式,将创建5个元素的数组,其元素依次为1,2,3,5,25。第二种初始化方式,会创建4个元素的数组,其元素依次为34,23,12,6。
int arr2[]={34,23,12,6}; 从中可以看出,数组的初始化就是包括在大括号之内用逗号分开的表达式列表。用逗号(,)分割数组中的各个元素,系统自动为数组分配一定的空间。用第一种初始化方式,将创建5个元素的数组,其元素依次为1,2,3,5,25。第二种初始化方式,会创建4个元素的数组,其元素依次为34,23,12,6。
5.2.3 使用一维数组
例题5.1 使用一维数组输出1~12月每个月份的天数
代码为: public class GetDay { //创造类
public static void main(String[] args) { //主方法
int day[] = new int[] {31,28,31,30,31,30,31,31,30,31,30,31}; //创造并初始化一维数组
for(int i = 0;i<12;i++) { //利用循环将信息输出
System.out.println((i+1)+"月有"+day[i]+"天;"); //输出每月的天数
}
}
}
public static void main(String[] args) { //主方法
int day[] = new int[] {31,28,31,30,31,30,31,31,30,31,30,31}; //创造并初始化一维数组
for(int i = 0;i<12;i++) { //利用循环将信息输出
System.out.println((i+1)+"月有"+day[i]+"天;"); //输出每月的天数
}
}
}
结果如上:
5.3 二维数组
如果一维数组中各个元素仍然是一个数组,那么它就是一个二维数组。二维数组常用于表示表,表中的信息以行和列的形式组织,第一个下标代表元素所在的行,第二个下标代表元素所在的列。
5.3.1 创建二维数组
二维数组可以看作是特殊的一维数组,因此二维数组的创建同样有两种方式。
1、先声明,再用new关键字进行内存分配
声明二维数组的语法如下:
数组元素的类型 数组名字[][];
数组元素的类型[][] 数组名字;
声明二维数组,代码如下: int a[][]; 同一维数组一样,二维数组在声明时也没有分配内存空间,同样要使用new关键字来分配内存,然后才可以访问每个元素。对于高维数组,有两种为数组分配内存的方式。第一种内存分配方式是直接为每一维分配内存空间,代码如下:a==new int[2][4] 上述代码创建了二维数组a,二维数组a中包括两个长度为4的数组,内存分配图如右所示
声明二维数组的语法如下:
数组元素的类型 数组名字[][];
数组元素的类型[][] 数组名字;
声明二维数组,代码如下: int a[][]; 同一维数组一样,二维数组在声明时也没有分配内存空间,同样要使用new关键字来分配内存,然后才可以访问每个元素。对于高维数组,有两种为数组分配内存的方式。第一种内存分配方式是直接为每一维分配内存空间,代码如下:a==new int[2][4] 上述代码创建了二维数组a,二维数组a中包括两个长度为4的数组,内存分配图如右所示
第二种内存分配方式是分别为每一维分配内存,代码如下:
a = new int[2][];
a[0]=new int[2];
a[1]=new int[3]; 上述代码创建了二维数组a,但是只声明了a第一维的长度,也就是“行数”,第二维的长度也就是“列数”,则是为每一行单独声明的,因此创建的数组a是“不定长数组”,其内存分配如右图所示。
a = new int[2][];
a[0]=new int[2];
a[1]=new int[3]; 上述代码创建了二维数组a,但是只声明了a第一维的长度,也就是“行数”,第二维的长度也就是“列数”,则是为每一行单独声明的,因此创建的数组a是“不定长数组”,其内存分配如右图所示。
2、声明的同时为数组分配内存 第二种创建方式与第一种实现的功能相同,只不过声明与赋值合并到同一行代码中。例如,创建一个2行4列的二维数组,代码如下: int a=new int[2][4]
5.3.2 初始化二维数组
二维数组的初始化与一维数组初始化类似,同样可以使用大括号完成。语法如下:
type arrayname[][]={value1,value2,……valuen};
type:数组数据类型。
arrayname:数组名称,一个合法的标识符。
value:二维数组中各元素,都代表一个一维数组。
初始化二维数组,代码如下:
int myarr[][]={{12,0},{45,10}}; 初始化二维数组后,要明确数组的下标都是0开始。例如,上面的代码中myarr[1][1]的值10。
int型二维数组是以int a[][]来定义的,所以可以直接给a[x][y]赋值。例如,给a[1]的第2个元素赋值的语句如下: a[1][1]=20
type arrayname[][]={value1,value2,……valuen};
type:数组数据类型。
arrayname:数组名称,一个合法的标识符。
value:二维数组中各元素,都代表一个一维数组。
初始化二维数组,代码如下:
int myarr[][]={{12,0},{45,10}}; 初始化二维数组后,要明确数组的下标都是0开始。例如,上面的代码中myarr[1][1]的值10。
int型二维数组是以int a[][]来定义的,所以可以直接给a[x][y]赋值。例如,给a[1]的第2个元素赋值的语句如下: a[1][1]=20
5.3.3 使用二维数组
例5.2 输出一个3行4列且所有元素都为0的矩阵
代码为: public class Matrix { //创造类
public static void main(String[] args) { //主方法
int a[][] = new int[3][4]; //定义二维数组
for(int i = 0;i<a.length;i++) {
for(int j = 0;j<a[i].length;j++) { //循环遍历数组中每一个元素
System.out.print(a[i][j]); //将数组中的元素输出
}
System.out.println(); //输出空格
}
}
}
public static void main(String[] args) { //主方法
int a[][] = new int[3][4]; //定义二维数组
for(int i = 0;i<a.length;i++) {
for(int j = 0;j<a[i].length;j++) { //循环遍历数组中每一个元素
System.out.print(a[i][j]); //将数组中的元素输出
}
System.out.println(); //输出空格
}
}
}
代码结果
5.4 数组的基本操作
5.4.1 遍历数组
遍历数组就是获取数组中的每一个元素。通常遍历数组都是使用for循环来实现。遍历二维数组需使用双层for循环,通过数组的length属性可获得数组的长度。
例5.3 呈梯形输出二维数组中的元素
代码为: public class Trap { //创造类
public static void main(String[] args) { //主方法
int b[][] = new int[][] {{ 1 },{2,3},{4,5,6}}; //定义二维数组
for(int k = 0;k < b.length;k++) {
for(int c = 0;c<b[k].length;c++) { //循环遍历二维数组中每一个元素
System.out.print(b[k][c]); //将数组中的元素输出
}
System.out.println( ); //输出空格
}
}
}
public static void main(String[] args) { //主方法
int b[][] = new int[][] {{ 1 },{2,3},{4,5,6}}; //定义二维数组
for(int k = 0;k < b.length;k++) {
for(int c = 0;c<b[k].length;c++) { //循环遍历二维数组中每一个元素
System.out.print(b[k][c]); //将数组中的元素输出
}
System.out.println( ); //输出空格
}
}
}
代码结果
在遍历数组时,使用foreach语句可能会更简单。
例5.4 使用foreach语句遍历二维数组
代码为: public class Tautog { //创造类
public static void main(String[] args) { //主方法
int arr2[][] = {{4,3},{1,2}}; //定义二维数组
System.out.println("数组中的元素是:"); //提示信息
int i = 0; //外层循环计数器变量
for(int x[]:arr2) { //外层循环变量为一维数组
i++; //外层计数器递增
int j = 0; //内层循环计数器变量
for(int e : x) { //循环遍历每一个数组元素
j++; //内层计数器递增
if(i==arr2.length&&j==x.length) { //判断变量是二维数组中最后一个元素
System.out.print(e); //输出二维数组的最后一个元素
}else //如果不是二维数组中的最后一个元素
System.out.print(e+"、"); //输出信息
}
}
}
}
public static void main(String[] args) { //主方法
int arr2[][] = {{4,3},{1,2}}; //定义二维数组
System.out.println("数组中的元素是:"); //提示信息
int i = 0; //外层循环计数器变量
for(int x[]:arr2) { //外层循环变量为一维数组
i++; //外层计数器递增
int j = 0; //内层循环计数器变量
for(int e : x) { //循环遍历每一个数组元素
j++; //内层计数器递增
if(i==arr2.length&&j==x.length) { //判断变量是二维数组中最后一个元素
System.out.print(e); //输出二维数组的最后一个元素
}else //如果不是二维数组中的最后一个元素
System.out.print(e+"、"); //输出信息
}
}
}
}
代码结果
5.4.2 填充替换数组元素
数组中的元素定义完成后,可通过Arrays类的静态方法fill()来对数组中的元素进行替换。该方法通过各种重载形式可完成对任意类型的数组元素的替换。
1、fill(int[]a,int value) 该方法可将指定的int值分配给int型数组的每个元素。语法如下: fill(int[]a,int value)
a:要进行元素替换的数组
value:要存储数组中所有元素的值。
a:要进行元素替换的数组
value:要存储数组中所有元素的值。
例5.5 使用fill(方法填充数组元素)
代码为:
import java.util.Arrays; //导入java.util.Arrays类
public class Swap { //创造类
public static void main(String[] args) { //主方法
int arr[] = new int[5]; //创建int型数组
Arrays.fill(arr,8); //使用同一个值对数组进行填充
for(int i = 0;i<arr.length;i++) { //循环遍历数组中的元素
System.out.println("第"+i+"个元素是:"+arr[i]); //将数组中的元素依次输出
}
}
}
import java.util.Arrays; //导入java.util.Arrays类
public class Swap { //创造类
public static void main(String[] args) { //主方法
int arr[] = new int[5]; //创建int型数组
Arrays.fill(arr,8); //使用同一个值对数组进行填充
for(int i = 0;i<arr.length;i++) { //循环遍历数组中的元素
System.out.println("第"+i+"个元素是:"+arr[i]); //将数组中的元素依次输出
}
}
}
代码结果
2、fill(int[]a,int fromIndex,int toIndex,int value)(前改索引后不改索引) 该方法将指定的int值分配给int型数组指定范围中的每个元素。填充的范围从索引(下标)fromIndex(包括)一直到索引toIndex(不包括)。如果fromlndex==toIndex,则填充范围为空。语法如下:
fill(int[]a,int fromIndex,int toIndex,int value)
a:要进行填充的数组。
fromIndex:要使用指定值填充的第一个元素的索引(包括)。
toIndex:要使用指定值填充的最后一个元素的索引(不包括)。
value:要分配给数组指定范围中的每个元素的值。
fill(int[]a,int fromIndex,int toIndex,int value)
a:要进行填充的数组。
fromIndex:要使用指定值填充的第一个元素的索引(包括)。
toIndex:要使用指定值填充的最后一个元素的索引(不包括)。
value:要分配给数组指定范围中的每个元素的值。
例5.6 使用fill()方法替换数组中的元素
代码为: import java.util.Arrays; //导入java.util.Arrays类
public class Displace { //创造类
public static void main(String[] args) { //主方法
int arr[] = new int[]{45,12,2,10}; //定义并初始化int型数组arr
Arrays.fill(arr,1,2,8); //使用fill方法替换数组指定范围内的元素
for(int i = 0;i < arr.length;i++) { //循环遍历数组中的元素
System.out.println("第"+i+"个元素是:"+arr[i]); //将数组中的每个元素输出
}
}
}
public class Displace { //创造类
public static void main(String[] args) { //主方法
int arr[] = new int[]{45,12,2,10}; //定义并初始化int型数组arr
Arrays.fill(arr,1,2,8); //使用fill方法替换数组指定范围内的元素
for(int i = 0;i < arr.length;i++) { //循环遍历数组中的元素
System.out.println("第"+i+"个元素是:"+arr[i]); //将数组中的每个元素输出
}
}
}
代码结果
5.4.3 对数组进行排序
通过Arrays类的静态方法sort()可以实现对数组的排序。sort()方法提供了多种重载形式,可对任意类型的数组进行升序排序。语法如下:
Arrays,sort(object)
Arrays,sort(object)
例5.7 使用sort()方法将数组排序后输出
代码为: import java.util.Arrays; //导入java.util.Arrays类
public class Taxis { //创造类
public static void main(String[] args) { //主方法
int arr[]= new int[] {23,42,12,8}; //声明数组
Arrays.sort(arr); //将数组进行排序
for(int i = 0;i<arr.length;i++ ) { //循环遍历排序后的数组
System.out.println(arr[i]); //将排序后数组中的各个袁旭输出
}
}
}
public class Taxis { //创造类
public static void main(String[] args) { //主方法
int arr[]= new int[] {23,42,12,8}; //声明数组
Arrays.sort(arr); //将数组进行排序
for(int i = 0;i<arr.length;i++ ) { //循环遍历排序后的数组
System.out.println(arr[i]); //将排序后数组中的各个袁旭输出
}
}
}
代码结果·
5.4.4 复制数组
Arrays类的copyOf()方法与copyOfRange()方法可以实现对数组的复制。copyOf()方法是复制数组至指定长度,copyOfRange()方法则将指定数组的指定长度复制到一个新数组中。
1、copyOf()方法 该方法提供了多种重裁形式,用于满足不同类型数组的复制。语法如下:
copyOf(arr,int newlength)
arr:要进行复制的数组。
newlength:int型常量,指复制后的新数组的长度。(空位补0,溢出去掉)
copyOf(arr,int newlength)
arr:要进行复制的数组。
newlength:int型常量,指复制后的新数组的长度。(空位补0,溢出去掉)
例5.8 复制数组
代码为: import java.util.Arrays; //导入java.util.Arrays类
public class Cope { //创造类
public static void main(String[] args) { //主方法
int arr[] = new int[] {23,42,12}; //定义数组
int newarr[] = Arrays.copyOf(arr, 5); //复制数组arr
for(int i = 0;i < newarr.length;i++) { //循环遍历复制后的新数组
System.out.println(newarr[i]); //将新数组输出
}
}
}
public class Cope { //创造类
public static void main(String[] args) { //主方法
int arr[] = new int[] {23,42,12}; //定义数组
int newarr[] = Arrays.copyOf(arr, 5); //复制数组arr
for(int i = 0;i < newarr.length;i++) { //循环遍历复制后的新数组
System.out.println(newarr[i]); //将新数组输出
}
}
}
代码结果
2、copyOfRange()方法(前在后不在) 该方法同样提供了多种重裁形式,语法如下:
copyOfRange(arr,int formIndex,int toIndex)
arr:要进行复制的数组对象。
formIndex:指定开始复制数组的索引位置。formIndex必须在0至整个数组的长度之间。新数组包括索引是formIndex的元素。
toIndex:要复制范围的最后索引位置。可大于数组arr的长度。新数组不包括索引是toIndex的元素。
copyOfRange(arr,int formIndex,int toIndex)
arr:要进行复制的数组对象。
formIndex:指定开始复制数组的索引位置。formIndex必须在0至整个数组的长度之间。新数组包括索引是formIndex的元素。
toIndex:要复制范围的最后索引位置。可大于数组arr的长度。新数组不包括索引是toIndex的元素。
例5.9按照索引复制数组
代码为: import java.util.Arrays; //导入java.util.Arrays类
public class Repeat { //创造类
public static void main(String[] args) { //主方法
int arr[] = new int[] {23,43,12,84,10}; //定义数组
int newarr[] = Arrays.copyOfRange( arr, 0, 3); //复制数组
for(int i = 0;i<newarr.length;i++) { //循环遍历复制后的新数组
System.out.println(newarr[i]); //将新数组中的每个元素输出
}
}
}
public class Repeat { //创造类
public static void main(String[] args) { //主方法
int arr[] = new int[] {23,43,12,84,10}; //定义数组
int newarr[] = Arrays.copyOfRange( arr, 0, 3); //复制数组
for(int i = 0;i<newarr.length;i++) { //循环遍历复制后的新数组
System.out.println(newarr[i]); //将新数组中的每个元素输出
}
}
}
代码结果
5.4.5 查询数组
Arrays类的binarySearch()方法,可使用二分搜索法来搜索指定数组,以获得指定对象,该方法返回要搜索元素的索引值。binarySearch()方法提供了多种重裁形式,用于满足各种类型数组的查找需要。
1、binarySearch(Object[]a,Object key)(先排序,后查询) 语法如下:
a:要搜索的数组。
key:要搜索的值。
如果key包含在数组中,则返回搜索值的索引;否则返回-1或“-”(插入点)。插入点是搜索键将要插入数组的那一点,即第一个大于此键的元素索引。
查询数组元素,代码如下: int arr[]=new int{4,25,10}; //创建并初始化数组
Arrays.sort(arr); //将数组进行排序
int index=Arrays.binartSearch(arr,8); 上面的代码中变量index的值是元素“8”在数组arr中索引在0~1内的索引位置。由于在指定的范围并不存在元素“8”,index的值是“-”(插入点)。如果数组进行排序,元素“8”应该在“25”的前面,因此插入点应是元素“25”的索引值为2,所以index的值是-2。
如果数组中的所有元素都小于指定的键,则为a.length(注意,这保证了当且仅档此键被找到时,返回的值将大于等于0)。
a:要搜索的数组。
key:要搜索的值。
如果key包含在数组中,则返回搜索值的索引;否则返回-1或“-”(插入点)。插入点是搜索键将要插入数组的那一点,即第一个大于此键的元素索引。
查询数组元素,代码如下: int arr[]=new int{4,25,10}; //创建并初始化数组
Arrays.sort(arr); //将数组进行排序
int index=Arrays.binartSearch(arr,8); 上面的代码中变量index的值是元素“8”在数组arr中索引在0~1内的索引位置。由于在指定的范围并不存在元素“8”,index的值是“-”(插入点)。如果数组进行排序,元素“8”应该在“25”的前面,因此插入点应是元素“25”的索引值为2,所以index的值是-2。
如果数组中的所有元素都小于指定的键,则为a.length(注意,这保证了当且仅档此键被找到时,返回的值将大于等于0)。
例5.10 查找元素在数组中的索引位置
代码为: import java.util.Arrays; //导入java.util.Arrays类
public class Reference { //创造类
public static void main(String[] args) { //主方法
int ia[]= new int[] {1,8,9,4,5}; //定义int型数组
Arrays.sort(ia); //将数组进行排列
int index = Arrays.binarySearch(ia, 4); //查找数组ia中元素4的索引位置
System.out.println("4的索引位置是:"+index); //将索引输出
}
}
public class Reference { //创造类
public static void main(String[] args) { //主方法
int ia[]= new int[] {1,8,9,4,5}; //定义int型数组
Arrays.sort(ia); //将数组进行排列
int index = Arrays.binarySearch(ia, 4); //查找数组ia中元素4的索引位置
System.out.println("4的索引位置是:"+index); //将索引输出
}
}
代码结果
2、binarySearch(Object[]a,int fromIndex,int toIndex,Object key) 该方法在指定的范围内检查某一元素。语法如下:
binarySearch(Object[]a,int fromIndex,int toIndex,Object key)
a:要进行检索的数组。
fromIndex:指定范围的开始处索引(包含)。
toIndex:指定范围的结束处索引(不包含)。
key:要搜素的元素。
在使用该方法前,同样要对数组进行排序,这样才能获得获得准确的索引值。如果要搜索的元素key在指定的范围内,则返回搜索键的索引;否则返回-1或“-”(插入点)。如果范围中的所有元素都小于指定的键,则插入点为toIndex(注意,这保证当且仅档此键被找到时,返回的值将大于等于0)。
binarySearch(Object[]a,int fromIndex,int toIndex,Object key)
a:要进行检索的数组。
fromIndex:指定范围的开始处索引(包含)。
toIndex:指定范围的结束处索引(不包含)。
key:要搜素的元素。
在使用该方法前,同样要对数组进行排序,这样才能获得获得准确的索引值。如果要搜索的元素key在指定的范围内,则返回搜索键的索引;否则返回-1或“-”(插入点)。如果范围中的所有元素都小于指定的键,则插入点为toIndex(注意,这保证当且仅档此键被找到时,返回的值将大于等于0)。
例5.11在指定范围内查找元素在数组中的索引位置
代码为: import java.util.Arrays; //导入java.util.Arrays类
public class Rakel { //创造类
public static void main(String[] args) { //主方法
String str[] = new String[] {"ab","cd","ef","yz"}; //定义Steing型数组str
Arrays.sort(str); //将数组进行排序
int index = Arrays.binarySearch(str, 0,2,"cd"); //在指定范围内搜索元素“cd”的索引位置
System.out.println("cd的索引位置是:"+index); //将索引输出
}
}
public class Rakel { //创造类
public static void main(String[] args) { //主方法
String str[] = new String[] {"ab","cd","ef","yz"}; //定义Steing型数组str
Arrays.sort(str); //将数组进行排序
int index = Arrays.binarySearch(str, 0,2,"cd"); //在指定范围内搜索元素“cd”的索引位置
System.out.println("cd的索引位置是:"+index); //将索引输出
}
}
代码结果
5.5 数组排序算法
5.5.1 冒泡排序
冒泡排序是最常用的数组排序算法之一,它排序数组元素的过程总是将较小的数往前放、较大的数往后放,类似水中气泡往上升的动作,所以称为冒泡排序。
5.5.2 直接选择排序
直接选择排序属于的基本思想是将排序位置元素与其他数组元素分别对比,如果满足条件就交换元素值。
5.5.3 反转排序
反转排序的基本思想比较简单,也很好理解,其实现思路就是把数组最后一个元素与第一个元素替换,倒数第二个元素与第二个元素替换,以此类推,直到把所有数组元素反转替换。
六、类和对象
6.1 面向对象概述
在程序开发初期,人们使用结构化开发语言。随着软件的规模越来越庞大,结构化语言的弊端也逐渐暴露出来,开发周期越来越长,产品的质量也不尽人意。这时人们开始将另一种开发思想引入程序中,即面向对象的开发思想。面向对象思想是人类最自然的一种思考方式,它将所有预处理的问题抽象为对象,通过了解这些对象具有哪些相应的属性以及展示这些对象行为,以解决这些对象面临的一些实际问题。在程序开发中引入面向对象设计的概念,其实质上就是对现实世界中的对象进行建模操作。
6.1.1 对象
现实生活中,随处可见的一种事物就是对象。对象是事物存在的实体,如人、书桌、计算机、高楼大厦等。人类解决问题的方式总是将复杂的事物简单化,于是就会思考这些对象都是由哪些部分组成的。通常都会将对象划分为两个部分,即静态部分与动态部分。顾名思义,静态部分就是不能动的部分,这个部分被称为“属性”,任何对象都会具备其自身属性,如一个人,其属性包含高矮、胖瘦、性别、年龄等。动态部分即对象可执行的动作,这部分称为“行为”,也是一个值得探讨的部分,同样对于一个人,其可以哭泣、微笑、说话、行走,这些都是这个人具备的行为。人类通过探讨对象的属性和观察对象的行为来了解对象。
在计算机的世界中,面向对象程序设计的思想要以对象来思考问题,首先要将现实世界的实体抽象为对象,然后考虑这个对象具备的属性和行为。
在计算机的世界中,面向对象程序设计的思想要以对象来思考问题,首先要将现实世界的实体抽象为对象,然后考虑这个对象具备的属性和行为。
6.1.2 类
不能将一个事物描述成一类事物,如一只鸟不能称为鸟类。但如果要给某一事物一个统称,就需要用到类这个概念。
类及时同一类事物的统称,如果将现实世界中的一个事物抽象成对象,类就是这类对象等等统称,如鸟类、家禽类、人类等。类是构造对象时所依赖的规范,如一只鸟有一对翅膀,它可以用这对翅膀飞行,而基本上所有的鸟都具有“有翅膀”这个特性和飞行的技能,这样具有相同特性和行为的一类事物就称为类,类的思想就是这样产生的。
类是封装对象的属性和行为的载体,反过来说,具有相同属性和行为的一类实体被称为类。
在JAVA语言中,类对象的行为是以方法的形式定义的,对象的属性是以成员变量的形式定义的,所以类包括对象的属性和方法
类及时同一类事物的统称,如果将现实世界中的一个事物抽象成对象,类就是这类对象等等统称,如鸟类、家禽类、人类等。类是构造对象时所依赖的规范,如一只鸟有一对翅膀,它可以用这对翅膀飞行,而基本上所有的鸟都具有“有翅膀”这个特性和飞行的技能,这样具有相同特性和行为的一类事物就称为类,类的思想就是这样产生的。
类是封装对象的属性和行为的载体,反过来说,具有相同属性和行为的一类实体被称为类。
在JAVA语言中,类对象的行为是以方法的形式定义的,对象的属性是以成员变量的形式定义的,所以类包括对象的属性和方法
6.1.3 封装
面向对象程序设计具有一下特点:封装性、继承性和多态性。
封装是面向对象编程的核心思想。将对象的属性和行为封装起来,其载体就是类,类通常对客户隐藏其实现细节,这就是封装思想。例如,用户使用计算机时,只需要使用手指敲击键盘就可以实现一些功能,无须知道计算机内部是如何工作原理,但在使用计算机时也并不完全依赖于计算机工作原理等细节。
采用封装的思想保证了类内部数据结构的完整性,使用类的用户不能轻易地直接操作类的数据结构,只能执行类允许公开的数据。这样就避免了外部操作对内部数据的影响,提高了程序的可维护性。
封装是面向对象编程的核心思想。将对象的属性和行为封装起来,其载体就是类,类通常对客户隐藏其实现细节,这就是封装思想。例如,用户使用计算机时,只需要使用手指敲击键盘就可以实现一些功能,无须知道计算机内部是如何工作原理,但在使用计算机时也并不完全依赖于计算机工作原理等细节。
采用封装的思想保证了类内部数据结构的完整性,使用类的用户不能轻易地直接操作类的数据结构,只能执行类允许公开的数据。这样就避免了外部操作对内部数据的影响,提高了程序的可维护性。
6.1.4 继承
类与类之间同样具有关系,这种关系被称为关联。关联主要描述两个类之间的一般二元关系。例如,一个百货公司类与销售员类就是一个关联,学生类与教师类就是一个关联。两个类之间的关系有很多种,继承是关联的一种。
从上图中可以看出,继承关系可以使用树形关系来表达,父类与子类存在一种层次关系。一个类处于继承体系中,它既可以是其他类型的父类,为其他类提供属性和行为,也可以是其他类的子类,继承父类的属性和方法,如三角形类既是图形类的子类也是等边三角形的父类。
6.1.5多态
6.2 类
6.2.1 成员变量
在Java中,对象的属性也称为成员变量,成员变量可以是任意类型,整个类中均是成员变量作用范围。
6.2.2 成员方法
在Java语言中,使用成员方法对应于类对象的行为。一个·成员方法可以有参数,这个参数可以是对象,也可以是基本数据类型的变量,同时成员方法有返回值和不返回任何值的选择,如果方法需要返回值,可以在方法体中使用return关键字,使用这个关键字后,方法的执行将被终止。
6.2.3 仅限修饰符
6.2.4 局部变量
局部变量是在方法被执行是创建,在方法执行结束时销毁。局部变量在使用时必须进行赋值操作或被初始化,否则会出现编译器错误。
6.2.5 局部变量的有效范围
可以将局部变量的有效范围称为变量的作用域,局部变量的有效范围从该变量的声明开始到该变量的结束为止。
6.2.6 this关键字
语法:public void setName(String name){ //定义一个setName()方法 this.name = name; // 将参数值赋予类中的成员变量
6.3 类的构造方法
构造方法是一个与类同名的方法,对象的创建就是通过构造方法完成的。构造方法符特点为:构造方法没有返回值,构造方法的名称要与本类的名称相同
6.4静态变量和静态方法
静态就是static,可以有静态常量、静态变量、静态方法和多个语句静态
静态是这个类的专属,只有这个类可以用,就是这个文件可以用,只要它们在一个文件里就行
静态是这个类的专属,只有这个类可以用,就是这个文件可以用,只要它们在一个文件里就行
6.5 类的主方法
(String [] args)有什么用,怎么用
package b;
public class s {
public static void main(String [] args) {//主方法
for(int i=0;i<args.length;i++) {//根据参数个数做循环操作
System.out.println(args[i]);//打印结果
}
}
} 在代码运行前要先设置参数,右击界面
public class s {
public static void main(String [] args) {//主方法
for(int i=0;i<args.length;i++) {//根据参数个数做循环操作
System.out.println(args[i]);//打印结果
}
}
} 在代码运行前要先设置参数,右击界面
点击,然后以下操作
然后输入,用换行隔开
、运行结果
6.6 对象
6.6.1 对象的创建
test对象被创建出来时,就是一个对象的引用,这个引用在内存中为对象分配了存储空间
6.6.2 反问对象的属性和行为
6.6.3对象的引用
真正的操作标识符实质上是一个引用,引用的语法 类名 对象的引用变量
b d1 =new b();
b是类名,d1是引用名,new b对象的实体
b d1 =new b();
b是类名,d1是引用名,new b对象的实体
6.6.4 对象的销毁
为什么要销毁对象
每个对象都有生命周期,当对象的生命周期结束时,分配给该对象的内存地址需要被回收
垃圾回收器
在其他语言中,需要用户手动回收废弃的对象,JAVA拥有一套完整的垃圾回收机制,用户不必担心废弃的对象占用内存,垃圾回收器会自动回收无用却占用内存的资源
怎么判断对象会被JAVA虚拟机视为垃圾?主要包括两种情况:1、对象引用超过其作用范围,这个对象将被视为垃圾。2、将对象赋值为null
每个对象都有生命周期,当对象的生命周期结束时,分配给该对象的内存地址需要被回收
垃圾回收器
在其他语言中,需要用户手动回收废弃的对象,JAVA拥有一套完整的垃圾回收机制,用户不必担心废弃的对象占用内存,垃圾回收器会自动回收无用却占用内存的资源
怎么判断对象会被JAVA虚拟机视为垃圾?主要包括两种情况:1、对象引用超过其作用范围,这个对象将被视为垃圾。2、将对象赋值为null
虽然JAVA的垃圾回收机制已经很完善,但垃圾回收只能回收那些由new操作符创建的对象
某些对象不是通过new创造并获得存储空间的这些对象是无法被垃圾回收机制所识别
finalize()
那么JAVA提供了一个finalize方法
这个方法是object类方法,他被声明为protected,用户可以在自己的类中定义这个方法,定义了这个方法后,垃圾回收时会首先调用该方法
system.gc()
由于垃圾回收不受人为控制,具体的执行时间也不能明确的确定,所以finalize()方法也就无法执行,因此JAVA又提供了system.gc()方法来强制启动垃圾回收器,会主动告知垃圾回收器来清理垃圾
某些对象不是通过new创造并获得存储空间的这些对象是无法被垃圾回收机制所识别
finalize()
那么JAVA提供了一个finalize方法
这个方法是object类方法,他被声明为protected,用户可以在自己的类中定义这个方法,定义了这个方法后,垃圾回收时会首先调用该方法
system.gc()
由于垃圾回收不受人为控制,具体的执行时间也不能明确的确定,所以finalize()方法也就无法执行,因此JAVA又提供了system.gc()方法来强制启动垃圾回收器,会主动告知垃圾回收器来清理垃圾
七、继承、多态、抽象类与接口
7.1 类的继承
继承在面向对象开发思想中是一个非常重要的概念,它使整个程序架构具有一定的弹性。在程序中复用一些已经定义完善的类,不仅可以减少软件开发周期,也可以提高软件的可维护性和可扩展性。
在Java语言中,一个类继承另一个类需要使用关键字extends,关键字extends的使用方法如下:
class Child extends Parent{ }
因为Java只支持单继承,即一个类只能有一个父类,所以类下面的代码是错误的:
class Child estends Parent1,parents2{ }
子类在继承父类之后,创建子类对象的同时也会调用父类的构造方法。
在Java语言中,一个类继承另一个类需要使用关键字extends,关键字extends的使用方法如下:
class Child extends Parent{ }
因为Java只支持单继承,即一个类只能有一个父类,所以类下面的代码是错误的:
class Child estends Parent1,parents2{ }
子类在继承父类之后,创建子类对象的同时也会调用父类的构造方法。
7.2 Object类
Object类是比较特殊的类,它是所有类的父类,是Java类层中最高层类。用户创建一个类时,除非已经指定要从其他类继承,否则它就是从Java.lang.Object类继承而来的。Java中的每个类都源于Java.lang.Object类,如String类、Integer类等都是继承Object类。除此之外,自定义的类也都继承于Object类。
在Object类中,主要包括clone()、finalize()、equals()、toString()等方法,由于所有的类都是Object类的子类,所以任何类都可以重写Object类中的方法。
注意:Object类中的getClass()、notify()、notifyAll()、wait()等方法不能被重写,因为这些方法被定义为final类型。
在Object类中,主要包括clone()、finalize()、equals()、toString()等方法,由于所有的类都是Object类的子类,所以任何类都可以重写Object类中的方法。
注意:Object类中的getClass()、notify()、notifyAll()、wait()等方法不能被重写,因为这些方法被定义为final类型。
getClass()方法
getClass()方法是Object类定义的方法,它会返回对象执行时的Class实例,然后使用此实例调用getName()方法可以取得类的名称。语法如下:
getClass().getname();
可以将getClass()方法与toString()方法联合使用。
getClass().getname();
可以将getClass()方法与toString()方法联合使用。
toString()方法
toString()方法的功能是将一个对象返回为字符串形式,它会返回一个String实例。在实际的应用中通常重写toString()方法,为对象提供一个特定的输出模式。当这个类转换为字符串或与字符串连接时,将自动调用重写的toString()方法。
equals()方法
在Java语言中,有两种比较对象的方式,分别为“==”运算符与equals()方法。两者的区别在于:“==”比较的两个对象引用内地地址是否相等,而equals()方法比较的是两个对象的实际内容。
7.3 对象类型的转换
7.3.1 向上转型
向上转型可以被理解为将子类类型的对象转换为父类类型的对象,即把子类类型的对象之间赋值给父类类型的对象,进而实现按照父类描述子类的效果。
7.3.2 向下转型
向下转型可以被理解为将父类类型的对象转换为子类类型的对象。但是,运用向下转型,如果把一个较抽象的类的对象转换为一个较具体的类的对象,这样的转型通常会出现错误。
7.4 使用instanceof关键字判断对象类型
当在程序中执行向下转型操作时,如果父类对象不是子类对象的实例,就会发生ClassCastException异常,所以在执行向下转型之前需要养成一个良好的习惯,就是判断父类对象是否为子类对象的实例。可以使用instanceof关键字判断是否一个类实现了某个接口,也可以用它来判断一个实例对象是否属于一个类。语法如下:
myobject instanceof ExampleClass
myobject:某类的对象引用
ExampleClass:某个类
myobject instanceof ExampleClass
myobject:某类的对象引用
ExampleClass:某个类
7.5 方法的重载
方法的重载就是在同一个类中允许存在一个以上的同名方法,只要这些方法的参数个数或类型不同即可。
7.6 final关键字
7.6.1 final变量
final关键字可用于变量声明,一旦该变量被设定,就不可以再改变该变量的值。通常,由final定义的变量为常量。final关键字定义的变量必须声明时对其进行赋值操作。final除了可以修饰基本数据类型的常量还可以修饰对象的引用,也可以用来修饰数组。一旦一个对象引用被修饰为final后,它就只能恒定指向一个对象,无法将其改变以指向另一个对象。
7.6.2 final方法
将方法定义为final类型,可以防止子类修改父类的定义与实现方式,同时定义为final的方法的执行效率要高于非final方法。如果一个父类的某个方法被设置为private,子类将无法访问该方法,自然无法覆盖该方法。
7.6.3 final类
定义为final的类不能被继承。如果希望一个类不被任何类继承,并且不允许其他人对这个类进行任何改动,可以将这个类设置为final类。语法如下:
final 类名{}
如果将某个类设置为final类,则该类中的所有方法都被隐式设置为final方法,但是final类中的成员变量可以被定义为final或非final形式。
版权协议,转载请附上原文出处链接及本声明。
final 类名{}
如果将某个类设置为final类,则该类中的所有方法都被隐式设置为final方法,但是final类中的成员变量可以被定义为final或非final形式。
版权协议,转载请附上原文出处链接及本声明。
7.7 多态
多态的意思是多种形态,利用多态可以使程序具有良好的扩展性,并可以对所有类对象进行通用的处理。已经学习过子类对象可以作为父类的对象实例使用,这种将子类对象视为父类对象的做法称为“向上转型”。
class Shape1{}; //图形类
class Square1 extends Shape1{}; //正方形类继承图形类
class Circular1 extends Shape1{}; //图形类继承图形类
public class Demo6 {
public static void draw(Shape1 s) { //绘制方法
if(s instanceof Square1) { //如果是正方形
System.out.println("绘制正方形");
}else if(s instanceof Circular1) { //如果是圆形
System.out.println("绘制圆形");
}else { //如果是其他类型
System.out.println("绘制父类图形");
}
}
public static void main(String[]args) {
draw(new Shape1());
draw(new Square1());
draw(new Circular1());
}
}
class Square1 extends Shape1{}; //正方形类继承图形类
class Circular1 extends Shape1{}; //图形类继承图形类
public class Demo6 {
public static void draw(Shape1 s) { //绘制方法
if(s instanceof Square1) { //如果是正方形
System.out.println("绘制正方形");
}else if(s instanceof Circular1) { //如果是圆形
System.out.println("绘制圆形");
}else { //如果是其他类型
System.out.println("绘制父类图形");
}
}
public static void main(String[]args) {
draw(new Shape1());
draw(new Square1());
draw(new Circular1());
}
}
从实例中可以看出,以不同类对象为参数调用draw()方法,可以处理不同的图形绘制问题。使用多态节省了开发和维护时间,因为程序员无须在所有的子类中定义执行相同功能的方法,避免了大量重复代码的编写。同时,只要实例化一个继承父类的子类对象,即可调用相应的方法,如果需求发生了变更,只需要维护一个draw()方法即可。
7.8 抽象类与接口
7.8.1 抽象类
抽象方法:修饰符 abstract 返回参数 方法名(传入参数); 使用abstract关键字定义的类称为抽象类,而使用这个关键字定义的方法称为抽象方法。抽象方法没有方法体,没有意义,除非它被重写,而承载这个抽象方法的抽象类必须被继承,实际上抽象类除了被继承没有任何意义。语法如下: public abstract class Parent{ //修饰类 abstract class 类名
abstract void testAbstract(); //定义抽象方法 如果声明一个抽象方法,就必须将承载这个抽象方法的类定义为抽象类,不能在非抽象中获取抽象方法。只要类中有一个抽象方法,此类就被标记为抽象类。抽象类被继承后需要实现其中所有的抽象方法,也就是保证以相同的方法名称、参数列表和返回值类型创建出非抽象方法,当然也可以是抽象方法。
abstract void testAbstract(); //定义抽象方法 如果声明一个抽象方法,就必须将承载这个抽象方法的类定义为抽象类,不能在非抽象中获取抽象方法。只要类中有一个抽象方法,此类就被标记为抽象类。抽象类被继承后需要实现其中所有的抽象方法,也就是保证以相同的方法名称、参数列表和返回值类型创建出非抽象方法,当然也可以是抽象方法。
7.8.2 接口
接口是抽象类的延伸,可以将它看作纯粹的抽象类,所有的方法都是抽象方法,接口中的所有方法都设有方法体。Java语言每个语言每个类可以实现多个接口。接口使用interface关键字进行定义,语法如下: public interface Paintable{
void draw(); //定义接口方法可省略public abstract关键字
} public:修饰符。
interface:定义接口关键字
Paintable:接口名称
void draw(); //定义接口方法可省略public abstract关键字
} public:修饰符。
interface:定义接口关键字
Paintable:接口名称
interface Paintable{ //可绘制接口
public void draw(); //绘制抽象方法
}
class Quadrangle6{
public void doAnything() {
System.out.println("四边形提供的方法");
}
}
//平行四边形类,继承四边形类,并实现了可绘制接口
class Parallelogram extends Quadrangle6 implements Paintable{
public void draw() {
System.out.println("绘制平行四边形");
}
}
//正方形类,继承四边形类,并实现了可绘制接口
class Square5 extends Quadrangle6 implements Paintable{
public void draw() {
System.out.println("绘制正方形");
}
}
//圆形类,仅实现了可绘制接口
class Circular2 implements Paintable{
public void draw() {
System.out.println("绘制圆形");
}
}
public class Demo7 {
public static void main(String[]args) {
Square5 s = new Square5();
s.draw();
s.doAnything();
Parallelogram p = new Parallelogram();
p.draw();
p.doAnything();
Circular2 c = new Circular2();
c.draw();
}
}
public void draw(); //绘制抽象方法
}
class Quadrangle6{
public void doAnything() {
System.out.println("四边形提供的方法");
}
}
//平行四边形类,继承四边形类,并实现了可绘制接口
class Parallelogram extends Quadrangle6 implements Paintable{
public void draw() {
System.out.println("绘制平行四边形");
}
}
//正方形类,继承四边形类,并实现了可绘制接口
class Square5 extends Quadrangle6 implements Paintable{
public void draw() {
System.out.println("绘制正方形");
}
}
//圆形类,仅实现了可绘制接口
class Circular2 implements Paintable{
public void draw() {
System.out.println("绘制圆形");
}
}
public class Demo7 {
public static void main(String[]args) {
Square5 s = new Square5();
s.draw();
s.doAnything();
Parallelogram p = new Parallelogram();
p.draw();
p.doAnything();
Circular2 c = new Circular2();
c.draw();
}
}
Java中不允许出现多重继承,但使用接口就可以实现多重继承。一个类可以同时实现多个接口,因此可以将所有需要继承的接口放置在implement关键字后并使用逗号隔开。实现多个接口的语法如下:
class 类名 implement 接口1,接口2,····,接口n
但这可能会在一个类中产生庞大的代码量,因为继承一个接口时需要实现接口中所有的方法。一个接口可以继承另一个接口,语法如下:
interface intf1{}
interface intf2 extendsintf1{} //接口继承接口
class 类名 implement 接口1,接口2,····,接口n
但这可能会在一个类中产生庞大的代码量,因为继承一个接口时需要实现接口中所有的方法。一个接口可以继承另一个接口,语法如下:
interface intf1{}
interface intf2 extendsintf1{} //接口继承接口
八、包和内部类
8.1 Java类包
8.1.1 类名冲突
Java中每个接口或类都来自不同的类包,无论是Java API中的类与接口,都需要隶属于某一个类包,这个类包包含了一些类和接口。如果没有包存在,管理程序中的类名称将是一件麻烦的事情。为了避免类名重叠的问题,则需创建新的类。
8.1.2 完整的类路径
一个完整的类名需要包名和类名的组合,每个类都隶属一个类包,只要保证同一类包的类不同名,就可以有效避免同名类冲突的情况。
8.1.3 创建包
(1)在项目的src节点上右击,选择“新建”/“包”命令(英文为New/Package)。
(2)弹出“新建Java包”(New java Package)对话框,在“名称”(Name)文本框中输入新建的包名,然后单击“完成”(Finish)按钮。
(3)在Eclipse中创建类时,可以在新建立的包上右击,选择“新建”(New)命令,这样新建的类会默认保存在该包中。另外也可以在New Java Class对话框中指定新建类的所在包。
在Java中包含设计应与文件系统结构相对应。没有定义包的类会被归纳在默认包(defaul package)中。在类中定义包名的语法为:**package 包名**
(2)弹出“新建Java包”(New java Package)对话框,在“名称”(Name)文本框中输入新建的包名,然后单击“完成”(Finish)按钮。
(3)在Eclipse中创建类时,可以在新建立的包上右击,选择“新建”(New)命令,这样新建的类会默认保存在该包中。另外也可以在New Java Class对话框中指定新建类的所在包。
在Java中包含设计应与文件系统结构相对应。没有定义包的类会被归纳在默认包(defaul package)中。在类中定义包名的语法为:**package 包名**
创建自定义Math类 package com.mr; //指定包名
public class Math {
public static void main(String[] args) {
System.out.println("不是java.lang.Math类,而是com.mr.Math 类");
}
}
public class Math {
public static void main(String[] args) {
System.out.println("不是java.lang.Math类,而是com.mr.Math 类");
}
}
8.1.4 导入包
1.使用import关键字导入包语法如下:
**import com.mr.*; // 导入com.mr包中的所有类。** **import com.mr/Math //导入com.mr包中的Math类**
2.使用import导入静态成员语法:import static 静态成员
**import com.mr.*; // 导入com.mr包中的所有类。** **import com.mr/Math //导入com.mr包中的Math类**
2.使用import导入静态成员语法:import static 静态成员
使用Import导入静态成员 package com.mr;
import static java.lang.Math.max; //导入静态成员方法
import static java.lang.System.out; //导入静态成员变量
public class ImportTest {
public static void main(String[] args) {
out.println("1和4的较大值为:"+ max(1,4));
}
}
import static java.lang.Math.max; //导入静态成员方法
import static java.lang.System.out; //导入静态成员变量
public class ImportTest {
public static void main(String[] args) {
out.println("1和4的较大值为:"+ max(1,4));
}
}
8.2 内部类
在一个文件中定义两个类,则其中任何一个类都不在另一个类的内部,如果在类中再定义一个类,则将在类中再定义的那个类称为内部类。
1.成员内部类简介
在一个类中使用内部类,可以在内部类中直接存取其所在类的语法如下:
class OuterClass{
class InnerClass{
}
}
class OuterClass{
class InnerClass{
}
}
使用成员内部类模拟发动机点火 public class Car {
//成员变量
private String brand;
//构造方法
public Car(String brand) {
this.brand = brand;
}
//成员方法
//成员内部类(发动机类)
class Engine{
String model;
private String brand;
public Engine(String model) {
this.model = model;
}
public void ignite() {//点火方法
System.out.println("发动机"+ this.model +"点火");
}
}
public void start() {//启动汽车方法
System.out.println("启动" + this.brand);
}
public static void main(String[] args) {
Car car = new Car("大众郎行");//创建汽车对象并为汽车品牌赋值
car.start(); //汽车类对象调用启动汽车方法
//创建内部类对象,并为发动机型号赋值
Car.Engine engine = car.new Engine("EA211");
engine.ignite();//发动机类对象调用点火方法
}
}
//成员变量
private String brand;
//构造方法
public Car(String brand) {
this.brand = brand;
}
//成员方法
//成员内部类(发动机类)
class Engine{
String model;
private String brand;
public Engine(String model) {
this.model = model;
}
public void ignite() {//点火方法
System.out.println("发动机"+ this.model +"点火");
}
}
public void start() {//启动汽车方法
System.out.println("启动" + this.brand);
}
public static void main(String[] args) {
Car car = new Car("大众郎行");//创建汽车对象并为汽车品牌赋值
car.start(); //汽车类对象调用启动汽车方法
//创建内部类对象,并为发动机型号赋值
Car.Engine engine = car.new Engine("EA211");
engine.ignite();//发动机类对象调用点火方法
}
}
成员内部类不止可以在外部类中使用,在其他类中也可以使用。语法如下:
外部类 outer = new 外部类();
外部类.内部类 inner = outer.new 内部类();
注意:(1)如果在外部类和非静态方法之外实例化内部类对象,需要使用“外部类.内部类”的形式指定该对象的类型。
(2)内部类对象会依赖于外部类对象,除非已经存在一个外部类对象,否则类中不会出现内部类对象。
外部类 outer = new 外部类();
外部类.内部类 inner = outer.new 内部类();
注意:(1)如果在外部类和非静态方法之外实例化内部类对象,需要使用“外部类.内部类”的形式指定该对象的类型。
(2)内部类对象会依赖于外部类对象,除非已经存在一个外部类对象,否则类中不会出现内部类对象。
2、使用this关键字获取内部类与外部类的引用
如果在外部类中定义的成员变量与内部类的成员变量名称相同,可以使用this关键字。
在内部类中调用外部类对象 public class TheSameName {
private int x = 7;
private class lnnre{
private int x = 9;
public void doit() {
int x = 11;
x++;
this.x++;
TheSameName.this.x++;
}
}
}
private int x = 7;
private class lnnre{
private int x = 9;
public void doit() {
int x = 11;
x++;
this.x++;
TheSameName.this.x++;
}
}
}
3、匿名内部类
匿名类是只在创建对象时才会编写类体的一种写法。匿名类的特点是“现写现用”,其语法如下:
new 父类/父类口(){
子类实现的内容
};
new 父类/父类口(){
子类实现的内容
};
使用匿名内部类创建一个抽象狗类的对象 abstract class Dog{//抽象类
String color;
public abstract void call();//抽象方法
public abstract void move();//抽象方法
}
public class Demo {
public static void main(String[] args) {
// TODO Auto-generated method stub
Dog wenin = new Dog() {
//匿名内部类
public void move(){
System.out.println("四腿狂奔");
}
public void call() {
System.out.println("汪汪汪");
}
};
wenin.color = "灰色";
wenin.move();
wenin.call();
}
}
String color;
public abstract void call();//抽象方法
public abstract void move();//抽象方法
}
public class Demo {
public static void main(String[] args) {
// TODO Auto-generated method stub
Dog wenin = new Dog() {
//匿名内部类
public void move(){
System.out.println("四腿狂奔");
}
public void call() {
System.out.println("汪汪汪");
}
};
wenin.color = "灰色";
wenin.move();
wenin.call();
}
}
使用匿名类时应该遵循以下原则:
1、匿名类不能写构造方法。
2、匿名类不能定义静态的成员。
3、如果匿名类创建的对象没有赋值给任何应用变量,会导致该对象用完一次就会被Java虚拟机销毁。
1、匿名类不能写构造方法。
2、匿名类不能定义静态的成员。
3、如果匿名类创建的对象没有赋值给任何应用变量,会导致该对象用完一次就会被Java虚拟机销毁。
九、异常处理
9.1 异常概述
在程序中,异常可能是由程序员没有预料到的各种情况产生,也可能由超出了程序员可控范围的环境因素产生。异常是一个程序执行期间发生的事件,它中断了正在执行的程序的正常指令流。
例 9.1 0可以作为除数吗? public class Baulk { //创建类Baulk
public static void main(String[] args) { //主方法
int result = 3/0; //定义int型变量并赋值
System.out.println(result); //将变量输出
}
}
public static void main(String[] args) { //主方法
int result = 3/0; //定义int型变量并赋值
System.out.println(result); //将变量输出
}
}
程序运行的结果报告发生了算术异常ArithmeticException,系统不再执行下去,提前结束。这种情况就是所说的异常
9.2 异常的抛出与捕捉
为了保证程序有效地执行,需要抛出的异常进行相应的处理。
9.2.1 抛出异常
异常抛出后,如果不做·任何处理,程序就会被终止。
例9.2 控制台输出“lili年龄是:20L” public class Thunderiing { //创建类
public static void main(String[] args) {//主方法
String str = "lili"; //定义字符串
System.out.println(str+"年龄是:"); //输出的提示信息
int age = Integer.parseInt("20L"); //数据类型的转换
System.out.println(age); //输出信息
}
}
public static void main(String[] args) {//主方法
String str = "lili"; //定义字符串
System.out.println(str+"年龄是:"); //输出的提示信息
int age = Integer.parseInt("20L"); //数据类型的转换
System.out.println(age); //输出信息
}
}
结果可以看出,报出的是NumberFormatException异常。提示信息“lili年龄是”已经输出,可知该句代码之前并没有异常,而变量age没有输出,可知程序在执行类型代码转换代码时已经终止。
9.2.2 捕捉异常
Java语言的异常捕获结构由try、catch和finally 3部分组成·。其中,try语句块存放的是可能发生异常的Java语句:catch语句块在try语句块之后,用来激发被捕获的异常;finally语句块是异常处理结构的最后执行部分,无论try语句块中的代码如何退出都会执行finally语句块。语法如下: try{
//程序代码块
}
catch(Exceptiontype1 e){
//对Exceptiontype1的处理
}
catch(Exceptiontype2 e){
//对Exceptiontype2的处理
}
……
finally {
//程序代码块
}
//程序代码块
}
catch(Exceptiontype1 e){
//对Exceptiontype1的处理
}
catch(Exceptiontype2 e){
//对Exceptiontype2的处理
}
……
finally {
//程序代码块
}
1.try-catch语句块
例 9.3 捕获例9.2中主方法抛出的异常 public class Take { //创造类
public static void main(String[] args) {
try { //try语句块中包含可能出现异常的程序代码
String str = "lili"; //定义字符串变量
System.out.println(str+"年龄是: ");//输出的信息
int age = Integer.parseInt("20L");//数据类型转换
System.out.println(age);
}catch(Exception e) { //catch语句块用来获取异常信息
e.printStackTrace(); //输出异常性质
}
System.out.println("program over");//输出信息
}
}
public static void main(String[] args) {
try { //try语句块中包含可能出现异常的程序代码
String str = "lili"; //定义字符串变量
System.out.println(str+"年龄是: ");//输出的信息
int age = Integer.parseInt("20L");//数据类型转换
System.out.println(age);
}catch(Exception e) { //catch语句块用来获取异常信息
e.printStackTrace(); //输出异常性质
}
System.out.println("program over");//输出信息
}
}
从结果可以看出,程序仍然输出最后的提示信息,没有因为异常终止。在上例题中,将可能出现的异常代码用try-catch语句块处理,当try语句块中的语句发生异常时,程序就会跳转到catch语句块执行。执行完catch语句块中的程序代码后,将继续执行catch语句块后的其他代码,而不会执行try语句块中发生异常语句后面的代码。Java的异常处理是结构化的,不会因为一个异常影响整个程序的执行。
2.finally 语句块
完整的异常处理语句一定要包含finally语句,无论程序有无异常发生,并且无论之前的try-catch语句块是否顺利执行完毕,都会执行finally语句。但是,在一下4中特殊情况下,finally块不会被执行: 1、在finally语句块中发生了异常
2、在前面的代码中使用了System.exit()退出程序
3、程序所在的线程死亡
4、关闭CPU。
2、在前面的代码中使用了System.exit()退出程序
3、程序所在的线程死亡
4、关闭CPU。
9.3 Java常见的异常类
9.4 自定义异常
在程序中使用自定义异常类,大体可分为以下几个步骤:
1、创建自定义异常类
2、在方法中通过throw关键字抛出异常对象
3、如果在当前抛出异常的方法中处理异常,可以使用try-catch语句捕获并处理,否则在方法的声明处通过throws关键字指明要抛出给方法调用者异常,继续进行下一步操作。
4、在出现异常的方法的调用者中捕获并处理异常。
1、创建自定义异常类
2、在方法中通过throw关键字抛出异常对象
3、如果在当前抛出异常的方法中处理异常,可以使用try-catch语句捕获并处理,否则在方法的声明处通过throws关键字指明要抛出给方法调用者异常,继续进行下一步操作。
4、在出现异常的方法的调用者中捕获并处理异常。
例9.4 如何创建自定义异常 public class MyException extends Exception{ //创建自定义异常,继承Exception类
public MyException(String ErrorMessage) {//构造方法
super(ErrorMessage);//父类构造方法
}
}
public MyException(String ErrorMessage) {//构造方法
super(ErrorMessage);//父类构造方法
}
}
例9.5 自定义异常的抛出与捕捉 public class Tran { //创建类
static int avg(int number1,int number2)throws MyException{ //定义方法,抛出异常
if(number1 < 0||number2<0) { //判断方法中参数是否满足指定条件
throw new MyException("不可以使用负数"); //错误信息
}
if(number1>100||number2>100) { //判断方法中参数是否满足指定条件
throw new MyException("数值太大了"); //错误信息
}
return (number1 + number2)/2; //将参数的平均值返回
}
public static void main(String[] args) { //主方法
try { //try语句块处理可能出现异常的代码
int result = avg(102,150); //调用avg()方法
System.out.println(result); //将avg()方法返回值输出
}catch(MyException e) {
System.out.println(e); //输出异常信息
}
}
static int avg(int number1,int number2)throws MyException{ //定义方法,抛出异常
if(number1 < 0||number2<0) { //判断方法中参数是否满足指定条件
throw new MyException("不可以使用负数"); //错误信息
}
if(number1>100||number2>100) { //判断方法中参数是否满足指定条件
throw new MyException("数值太大了"); //错误信息
}
return (number1 + number2)/2; //将参数的平均值返回
}
public static void main(String[] args) { //主方法
try { //try语句块处理可能出现异常的代码
int result = avg(102,150); //调用avg()方法
System.out.println(result); //将avg()方法返回值输出
}catch(MyException e) {
System.out.println(e); //输出异常信息
}
}
9.5 在方法中抛出异常
9.5.1 使用throws关键字抛出异常
throws关键字通常被应用在声明方法时,用来指定方法可能抛出的异常。多个异常可使用逗号分隔。
例 9.6 指明异常起源于何处 public class Shoot { //创建类
static void pop()throws NegativeArraySizeException{
//定义方法并抛出NegativeArraySizeException异常
int[]arr = new int[-3]; //创建数组
}
public static void main(String[] args) { //主方法
try { //try语句处理异常信息
pop(); //调用pop()方法
}catch(NegativeArraySizeException e) {
System.out.println("pop()方法抛出的异常"); //输出异常信息
}
}
}
static void pop()throws NegativeArraySizeException{
//定义方法并抛出NegativeArraySizeException异常
int[]arr = new int[-3]; //创建数组
}
public static void main(String[] args) { //主方法
try { //try语句处理异常信息
pop(); //调用pop()方法
}catch(NegativeArraySizeException e) {
System.out.println("pop()方法抛出的异常"); //输出异常信息
}
}
}
如结果所示,使用throws关键字将异常抛给上一级后,如果不想处理异常,可以继续向上抛出,但最终要有能够处理该异常的代码。
9.5.2 使用throw关键字抛出异常
throw关键字通常用于方法体中,并且抛出一个异常对象。程序在执行到throw语句时立即终止,它后面的语句都不执行。通过throw抛出异常后,如果想在上一级代码中捕获并处理异常,则需要在抛出异常的方法中使用throws关键字在方法的声明中指明要抛出的异常;如果要捕捉throw抛出的异常,则必须使用try-catch语句块。
例9.7创建自定义异常类 public class MyException extends Exception{ //创建自定义异常类
String message; //定义String类型变量
public MyException(String ErrorMessage) { //父类方法
message = ErrorMessage;
}
public String getMessage() { //覆盖getMessage()方法
return message;
}
}
String message; //定义String类型变量
public MyException(String ErrorMessage) { //父类方法
message = ErrorMessage;
}
public String getMessage() { //覆盖getMessage()方法
return message;
}
}
例 9.8使用throw关键字捕捉自定义异常 public class Captor { //创建类
static int quotient(int x,int y) throws MyException{ //定义方法抛出异常
if(y<0) { //判断参数是否小于0
throw new MyException("除数不能是负数"); //异常信息
}
return x/y; //返回值
}
public static void main(String[] args) { //主方法
try { //try语句块包含可能发生异常的语句
int result = quotient(3,-1); //调用方法quotient()
}catch(MyException e) { //处理自定义异常
System.out.println(e.getMessage()); //输出异常信息
}catch(ArithmeticException e) { //处理ArithmeticException异常
System.out.println("除数不能为0"); //输出提示信息
}catch(Exception e) { //处理其他异常
System.out.println("程序发生了其他异常"); //输出提示信息
}
}
}
static int quotient(int x,int y) throws MyException{ //定义方法抛出异常
if(y<0) { //判断参数是否小于0
throw new MyException("除数不能是负数"); //异常信息
}
return x/y; //返回值
}
public static void main(String[] args) { //主方法
try { //try语句块包含可能发生异常的语句
int result = quotient(3,-1); //调用方法quotient()
}catch(MyException e) { //处理自定义异常
System.out.println(e.getMessage()); //输出异常信息
}catch(ArithmeticException e) { //处理ArithmeticException异常
System.out.println("除数不能为0"); //输出提示信息
}catch(Exception e) { //处理其他异常
System.out.println("程序发生了其他异常"); //输出提示信息
}
}
}
十、字符串
10.1 String 类
10.1.1 声明字符串
在java语言中,字符串必须包含在一对双引号(" ")之内。
在Java中由双引号(" ")包围的都是字符串,不能作为其他数据类型来使用。
可以通过String str;语句来声明字符串变量。String:指定该变量为字符串类型。str:任意有效的标识符,表示字符串变量的名称。
声明的字符串变量必须经过初始化才能使用,否则编译器会报出“变量未被初始化错误”。
在Java中由双引号(" ")包围的都是字符串,不能作为其他数据类型来使用。
可以通过String str;语句来声明字符串变量。String:指定该变量为字符串类型。str:任意有效的标识符,表示字符串变量的名称。
声明的字符串变量必须经过初始化才能使用,否则编译器会报出“变量未被初始化错误”。
10.1.2 创建字符串
在Java语言中,将字符串作为对象来处理,因此可以像创建其他类对象一样来创建字符串对象。创建对象要使用类的构造方法。
10.2 连接字符串
10.2.1 连接多个字符串
使用“+”运算符可实现连接多个字符串的功能。“+”运算符可以连接多个String对象并产生一个新的String对象。
例 10.1先连接一幅对联的上、下联,再分行输出在控制台上 public class Join { //创造类
public static void main(String[] args) { //主方法
String s1 = new String("春风绿千里"); //声明String对象s1
String s2 = new String("马蹄香万家"); //声明String对象s2
String s =s1 +"\n"+s2; //将对象s1、"/n"和对象s2连接并结果赋值给s
System.out.println(s); //将s输出
}
}
public static void main(String[] args) { //主方法
String s1 = new String("春风绿千里"); //声明String对象s1
String s2 = new String("马蹄香万家"); //声明String对象s2
String s =s1 +"\n"+s2; //将对象s1、"/n"和对象s2连接并结果赋值给s
System.out.println(s); //将s输出
}
}
10.2.2 连接其他数据类型
字符串也可同其他基本数据类型进行连接。如果将字符串同其他数据类型数据进行连接,会将其他数据类型的数据直接转换成字符串。
例 10.2 统计每天的阅读和上机时间 public class Link { //创建类
public static void main(String[] args) { //主方法
int booktime = 4; //声明的int型变量booktime
float practice = 2.5f; //声明的float型变量practice
//将字符串与整型、浮点型变量相连,并将结果输出
System.out.println("我每天花费"+booktime+"小时看书;"+practice+"小时上机练习");
}
}
public static void main(String[] args) { //主方法
int booktime = 4; //声明的int型变量booktime
float practice = 2.5f; //声明的float型变量practice
//将字符串与整型、浮点型变量相连,并将结果输出
System.out.println("我每天花费"+booktime+"小时看书;"+practice+"小时上机练习");
}
}
10.3 获取字符串信息
10.3.1 获取字符串长度
使用Sring类型的length()方法可获取声明的字符串对象的长度。语法:str.length();
其中,str为字符串对象
其中,str为字符串对象
10.3.2 字符串查找
1、indexOf(String s)
该方法用于放回参数字符串s在指定字符串中首次出现的索引位置。当调用String类的indexOf()方法时,会从当前字符串的开始位置搜索s的位置。如果没有检索到字符串s,该方法的返回值是-1。
语法:indexOf(substr)
str:任意字符串对象。
substr:要搜索的字符串。
语法:indexOf(substr)
str:任意字符串对象。
substr:要搜索的字符串。
2、lastlndexOf(String str)
该方法用于指定字符串最后一次出现的索引位置。当调用String类的lastlndexOf()方法时,会从当前字符串的开始位置检索参数字符串str,并将最后一次出现str的索引位置返回。如果没有检索到字符串str,该方法返回-1。语法:str.lastIndexOf(substr)
str:任意字符串
substr:要搜索的字符串
str:任意字符串
substr:要搜索的字符串
例3:用两种方式判断字符串的长度 public class Text { //创造类
public static void main(String[] args) { //主方法
String str = "We are students"; //定义字符串str
int size = str.lastIndexOf(""); //将空字符串在str中的索引位置赋值给变量size
System.out.println("空字符串在字符串str中的索引位置是:"+size); //将变量size输出
System.out.println("字符串str的长度是:"+str.length()); //将字符串str的长度输出
}
}
public static void main(String[] args) { //主方法
String str = "We are students"; //定义字符串str
int size = str.lastIndexOf(""); //将空字符串在str中的索引位置赋值给变量size
System.out.println("空字符串在字符串str中的索引位置是:"+size); //将变量size输出
System.out.println("字符串str的长度是:"+str.length()); //将字符串str的长度输出
}
}
10.3.3 获取指定索引位置的字符
使用charAt()方法可将指定索引处的字符返回。语法如下:
str:
任意字符串。
index:
整型值,用于指定要返回字符的下标。
str:
任意字符串。
index:
整型值,用于指定要返回字符的下标。
例4:查看指定索引位置上的字符 public class Ref { //创造类
public static void main(String[] args) { //主方法
String str = "hello world"; //定义字符串str
char mychar = str.charAt(6); //将字符串str中索引位置6的字符返回
System.out.println("字符串str中索引位置是6的字符为:"+mychar); //输出信息
}
}
public static void main(String[] args) { //主方法
String str = "hello world"; //定义字符串str
char mychar = str.charAt(6); //将字符串str中索引位置6的字符返回
System.out.println("字符串str中索引位置是6的字符为:"+mychar); //输出信息
}
}
10.4 字符串操作
10.4.1 获取子字符串
通过String类的substring()方法可对字符串进行截取。substring()方法被两种不同的重载形式,来满足不同的需要。这些形式的共同点就是都利用字符串的下标进行截取,且应明确字符串下标是从0开始的。
1.substring(int beginlndex)
该方法返回的是从指定的索引位置开始截取直到该字符串结尾的子串。语法如下:
str.substring(int beginlndex)
其中,beginlndex指定从某一索引处开始截取字符串。
str.substring(int beginlndex)
其中,beginlndex指定从某一索引处开始截取字符串。
2.substring(int beginlndex,int endlndex)
该方法返回的是从字符串某一索引位置开始截取至某一索引位置结束的子串,代码如下:
substring(int beginlndex,int endlndex)
beginlndex:开始截取子字符串的索引位置。
endlndex:子字符串在整个字符串中的结束位置。
substring(int beginlndex,int endlndex)
beginlndex:开始截取子字符串的索引位置。
endlndex:子字符串在整个字符串中的结束位置。
例5:《将进酒》的作者是哪位诗人? public class Subs { //创建类
public static void main(String[] args) { //主方法
String str = "《将进酒》:李白(唐)"; //定义字符串
String substr = str.substring(6,8); //对字符串进行截取
System.out.println("《将进酒》的作者是"+substr); //输出截取后的字符串
}
}
public static void main(String[] args) { //主方法
String str = "《将进酒》:李白(唐)"; //定义字符串
String substr = str.substring(6,8); //对字符串进行截取
System.out.println("《将进酒》的作者是"+substr); //输出截取后的字符串
}
}
10.4.2 去除空格
trim()方法返回字符串的副本,忽略前导空格和尾部空格。语法如下:
str.trim
其中,str为任何字符串对象。
str.trim
其中,str为任何字符串对象。
例6:去掉字符首、尾的空格 public class Blak { //创建类
public static void main(String[] args) { //主方法
String str = " java class "; //定义字符串str
System.out.println("字符串原来的长度:"+str.length()); //将str原来的长度输出
System.out.println("去掉空格后的长度:"+str.trim().length());
}
}
public static void main(String[] args) { //主方法
String str = " java class "; //定义字符串str
System.out.println("字符串原来的长度:"+str.length()); //将str原来的长度输出
System.out.println("去掉空格后的长度:"+str.trim().length());
}
}
10.4.3 字符串替换
replace()方法可实现将指定的字符或字符串替换成新的字符或字符串。
语法:str.replace(CharSequence target,CharSequence replacement)
1.targt: 要替换的字符或字符串。
2.replacement:用于替换原来字符串的内容。
replace()方法返回的结果是一个新的字符串。如果字符或字符串 oldChar 没有出现在该对象表达式中的字符串序列中,则将原字符串返回。
语法:str.replace(CharSequence target,CharSequence replacement)
1.targt: 要替换的字符或字符串。
2.replacement:用于替换原来字符串的内容。
replace()方法返回的结果是一个新的字符串。如果字符或字符串 oldChar 没有出现在该对象表达式中的字符串序列中,则将原字符串返回。
例7:将单词中的字母a替换为字母A public class NewStr { //创建类
public static void main(String[] args) { //主方法
String str = "address"; //定义字符串str
String newstr = str.replace("a", "A"); //将str中"a"替换成"A"并返回新字符串newstr
System.out.println(newstr); //将字符串newstr输出
}
}
public static void main(String[] args) { //主方法
String str = "address"; //定义字符串str
String newstr = str.replace("a", "A"); //将str中"a"替换成"A"并返回新字符串newstr
System.out.println(newstr); //将字符串newstr输出
}
}
10.4.4.判断字符串的开始和结尾
startsWith()方法与endsWith()方法分别用于判断字符串是否以指定的内容开始或结束。这两个方法的返回值都为boolean类型。
1.startsWith()方法
该方法用于判断当前字符串对象的前缀是否为参数指定的字符串。语法:str.startsWith(String prefix)
其中,prefix是指作为前缀的字符串。
其中,prefix是指作为前缀的字符串。
2.endsWith()方法
该方法用于判断当前字符串是否为给定的子字符串。语法:str.endsWith(String suffix)
其中,suffix是指作为后缀的字符串。
其中,suffix是指作为后缀的字符串。
例8:判断字符串是否以指定的内容开始或结束 public class StartOrEnd { //创造类
public static void main(String[] args) { //主方法
String num1 = "22045612"; //定义字符串num1
String num2 = "21304578"; //定义字符串num2
boolean b = num1.startsWith("22"); //判断字符串num1是否以‘22’开头
boolean b2 = num2.endsWith("78"); //判断字符串num2是否以‘78‘结束
System.out.println("字符串num1是以'22'开始的吗?"+b);
System.out.println("字符串num2是以'78'结束的吗?"+b2); //输出信息
}
}
public static void main(String[] args) { //主方法
String num1 = "22045612"; //定义字符串num1
String num2 = "21304578"; //定义字符串num2
boolean b = num1.startsWith("22"); //判断字符串num1是否以‘22’开头
boolean b2 = num2.endsWith("78"); //判断字符串num2是否以‘78‘结束
System.out.println("字符串num1是以'22'开始的吗?"+b);
System.out.println("字符串num2是以'78'结束的吗?"+b2); //输出信息
}
}
10.4.5.判断字符串是否相等
对字符串对象进行比较不能简单地使用比较运算符“==”,因为比较运算符比较的是两个字符串的地址是否相同。即使两个字符串的内容相同,两个对象的内存地址也是不同的,使用两个字符串的内容相同,两个对象的内存地址也是不同的,使用比较运算符仍然会返回false。
此时,布尔型变量b的值为false,因为字符串是对象,tom、jerry是引用。
因此,要比较两个字符串内容是否相等,应使用equals()方法和equalsIgnoreCase()方法。
A版权协议,转载请附上原文出处链接及本声明。
此时,布尔型变量b的值为false,因为字符串是对象,tom、jerry是引用。
因此,要比较两个字符串内容是否相等,应使用equals()方法和equalsIgnoreCase()方法。
A版权协议,转载请附上原文出处链接及本声明。
1.equals()方法
如果两个字符串具有相同的字符和长度,则使用equals()方法进行比较时,返回true。否则返回false。
语法:str.equals(String otherstr)
其中,str、otherstr是要比较的两个字符串对象。
语法:str.equals(String otherstr)
其中,str、otherstr是要比较的两个字符串对象。
2.equalsLgnoreCase()方法
使用equals()方法对字符串进行比较时是否分大小写的,而使用equalsLgnoreCase()方法是在忽略了大小写的情况下比较两个字符串是否相等,返回结果仍为boolean类型。语法如下:
str.equalsLgnoreCase(String otherstr)
其他,str、otherstr是要比较的两个字符串对象。
str.equalsLgnoreCase(String otherstr)
其他,str、otherstr是要比较的两个字符串对象。
例9:判断“abc”与“ABC”是否相等 public class Opinion { //创造类
public static void main(String[] args) { //主方法
String s1 = new String("abc"); //创建字符串对象s1
String s2 = new String("ABC"); //创建字符串对象s2
boolean b = s1.equals(s2); //使用equals()方法比较s1与s2
boolean b2 = s1.equalsIgnoreCase(s2); //使用equalsIgnoreCase()方法比较s1与s2
System.out.println(s1+ " equals " +s2 +":"+ b); //输出信息
System.out.println(s1+ " equalsIgnoreCas "+s2+":"+b2);
}
}
public static void main(String[] args) { //主方法
String s1 = new String("abc"); //创建字符串对象s1
String s2 = new String("ABC"); //创建字符串对象s2
boolean b = s1.equals(s2); //使用equals()方法比较s1与s2
boolean b2 = s1.equalsIgnoreCase(s2); //使用equalsIgnoreCase()方法比较s1与s2
System.out.println(s1+ " equals " +s2 +":"+ b); //输出信息
System.out.println(s1+ " equalsIgnoreCas "+s2+":"+b2);
}
}
10.4.6.按字典顺序比较两个字符串
compareTo()方法为按字典顺序比较两个字符串,该比较基于字符串中各个字符的Unicode值,按字典顺序将String对象表示的字符序列与参数字符串所表示的字符序列进行比较。如果按字典顺序此String对象位于参数字符串之前,则比较结果为一个负整数;如果按字典顺序此String对象位于参数字符串之后,则比较结果为一个正整数;如果这两个字符串相等,则结果为0。语法如下:
str.compareTo(String otherstr)
其中,str、otherstr是要比较的两个字符串对象。
str.compareTo(String otherstr)
其中,str、otherstr是要比较的两个字符串对象。
例10:判断字母b的位置 public class Wordbook { //创造类
public static void main(String[] args) { //主方法
String str = new String("b"); //用于比较的3个字符串
String str2 = new String("a");
String str3 = new String("c");
System.out.println(str + " compareTo " + str2 +":"+str.compareTo(str2));
//将str与str2比较的结果输出
System.out.println(str + " compareTo " + str3 +":"+str.compareTo(str3));
//将str与str3比较的结果输出
}
}
public static void main(String[] args) { //主方法
String str = new String("b"); //用于比较的3个字符串
String str2 = new String("a");
String str3 = new String("c");
System.out.println(str + " compareTo " + str2 +":"+str.compareTo(str2));
//将str与str2比较的结果输出
System.out.println(str + " compareTo " + str3 +":"+str.compareTo(str3));
//将str与str3比较的结果输出
}
}
10.4.7.字母大小写转换
String类的toLowerCase()方法可将字符串中的所有大小字母改写为小写字母,而toUpperCase()方法可将字符串中的所有小写字母改写为大写字母
1.toLowerCase()方法
该方法将字符串中的所有大写字母转换为小写。如果字符串中没有应该被转换的字符,则将原字符串返回;否则将返回一个新的字符串,将原字符串中每个大写字母都转换成小写,字符串长度不变。语法如下:
str.toLowerCase()
其中,str是要进行转换的字符串。
str.toLowerCase()
其中,str是要进行转换的字符串。
2.toUpperCase()方法
该方法将字符串中所有的小写字母转换为大写。如果字符串中没有应该被转换的字符,则将原字符串返回;否则返回一个新字符串,将原字符串中每个小写字母都转换为大写,字符串长度不变,语法如下:
str.toUpperCase()
其中,str是要进行转换的字符串。
str.toUpperCase()
其中,str是要进行转换的字符串。
例11:字母大小写转换 public class UpAndLower { //创造类
public static void main(String[] args) { //主方法
String str = new String("Oh My God"); //创建字符串str
String newstr = str.toLowerCase(); //使用toLowerCase()方法实行小写转换
String newstr2 = str.toUpperCase(); //使用toUpperCase()方法实行大写转换
System.out.println(newstr); //将转换后的结果输出
System.out.println(newstr2);
}
}
public static void main(String[] args) { //主方法
String str = new String("Oh My God"); //创建字符串str
String newstr = str.toLowerCase(); //使用toLowerCase()方法实行小写转换
String newstr2 = str.toUpperCase(); //使用toUpperCase()方法实行大写转换
System.out.println(newstr); //将转换后的结果输出
System.out.println(newstr2);
}
}
10.4.8.字符串分割
使用split()方法可以使字符串按指定的分割字符或字符串进行分割,并将分割后的结果存放在字符串数组中。split()方法提供了以下两种字符串分割形式
1.split(String sign)
该方法可根据给定的分割符对字符串进行拆分。语法:str.split(String sign)
其中,sign 为分割字符串的分割符,也可以使用正则表达式。
其中,sign 为分割字符串的分割符,也可以使用正则表达式。
2.split(String sign,int limit)
该方法可根据给定的分割符对字符串进行拆分,并限定拆分的次数。语法:str.split(String sign,int limit)
sign:分割字符串的分割符,也可以使用正则表达式。
limit: 限制的分割次数。
sign:分割字符串的分割符,也可以使用正则表达式。
limit: 限制的分割次数。
例12:按要求分割“192.168.0.1” public class Division { //创造类
public static void main(String[] args) { //主方法
String str = "192.168.0.1"; //创建字符串
String[] firstArray = str.split("\\."); //按照“.”进行分割,使用转义字符“\\.”
String[] secondArray = str.split("\\.",2); //按照“.”进行再次分割,使用转义字符“\\.”
System.out.println("str的原值为:["+ str +"]"); //输出str原值
System.out.print("全部分割的结果:"); //输出全部分割的结果
for(String a:firstArray) {
System.out.print("["+a+"]");
}
System.out.println(); //换行
System.out.print("分割两次的结果:"); //输出分割两次的结果
for(String a:secondArray) {
System.out.print("["+a+"]");
}
System.out.println();
}
}
public static void main(String[] args) { //主方法
String str = "192.168.0.1"; //创建字符串
String[] firstArray = str.split("\\."); //按照“.”进行分割,使用转义字符“\\.”
String[] secondArray = str.split("\\.",2); //按照“.”进行再次分割,使用转义字符“\\.”
System.out.println("str的原值为:["+ str +"]"); //输出str原值
System.out.print("全部分割的结果:"); //输出全部分割的结果
for(String a:firstArray) {
System.out.print("["+a+"]");
}
System.out.println(); //换行
System.out.print("分割两次的结果:"); //输出分割两次的结果
for(String a:secondArray) {
System.out.print("["+a+"]");
}
System.out.println();
}
}
10.5格式化字符串
Sting 类的静态format()方法用于创建格式化的字符串。format()方法有两种重载形式
1…format(String format,Object…args)
该方法使用指定的格式字符串和参数返回一个格式化字符串,格式化后的新字符串使用本地默认的语言环境。语法:str.format(String format,Object…args)
format:格式字符串。
args:格式字符串中由格式说明符引用的参数。如果还有格式说明符以外的参数,则忽略这些额外的参数。此参数的数目是可变的,可以为0。
format:格式字符串。
args:格式字符串中由格式说明符引用的参数。如果还有格式说明符以外的参数,则忽略这些额外的参数。此参数的数目是可变的,可以为0。
2.format(Local l,String format,Object…args)
该方法使用指定的语言环境、格式字符串和参数返回一个格式化字符串,格式化后的新字符串便用其指定的语言环境。语法:str.format(Local l,String format,Object…args)
l:格式化过程中要应用的语言环境。如果1为null,则不进行本地化。
format:格式字符串。
args:格式字符串中由格式说明符引用的参数。如果还有格式说明符以外的参数,则忽略这些额外的参数。此参数的数目是可变的,可以为0。
l:格式化过程中要应用的语言环境。如果1为null,则不进行本地化。
format:格式字符串。
args:格式字符串中由格式说明符引用的参数。如果还有格式说明符以外的参数,则忽略这些额外的参数。此参数的数目是可变的,可以为0。
10.5.1.日期和时间字符串格式化
在应用程序设计中,经常需要显示日期和时间。如果想输出满意的日期和时间格式,一般需要编写大量的代码、经过各种算法才能实现。formatI()方法通过给定的特殊转换符作为参数来实现对日期和时间的格式化。
1.日期格式化
例13:按照格式输出今天的年、月、日 import java.util.Date; //导入java.util.Date类
public class Eval { //新建类
public static void main(String[] args) { //主方法
Date date = new Date(); //创建Date对象date
String year = String.format("%tY",date); //将date进行格式化
String month = String.format("%tB",date);
String day = String.format("%td",date);
System.out.println("今年是:"+year+"年"); //输出信息
System.out.println("现在是:"+month);
System.out.println("今天是:"+day+"号");
}
}
public class Eval { //新建类
public static void main(String[] args) { //主方法
Date date = new Date(); //创建Date对象date
String year = String.format("%tY",date); //将date进行格式化
String month = String.format("%tB",date);
String day = String.format("%td",date);
System.out.println("今年是:"+year+"年"); //输出信息
System.out.println("现在是:"+month);
System.out.println("今天是:"+day+"号");
}
}
2.时间格式化
使用 format()方法不仅可以完成日期的格式化也可以实现时间的格式化。时间的格式化转换符要比日期的格式化转换符更多、更精确,它可以将时间格式化为时、分、秒、毫秒等。
例14:按照格式输出当下的时、分、秒 import java.util.Date; //导入java.util.Date类
public class GetDate { //新建类
public static void main(String[] args) { //主方法
Date date = new Date(); //创建Date对象date
String hour = String.format("%tH",date); //将date进行格式化
String minute = String.format("%tM",date);
String second = String.format("%tS",date);
System.out.println("现在是:"+hour+"时"+minute+"分"+second+"秒");
//输出的信息
}
}
public class GetDate { //新建类
public static void main(String[] args) { //主方法
Date date = new Date(); //创建Date对象date
String hour = String.format("%tH",date); //将date进行格式化
String minute = String.format("%tM",date);
String second = String.format("%tS",date);
System.out.println("现在是:"+hour+"时"+minute+"分"+second+"秒");
//输出的信息
}
}
3.格式化常见的日期时间组合
格式化日期与时间组合的转换符定义了各种日期时间组合式,其中常见的如图所示
例15:按照格式输出当下的年、月、日 import java.util.Date; //导入java.util.Date类
public class DateAndTime { //新建类
public static void main(String[] args) { //主方法
Date date = new Date(); //创建Date对象date
String time = String.format("%tc", date); //将date格式化
String form = String.format("%tF", date);
System.out.println("全部的时间信息是:"+time); //将格式化后的日期时间输出
System.out.println("年-月-日格式:"+form);
}
}
public class DateAndTime { //新建类
public static void main(String[] args) { //主方法
Date date = new Date(); //创建Date对象date
String time = String.format("%tc", date); //将date格式化
String form = String.format("%tF", date);
System.out.println("全部的时间信息是:"+time); //将格式化后的日期时间输出
System.out.println("年-月-日格式:"+form);
}
}
10.5.2.常规类型格式化
常规类型格式化可应用于任何参数类型,可通过表中的转换符来实现。
例16:使用转换符获取表达式的结果 public class General { //新建类
public static void main(String[] args) { //主方法
String str = String.format("%d", 400/2); //将结果以十进制格式显式
String str2 = String.format("%b", 3>5); //将结果以boolean型显式
String str3 = String.format("%x", 200); //将结果以十六进制格式显式
System.out.println("400的一半是:"+str); //输出格式化字符串
System.out.println("3>5正确吗:"+str2);
System.out.println("200的十六进制数是:"+str3);
}
}
public static void main(String[] args) { //主方法
String str = String.format("%d", 400/2); //将结果以十进制格式显式
String str2 = String.format("%b", 3>5); //将结果以boolean型显式
String str3 = String.format("%x", 200); //将结果以十六进制格式显式
System.out.println("400的一半是:"+str); //输出格式化字符串
System.out.println("3>5正确吗:"+str2);
System.out.println("200的十六进制数是:"+str3);
}
}
10.6 使用正则表达式
正则表达式通常被用于判断语句中,用来检查某一字符串是否满足某一格式。正则表达式是含有-些具有特殊意义字符的字符串,这些特殊字符称为正则表达式的元字符。例如,“\d”表示数字0~9中的任何一个,“\d”就是元字符。正则表达式中的元字符及其意义如表中所示。
在正则表达式中,可以使用方括号括起若干个字符来表示一个元字符,该元字特可代表方括号中的任何一个字符。例如,reg ="[abc]4”,这样字符串 a4、b4、c4 都是和正则表达式匹配的字符串,方括号元字符还可以为其他格式。如:
1.[456]: 表 4、5、6之外的任何字符。
2.[a-r]: 代表 a~r中的任何一个字母。
3.[a-zA-Z]: 可表示任意一个英文字母。
4.[a-e[g-z]]: 代表a~e或 g~z中的任何一个字母(并运算)。
5.[a-o&&[def]]: 代表字母 d、e、f (交运算)。
6.[a-d&&[bc]]: 代表字母a、d (差运算)。
1.[456]: 表 4、5、6之外的任何字符。
2.[a-r]: 代表 a~r中的任何一个字母。
3.[a-zA-Z]: 可表示任意一个英文字母。
4.[a-e[g-z]]: 代表a~e或 g~z中的任何一个字母(并运算)。
5.[a-o&&[def]]: 代表字母 d、e、f (交运算)。
6.[a-d&&[bc]]: 代表字母a、d (差运算)。
在正则表达式中允许使用限定修饰符来限定元字符出现的次数。例如:“A*”代表A可在字符串中出现0次或多次。限定修饰符的用法如表所示。
例:17验证E-mail地址是否“合法” public class Judge { //新建类
public static void main(String[] args) { //主方法
String regex = "\\w+@\\w+(\\.\\w{2,3})*\\.\\w{2,3}";
//定义要匹配E-mail地址的正则表达式
String str1 = "aaa@"; //定义要进行验证的字符串
String str2 = "aaaaa";
String str3 = "1111@111ffyu.dfg.com";
if(str1.matches(regex)) {
//判断字符串变量是否与正则表达式匹配
System.out.println(str1+"是一个合法的E-mail地址格式");
}
if(str2.matches(regex)) {
System.out.println(str2+"是一个合法的E-mail地址格式");
}
if(str3.matches(regex)) {
System.out.println(str3+"是一个合法的E-mail地址格式");
}
}
}
public static void main(String[] args) { //主方法
String regex = "\\w+@\\w+(\\.\\w{2,3})*\\.\\w{2,3}";
//定义要匹配E-mail地址的正则表达式
String str1 = "aaa@"; //定义要进行验证的字符串
String str2 = "aaaaa";
String str3 = "1111@111ffyu.dfg.com";
if(str1.matches(regex)) {
//判断字符串变量是否与正则表达式匹配
System.out.println(str1+"是一个合法的E-mail地址格式");
}
if(str2.matches(regex)) {
System.out.println(str2+"是一个合法的E-mail地址格式");
}
if(str3.matches(regex)) {
System.out.println(str3+"是一个合法的E-mail地址格式");
}
}
}
10.7.字符串生成器
创建成功的字符串对象,其长度是固定的,内容不能被改变和编译。虽然使用“+”可以达到附加新字符或字符串的目的,但“+”会产生一个新的 String 实例,会在内存中创建新的字符串对象。如重复地对字符串进行修改,将极大地增加系统开销。而JDK 新增了可变的字符序列 StringBuilder类大大提高了频繁增加字符串的效率。
例18:效率比拼 public class Jerque {
public static void main(String[] args) {
String str="";//创建空字符串
long StarTime=System.currentTimeMillis();//获取字符串执行前的时间
for(int i=0;i<10000;i++) {//循环追加字符串
str=str+i;
}
long endTime=System.currentTimeMillis();//获取字符串执行后的时间
long time=endTime-StarTime;//计算时间差
System.out.println("string消耗的时间:"+time);//输出
StringBuilder builder=new StringBuilder("");//创建字符串生成器
StarTime=System.currentTimeMillis();//获取字符串执行前的时间
for(int j=0;j<10000;j++) {//循环追加字符串
builder.append(j);
}
endTime=System.currentTimeMillis();//获取字符串执行后的时间
time=endTime-StarTime;//计算时间差
System.out.println("stringBuilder消耗的时间:"+time);//输出
}
}
public static void main(String[] args) {
String str="";//创建空字符串
long StarTime=System.currentTimeMillis();//获取字符串执行前的时间
for(int i=0;i<10000;i++) {//循环追加字符串
str=str+i;
}
long endTime=System.currentTimeMillis();//获取字符串执行后的时间
long time=endTime-StarTime;//计算时间差
System.out.println("string消耗的时间:"+time);//输出
StringBuilder builder=new StringBuilder("");//创建字符串生成器
StarTime=System.currentTimeMillis();//获取字符串执行前的时间
for(int j=0;j<10000;j++) {//循环追加字符串
builder.append(j);
}
endTime=System.currentTimeMillis();//获取字符串执行后的时间
time=endTime-StarTime;//计算时间差
System.out.println("stringBuilder消耗的时间:"+time);//输出
}
}
1.append()方法
该方法用于向字符串生成器中追加内容。通过该方法的多个重载形式,可实现接受任何类型的数据,如int、boolean、char、String、double 或者另一个字符串生成器等。语法如下:
append(comtemt)
其中,content表示要追加到字符串生成器中的内容,可以是任何类型的数据或者其他对象。
append(comtemt)
其中,content表示要追加到字符串生成器中的内容,可以是任何类型的数据或者其他对象。
2.insert(int offset, arg)方法
该方法用于向字符串生成器中的指定位置插入数据内容。通过该方法的不同重载形式,可实现向字符串生成器中插入int、float、char 和 boolean 等基本数据类型的数据或其他对象。语法如下:
insert(int offset, arg)
ofset:字符串生成器的位置。该参数必须大于等于0,且小于等于此序列的长度。
arg:将插入至字符串生成器的位置。该参数可以是任何数据类型的数据或其他对象。
协议,转载请附上原文出处链接及本声明。
insert(int offset, arg)
ofset:字符串生成器的位置。该参数必须大于等于0,且小于等于此序列的长度。
arg:将插入至字符串生成器的位置。该参数可以是任何数据类型的数据或其他对象。
协议,转载请附上原文出处链接及本声明。
3.delete(int start , int end)方法
移除此序列的子字符串中的字符。该子字符串从指定的 stat 处开始,一直到索引 end-1 处的字符如果不存在这种字符,则一直到序列尾部。如果 start 等于 end,则不发生任何更改。语法如下:
delete(int start , int end)
1.start: 将要删除的字符串的起点位置。
2. end:将要删除的字符串的终点位置。
移除此序列的子字符串中的字符。该子字符串从指定的 stat 处开始,一直到索引 end-1 处的字符如果不存在这种字符,则一直到序列尾部。如果 start 等于 end,则不发生任何更改。语法如下:
delete(int start , int end)
1.start: 将要删除的字符串的起点位置。
2. end:将要删除的字符串的终点位置。
十一、常用类库
Java 是一种面向对象语言,Java 中的类把方法与数据连接在一起,构成了自包含式的处理单元。为了提升Java 程序的开发效率,Java 的类包中提供了很多常用类以方便开发人员使用。正所谓,术业有专攻,在常用类中主要包含可以将基本数据类型封装起来的包装类、解决常见数学问题的 Math 类、成随机数的 Random类,以及处理日期时间的相关类等。
11.1 包装类
Java 是一种面向对象语言,但在 Java 中不能定义基本数据类型的对象,为了能将基本数据类型视为对象进行处理,Java 提出了包装类的概念,它主要是将基本数据类型封装在包装类中,如 int 型的包装类Integer、boolean型的包装类 Boolean等,这样便可以把这些基本数据类型转换为对象进行处理Java中的包装类及其对应的基本数据类型
11.1.1.Integer类
ava.lang 包中的 Integer 类、Byte 类、Short 类和 Long 类,分别将基本数据类型 int、byte、short和 long 封装成一个类,由于这些类都是 Number 类的子类,区别就是封装不同的数据类型,其包含方法基本相同,所以本节以Integer 类为例讲解整数包装类。
nteger 类在对象中包装了一个基本数据类型 int 的值,该类的对象包含一个 int 类型的字段。此外该类提供了多个方法,能在 int 类型和 String 类型之间互相转换,同时还提供了其他一些处理 int 类时非常有用的常量和方法。Integer 类的常用方法如表:
nteger 类在对象中包装了一个基本数据类型 int 的值,该类的对象包含一个 int 类型的字段。此外该类提供了多个方法,能在 int 类型和 String 类型之间互相转换,同时还提供了其他一些处理 int 类时非常有用的常量和方法。Integer 类的常用方法如表:
例1:Integer类的常用方法 public class IntegerDome {
public static void main(String[]args) {
int num = Integer.parseInt("456");//将字符串转换为int类型
Integer iNum = Integer.valueOf("456");//创建一个Integer对象
System.out.println("int数据与Integer对象的比较:"+iNum.equals(num));
String str2 = Integer.toBinaryString(num);//获取数字的二进制表示
String str3 = Integer.toHexString(num);//获取数字的十六进制表示
String str4 = Integer.toOctalString(num);//获取数字的八进制表示
String str5 = Integer.toString(num,15);//获取数字的十五进制表示
System.out.println("456的二进制表示为:"+str2);//输出
System.out.println("456的十六进制表示为:"+str3);
System.out.println("456的八进制表示为:"+str4);
System.out.println("456的十五进制表示为:"+str5);
}
}
public static void main(String[]args) {
int num = Integer.parseInt("456");//将字符串转换为int类型
Integer iNum = Integer.valueOf("456");//创建一个Integer对象
System.out.println("int数据与Integer对象的比较:"+iNum.equals(num));
String str2 = Integer.toBinaryString(num);//获取数字的二进制表示
String str3 = Integer.toHexString(num);//获取数字的十六进制表示
String str4 = Integer.toOctalString(num);//获取数字的八进制表示
String str5 = Integer.toString(num,15);//获取数字的十五进制表示
System.out.println("456的二进制表示为:"+str2);//输出
System.out.println("456的十六进制表示为:"+str3);
System.out.println("456的八进制表示为:"+str4);
System.out.println("456的十五进制表示为:"+str5);
}
}
Integer 类提供了以下4个常量:
1、MAX_VALUE:表示int 类型可取的最大值,即2(31次方)-1。
2、MIN_VALUE:表示int 类型可取的最小值,即-2(31次方)。
3、SIZE:用来以二进制补码形式表示 int 值的位数。
4、TYPE:表示基本类型int的 Class 实例。
1、MAX_VALUE:表示int 类型可取的最大值,即2(31次方)-1。
2、MIN_VALUE:表示int 类型可取的最小值,即-2(31次方)。
3、SIZE:用来以二进制补码形式表示 int 值的位数。
4、TYPE:表示基本类型int的 Class 实例。
例2:查看Integer类的常量值 public class GetCon {
public static void main(String[] args) {
int maxint = Integer.MAX_VALUE;//获取Integer类的常量
int minint = Integer.MIN_VALUE;
int intsize = Integer.SIZE;
System.out.println("int类型可取的最大值:"+maxint);//将常量值
System.out.println("int类型可取的最小值:"+minint);
System.out.println("int类型二进制位数是:"+intsize);
}
}
public static void main(String[] args) {
int maxint = Integer.MAX_VALUE;//获取Integer类的常量
int minint = Integer.MIN_VALUE;
int intsize = Integer.SIZE;
System.out.println("int类型可取的最大值:"+maxint);//将常量值
System.out.println("int类型可取的最小值:"+minint);
System.out.println("int类型二进制位数是:"+intsize);
}
}
11.1.2.Double类
Double类和 Float类是对 double、float 基本类型的封装,它们都是Number 类的子类,都是对浮点数进行操作,所以常用方法基本相同,本节将对 Double 类进行讲解。对于 Float 类,可以参考 Double类的相关内容。
Double类在对象中包装一个基本类型为 double 的值,每个Double类的对象都包含一个double类的字段。此外,该类还提供多个方法,可以将 double类型转换为 String类型,将 String类型转换为 doubl类型,也提供了其他一些处理 double 类型时有用的常量和方法。Double类的常用方法如表:
Double类在对象中包装一个基本类型为 double 的值,每个Double类的对象都包含一个double类的字段。此外,该类还提供多个方法,可以将 double类型转换为 String类型,将 String类型转换为 doubl类型,也提供了其他一些处理 double 类型时有用的常量和方法。Double类的常用方法如表:
例3:Dounle类的常用方法
public class DoubleDemo {
public static void main(String[] args) {
Double dNum = Double.valueOf("3.14");//创建一个Double对象
//判断是否为非数字值
System.out.println("3.14是否为非数字值:"+Double.isNaN(dNum.doubleValue()));
System.out.println("3.14转换为int值为:"+dNum.intValue());//转换为int类型
//判断大小
System.out.println("值为3.14的Double对象与3.14的比较结果:"+dNum.equals(3.14));
//转换为十六进制
System.out.println("3.14的十六进制表示为:"+Double.toHexString(dNum));
}
}
public class DoubleDemo {
public static void main(String[] args) {
Double dNum = Double.valueOf("3.14");//创建一个Double对象
//判断是否为非数字值
System.out.println("3.14是否为非数字值:"+Double.isNaN(dNum.doubleValue()));
System.out.println("3.14转换为int值为:"+dNum.intValue());//转换为int类型
//判断大小
System.out.println("值为3.14的Double对象与3.14的比较结果:"+dNum.equals(3.14));
//转换为十六进制
System.out.println("3.14的十六进制表示为:"+Double.toHexString(dNum));
}
}
Double类主要提供了以下常量:
1、MAX_EXPONENT:返回int 值,表示有限double 变量可能具有的最大指数
2、MIN_EXPONENT:返回 int 值,表示标准化 double 变量可能具有的最小指数。
3、NEGATIVE_INFINITY:返回 double 值,表示保存 double 类型的负无穷大值的常量。
4、POSITIVE_INFINITY:返回double 值,表示保存double 类型的正无穷大值的常量。
1、MAX_EXPONENT:返回int 值,表示有限double 变量可能具有的最大指数
2、MIN_EXPONENT:返回 int 值,表示标准化 double 变量可能具有的最小指数。
3、NEGATIVE_INFINITY:返回 double 值,表示保存 double 类型的负无穷大值的常量。
4、POSITIVE_INFINITY:返回double 值,表示保存double 类型的正无穷大值的常量。
11.1.3.Boolean类
Boolean 类将基本类型为 boolean 的值包装在一个对象中。一个 Boolean 类型的对象只包含一个类型为boolean 的字段。此外,此类还为 boolean 类型和 String 类型的相互转换提供了许多方法,并提供了处理 boolean 类型时非常有用的其他一些常量和方法。Boolean类的常用方法如表:
例4:Boolean类的常用方法 public class BooleabDemo {
public static void main(String[] args) {
Boolean b1 = Boolean.valueOf("true");//创建Boolean对象
Boolean b2 = Boolean.valueOf("ok");
System.out.println("b1:"+b1.booleanValue());//输出
System.out.println("b2:"+b2.booleanValue());
}
}
public static void main(String[] args) {
Boolean b1 = Boolean.valueOf("true");//创建Boolean对象
Boolean b2 = Boolean.valueOf("ok");
System.out.println("b1:"+b1.booleanValue());//输出
System.out.println("b2:"+b2.booleanValue());
}
}
Boolean 提供了以下3个常量:
1、TRUE:对应基值 true的 Boolean 对象。
2、FALSE:对应基值 false的 Boolean 对象。
3、TYPE:基本类型 boolean的 Class 对象。
1、TRUE:对应基值 true的 Boolean 对象。
2、FALSE:对应基值 false的 Boolean 对象。
3、TYPE:基本类型 boolean的 Class 对象。
11.1.4.Character类
Character 类在对象中包装一个基本类型为 char 的值,该类提供了多种方法,以确定字符的类别(小写字母、数字等),并可以很方便地将字符从大写转换成小写,反之亦然。Character 类提供了很多方法来完成对字符的操作,常用的方法如表:
例5:Character类的常用方法
public class UpperOrLower {
public static void main(String[] args) {
Character mychar1 = Character.valueOf('A');
Character mychar2 = Character.valueOf('a');
if(Character.isUpperCase(mychar1)) {//判断是否为大写字母
System.out.println(mychar1 + "是大写字母");
//转换为小写并输出
System.out.println("转换为小写字母的结果:" + Character.toLowerCase(mychar1));
}
if(Character.isLowerCase(mychar2)) {//判断是否为小写字母
System.out.println(mychar2 + "是小写字母");
//转换为大写并输出
System.out.println("转换为大写字母的结果:" + Character.toUpperCase(mychar2));
}
}
}
public class UpperOrLower {
public static void main(String[] args) {
Character mychar1 = Character.valueOf('A');
Character mychar2 = Character.valueOf('a');
if(Character.isUpperCase(mychar1)) {//判断是否为大写字母
System.out.println(mychar1 + "是大写字母");
//转换为小写并输出
System.out.println("转换为小写字母的结果:" + Character.toLowerCase(mychar1));
}
if(Character.isLowerCase(mychar2)) {//判断是否为小写字母
System.out.println(mychar2 + "是小写字母");
//转换为大写并输出
System.out.println("转换为大写字母的结果:" + Character.toUpperCase(mychar2));
}
}
}
Character 类提供了大量表示特定字符的常量,例如:
1、CONNECTOR_PUNCTUATION:返回 byte 型值,表示Unicode 规范中的常规类别“Pc”
2、UNASSIGNED:返回 byte 型值,表示Unicode 规范中的常规类别“Cn”。
3、TITLECASE_LETTER:返回 byte 型值,表示Unicode 规范中的常规类别“Lt”。
1、CONNECTOR_PUNCTUATION:返回 byte 型值,表示Unicode 规范中的常规类别“Pc”
2、UNASSIGNED:返回 byte 型值,表示Unicode 规范中的常规类别“Cn”。
3、TITLECASE_LETTER:返回 byte 型值,表示Unicode 规范中的常规类别“Lt”。
11.1.5.Number类
前面介绍了 Java 中的包装类,对于数值型的包装类,它们有一个共同的父类-Number 类,该类是一个抽象类,它是 Byte、Integer、Short、Long、Float 和 Double 类的父类,其子类必须提供将表示的数值转换为 byteint、short、long、float 和 double 的方法。例如,doubleValue()方法返回双精度浮点值,floatValue0方法返回单精度浮点值,这些方法如表:
11.2 数字处理
在 Java 语言中,提供了一个执行数学基本运算的 Math 类,该类包括常用的数学运算方法,如角函数方法、指数函数方法、对数函数方法、平方根函数方法等一些常用数学函数方法。除此之外还提供了一些常用的数学常量,如PI、E等。本节将讲解 Math 类以及其中的一些常用方法。
在实际开发中,随机数的使用是很普遍的,所以要掌握生成随机数的操作。在Java 中主要提供了两种生成随机数的方式,分别为调用 Math 类的random0方法生成随机数和调用 Random类生成各种据类型的随机数。
在Java中,还提供了大数字的操作类,即javamath.BigInteger类与javamath.BigDecimal类。这两个类用于高精度计算,其中 BigInteger 类是针对大整数的处理类,而 BigDecimal类则是针对大小数的处理类。
在实际开发中,随机数的使用是很普遍的,所以要掌握生成随机数的操作。在Java 中主要提供了两种生成随机数的方式,分别为调用 Math 类的random0方法生成随机数和调用 Random类生成各种据类型的随机数。
在Java中,还提供了大数字的操作类,即javamath.BigInteger类与javamath.BigDecimal类。这两个类用于高精度计算,其中 BigInteger 类是针对大整数的处理类,而 BigDecimal类则是针对大小数的处理类。
11.2.1.数字格式化
数字格式化在解决实际问题时应用非常普遍,如表示某超市的商品价格,需要保留两位有效数字数字格式化操作主要针对的是浮点型数据,包括 double 型和 foat 型数据。在 Java 中使用 java.textDecimalFormat格式化数字,本节将着重讲解DecimalFormat类。
在Java 中,没有格式化的数据遵循以下原则:
1、如果数据绝对值大于0.001 并且小于10000000,使以常规小数形式表示
2、如果数据绝对值小于0.001或者大于10000000,使用科学记数法表示。
由于上述输出格式不能满足解决实际问题的要求,通常将结果格式化为指定形式后输出。在 Java中,可以使用DecimalFormat类进行格式化操作
DecimalForat类是NumberFormat 的一个子类,用于格式化十进制数字。它可以将一些数字格式化为整数、浮点数、百分数等。通过使用该类可以为要输出的数字加上单位或控制数字的精度。一般情况下,可以在实例化 DecimalFormat 对象时传递数字格式,也可以通过 DecimalFormat 类中的applyPatten0方法来实现数字格式化。
当格式化数字时,可在 DecimalFormat类中使用一些特殊字符构成一个格式化模板,使数字按照-定的特殊字符规则进行匹配。表中列举了格式化模板中的特殊字符及其所代表的含义。
在Java 中,没有格式化的数据遵循以下原则:
1、如果数据绝对值大于0.001 并且小于10000000,使以常规小数形式表示
2、如果数据绝对值小于0.001或者大于10000000,使用科学记数法表示。
由于上述输出格式不能满足解决实际问题的要求,通常将结果格式化为指定形式后输出。在 Java中,可以使用DecimalFormat类进行格式化操作
DecimalForat类是NumberFormat 的一个子类,用于格式化十进制数字。它可以将一些数字格式化为整数、浮点数、百分数等。通过使用该类可以为要输出的数字加上单位或控制数字的精度。一般情况下,可以在实例化 DecimalFormat 对象时传递数字格式,也可以通过 DecimalFormat 类中的applyPatten0方法来实现数字格式化。
当格式化数字时,可在 DecimalFormat类中使用一些特殊字符构成一个格式化模板,使数字按照-定的特殊字符规则进行匹配。表中列举了格式化模板中的特殊字符及其所代表的含义。
例6:DecimalFormat类的常用方法
import java.text.DecimalFormat;
public class DecimalFormatSimpleDemo {
static public void SimgleFormat(String pattern,double value) {
DecimalFormat myFormat = new DecimalFormat(pattern);//实例化DecimalMformat对象
String output = myFormat.format(value);//将数字进行格式化
System.out.println(value +""+ pattern +""+ output);
}
static public void UseApplyPatternMethodFormat(String pattern,double value) {
DecimalFormat myFormat = new DecimalFormat();//实例化DecimalFormat对象
myFormat.applyPattern(pattern);//调用applyPattern()方法设置格式化模板
System.out.println(value +""+ pattern +""+ myFormat.format(value));
}
public static void main(String[] args) {
SimgleFormat("###,###.###",123456.789);//调用静态SimgleFormat()方法
SimgleFormat("00000000.###kg",123456.789);//在数字后加上单位
//按照格式模板格式化数字,不存在的位以0显示
SimgleFormat("000000.000",123.78);
//调用静态UseApplyPatternMethodFormat()方法
UseApplyPatternMethodFormat("#.###%",0.789);//将数字转换为百分数形式
UseApplyPatternMethodFormat("###.##",123456.789);//将小数点后格式化为两位
UseApplyPatternMethodFormat("0.00\u2030",0.789);//将数字转换为千分数形式
}
}
import java.text.DecimalFormat;
public class DecimalFormatSimpleDemo {
static public void SimgleFormat(String pattern,double value) {
DecimalFormat myFormat = new DecimalFormat(pattern);//实例化DecimalMformat对象
String output = myFormat.format(value);//将数字进行格式化
System.out.println(value +""+ pattern +""+ output);
}
static public void UseApplyPatternMethodFormat(String pattern,double value) {
DecimalFormat myFormat = new DecimalFormat();//实例化DecimalFormat对象
myFormat.applyPattern(pattern);//调用applyPattern()方法设置格式化模板
System.out.println(value +""+ pattern +""+ myFormat.format(value));
}
public static void main(String[] args) {
SimgleFormat("###,###.###",123456.789);//调用静态SimgleFormat()方法
SimgleFormat("00000000.###kg",123456.789);//在数字后加上单位
//按照格式模板格式化数字,不存在的位以0显示
SimgleFormat("000000.000",123.78);
//调用静态UseApplyPatternMethodFormat()方法
UseApplyPatternMethodFormat("#.###%",0.789);//将数字转换为百分数形式
UseApplyPatternMethodFormat("###.##",123456.789);//将小数点后格式化为两位
UseApplyPatternMethodFormat("0.00\u2030",0.789);//将数字转换为千分数形式
}
}
在本实例中可以看到,代码的第一行使用import 关键字将javatext.DecimalFormat 这个类导入,这是告知系统下面的代码将使用到 DecimalFormat类。然后定义了两个格式化数字的方法,这两个方法参数都为两个,分别代表数字格式化模板和具体需要格式化的数字。虽然这两个方法都可以实现数字的格式化,但采用的方式有所不同,SimgleFormat()方法是在实例化 DecimalFormat对象时设置数字格式化模板,而UseApplyPattemMethodFormat()方法是在实例化 DecimalFormat 对象后调用applyPattern()方法设置数字格式化模板。最后,在主方法中根据不同形式模板格式化数字。在结果中可以看到以“0特殊字符构成的模板进行格式化时,当数字某位不存在时,将显示0:而以“#”特殊字符构成的模板进行格式化操作时,格式化后的数字位数与数字本身的位数一致。
在DecimalFormat类中,除了可通过格式化模板来格式化数字,还可以使用一些特殊方法对数字进行格式化设置。
在DecimalFormat类中,除了可通过格式化模板来格式化数字,还可以使用一些特殊方法对数字进行格式化设置。
11.2.2.Math类
Math 类提供了众多数学函数方法,主要包括三角函数方法,指数函数方法,取整函数方法,取最大值、最小值,以及平均值函数方法。这些方法都被定义为 static 形式,所以在程序中应用比较简便可以使用如下形式调用:
Math.数学方法
在Math 类中,除函数方法外还存在一些常用数学常量,如 PI、E等。这些数学常量作为Math类的成员变量出现,调用起来也很简单。可以使用如下形式调用:
Math.PI
Math.E
Math 类中的常用数学运算方法较多,大致可以将其分为四大类别,分别为三角函数方法,指数函数方法,取整函数方法,以及取最大值、最小值和绝对值函数方法。
Math.数学方法
在Math 类中,除函数方法外还存在一些常用数学常量,如 PI、E等。这些数学常量作为Math类的成员变量出现,调用起来也很简单。可以使用如下形式调用:
Math.PI
Math.E
Math 类中的常用数学运算方法较多,大致可以将其分为四大类别,分别为三角函数方法,指数函数方法,取整函数方法,以及取最大值、最小值和绝对值函数方法。
1.三角函数方法 Math 类中包含的三角函数方法如下:
public static double sin(double a): 返回角的三角正弦。
public static double cos(double a): 返回角的三角余弦。
public static double tan(double a): 返回角的三角正切。
public static double asin(double a):返回一个值的反正弦。
public static double acos(double a): 返回一个值的反余弦。
public static double atan(double a):返回一个值的反正切。
public static double toRadians(double angdeg): 将角度转换为弧度。
public static double toDegrees(double angrad):将狐度转换为角度。
以上每个方法的参数和返回值都是 double型的。将这些方法的参数的值设置为 double 型是有一定道理的,参数以弧度代替角度来实现,其中1°等于π /180 弧度,所以180°可以使用π弧度来表示。除了可以获取角的正弦、余弦、正切、反正弦、反余弦、反正切,Math 类还提供了角度和弧度相互转换的方法 toRadians()和 toDegrees()。但需要注意的是,角度与弧度的转换通常是不精确的。
public static double sin(double a): 返回角的三角正弦。
public static double cos(double a): 返回角的三角余弦。
public static double tan(double a): 返回角的三角正切。
public static double asin(double a):返回一个值的反正弦。
public static double acos(double a): 返回一个值的反余弦。
public static double atan(double a):返回一个值的反正切。
public static double toRadians(double angdeg): 将角度转换为弧度。
public static double toDegrees(double angrad):将狐度转换为角度。
以上每个方法的参数和返回值都是 double型的。将这些方法的参数的值设置为 double 型是有一定道理的,参数以弧度代替角度来实现,其中1°等于π /180 弧度,所以180°可以使用π弧度来表示。除了可以获取角的正弦、余弦、正切、反正弦、反余弦、反正切,Math 类还提供了角度和弧度相互转换的方法 toRadians()和 toDegrees()。但需要注意的是,角度与弧度的转换通常是不精确的。
例7:在java代码中进行三角函数运算
public class TrigonometricFunction {
public static void main(String[] args) {
System.out.println("90度的正弦值:"+Math.sin(Math.PI/2));//取90°的正弦
System.out.println("o度的余弦值:"+Math.cos(0));//取0°的余弦
System.out.println("60度的正切值:"+Math.tan(Math.PI/3));//取60°的正切
//取2的平方根与2商的反正弦
System.out.println("2的平方根与2的商色反正弦值:"+Math.asin(Math.sqrt(2)/2));
//取2的平方根与2商的反余弦
System.out.println("2的平方根与2的商色反余弦值:"+Math.acos(Math.sqrt(2)/2));
System.out.println("1的反正切值:"+Math.atan(1));//取1的反正切
System.out.println("120度的弧度值:"+Math.toRadians(120.0));//取120°的弧度值
System.out.println("Π/2的角度值:"+Math.toDegrees(Math.PI/2));//取Π/2的角度
}
}
public class TrigonometricFunction {
public static void main(String[] args) {
System.out.println("90度的正弦值:"+Math.sin(Math.PI/2));//取90°的正弦
System.out.println("o度的余弦值:"+Math.cos(0));//取0°的余弦
System.out.println("60度的正切值:"+Math.tan(Math.PI/3));//取60°的正切
//取2的平方根与2商的反正弦
System.out.println("2的平方根与2的商色反正弦值:"+Math.asin(Math.sqrt(2)/2));
//取2的平方根与2商的反余弦
System.out.println("2的平方根与2的商色反余弦值:"+Math.acos(Math.sqrt(2)/2));
System.out.println("1的反正切值:"+Math.atan(1));//取1的反正切
System.out.println("120度的弧度值:"+Math.toRadians(120.0));//取120°的弧度值
System.out.println("Π/2的角度值:"+Math.toDegrees(Math.PI/2));//取Π/2的角度
}
}
通过运行结果可以看出,90°的正弦值为1,0°的余弦值为 1,60°的正切与 Math.sqrt(3)的值该是一致的,也就是取3 的平方根。在结果中可以看到,第 4~6 行的值是基本相同的,这个值换算正是 45°,也就是获取的 Mathsqrt(2)/2 反正弦、反余弦值与1的反正切值都是 45°。最后两行打印语句实现的是角度和弧度的转换,其中 Math.toRadians(120.0)语句是获取 120°的弧度值,而 MadtoDegrees(Math.PI/2)语句是获取 π/2 的角度值。读者可以将这些具体的值使用的形式表示出来,与上述结果应该是基本一致的,这些结果不能做到十分精确,因为π本身也是一个近似值。
2.指数函数方法
Math 类中与指数相关的函数方法如下:
public static double exp(double a):用于获取e的a次方。
public static double log(double a):用于取自然对数,即取Ina的值。
public static double log10(double a):用于取底数为10 的a的对数。
public static double sqrt(double a): 用于取a的平方根,其中a 的值不能为负值。
public static double cbrt(doublea):用于取a的立方根。
public static double pow(double a,double b): 用于取a的b 次方。
Math 类中与指数相关的函数方法如下:
public static double exp(double a):用于获取e的a次方。
public static double log(double a):用于取自然对数,即取Ina的值。
public static double log10(double a):用于取底数为10 的a的对数。
public static double sqrt(double a): 用于取a的平方根,其中a 的值不能为负值。
public static double cbrt(doublea):用于取a的立方根。
public static double pow(double a,double b): 用于取a的b 次方。
例8:在java代码中进行指数函数运算
public class ExponentFunction {
public static void main(String[] args) {
System.out.println("e的平方根:"+Math.exp(2));//取e的2次方
System.out.println("以e为底2的对数值:"+Math.log(2));//取以为底2的对数
System.out.println("以10为底2的对数值:"+Math.log10(2));//取10为底2的对数
System.out.println("4的平方根值:"+Math.sqrt(4));//取4的平方根
System.out.println("8的立方根值:"+Math.cbrt(8));//取8的立方根
System.out.println("2的2次方值:"+Math.pow(2,2));//取2的2次方
}
}
public class ExponentFunction {
public static void main(String[] args) {
System.out.println("e的平方根:"+Math.exp(2));//取e的2次方
System.out.println("以e为底2的对数值:"+Math.log(2));//取以为底2的对数
System.out.println("以10为底2的对数值:"+Math.log10(2));//取10为底2的对数
System.out.println("4的平方根值:"+Math.sqrt(4));//取4的平方根
System.out.println("8的立方根值:"+Math.cbrt(8));//取8的立方根
System.out.println("2的2次方值:"+Math.pow(2,2));//取2的2次方
}
}
3.取整函数方法
在具体的问题中,取整操作使用也很普遍,所以 Java 在 Math 类中添加了数字取整方法。Math类中主要包括以下几种取整方法:
public static double ceil(double a): 返回大于等于参数的最小整数。
public static double floor(double a):返回小于等于参数的最大整数。
public static double rint(double a): 返回与参数最接近的整数,如果存在两个同样接近的整数V则结果取偶数。
public staticintround(float a):将参数加上0.5后返回与参数最近的整数。
public static longround(double a): 将参数加上0.5 后返与参数最近的整数,然后强制转换为长整型。
在具体的问题中,取整操作使用也很普遍,所以 Java 在 Math 类中添加了数字取整方法。Math类中主要包括以下几种取整方法:
public static double ceil(double a): 返回大于等于参数的最小整数。
public static double floor(double a):返回小于等于参数的最大整数。
public static double rint(double a): 返回与参数最接近的整数,如果存在两个同样接近的整数V则结果取偶数。
public staticintround(float a):将参数加上0.5后返回与参数最近的整数。
public static longround(double a): 将参数加上0.5 后返与参数最近的整数,然后强制转换为长整型。
例9:各场景下取整函数的运算结果
public class IntFunction {
public static void main(String[] args) {
System.out.println("使用ceil()方法取整:"+Math.ceil(5.2));//返回一个大于等于参数的整数
System.out.println("使用floor()方法取整:"+Math.floor(2.5));//返回一个小于等于参数的整数
System.out.println("使用rint()方法取整:"+Math.rint(2.7));//返回与参数最接近的整数
System.out.println("使用rint()方法取整:"+Math.rint(2.5));//返回与参数最接近的整数
//将参数加上0.5后返回最接近的整数
System.out.println("使用found()方法取整:"+Math.round(3.4f));
//将参数加上0.5后返回最接近的整数,并将结果强制转换为长整型
System.out.println("使用round()方法取整:"+Math.round(2.5));
}
}
public class IntFunction {
public static void main(String[] args) {
System.out.println("使用ceil()方法取整:"+Math.ceil(5.2));//返回一个大于等于参数的整数
System.out.println("使用floor()方法取整:"+Math.floor(2.5));//返回一个小于等于参数的整数
System.out.println("使用rint()方法取整:"+Math.rint(2.7));//返回与参数最接近的整数
System.out.println("使用rint()方法取整:"+Math.rint(2.5));//返回与参数最接近的整数
//将参数加上0.5后返回最接近的整数
System.out.println("使用found()方法取整:"+Math.round(3.4f));
//将参数加上0.5后返回最接近的整数,并将结果强制转换为长整型
System.out.println("使用round()方法取整:"+Math.round(2.5));
}
}
4.取最大、最小值和绝对值函数方法
在程序中最常用的方法就是取最大值、最小值、绝对值等,Math 类中包括的操作方法如下:
public static double max(double adouble b): 取a与b之间的最大值。
public static int min(int aint b): 取a与b之间的最小值,参数为整型。
public static long min(long a,long b): 取a与b之间的最小值,参数为长整型。
public static float min(float a,floatb):取a与b之间的最小值,参数为单精度浮点型
public static double min(double a,double b):取a与b之间的最小值,参数为双精度浮点型。
public static intabs(int a):返回整参数的绝对值。
public static longabs(long a):返回长整型参数的绝对值。
public static float abs(float a): 返回单精度浮点型参数的绝对值。
public static double abs(double a): 返回双精度浮点型参数的绝对值。
在程序中最常用的方法就是取最大值、最小值、绝对值等,Math 类中包括的操作方法如下:
public static double max(double adouble b): 取a与b之间的最大值。
public static int min(int aint b): 取a与b之间的最小值,参数为整型。
public static long min(long a,long b): 取a与b之间的最小值,参数为长整型。
public static float min(float a,floatb):取a与b之间的最小值,参数为单精度浮点型
public static double min(double a,double b):取a与b之间的最小值,参数为双精度浮点型。
public static intabs(int a):返回整参数的绝对值。
public static longabs(long a):返回长整型参数的绝对值。
public static float abs(float a): 返回单精度浮点型参数的绝对值。
public static double abs(double a): 返回双精度浮点型参数的绝对值。
例10:取最大值、最小值、绝对值的方法
public class AnyFunction {
public static void main(String[] args) {
System.out.println("4和8较大者:"+Math.max(4,8));//取两个参数的最大值
System.out.println("4.4和4较小者:"+Math.min(4.4,4));//取两个参数的最小值
System.out.println("-7的绝对值:"+Math.abs(-7));//取参数的绝对值
}
}
public class AnyFunction {
public static void main(String[] args) {
System.out.println("4和8较大者:"+Math.max(4,8));//取两个参数的最大值
System.out.println("4.4和4较小者:"+Math.min(4.4,4));//取两个参数的最小值
System.out.println("-7的绝对值:"+Math.abs(-7));//取参数的绝对值
}
}
11.2.3.Random类
Random 类是JDK 中的随机数生成器类,可以通过实例化一个 Radom 对象创建一个随机数生器,语法如下:
Random r = new Random();
以这种方式实例化对象时,Java 编译器将以系统当前时间作为随机数生成器的种子。因为每时刻的时间不可能相同,所以产生的随机数不同。但是如果运行速度太快,也会产生两个运行结果相同的随机数。
用户也可以在实例化 Random 类对象时,设置随机数生成器的种子。语法如下:
Random r = new Random(seedValue);
r: Random类对象。
seedValue:随机数生成器的种子。
Random r = new Random();
以这种方式实例化对象时,Java 编译器将以系统当前时间作为随机数生成器的种子。因为每时刻的时间不可能相同,所以产生的随机数不同。但是如果运行速度太快,也会产生两个运行结果相同的随机数。
用户也可以在实例化 Random 类对象时,设置随机数生成器的种子。语法如下:
Random r = new Random(seedValue);
r: Random类对象。
seedValue:随机数生成器的种子。
在Random 类中,提供了获取各种数据类型随机数的方法,下面列举几个常用的方法:
public intnextInt():返回一个随机整数。
public int nextInt(int n): 返回大于等于0且小于n的随机整数。
public long nextLong0: 返回一个随机长整型值。
public boolean nextBoolean0: 返回一个随机布尔型值。
public float nextFloat0:返回一个随机单精度浮点型值。
日 public doublenextDouble0:返回一个随机双精度浮点型值。
public double nextGaussian():返回一个概率密度为高斯分布的双精度浮点型值。
public intnextInt():返回一个随机整数。
public int nextInt(int n): 返回大于等于0且小于n的随机整数。
public long nextLong0: 返回一个随机长整型值。
public boolean nextBoolean0: 返回一个随机布尔型值。
public float nextFloat0:返回一个随机单精度浮点型值。
日 public doublenextDouble0:返回一个随机双精度浮点型值。
public double nextGaussian():返回一个概率密度为高斯分布的双精度浮点型值。
例11:获取不同取值范围、不同类型的随机数 import java.util.Random;
public class RandomDemo {
public static void main(String[] args) {
Random r = new Random();//实例化一个Random类
//随机产生一个整数
System.out.println("随机产生一个整数:"+r.nextInt());
//随机产生一个大于等于0且小于10的整数
System.out.println("随机产生一个大于0小于10的整数:"+r.nextInt(10));
//随机产生一个布尔型的值
System.out.println("随机产生一个布尔型的值:"+r.nextBoolean());
//随机产生一个双精度浮点型的值
System.out.println("随机产生一个双精度浮点型的值:"+r.nextDouble());
//随机产生一个单精度浮点型的值
System.out.println("随机产生一个单精度浮点型的值:"+r.nextFloat());
//随机产生一个概略密度为高斯分布的双精度浮点型的值
System.out.println("随机产生一个概略密度为高斯分布的双精度浮点型的值:"+r.nextGaussian());
}
}
public class RandomDemo {
public static void main(String[] args) {
Random r = new Random();//实例化一个Random类
//随机产生一个整数
System.out.println("随机产生一个整数:"+r.nextInt());
//随机产生一个大于等于0且小于10的整数
System.out.println("随机产生一个大于0小于10的整数:"+r.nextInt(10));
//随机产生一个布尔型的值
System.out.println("随机产生一个布尔型的值:"+r.nextBoolean());
//随机产生一个双精度浮点型的值
System.out.println("随机产生一个双精度浮点型的值:"+r.nextDouble());
//随机产生一个单精度浮点型的值
System.out.println("随机产生一个单精度浮点型的值:"+r.nextFloat());
//随机产生一个概略密度为高斯分布的双精度浮点型的值
System.out.println("随机产生一个概略密度为高斯分布的双精度浮点型的值:"+r.nextGaussian());
}
}
11.2.4.BigInteger类
Biginteger 类的数字范围较 Integer 类的数字范围要大得多。前文介绍过 Integer 类是 int 的包装类int 的最大值为 23-1,如果要计算更大的数字,使用 nteer 类就无法实现了,所以 Java 中提供]BigInteger 类来处理更大的数字。Biginteger 类支持任意精度的整数,也就是说,在运算中 BigIntege类可以准确地表示任何大小的整数值而不会丢失信息。
在 BigInteger 类中封装了多种操作,除了基本的加、减、乘、除操作,还提供了绝对值、相反数最大公约数以及判断是否为质数等操作。
使用 BigInteger类,可以实例化一个 BigInteger 对象,并自动调用相应的构造函数。BigInteger类具有很多构造函数,但最直接的一种方式是参数以字符串形式代表要处理的数字。
例如,将2转换为 BigInteger 类型,可以使用以下语句进行初始化操作:
BigIntege twoInstance = new BigIntege(“2”);
在 BigInteger 类中封装了多种操作,除了基本的加、减、乘、除操作,还提供了绝对值、相反数最大公约数以及判断是否为质数等操作。
使用 BigInteger类,可以实例化一个 BigInteger 对象,并自动调用相应的构造函数。BigInteger类具有很多构造函数,但最直接的一种方式是参数以字符串形式代表要处理的数字。
例如,将2转换为 BigInteger 类型,可以使用以下语句进行初始化操作:
BigIntege twoInstance = new BigIntege(“2”);
一旦创建了对象实例,就可以调用 Bielncger 类中的一些方法进行运算操作,包括基本的数学这算和位运算以及一些取相反数、取绝对值等操作。列举了 BigInteger 类中常用的几种运算方法:
public BigInteger add(BigInteger val): 做加法运算。
public BigInteger subtract(BigInteger val): 做减法运算。
public BigInteger multiply(BigInteger val): 做乘法运算。
public BigInteger divide(BigInteger val): 做除法运算。
public BigInteger remainder(BigInteger val): 做取余操作。
public BigInteger divideAndRemainder(Biplntegcr val): 用数组返回余数和商,结果数组中第一个值为商,第二个值为余数。
public BigInteger pow(intexponent): 进行取参数的exponent 次方操作。
public BigInteger negate0: 取相反数。
public BigInteger shifLeft(intn):将数字左移n位,如果n为负数,做右移操作。
public BigInteger shiftRight(intn):将数字右移n位,如果n为负数,做左移操作。
public BigInteger and(BigInteger val): 做与操作。
口 public BigInteger or(BigInteger val):做或操作。
publicintcompareTo(BigInteger val):做数字比较操作。
public boolean equals(Object x):当参数x是BigInteger类型的数字并且数值与对象实例的数值相等时,返回true。
public BigInteger min(BigInteger val):返回较小的数值。
public BigInteger max(BigIntegerval):返回较大的数值。
public BigInteger add(BigInteger val): 做加法运算。
public BigInteger subtract(BigInteger val): 做减法运算。
public BigInteger multiply(BigInteger val): 做乘法运算。
public BigInteger divide(BigInteger val): 做除法运算。
public BigInteger remainder(BigInteger val): 做取余操作。
public BigInteger divideAndRemainder(Biplntegcr val): 用数组返回余数和商,结果数组中第一个值为商,第二个值为余数。
public BigInteger pow(intexponent): 进行取参数的exponent 次方操作。
public BigInteger negate0: 取相反数。
public BigInteger shifLeft(intn):将数字左移n位,如果n为负数,做右移操作。
public BigInteger shiftRight(intn):将数字右移n位,如果n为负数,做左移操作。
public BigInteger and(BigInteger val): 做与操作。
口 public BigInteger or(BigInteger val):做或操作。
publicintcompareTo(BigInteger val):做数字比较操作。
public boolean equals(Object x):当参数x是BigInteger类型的数字并且数值与对象实例的数值相等时,返回true。
public BigInteger min(BigInteger val):返回较小的数值。
public BigInteger max(BigIntegerval):返回较大的数值。
例12:使用BigInteger类进行数学运算 import java.math.BigInteger;
public class BiglntegerDemo {
public static void main(String[] args) {
BigInteger b1 = new BigInteger("987654321987654321");//第1个大数字
BigInteger b2 = new BigInteger("123456789123456789");//第2个大数字
System.out.println("加法操作:"+b1.add(b2));//加法运算
System.out.println("减法操作:"+b1.subtract(b2));//减法运算
System.out.println("乘法操作:"+b1.multiply(b2));//乘法运算
System.out.println("除法操作:"+b1.divide(b2));//除法运算
System.out.println("取商:"+b1.divideAndRemainder(b2)[0]);//取商运算
System.out.println("取余数:"+b1.divideAndRemainder(b2)[1]);//取余运算
System.out.println("做2次方操作:"+b1.pow(2));//2次方运算
System.out.println("取相反数操作:"+b1.negate());//相反数运算
}
}
public class BiglntegerDemo {
public static void main(String[] args) {
BigInteger b1 = new BigInteger("987654321987654321");//第1个大数字
BigInteger b2 = new BigInteger("123456789123456789");//第2个大数字
System.out.println("加法操作:"+b1.add(b2));//加法运算
System.out.println("减法操作:"+b1.subtract(b2));//减法运算
System.out.println("乘法操作:"+b1.multiply(b2));//乘法运算
System.out.println("除法操作:"+b1.divide(b2));//除法运算
System.out.println("取商:"+b1.divideAndRemainder(b2)[0]);//取商运算
System.out.println("取余数:"+b1.divideAndRemainder(b2)[1]);//取余运算
System.out.println("做2次方操作:"+b1.pow(2));//2次方运算
System.out.println("取相反数操作:"+b1.negate());//相反数运算
}
}
11.2.5.BigDecimal类
BigDecimal类和BigInteger类都能实现大数字的运算,不同的是 BigDecimal类加入了小数的概念般的foat 型和 double 型数据只可以用来做科学计算或工程计算,但由于在商业计算中要求数字精度比较高,所以要用到 BigDecimal类。BigDecimal类支持任何精度的定点数,可以用它来精确计算货币值。在BigDecimal类中,常用的两个构造方法如表:
BigDecimal类型的数字可以用来做超大的浮点数的运算,如加、减、乘、除等,但是在所有的运算中除法是最复杂的,因为在除不尽的情况下商小数点后的末位的处理是需要考虑的。BigDecimal类实现的加、减、乘、除的方法 下表:
在上述方法中,BigDecimal类中divide()方法有多种设置,用于返回商小数点后的末位的处理,这些模式的名称与含义下表
例13:使用BigDecimal类进行数学运算 import java.math.BigDecimal;
import java.math.RoundingMode;
public class BigDecimalDemo {
public static void main(String[] args) {
BigDecimal b1 = new BigDecimal("0.00987654321987654321");//第1个大小数
BigDecimal b2 = new BigDecimal("0.00123456789123456789");//第2个大小数
System.out.println("两个数字相加结果:"+b1.add(b2));//加法运算
System.out.println("两个数字相减结果:"+b1.subtract(b2));//减法运算
System.out.println("两个数字相乘结果:"+b1.multiply(b2));//乘法运算
//除法运算,商小数点后保留9位,并将结果进行四舍五入操作
System.out.println("两个数字相除,保留小数点后9位:"+b1.divide(b2,9,RoundingMode.HALF_UP));//
}
}
import java.math.RoundingMode;
public class BigDecimalDemo {
public static void main(String[] args) {
BigDecimal b1 = new BigDecimal("0.00987654321987654321");//第1个大小数
BigDecimal b2 = new BigDecimal("0.00123456789123456789");//第2个大小数
System.out.println("两个数字相加结果:"+b1.add(b2));//加法运算
System.out.println("两个数字相减结果:"+b1.subtract(b2));//减法运算
System.out.println("两个数字相乘结果:"+b1.multiply(b2));//乘法运算
//除法运算,商小数点后保留9位,并将结果进行四舍五入操作
System.out.println("两个数字相除,保留小数点后9位:"+b1.divide(b2,9,RoundingMode.HALF_UP));//
}
}
11.3 System类
System类是JDK中提供的系统类,该类是用final修饰的,所以不允许被继承。System类提供了很多系统层面的操作方法,并且这些方法全部但是静态的。
11.3.1.控制台输出字符
System 类提供了标准输入、标准输出和错误输出流,也就是说,System 类提供了3 个静态对象:in、out 和 err。本书中的代码多次使用了这些对象,最常见的就是 out 对象。在控制台输出字符事,验出的方法有两种:
1.不会自动换行的print()方法
print()方法语法如下:
System.out.print(“Hello”);
此方法输出“Hello”文字,输出完毕后,光标会停留在“Hello”文字末尾,不会自动换行。
2.可以自动换行的println()方法
printin0方法在print后面加上了“In”后缀(就是 line的简写),语法如下:
System.out.println(“书籍是人类进步的阶梯!”);
此方法输出“书籍是人类进步的阶梯!”后会自动换行。光标停留在下一行的开头。
Print()方法和println()方法输出的对比效果下表:
1.不会自动换行的print()方法
print()方法语法如下:
System.out.print(“Hello”);
此方法输出“Hello”文字,输出完毕后,光标会停留在“Hello”文字末尾,不会自动换行。
2.可以自动换行的println()方法
printin0方法在print后面加上了“In”后缀(就是 line的简写),语法如下:
System.out.println(“书籍是人类进步的阶梯!”);
此方法输出“书籍是人类进步的阶梯!”后会自动换行。光标停留在下一行的开头。
Print()方法和println()方法输出的对比效果下表:
11.3.2.计时
System.currentTimeMillis()方法可以获取1970年1月1日零点至今的毫秒数。虽然 Date日期也有类似的方法,但代码会比System 类多,所以System.currentTimeMillis()方法是为获取当前毫秒梦最常用的方法。因为该方法的返回值精确到毫秒,所以可以利用该方法来记录程序的运行时间。
例14:查看执行一万次字符串拼接所消耗的时间
public class SystemTimeDmeo {
public static void main(String[] args) {
long start = System.currentTimeMillis();//程序开始记录时间
String str = null;//创建null字符串
for(int i = 0;i < 10000;i++) {//循环一万次
str += i;//字符串与循环变量拼接
}
long end = System.currentTimeMillis();//记录循环结束时间
System.out.println("循环用时:"+(end - start)+"毫秒");
}
}
public class SystemTimeDmeo {
public static void main(String[] args) {
long start = System.currentTimeMillis();//程序开始记录时间
String str = null;//创建null字符串
for(int i = 0;i < 10000;i++) {//循环一万次
str += i;//字符串与循环变量拼接
}
long end = System.currentTimeMillis();//记录循环结束时间
System.out.println("循环用时:"+(end - start)+"毫秒");
}
}
11.4 .Scanner类
与C语言不同,Java从控制台中读出用户输入的值,用到的不是一行可以直接使用的代码,而是由一个叫Scanner的类来实现的。Scanner英文直译就是扫描仪,它的用途就和现实生活中的扫描仪一样,可以把数字化信息流为人类可识别的文字。控制台输出内容用到了System.out就表示向控制台输出,System.in就表示从控制台输入,让Scanner扫描System.in就可以获取用户输入的值了。
使用Scanner类首先要引入该类,其语法如下:
import java.util.Scanner;
Scanner类提供了下表中的几种常用的方法,通过这些方法可以获取控制台输入的不同类型的值。
使用Scanner类首先要引入该类,其语法如下:
import java.util.Scanner;
Scanner类提供了下表中的几种常用的方法,通过这些方法可以获取控制台输入的不同类型的值。
使用Scanner类扫描控制台的代码如下:
Scanner sc = new Scanner(System.in);
Scanner sc = new Scanner(System.in);
11.5. 日期时间类
11.5.1.Date类
Date类用于表示日期时间,使用该类表示时间需要使用其构造方法创建对象,其构造方法及其说明如下图:
使用Date类的第2种构造方法创建一个Date类的对象,代码如下:
long timeMillis = System.currentTimeMillis();
Date date = new Date(TimeMillis);
上述代码中的System类的currentTimeMillis()方法主要用于获取当前系统时间距标准时间的毫秒数。另外,这里需要注意的是,创建Date类对象时使用的是long型整数,而不是double型,这主要是因为double类型可能会损失精度。Date类的常用方法及其说明,图如下:
long timeMillis = System.currentTimeMillis();
Date date = new Date(TimeMillis);
上述代码中的System类的currentTimeMillis()方法主要用于获取当前系统时间距标准时间的毫秒数。另外,这里需要注意的是,创建Date类对象时使用的是long型整数,而不是double型,这主要是因为double类型可能会损失精度。Date类的常用方法及其说明,图如下:
例16:获取当前的日期和时间 import java.util.Date;
public class DateDemo {
public static void main(String[] args) {
Date date = new Date(); //创建现在的日期
long value = date.getTime(); //获取毫秒数
System.out.println("日期:"+date);//输出
System.out.println("到现在所经历的毫秒数为:"+value);
}
}
public class DateDemo {
public static void main(String[] args) {
Date date = new Date(); //创建现在的日期
long value = date.getTime(); //获取毫秒数
System.out.println("日期:"+date);//输出
System.out.println("到现在所经历的毫秒数为:"+value);
}
}
11.5.2.日期时间格式化
DateFormat类是日期时间格式化子类的抽象类,可以按照指定的格式对日期或时间进行格式化,DateFormat类提供了很多类方法,以获得基于默认或给定语环境和多种格式化风格的默认日期时间formatter,格式化风格主要包括SHORT、MEDIUM、LONG和FULL4种:
1.SHORT: 完全为数字,如11.13.42或3:30pm。
2.MEDIUM: 较长,如Jan 12,1343。
3.LONG: 更长,如January 12,1343或3:30:32pm。
4.FULL: 完全指定,如Tuesday、April 12、1952AD或3:30:42pm PST。
另外,使用DateFormat类还可以自定义日期时间的格式。要格式化一个当前语言环境下的日期,首先需要创建DateFormat类的一个对象,由于它是抽象类,因此使用其静态方法getDateInstance()进行创建,语法如下:
DateFormat of = DateFormat.getDateInstanse();
使用getDateInstance()方法获取的是所在国家或地区的标准日期格式。另外,DateFormat 类还提供了一些其他静态方法。例如,使用 getTimeInstance()方法可获取所在国家或地区的时间格式,使用getDateTimelnstance()方法可获取日期和时间格式。DateFormat 类的常用方法及其说明下表:
1.SHORT: 完全为数字,如11.13.42或3:30pm。
2.MEDIUM: 较长,如Jan 12,1343。
3.LONG: 更长,如January 12,1343或3:30:32pm。
4.FULL: 完全指定,如Tuesday、April 12、1952AD或3:30:42pm PST。
另外,使用DateFormat类还可以自定义日期时间的格式。要格式化一个当前语言环境下的日期,首先需要创建DateFormat类的一个对象,由于它是抽象类,因此使用其静态方法getDateInstance()进行创建,语法如下:
DateFormat of = DateFormat.getDateInstanse();
使用getDateInstance()方法获取的是所在国家或地区的标准日期格式。另外,DateFormat 类还提供了一些其他静态方法。例如,使用 getTimeInstance()方法可获取所在国家或地区的时间格式,使用getDateTimelnstance()方法可获取日期和时间格式。DateFormat 类的常用方法及其说明下表:
由于DateFormat类是一个抽象类,不能用new 创建实例对象。因此,除了使用getXXXInstance()方法创建其对象,还可以使用其子类,如 SimpleDateFormat 类,该类是一个以与语言环境相关的方式来格式化和分析日期的具体类,它允许进行格式化(日期一文本)、分析(文本一日期)和规范化。
SimpleDateFormat类提供了19个格式化字符,可以让开发者随意编写日期格式,这19个格式化字符下表:
SimpleDateFormat类提供了19个格式化字符,可以让开发者随意编写日期格式,这19个格式化字符下表:
通常表中的字符出现的数量会影响数字的格式。例如,yyyy 表示4 位年份,这样输入会显示202l:yy 表示两位,这样输入就会显示为 21; 只有一个y的话,会按照 yyyy 显示:如果超过4个一些常用的日期时间格式如表中所示。y,如yyyyyy,会在4位年份左侧补0,结果为02021。一些常用的日期时间格式下表:
例17:以中文形式打印当前的日期和时间 import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.Date;
public class DateFormatDemo {
public static void main(String[] args) {
DateFormat df = new SimpleDateFormat("yyy年MM月dd日EEEEE HH时mm分ss秒");
System.out.print("各位观众大家好,现在是");
System.out.print(df.format(new Date()));
System.out.println(", 欢迎收看新闻。");
}
}
import java.text.SimpleDateFormat;
import java.util.Date;
public class DateFormatDemo {
public static void main(String[] args) {
DateFormat df = new SimpleDateFormat("yyy年MM月dd日EEEEE HH时mm分ss秒");
System.out.print("各位观众大家好,现在是");
System.out.print(df.format(new Date()));
System.out.println(", 欢迎收看新闻。");
}
}
DateFormat 类提供的Date parse(String source)方法可以将字符串转为其字面日期对应的 Date对象,整个过程相当于日期格式化的逆操作。
打开JavaAPI 文档可以看到 iava.utilDate 类提供的大部分方法都已经过时了,因为 Date类在设计之初没有考虑到国际化,而且很多方法也不能满足用户需求,比如需要获取指定时间的年月日时分和信息,或者想要对日期时间进行加减运算等复杂的操作,Date 类已经不能胜任,因此JDK 提供了新的时间处理类–Calendar日历类。
Calendar 类是一个抽象类,它为特定瞬间与一组诸如 YEAR、MONTH、DAY_OF_MONTH、HOUR等日历字段之间的转换提供了一些方法,并为操作日历字段(如获得下星期的日期)提供了一些方法。另外,该类还为实现包范围外的具体日历系统提供了其他字段和方法,这些字段和方法被定义为 protected。
Calendar 提供了一个类方法 getInstance(),以获得此类型的一个通用的对象。Calendar 类的getInstance()方法返回一个 Calendar 对象,其日历字段已由当前日期和时间初始化,其使用方法如下:
Calendar rightNow = Calendar.getInstance();
Calendar 类是一个抽象类,它为特定瞬间与一组诸如 YEAR、MONTH、DAY_OF_MONTH、HOUR等日历字段之间的转换提供了一些方法,并为操作日历字段(如获得下星期的日期)提供了一些方法。另外,该类还为实现包范围外的具体日历系统提供了其他字段和方法,这些字段和方法被定义为 protected。
Calendar 提供了一个类方法 getInstance(),以获得此类型的一个通用的对象。Calendar 类的getInstance()方法返回一个 Calendar 对象,其日历字段已由当前日期和时间初始化,其使用方法如下:
Calendar rightNow = Calendar.getInstance();
从表中可以看到,add()方法和 roll()方法都用来为给定的日历字段添加或减去指定的时间量,它们的主要区别在于:使用 add()方法时会影响大的字段,像数学里加法的进位或错位,而使用 roll()方法设置的日期字段只是进行增加或减少,不会改变更大的字段。
例18:具体离中华人民共和国成立100周年差多少天 import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.Date;
public class CountDown {
public static void main(String[] args) {
System.out.println("——————————————中华人民共和国成立100周年倒计时——————————————");
Date date = new Date();//当前时间
//创建SimpleDateFormat对象,指定目标格式
SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyy年MM月dd日");
//创建format方法,格式化时间,转换为指定格式
String today = simpleDateFormat.format(date);
System.out.println("今天是"+today);//输出当前日期
//获取自1970年1月1日至当前时间所经过的毫秒数
long time1 = date.getTime();
//使用默认时区和语言环境得一个日历calendar
Calendar calendar = Calendar.getInstance();
//设置日历calendar中的年、月和日的值。因为月份是从0开始计算的,所以这里要减一
calendar.set(2049,10-1,1);
//计算自1970年1月1日至2049年10月1日所经过的毫秒数
long time2 = calendar.getTimeInMillis();
//计算2049年10月1日距离当前时间的天数
long day = (time2 - time1)/(1000*60*60*24);
System.out.println("距离2049年10月1日还有"+day+"天!");
}
}
import java.util.Calendar;
import java.util.Date;
public class CountDown {
public static void main(String[] args) {
System.out.println("——————————————中华人民共和国成立100周年倒计时——————————————");
Date date = new Date();//当前时间
//创建SimpleDateFormat对象,指定目标格式
SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyy年MM月dd日");
//创建format方法,格式化时间,转换为指定格式
String today = simpleDateFormat.format(date);
System.out.println("今天是"+today);//输出当前日期
//获取自1970年1月1日至当前时间所经过的毫秒数
long time1 = date.getTime();
//使用默认时区和语言环境得一个日历calendar
Calendar calendar = Calendar.getInstance();
//设置日历calendar中的年、月和日的值。因为月份是从0开始计算的,所以这里要减一
calendar.set(2049,10-1,1);
//计算自1970年1月1日至2049年10月1日所经过的毫秒数
long time2 = calendar.getTimeInMillis();
//计算2049年10月1日距离当前时间的天数
long day = (time2 - time1)/(1000*60*60*24);
System.out.println("距离2049年10月1日还有"+day+"天!");
}
}
最后对 Calendar 类的使用做出几点总结:
c.set(Calendar.DAY OF_MONTHO)获取的是上个月的最后一天,所以调用前需要将月份往后加一个月。
Calenda.rMONTH 的第一个月是使用0记录的,所以在获得月份数字后要加1。年和日是从1开始记录的,不需要加 1。
Calendar.DAY_OF_WEEK 的第一天是周日,周一是第二天,周六是最后一天。
c.set(Calendar.DAY OF_MONTHO)获取的是上个月的最后一天,所以调用前需要将月份往后加一个月。
Calenda.rMONTH 的第一个月是使用0记录的,所以在获得月份数字后要加1。年和日是从1开始记录的,不需要加 1。
Calendar.DAY_OF_WEEK 的第一天是周日,周一是第二天,周六是最后一天。
11.6 Runtime类
Runtime类是JDK提供的运行时类,该类为Java程序提供了与当前运行环境相连接的一个通道,Java程序可以利用该类对当前的运行环境执行一些简单的操作。Runtime 类不能使用 new 关键字创建实例,只能通过 Runtime.getRuntime()方法获取实例。
1.执行本地命令
本地命令指的是操作系统的命令。例如,在 Linux 系统下就表示shell命令,在 Windows 系统下表示 cmd 命令。
Runtime类提供exec0方法让Java 代码可以执行系统的命令,exec0方法有很多重载的形式,例如:
process esec(String command)
process esec(String cmdarray)
command:要执行的系统命令,字符串类型。
cmdarray:要执行的命令和相应的命令参数,字符串数组类型。
其实这两个重载方式很类似,如执行“javac hello.java”这行命令,使用第一种重载方式的代码如下:
Runtime.getRuntime().exec(“javac hello.java);
使用第二种重载方式的代码如下:
String command[] = {“javac”,“hello.java”};
Runtime.getRuntime().exec(command);
exec()方法会返回一个 Process 对象。Process 类是 Java中进程类,该类是抽象类,不能使用关键字创建实例。Process类的常用方法下表所示,开发可以使用 getinputStream()方法获取返回的信息。
本地命令指的是操作系统的命令。例如,在 Linux 系统下就表示shell命令,在 Windows 系统下表示 cmd 命令。
Runtime类提供exec0方法让Java 代码可以执行系统的命令,exec0方法有很多重载的形式,例如:
process esec(String command)
process esec(String cmdarray)
command:要执行的系统命令,字符串类型。
cmdarray:要执行的命令和相应的命令参数,字符串数组类型。
其实这两个重载方式很类似,如执行“javac hello.java”这行命令,使用第一种重载方式的代码如下:
Runtime.getRuntime().exec(“javac hello.java);
使用第二种重载方式的代码如下:
String command[] = {“javac”,“hello.java”};
Runtime.getRuntime().exec(command);
exec()方法会返回一个 Process 对象。Process 类是 Java中进程类,该类是抽象类,不能使用关键字创建实例。Process类的常用方法下表所示,开发可以使用 getinputStream()方法获取返回的信息。
例19:让java程序执行Windows系统的help命令 import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
public class RuntimeExecDemo {
public static void main(String[] args) {
Runtime r= Runtime.getRuntime();//获取本地 Runtime 对象
try {
Process p = r.exec("help");
InputStream is = p.getInputStream();//获取本地 Runtime 对象
//将字节输入流转换为字符输入流
BufferedReader br = new BufferedReader(new InputStreamReader(is));
String str = null;//创建 null 字符串
while ((str = br.readLine()) != null) {//如果字符流中可以获取非空内容
System.out.println(str);//打印获取的内容
}
}catch(IOException e) {
e.printStackTrace();
}
}
}
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
public class RuntimeExecDemo {
public static void main(String[] args) {
Runtime r= Runtime.getRuntime();//获取本地 Runtime 对象
try {
Process p = r.exec("help");
InputStream is = p.getInputStream();//获取本地 Runtime 对象
//将字节输入流转换为字符输入流
BufferedReader br = new BufferedReader(new InputStreamReader(is));
String str = null;//创建 null 字符串
while ((str = br.readLine()) != null) {//如果字符流中可以获取非空内容
System.out.println(str);//打印获取的内容
}
}catch(IOException e) {
e.printStackTrace();
}
}
}
11.6.2.查看内存
Runtime 类可以通过 freeMemory()方法查看当前Java 虚拟机可用内存的剩余量。如果程序能够实时监控内存剩余量,就可以尽量控制程序对内存的占用,从而避免出现“内存溢出”的情况。同样,也可以用来对测试程序性能,检验程序算法是否导致内存紧张。
例20:监控虚拟机内存使用情况
public class MemoryDemo {
public static void main(String[] args) {
Runtime r= Runtime.getRuntime();//获取本地 Runtime对象
Integer ints[] = new Integer[10000];//创建长度为10000的整型数组
long before = r.freeMemory();//获取当前空闲内存数
System.out.println("赋值前空闲内存字节数:"+before);
for (int i = 0, length = ints.length;i < length; i++) {//循环为整型数组赋值
ints[i] = i;//赋值
}
long after = r.freeMemory();//获取当前空闲内存数
System.out.println("赋值后空闲内存字节数:"+after);
System.out.println("数组用掉的内存字节数:" +(before - after));//输出数组用掉的内存量
}
}
public class MemoryDemo {
public static void main(String[] args) {
Runtime r= Runtime.getRuntime();//获取本地 Runtime对象
Integer ints[] = new Integer[10000];//创建长度为10000的整型数组
long before = r.freeMemory();//获取当前空闲内存数
System.out.println("赋值前空闲内存字节数:"+before);
for (int i = 0, length = ints.length;i < length; i++) {//循环为整型数组赋值
ints[i] = i;//赋值
}
long after = r.freeMemory();//获取当前空闲内存数
System.out.println("赋值后空闲内存字节数:"+after);
System.out.println("数组用掉的内存字节数:" +(before - after));//输出数组用掉的内存量
}
}
十二、集合类
12.1 集合类概述
java.util包中提供了一些集合类,这些集合类又被称为容器。集合类与数组的不同之处:数组的长度是固定的,集合的长度是固定的,集合的长度是可变的;数组用来存放基本类型的数据,集合用来存放对象的引用。
常用集合类的继承关系 如右图所示
12.2 Collection接口
Collection接口是层次结构中的根接口,构成Collection的单位称为元素。Collection接口通常不能直接使用,但该接口提供了添加元素、删除元素、管理数据的方法。由于List接口与Set接口都继承了Collection接口,因此这些方法掉Lish集合与Set集合是通用的。Collection接口的常用方法如右图所示。
通常遍历集合,都是迭代器来实现。Collection接口中的Iterator()方法可返回在此Collection进行迭代的迭代器。右边实例是遍历集合的例题
12.3 List集合
List集合包括List接口以及List接口的所有实现类。List集合中的元素允许重复,各元素的顺序就是对象插入的顺序。类似Java数组,用户可通过使用索引来访问集合中的元素。
12.3.1 List接口
List接口继承了 Collection接口,因此包含 Collection接口中的所有方法。此外,List接口还定义了以下两个非常重要的方法:
get(int index):获取指定索引位置对对对元素
set(int index,Object obj):将集合中指定索引位置的对象修改为指定的对象。
get(int index):获取指定索引位置对对对元素
set(int index,Object obj):将集合中指定索引位置的对象修改为指定的对象。
12.3.2 List接口的实现类
List接口的常用实现类有ArrayList类与LinkedList类,简述如下:
ArrayList类实现了可变的数组,允许保存所有元素,包括null,并可以根据索引位置对集合进行快速的随机访问。缺点是向指定的索引位置插入对象或删除对象的速度较慢。
LinkedList类采用链表结构保存对象。这种结构的优点是便于向集合中插入和删除对象。需要向集合插入、删除对象时,使用LinkedList类实现的List集合的效率较高;但对于随机访问集合的对象,使用LinkedList类实现List集合的效率较低。
List<E>list = new ArrayList<>();
List<E>list2 = new LinkedList<>();
ArrayList类实现了可变的数组,允许保存所有元素,包括null,并可以根据索引位置对集合进行快速的随机访问。缺点是向指定的索引位置插入对象或删除对象的速度较慢。
LinkedList类采用链表结构保存对象。这种结构的优点是便于向集合中插入和删除对象。需要向集合插入、删除对象时,使用LinkedList类实现的List集合的效率较高;但对于随机访问集合的对象,使用LinkedList类实现List集合的效率较低。
List<E>list = new ArrayList<>();
List<E>list2 = new LinkedList<>();
右边代码举例说明List集合的常用方法
12.4 Set集合
Set集合中的对象不按特定的方式排序,只是简单地把对象加入集合中,但Set集合中不能包含重复对象。Set集合由Set接口和Set接口的实现类组成。Set接口继承了Collection接口,因此包含Cpllection接口的所有方法。
Set接口常用的实现类有HashSet类与TreeSet类简述: HashSet类实现Set接口,由哈希表支持,它不保证Set集合的迭代顺序,特别是它不保证该顺序恒久不变。此类允许使用null元素。 TressSet类不仅实现了Set接口,还实现了java.util.SortedSet接口,因此TreeSet类实现的Set集合在遍历集合时按照自然顺序递增排序,也可以按照指定比较器递增排序,既可以通过比较器对用TreeSet类实现的Set集合中的对象进行排序。
TreeSet类新增的方法如右图所示
实例 :使用TreeSet类自然排序
12.5 Map集合
Map 集合没有继承 Collection 接口,其提供的是 key 到 value 的映射。Map 集合中不能包含相同的kcy,每个 key 只能映射一个value。key 还决定了存储对象在映射中的储位置,但不是由ky 对象身决定的,而是通过一种“散列技术”进行处理,产生一个散列码的整数值。散列码通常用作一个信移量,该偏移量对应分配给映射的内存区域的起始位置,从而确定存储对象在映射中的存储位置。Ma集合包括 Map 接口以及 Map 接口的所有实现类。
12.5.1 Map接口
Map接口提供了将key映射到值的对象。一个映射不能包含重复的key,每一个key最多只能映射到一个值。除集合的常用的方法外,其他特殊方法如右图
12.5.2 Map接口的实现类
HashMap类是基于哈希表的Map接口的实现,此实现提供所有可选的映射操作,并允许使用null值和null值,但必须保证键的唯一性。HashMap类通过哈希表对其内部的映射关系进行快速查找。此类不保证映射的顺序,特别是它不保证该顺序恒久不变。
TreeMap类不仅实现了Map接口,还实现了java.utli.SortedMap接口,因此集合中的映射关系具有一定的顺序。但在添加、删除和定位映射关系,TreeMap类比HashMap类性能稍差。由于TreeMap类实现的Map集合中的映射关系是根据键对象按照一定的顺序排列的,因此不允许键对象是null。
TreeMap类不仅实现了Map接口,还实现了java.utli.SortedMap接口,因此集合中的映射关系具有一定的顺序。但在添加、删除和定位映射关系,TreeMap类比HashMap类性能稍差。由于TreeMap类实现的Map集合中的映射关系是根据键对象按照一定的顺序排列的,因此不允许键对象是null。
例题
十三、枚举类型与泛型
13.1 枚举类型
13.1.1 使用枚举类型设置常量
设置常量时,通常将常量放置在接口中,这样在程序中直接使用。该常量不能被修改,因为在接口定义常量时,该常量的修饰符为final与static。常规定义常量的代码: public interface Constants{
public static final int Constants_A=1;
public static final int Constants_B=12;
} 枚举类型出现后,逐渐取代了上述常量定义方式。使用枚举类型定义常量的语法如下: public enum Constants{ Constants_A,
Constants_B,
} 其中,enum是定义枚举类型的关键字。当需要在程序中使用该常量时,可以是使用Constants.Constants_A来表示
public static final int Constants_A=1;
public static final int Constants_B=12;
} 枚举类型出现后,逐渐取代了上述常量定义方式。使用枚举类型定义常量的语法如下: public enum Constants{ Constants_A,
Constants_B,
} 其中,enum是定义枚举类型的关键字。当需要在程序中使用该常量时,可以是使用Constants.Constants_A来表示
例题.分别创建四季接口常量和枚举
子主题
枚举类型较传统定义常量的方式,除具有参数类型检测的优势外,还具有其他方面的优势。用户可以将一个枚举类型看作是一个类,它继承于java.lang.Enum类,当定义一个枚举类型时,每个枚举类型成员都可以看作是枚举类型的一个实例,这些枚举类型成员都默认被 final、public、static修饰,所以当使用枚举类型成员时直接使用枚举类型名称调用枚举类型成员即可。
由于枚举类型对象继承于javalang.Enum类,所以该类中一些操作枚举类型的方法都可以应用到枚举类型中。
由于枚举类型对象继承于javalang.Enum类,所以该类中一些操作枚举类型的方法都可以应用到枚举类型中。
1.values()方法
枚举类型实例包含一个values()方法,该方法可以将枚举类型成员以数组的形式返回
枚举类型实例包含一个values()方法,该方法可以将枚举类型成员以数组的形式返回
打印四季枚举中的所有枚举值
2. valueOf()方法与compareTo()方法
枚举类型中静态方法valueOf()方法可以将普通字符串转换为枚举类型,而compareTo()方法用于比较两个枚举类型对象定义时的顺序。
枚举类型中静态方法valueOf()方法可以将普通字符串转换为枚举类型,而compareTo()方法用于比较两个枚举类型对象定义时的顺序。
使用字符串创建一个季节的枚举值,并判断季节的位置
3.ordinal()方法
枚举类型中的ordinal()方法用于获取某个枚举对象的位置索引值
枚举类型中的ordinal()方法用于获取某个枚举对象的位置索引值
输出每一个季节的索引位置
4.枚举类型中的构造方法
枚举类型定义的构造方法语法如右所示
枚举类型定义的构造方法语法如右所示
enum 枚举类型名称{
Constants_A("我是枚举成员A"),
Constants_B("我是枚举成员B"),
Constants_C("我是枚举成员C"),
Constants_D("3"),
private String description;
private Constants2(){ //定义默认构造方法
}
private Constants2(String description){ //定义带参数的构造方法,参数类型为字符串类型
this.description = description;
}
private Constants2(int i){ //定义带参数的构造方法,参数类型为整型
this.i=this.i+i;
}
}
Constants_A("我是枚举成员A"),
Constants_B("我是枚举成员B"),
Constants_C("我是枚举成员C"),
Constants_D("3"),
private String description;
private Constants2(){ //定义默认构造方法
}
private Constants2(String description){ //定义带参数的构造方法,参数类型为字符串类型
this.description = description;
}
private Constants2(int i){ //定义带参数的构造方法,参数类型为整型
this.i=this.i+i;
}
}
无论是有无参构造方法还是有参构造方法,修饰权限都为private.
为四季枚举创建构造方法,记录每一个季节的特性
13.1.3 使用枚举类型的优势
类型安全。
紧凑有效的数据定义。
可以和程序其他部分完美交互。
运行效率高。
紧凑有效的数据定义。
可以和程序其他部分完美交互。
运行效率高。
13.2 泛型
泛型实质上就是使程序员定义安全的类型。在没有出现泛型之前,Java也提供了对object类型的引用“任意化” 操作,这种“任意化”操作就是对object类型引用进行向下转型及向下转型操作,但某些强制类型转换的错误也许不会被编译器捕捉,而在运行后出现异常,可见强制类型转换存在安全隐患,所以在此提供了泛型机制。
13.2.1 回顾向上转型与向下转型
在介绍泛型之前,先来看一个例子,在项目中创建Test类,在该类中使基本类型向上转型为object类型
public class Test {
private Object b; //定义object类型成员变量
public Object getB() { //设置相应的getXXX()方法
return b;
}
public void setB(Object b) { //设置相应的setXXX()方法
this.b = b;
}
public static void main(String[] args) {
Test t = new Test();
t.setB(Boolean.valueOf(true)); //向上转型操作
System.out.println(t.getB());
t.setB(Float.valueOf("12.3")); //向下转型操作
Float f = (Float)t.getB();
System.out.println(f);
}
}
private Object b; //定义object类型成员变量
public Object getB() { //设置相应的getXXX()方法
return b;
}
public void setB(Object b) { //设置相应的setXXX()方法
this.b = b;
}
public static void main(String[] args) {
Test t = new Test();
t.setB(Boolean.valueOf(true)); //向上转型操作
System.out.println(t.getB());
t.setB(Float.valueOf("12.3")); //向下转型操作
Float f = (Float)t.getB();
System.out.println(f);
}
}
13.2.2 定义泛型类
Object类为最上层的父类,为了提前预防发生异常,Java提供了泛型机制其语法:类名<T> 其中,T是泛型的名称,代表某一种类型。如果不指定具体类型,T则采用Object类型。
例题.创建带泛型的图书类
13.2.3 泛型的常规用法
1.定义泛型类时声明多个类型
语法如下:
class MyClass<T1,T2>{ }
T1,T2为可能被定义的类型
在实例化指定类型的对象时就可以指定多个类型,例如:
MyClass<Boolean,Float> m = new MyClass <Boolean,Float>();
class MyClass<T1,T2>{ }
T1,T2为可能被定义的类型
在实例化指定类型的对象时就可以指定多个类型,例如:
MyClass<Boolean,Float> m = new MyClass <Boolean,Float>();
2.定义泛型类时声明数组类型
定义泛型类时也可以声明数组类型。
例题. 定义泛型数组
3.集合类声明容器的元素
JDK中的集合接口、集合类都被定义了泛型,其中List的泛型E实际上就是element元素的首字母,Map<K,V>的泛型K和V就是key键和value值的首字母。常用的被泛型化的集合类如下表:
例题. 使用泛型约束集合的元素类型
13.2.4 泛型的高级用法
泛型的高级用法包括限制泛型可用类型和使用类型通配符等。
1.限制泛型可用类型
默认可以使用任何类型来实例化一个泛型类对象,但Java中也对泛型类实例的类型做了限制,语法如下:
class 类名称<T extends anyClass>
其中anyClass指某个接口或类。
使用泛型限制后半泛型类的类型必须实现或者继承anyClass这个接口或类,无论anyclass是接口还是类,在进行泛型限制时都必须使用extends关键字
class 类名称<T extends anyClass>
其中anyClass指某个接口或类。
使用泛型限制后半泛型类的类型必须实现或者继承anyClass这个接口或类,无论anyclass是接口还是类,在进行泛型限制时都必须使用extends关键字
例题 限制泛型的类型必须是List的子类
2.使用类型通配符
在泛型机制中,提供了类型通配符,其主要作用是在创建一个泛型类对象时,限制这个泛型类的类型,实现或继承某个接口或类的子类。要声明这样一个对象可以使用“?”通配符来表示,同时使用extends。关键字来对泛型加以限制使用泛型类型通配符的语法,如下:
泛型类名称<?extends List> a=null;
其中,<? extends List>表示类型未知,当需要使用该泛型对象时,可以单独实例化,例如:
A <?extends List> a=null;//定了上界和下界
a=new A();
a=new A();
像上述例子的HashMap类没有实现List接口,那编译器就会报错.除了可以实例化一个限制泛型类型的实例,还可以将该实例放置在方法的参数
public void do Something(A<? extendsList>a){}
在上述代码中,定义方式有效地限制了传入do Something()方法的参数类型。如果使用A<?>这种形式实例化泛型类对象,则默认表示可以将a指定为实例化Object及以下的子类类型,例如:
List l1 = new ArraryList(); //实例化一个对象
l1.add(“成员”); //在集合中添加内容
List<?>l2=l1;
List<?>l3 = new LinkkedList();
System.out.println(2.get(0)); //获取集合中第一个值
在上面的例子中list类型的对象可以接受时君类型的和ArraryList集合也可以接受Integer类型的LLinkedList集合。
注意:List<?>12=11和List12=11有区别
使用通配符声明的名称实例化的对象不能对其加入新的信息,只能获取或删除。例如:
l1.set(0,“成员改变”); //没有使用通配符的对象调用set()方法
//l2.set(0,“成员改变”);//使用通配符的对象调用set()方法,不能被调用。
//l3.set(0,1);
l2.get(0); //可以使用l2的获取集合中的值
l2.remove(0);//根据键名删除集合中的值
泛型类名称<?extends List> a=null;
其中,<? extends List>表示类型未知,当需要使用该泛型对象时,可以单独实例化,例如:
A <?extends List> a=null;//定了上界和下界
a=new A();
a=new A();
像上述例子的HashMap类没有实现List接口,那编译器就会报错.除了可以实例化一个限制泛型类型的实例,还可以将该实例放置在方法的参数
public void do Something(A<? extendsList>a){}
在上述代码中,定义方式有效地限制了传入do Something()方法的参数类型。如果使用A<?>这种形式实例化泛型类对象,则默认表示可以将a指定为实例化Object及以下的子类类型,例如:
List l1 = new ArraryList(); //实例化一个对象
l1.add(“成员”); //在集合中添加内容
List<?>l2=l1;
List<?>l3 = new LinkkedList();
System.out.println(2.get(0)); //获取集合中第一个值
在上面的例子中list类型的对象可以接受时君类型的和ArraryList集合也可以接受Integer类型的LLinkedList集合。
注意:List<?>12=11和List12=11有区别
使用通配符声明的名称实例化的对象不能对其加入新的信息,只能获取或删除。例如:
l1.set(0,“成员改变”); //没有使用通配符的对象调用set()方法
//l2.set(0,“成员改变”);//使用通配符的对象调用set()方法,不能被调用。
//l3.set(0,1);
l2.get(0); //可以使用l2的获取集合中的值
l2.remove(0);//根据键名删除集合中的值
3.继承泛型类与接口
定义为泛型的类和接口也可以被继承与实现。例如让Subclass类继承Extendclass类的泛型,代码入下:
class ExtendClass<T1> {}
Class Sub Class <T1,T2,T3>extends Extend Class<T1>{}
如果在Sub Class类继承Extend Class类时保留父类的泛型类型,需要在继承时期指明。如果没有指明,直接使用extends Extends Class语句进行继承操作,则SubClass类中的 T1T2和T3都会自动变为object类型,所以在一般情况下都将父类的泛型类型保留。
定义为泛型的接口也可以被实现,例如让Sub Class类实现Some Interface接口,并继承接口的泛型。代码如下:
interface SomeInterface<T1>{}
class SubClass<T1,T2,T3>implements SomeInterface<T1>{}
class ExtendClass<T1> {}
Class Sub Class <T1,T2,T3>extends Extend Class<T1>{}
如果在Sub Class类继承Extend Class类时保留父类的泛型类型,需要在继承时期指明。如果没有指明,直接使用extends Extends Class语句进行继承操作,则SubClass类中的 T1T2和T3都会自动变为object类型,所以在一般情况下都将父类的泛型类型保留。
定义为泛型的接口也可以被实现,例如让Sub Class类实现Some Interface接口,并继承接口的泛型。代码如下:
interface SomeInterface<T1>{}
class SubClass<T1,T2,T3>implements SomeInterface<T1>{}
13.2.5 泛型总结
总结一下泛型的使用方法。
1泛型类型参数只能是类类型,不可以是简单类型,比如A< int>这种泛型定义就是错误的。
2.泛型的类型个数可以是多个
3.可以使用extends关键字限制泛型的类型
4.可以使用通配符限制泛型的类型
1泛型类型参数只能是类类型,不可以是简单类型,比如A< int>这种泛型定义就是错误的。
2.泛型的类型个数可以是多个
3.可以使用extends关键字限制泛型的类型
4.可以使用通配符限制泛型的类型
十四、lambda表达式与流处理
14.1 lambda表达式
14.1.1 lambda表达式简介
1.lambda表达式可以用非常少的代码实现抽象方法。
2.lambda表达式不能独立执行,因此必须实现函数式接口,并且会返回一个函数式接口的对象。
3.lambdab表达式的语法非常特殊
2.lambda表达式不能独立执行,因此必须实现函数式接口,并且会返回一个函数式接口的对象。
3.lambdab表达式的语法非常特殊
语法格式:
()-> 结果表达式
参数-> 结果表达式
(参数1,参数2...,参数n)-> 结果表达式
第1行实现无参方法,单独写一对圆括号表示方法无参数,操作符右侧的结果表达式表示方法的返回值。
第2行实现只有一个参数的方法,参数可以写在圆括号里,或者不写圆括号。
第3行实现多参数的方法,所有参数按顺序写在圆括号里,且圆括号不可以省略。
()-> 结果表达式
参数-> 结果表达式
(参数1,参数2...,参数n)-> 结果表达式
第1行实现无参方法,单独写一对圆括号表示方法无参数,操作符右侧的结果表达式表示方法的返回值。
第2行实现只有一个参数的方法,参数可以写在圆括号里,或者不写圆括号。
第3行实现多参数的方法,所有参数按顺序写在圆括号里,且圆括号不可以省略。
lambda表达式也可以实现复杂方法,将操作符右侧的结果表达式换成代码块即可
语法格式如下:
()->{代码块)
参数->(代码块}
(参数1,参数2,..参数n)->{代码块)
第1行实现无参方法,方法体是操作符右侧代码块。
第2行实现只有一个参数的方法,方法体是操作符右侧代码块。
第3行实现多参数的方法,方法体是操作符右侧代码块。
语法格式如下:
()->{代码块)
参数->(代码块}
(参数1,参数2,..参数n)->{代码块)
第1行实现无参方法,方法体是操作符右侧代码块。
第2行实现只有一个参数的方法,方法体是操作符右侧代码块。
第3行实现多参数的方法,方法体是操作符右侧代码块。
lambda表达式的功能归纳总结,语法理解为:
() -> {代码块}
这个方法 按照 这样的代码来实现
简单总结:操作符左侧的方法参数,操作符右侧是方法体
() -> {代码块}
这个方法 按照 这样的代码来实现
简单总结:操作符左侧的方法参数,操作符右侧是方法体
14.1.2 lambda表达式实现函数式接口
1. 函数式接口
开发者可以常见自定义的函数式接口
例如:
interface MyInterface{
void method();
}
如果接口中包含一个以上的抽象方法,则不符合函数式接口的规范,这样的接口不能用Iambda表达式创建匿名对象
例如:
interface MyInterface{
void method();
}
如果接口中包含一个以上的抽象方法,则不符合函数式接口的规范,这样的接口不能用Iambda表达式创建匿名对象
2.Iambda表达式实现无参数抽象方法
很多函数式接口的抽象方法是无参数的,如线程接口Runnable接口只有一个ryn()方法,这样的无参抽象方法在lambda表达式中使用"()"表示
使用lambda表达式实现打招呼接口
3.lambda表达式实现有参抽象方法
如果抽象方法中只有一个参数,lambda表达式则可以省略圆括号
例题. 使用lambda表达式做加法计算
4.lambda表达式使用代码块
lambda表达式会自动判断返回值类型是否符合抽象方法的定义
14.1.3 Iambda表达式调用外部变量
这些外部的变量有些可以被更改,有些则不能。例如,lambda表达式无法更改局部变量的值,但是却可以更改外部类的成员变量(也可以叫做类属性)的值他。
1.lambda表达式无法更改局部变量
局部变量在lambda表达式中默认被定义为final(静态)的,也就是说,lambda表达式只能调用局部变量,却不能改变其值。
结果可以看到,更改局部变量的相关代码被标注编译有误。
2.lambda表达式可以更改类成员变量
类成员变量是在lambda表达式中不是被final修饰的,所以lambda表达式可以改变其值
例题. 使用lambda表达式修改类成员变量
从上述代码结果中可以看出以下几点:
lambda 表达式可以调用并修改类成员变量的值
lambda表达式只是描述了抽象方法是如何实现的,在抽象方法没有被调用前,lambda表达式中的代码并没有被执行,所以运行抽象方法之前类成员变量的值不会发生变化
只要抽象方法被调用,就会执行lambda 表达式中的代码,类成员变量的值就会被修改。
lambda 表达式可以调用并修改类成员变量的值
lambda表达式只是描述了抽象方法是如何实现的,在抽象方法没有被调用前,lambda表达式中的代码并没有被执行,所以运行抽象方法之前类成员变量的值不会发生变化
只要抽象方法被调用,就会执行lambda 表达式中的代码,类成员变量的值就会被修改。
14.1.4 Iambda表达式与异常处理
lambda 表达式中并有抛出异常的语法,这是因为lambda表达式会默认抛出抽象方法原有的异常,当此方法被调用时则要进行异常处理。
例题 防沉迷接口
14.2 方法的引用
14.2.1 引用静态方法
语法:
类名::静态方法名
新的操作符“::”,中间无空格,左边表示方法所属的类名,右边是方法名,语法中方法名是没有括号的。
类名::静态方法名
新的操作符“::”,中间无空格,左边表示方法所属的类名,右边是方法名,语法中方法名是没有括号的。
例题. 使用lambda表达式引用静态方法
从代码结果可以看出,接口的方法得出的结果正是按照add()方法中的逻辑计算出来的
14.2.2 引用成员方法
引用成员方法的语法:
对象名::成员方法名
操作符左侧必须是一个对象名,而不是类名。
对象名::成员方法名
操作符左侧必须是一个对象名,而不是类名。
例题. 使用lambda表达式引用成员方法
结果可以看出,抽象方法的结果是按照类成员方法的逻辑计算出来的
14.2.3 引用构造方法
Iambda表达式有3种引用构造方法的语法,分别是引用无参数构造方法、引用有参构造方法和引用数构造方法
1.引用无参构造方法
语法:
类名::new
注意:new关键字之后没有圆括号,也没有参数的定义
类名::new
注意:new关键字之后没有圆括号,也没有参数的定义
例题. 使用lambda表达式引用无参构造方法
结果可以看出,如果接口方法没有参数,调用的就是无参的构造方法
2.引用有参构造方法
引用有参构造方法的语法与引用无参构造方法一样。区别就是函数式接口的抽象方法是有参数的
例题. 使用lambda表达式引用有参数的构造方法
结果可以看出,无参构造方法没有被调用,接口方法使用的就是有参数的构造方法
3.引用数组构造方法
语法;
类名[]::new
类名[]::new
14.2.4 Fuction接口
这个接口有以下两个泛型:
T:被操作的类型,可以理解为方法参数类型。
R:操作结果类型,可以理解为方法的返回类型。
Function 接口是函数式接口,所以只有一个抽象方法,但是Function 接口还提供方法以方便开发者对函数逻辑进行更深层的处理。
T:被操作的类型,可以理解为方法参数类型。
R:操作结果类型,可以理解为方法的返回类型。
Function 接口是函数式接口,所以只有一个抽象方法,但是Function 接口还提供方法以方便开发者对函数逻辑进行更深层的处理。
14.3 流处理
流处理有点类似数据库的 SQL 语句,可以执行非常复杂的过滤、映射、查找和收集功能,并且代码量很少。唯一的缺点是代码可读性不高。
14.3.1 Stream接口简介
流处理的接口都定义在java.uil.stream 包下。BaseStream接口是最基础的接口,但最常用的是BaseStream 接口的一个子接口——Stream 接口,基本上绝大多数的流处理都是在Stream 接口上实现的。Stream 接口是泛型接口,所以流中操作的元素可以是任何类的对象。
Collection 接口新增两个可以获取流对象的方法。第一个方法最常用,可以获取集合的顺序流,方法如下:
Stream stream();
第二个方法可以获取集合的并行流,方法如下:
Stream parallelstream();
因为所有集合类都是Collection 接口的子类,如ArrayList类、HashSet类等,所以这些类都可以进行流处理。例如:
List list = new ArrayList(); //创建集合
Streamcinteger> s = list.stream();//获取集合流对象
Collection 接口新增两个可以获取流对象的方法。第一个方法最常用,可以获取集合的顺序流,方法如下:
Stream stream();
第二个方法可以获取集合的并行流,方法如下:
Stream parallelstream();
因为所有集合类都是Collection 接口的子类,如ArrayList类、HashSet类等,所以这些类都可以进行流处理。例如:
List list = new ArrayList(); //创建集合
Streamcinteger> s = list.stream();//获取集合流对象
14.3.2 Optional类
Optional 类是用final 修饰的,所以不能有子类。Optional类是带有泛型的类,所以该类可以保存
任何对象的值。
从Optional类的声明代码中就可以看出这些特性,JDK中的部分代码如下
public final class Optional<T>{
private final T value;
} //省略其他代码
Optional 类中有一个叫作value的成员属性,这个属性就是用来保存具体值的。value 是用泛型了
修饰的,并且还用了final 修饰,这表示一个 Optional 对象只能保存一个值。
任何对象的值。
从Optional类的声明代码中就可以看出这些特性,JDK中的部分代码如下
public final class Optional<T>{
private final T value;
} //省略其他代码
Optional 类中有一个叫作value的成员属性,这个属性就是用来保存具体值的。value 是用泛型了
修饰的,并且还用了final 修饰,这表示一个 Optional 对象只能保存一个值。
14.3.3 Collectors类
Collectors类为收集类,该类实现了java.util.Collector接口
14.3.4 数据过滤
数据过滤就是在杂乱的数据中筛选出需要的数据,类似 SQL 语句中的WHERE 关键字,给出一定的条件,将符合条件的数据过滤并展示出来。
1. filter()方法
filterO方法是Stream 接口提供的过滤方法。该方法可以将lambda表达式作为参数,然后按照lambda表达式的逻辑过滤流中的元素。过滤出想要的流元素后,还需使用Stream 提供的collectO方法按照指定方法重新封装。
2. distinct()方法
该方法可以去除流中的重复元素,效果与SQL语句中的DISTINCT关键字一样
3. Iimit()方法
Iimit()方法是Stream接口提供的方法,该方法可以获取流中前N个元素
4. skip方法
skip()方法是Stream接口提供的方法,该方法可以忽略流中的前N个元素
14.3.5数据映射
数据的映射和过滤概念不同:过滤是在流中找到符合条件的元素,映射是在流中获得具体的数据。Stream 接口提供了mapO方法用来实现数据映射,mapO方法会按照参数中的函数逻辑获取新的流对象,新的流对象中元素类型可能与旧流对象元素类型不相同。
14.3.6 数据查找
1.allMatch()方法
该方法会判断流中的元素是否全部符合某一条件,返回结果是boolean值
2.anyMatch方法()方法
该方法会判断流中的元素是否有符合某一条件
3.noneMatch()方法
该方法会判断流中的所有元素是否都不符合某一条件
4.findFirst()方法
这个方法会返回符合条件的第一个元素
14.3.7 数据收集
1.数据统计
不仅可以筛选出特殊元素,还可以对元素的属性进行统计计算
2.数据分组
将流中元素按照指定的条件分开保存
数据分组有一级分组和多级分组
一级分组:将所有数据按照一个条件进行分类
数据分组有一级分组和多级分组
一级分组:将所有数据按照一个条件进行分类
十五、I/O(输入、输出)
15.1 输入/输出流
流是一组有序的数据序列,可分为输入流和输出流两种。
程序从指向源的输入流中读取源中数据,源可以是文件、网络、压缩包或者其他数据源。
程序从指向源的输入流中读取源中数据,源可以是文件、网络、压缩包或者其他数据源。
输出流的指向是数据要到达的目的地,输出流的目标可以是文件、网络、压缩包、控制台和其他数据输出目标。
15.1.1 输入流
InputStream类是字节输入流的抽象类,他是所有字节输入流的父类。InputStream类的具体层次结构如下:
1、read()方法:从输入流中读取数据的下一字节。返回0~255的int字节值。如果因为已经到达流末尾而没有可用的字节,则返回值为-1.
2、mark(int readlimit)方法: 在输入流的当前位置放置一个标记,readlimit参数告知此输入流再标记位置失效之前允许读取的字节数。
3、reset()方法:将输入指针返回到当前所做的标记处。
4、skip(long n)方法:跳过输入流上的n个字节并返回实际跳过的字节数。
5、markSupported()方法:如果当前流支持mark()/reset()操作就返回turn。
6、close方法:关闭此输入流并释放与该流关联的所有系统资源。
并不是所有的 InputStream类的子类都支持 InputStream 类中定义的所有方法、如skip0、mark0、Tset0等方法只对某些子类有用。
Java 中的字符是Unicode 编码,是双字节的。InputStream 类是用来处理字节的,并不适合处理字符文本。Java为字符文本的输入专门提供了一套单独的类,即Reader 类,但Reader 类并不是InputStear类的替换者,只是在处理字符串时简化了编程。Reader 类是字符输入流的抽象类,所有字符输入流的实现都是它的子类。Reader 类的具体层次结构如下图所示。
2、mark(int readlimit)方法: 在输入流的当前位置放置一个标记,readlimit参数告知此输入流再标记位置失效之前允许读取的字节数。
3、reset()方法:将输入指针返回到当前所做的标记处。
4、skip(long n)方法:跳过输入流上的n个字节并返回实际跳过的字节数。
5、markSupported()方法:如果当前流支持mark()/reset()操作就返回turn。
6、close方法:关闭此输入流并释放与该流关联的所有系统资源。
并不是所有的 InputStream类的子类都支持 InputStream 类中定义的所有方法、如skip0、mark0、Tset0等方法只对某些子类有用。
Java 中的字符是Unicode 编码,是双字节的。InputStream 类是用来处理字节的,并不适合处理字符文本。Java为字符文本的输入专门提供了一套单独的类,即Reader 类,但Reader 类并不是InputStear类的替换者,只是在处理字符串时简化了编程。Reader 类是字符输入流的抽象类,所有字符输入流的实现都是它的子类。Reader 类的具体层次结构如下图所示。
15.1.2 输出流
OutputStream类是字节输出流的抽象类,此抽象类是表示输出字节流的所有类的超类
OutputStream类中的所有方法均返回void,在遇到错误时会引发IOException异常,
1.write(intb)方法:将指定的字节写入此输出流。
2. writebyte[]b)方法:将b个字节从指定的byte 数组写入此输出流。
3.write(byte[ b,int off,int len)方法:将指定 byte 数组中从偏移量of开始的len个字节写入此输
出流。
4.fush0方法:彻底完成输出并清空缓存区。
5.close0方法:关闭输出流。
Writer 类是字符输出流的抽象类,所有字符输出类的实现都是它的子类。Writer 类的层次结构如下图
1.write(intb)方法:将指定的字节写入此输出流。
2. writebyte[]b)方法:将b个字节从指定的byte 数组写入此输出流。
3.write(byte[ b,int off,int len)方法:将指定 byte 数组中从偏移量of开始的len个字节写入此输
出流。
4.fush0方法:彻底完成输出并清空缓存区。
5.close0方法:关闭输出流。
Writer 类是字符输出流的抽象类,所有字符输出类的实现都是它的子类。Writer 类的层次结构如下图
15.2 File类
File 类是 java.io包中唯一代表磁盘文件本身的类。File类定义了一些与平台无关的方法来操作文件,可以通过调用 File类中的方法,实现创建、删除、重命名文件等操作。File类的对象主要用来获取文件本身的一些信息,如文件所在的目录、文件的长度、文件读写权限等。数据流可以将数据写入文件中,文件也是数据流最常用的数据媒体
15.2.1 文件的创建与删除
可以使用File类创建一个文件对象。通常使用以下3种构造方法来创建文件对象。
1. File(String pathname)
该构造方法通过将给定的路径名字符串转换为抽象路径名来创建一个新File实例。语法如下:
new File(String pathname)
其中,pathname代表路径名称(包含文件名)。例如
File file = new File("d:/1.txt");
new File(String pathname)
其中,pathname代表路径名称(包含文件名)。例如
File file = new File("d:/1.txt");
2. File(String parent,String child)
该构造方法根据定义的父路径和子路径字符串(包含文件名)创建一个新的File对象。语法如下:
new File(String parent, String child)
new File(String parent, String child)
3. File(File f, String child)
该构造方法根据f抽象路径名和child路径名字符串创建一个新File实例。语法如下
new File(File f,String child)
f:父路径对象,如D:/doc/。
child:子路径字符串,如letter.txt。
当使用 File类创建一个文件对象后,例如:
Re lie =new FileCword.txt");
知果当前目录中不存在名称为word的文件,File 类对象可通过调用createNewFile0方法创建一个名称wndtxt 的文件;如果存在word.txt文件,可以通过文件对象的deleteO方法将其删除
new File(File f,String child)
f:父路径对象,如D:/doc/。
child:子路径字符串,如letter.txt。
当使用 File类创建一个文件对象后,例如:
Re lie =new FileCword.txt");
知果当前目录中不存在名称为word的文件,File 类对象可通过调用createNewFile0方法创建一个名称wndtxt 的文件;如果存在word.txt文件,可以通过文件对象的deleteO方法将其删除
在D盘创建文本文件
15.2.2 获取文件信息
例题. 读取文本文件的名称、长度和隐藏属性
15.3 文件输入/输出流
程序运行期间,大部分数据都在内存中进行操作,当程序结束或关闭时,这些数据将消失。如果需要将数据永久保存,可使用文件输入/输出流与指定的文件建立连接,将需要的数据永久保存到文件中。本节将讲解文件输入/输出流。
15.3.1 FilelnputStream 与 Fileouisieam 类
FilelnputStream 类与FileOutputStream类都用来操作磁盘文件。如果用户的文件读取需求比较简单,则可以使用FileInputStream 类,该类继承自 InputStream 类。FileOutputStream 类与FilelmputStream类对应,提供了基本的文件写入能力。FileOutputStream类是OutputStream类的子类。
FileinputStream 类常用的构造方法如下:
FileinputStream(String name)。
FilelnputStream(File file)。
第一个构造方法使用给定的文件名 name 创建一个FilelnputStream对象,第二个构造方法使用File对象创建FilelnputStream 对象。第一个构造方法比较简单,但第二个构造方法允许在把文件连接输入流之前对文件做进一步分析。
FileOutputStream 类有与FilelnputStream类相同的参数构造方法,创建一个FileOutputStream 对象时,可以指定不存在的文件名,但此文件不能是一个已被其他程序打开的文件。下面的实例就是使用FileinputStream 类与FileOutputStream类实现文件的读取与写入功能的。
FileinputStream(String name)。
FilelnputStream(File file)。
第一个构造方法使用给定的文件名 name 创建一个FilelnputStream对象,第二个构造方法使用File对象创建FilelnputStream 对象。第一个构造方法比较简单,但第二个构造方法允许在把文件连接输入流之前对文件做进一步分析。
FileOutputStream 类有与FilelnputStream类相同的参数构造方法,创建一个FileOutputStream 对象时,可以指定不存在的文件名,但此文件不能是一个已被其他程序打开的文件。下面的实例就是使用FileinputStream 类与FileOutputStream类实现文件的读取与写入功能的。
向文本文件中写入内容,再读取出来
15.3.2 FileReader 和 FileWriter类
使用FileOutputStream 类向文件中写入数据与使用FilelnputStream类从文件中将内容读出来,都存在一点不足,即这两个类都只提供了对字节或字节数组的读取方法。由于汉字在文件中占用两个字节,如果使用字节流,读取不好可能会出现乱码现象,此时采用字符流 FileReader 类或 FileWriter 类即可是兔这种现象。
FileReader 类和 FileWriter 类对应了FileInputStrcam 类和FileOutputStrcam 类。FileReader 类顺序地读取文件,只要不关闭流,每次调用 read0方法就顺序地读取源中其余的内容,直到源的末尾或流被关闭.
FileReader 类和 FileWriter 类对应了FileInputStrcam 类和FileOutputStrcam 类。FileReader 类顺序地读取文件,只要不关闭流,每次调用 read0方法就顺序地读取源中其余的内容,直到源的末尾或流被关闭.
例题. 使用字符流读写文本文件
15.4 带缓存的输入/输出流
缓存是I/O的一种性能优化。缓存流为I/O流增加了内存缓存区,使得在流上执行skip()、mar()和reset()方法都成为可能
15.4.1 BufferedInputStream 与BufferedOutputStream类
BufferedInputStream 类可以对所有 InputStream 类进行带缓存区的包装以达到性能的优化。BufferedInputStream 类有两个构造方法:
1. BufferedInputStream(InputStream in)。
2.BufferedInputStream(InputStream in,int size).
第一种形式的构造万法创建了一个有32个字节的缓存区;第二种形式的构造方法按指定的大小来创建缓存区。一个最优的缓存区的大小,取决于它所在的操作系统、可用的内存空间以及机器配置。从构造方法可以看出,BufferedInputStream对象位于InputStream类对象之后。下图描述了带缓存的字节流读取文件的过程。
1. BufferedInputStream(InputStream in)。
2.BufferedInputStream(InputStream in,int size).
第一种形式的构造万法创建了一个有32个字节的缓存区;第二种形式的构造方法按指定的大小来创建缓存区。一个最优的缓存区的大小,取决于它所在的操作系统、可用的内存空间以及机器配置。从构造方法可以看出,BufferedInputStream对象位于InputStream类对象之后。下图描述了带缓存的字节流读取文件的过程。
使用BufferedOutputStrcam 类输出信息和仅用0utputStream 类输出信息完全一样,只不过BufferedOutputStream 有一个fushO方法用来将缓存区的数据强制输出完。BufferedOutputStream类也有两个构造方法:
1. BufferedOutputStream(OutputStream in)。
2. BufferedOutputStream(OutputStream in,int size)。
第一种构造方法创建一个有32个字节的缓存区,第二种构造方法以指定的大小来创建缓存区。
1. BufferedOutputStream(OutputStream in)。
2. BufferedOutputStream(OutputStream in,int size)。
第一种构造方法创建一个有32个字节的缓存区,第二种构造方法以指定的大小来创建缓存区。
15.4.2 BufferedReader 与 BufferedWriter类
BufferedReader 类与BufferedWriter 类分别继承Reader 类与Writer 类。这两个类同样具有内部缓存机制,并能够以行为单位进行输入/输出。
根据BufferedReader类的特点,可以总结出如下图所示的带缓存的字符数据读取文件的过程。
根据BufferedReader类的特点,可以总结出如下图所示的带缓存的字符数据读取文件的过程。
BufferedReader 类常用的方法如下:
read( )方法:读取单个字符。
readLine( )方法:读取一个文本行,并将其返回为字符串。若无数据可读,则返回null。BufferedWriter 类中的方法都返回void。常用的方法如下:
write(String s,int off, int len)方法:写入字符串的某一部分。
flush()方法:刷新该流的缓存。
newLine( )方法:写入一个行分隔符。
在使用 BufferedWriter 类的Write( )方法时,数据并没有立刻被写入输出流,而是首先进入缓存区中。如果想立刻将缓存区中的数据写入输出流,一定要调用flushO方法。
read( )方法:读取单个字符。
readLine( )方法:读取一个文本行,并将其返回为字符串。若无数据可读,则返回null。BufferedWriter 类中的方法都返回void。常用的方法如下:
write(String s,int off, int len)方法:写入字符串的某一部分。
flush()方法:刷新该流的缓存。
newLine( )方法:写入一个行分隔符。
在使用 BufferedWriter 类的Write( )方法时,数据并没有立刻被写入输出流,而是首先进入缓存区中。如果想立刻将缓存区中的数据写入输出流,一定要调用flushO方法。
例题. 使用缓冲流读写文本文件
15.5 数据输入/输出流
数据输入/输出流(DataInputStream 类与DataOutputStream类)允许应用程序以与机器无关的方式从底层输入流中读取基不)ava数据类型。也就是说,当读取一不数据时,不必再关心这个数值应当是哪种字节。DatalnputStream 类与DataOutputStream类的构造方法如下。
1. DatalnputStream(InputStream in):使用指定的基础 InputStream 对象创建一个DataInputStream对象。
2. DataOutputStream(OutputStream out):创建一个新的数据输出流,将数据写入指定基础输出流。
DataOutputStream 类提供了将字符串、double 数据、int 数据、boolean数据写入文件的方法。其中,将字符串写入文件的方法有 3种,分别是writeBytes(String s)、writeChars(String s)、writeUTF(String s)。由于Java 中的字符是Unicode 编码,是双字节的,writeBytes( )方法只是将字符串中的每一个字符的低字节内容写入目标设备中;而writeChars( )方法将字符串中的每一个字符的两个字节的内容都写到目标设备中;writeUTF( )方法将字符串按照UTF 编码后的字节长度写入目标设备,然后才是每一个字节的UTF 编码。
DatalnputStream 类只提供了一个readUTF( )方法返回字符串。这是因为要在一个连续的字节流读取一个字符串,如果没有特殊的标记作为一个字符串的结尾,并且不知道这个字符串的长度,就无法知道读取到什么位置才是这个字符串的结束。DataOutputStream 类中只有writeUTF( )方法向目标设备中写入字符串的长度,所以也能准确地读回写入字符串。
2. DataOutputStream(OutputStream out):创建一个新的数据输出流,将数据写入指定基础输出流。
DataOutputStream 类提供了将字符串、double 数据、int 数据、boolean数据写入文件的方法。其中,将字符串写入文件的方法有 3种,分别是writeBytes(String s)、writeChars(String s)、writeUTF(String s)。由于Java 中的字符是Unicode 编码,是双字节的,writeBytes( )方法只是将字符串中的每一个字符的低字节内容写入目标设备中;而writeChars( )方法将字符串中的每一个字符的两个字节的内容都写到目标设备中;writeUTF( )方法将字符串按照UTF 编码后的字节长度写入目标设备,然后才是每一个字节的UTF 编码。
DatalnputStream 类只提供了一个readUTF( )方法返回字符串。这是因为要在一个连续的字节流读取一个字符串,如果没有特殊的标记作为一个字符串的结尾,并且不知道这个字符串的长度,就无法知道读取到什么位置才是这个字符串的结束。DataOutputStream 类中只有writeUTF( )方法向目标设备中写入字符串的长度,所以也能准确地读回写入字符串。
十六、反射与注释
16.1 反射
众所周知,所有Java 类均继承了 Object 类,在Object 类中定义了一个 getClassO方法,该方法返
回一个类型为Class 的对象。例如下面的代码:
JTextField textField = new JTextFieldO); //创建 JTextField 对象
Class textFieldC = textField.getClass(); //获取Class对象
利用Class 类的对象 textFieldC,可以访问用来返回该对象的textField对象的描述信息。可以访问
的主要描述信息如下表所示。
回一个类型为Class 的对象。例如下面的代码:
JTextField textField = new JTextFieldO); //创建 JTextField 对象
Class textFieldC = textField.getClass(); //获取Class对象
利用Class 类的对象 textFieldC,可以访问用来返回该对象的textField对象的描述信息。可以访问
的主要描述信息如下表所示。
16.1.1 访问构造方法
在通过下列一组方法访问构造方法时,将返回Constructor 类型的对象或数组。每个Constuctor 对象代表一个构造方法,利用Constructor 对象可以操纵相应的构造方法:
getConstructors()
getConstructor(Class<?>...parameterTypes)
getDeclaredConstructors()
getDeclaredConstructor(Class<?>..parameterTypes)
如果是访问指定的构造方法,需要根据该构造方法的入口参数的类型来访问。例如,访问一个入口参数类型依次为String型和 int型的构造方法,通过下面两种方式均可实现:
objeciClass.getDeclaredConstructor(String.class, int.class);
objectClass.getDeclaredConstructor(new Classil { String.class, int.class });
getConstructors()
getConstructor(Class<?>...parameterTypes)
getDeclaredConstructors()
getDeclaredConstructor(Class<?>..parameterTypes)
如果是访问指定的构造方法,需要根据该构造方法的入口参数的类型来访问。例如,访问一个入口参数类型依次为String型和 int型的构造方法,通过下面两种方式均可实现:
objeciClass.getDeclaredConstructor(String.class, int.class);
objectClass.getDeclaredConstructor(new Classil { String.class, int.class });
Constructor 类中提供的常用方法
Modifier 类中的常用解析方法
例如,判断对象 constructor 所代表的构造方法是否被 private 修饰,以及以字符串形式获得该构造
方法的所有修饰符的典型代码如下:
int modifiers = constructor.getModifiers();
boolean isEmbellishByPrivate = Modifier.isPrivate(modifiers);
String embelishment = Modifier.toString(modifiers);
方法的所有修饰符的典型代码如下:
int modifiers = constructor.getModifiers();
boolean isEmbellishByPrivate = Modifier.isPrivate(modifiers);
String embelishment = Modifier.toString(modifiers);
例题 . 反射一个类的所有构造方法
在com.mr包下创建一个Demo1类,在该类声明一个Strin型成员变量和3个int型成员变量,并提供三个构造方法
在com.mr包下创建一个Demo1类,在该类声明一个Strin型成员变量和3个int型成员变量,并提供三个构造方法
编写测试类ConstructorDemo1,在该类中通过反射访问com.mr.Demo1类中的所有构造方法,并将该构造方法是否允许带有可变数量的参数、入口参数类型和可能抛出的异常类型信息输出到控制台。
16.1.2 访问成员变量
在通过下列一组方法访问成员变量时,将返回Field 类型的对象或数组。每个Field对象代表一个成员变量,利用Ficld 对象可以操纵相应的成员变量:
getFields()
getField(String name)
getDeclaredFields()
getDeclaredField(String name)
如果是访问指定的成员变量,可以通过该成员变量的名称来访问。例如,访问一个名称为birthday的成员变量,访问方法如下:
object. getDeclaredField("birthday");
getFields()
getField(String name)
getDeclaredFields()
getDeclaredField(String name)
如果是访问指定的成员变量,可以通过该成员变量的名称来访问。例如,访问一个名称为birthday的成员变量,访问方法如下:
object. getDeclaredField("birthday");
Field 类中提供的常用方法
例题. 反射一个类的所有成员变量
在com.mr包下创建一个Demo2类
在com.mr包下创建一个Demo2类
16.1.3 访问成员方法
在通过下列一组方法访问成员方法时,将返回Method类型的对象或数组。每个Method对象代表-个方法,利用Method 对象可以操纵相应的方法:
getMethods()
getMethod(String name, Class<?>...parameterTypes)
getDeclaredMethods()
getDeclaredMethod(String name, Class<?>...parameterTypes)
如果是访问指定的方法,需要根据该方法的名称和入口参数的类型来访问。例如,访问一个名称为print、入口参数类型依次为String型和int型的方法,通过下面两种方式均可实现:
objectClass.getDeclaredMethod("print",String.class, int.class);
objectClass.getDeclaredMethod("print", new Class[] {String.class, int.class });
getMethods()
getMethod(String name, Class<?>...parameterTypes)
getDeclaredMethods()
getDeclaredMethod(String name, Class<?>...parameterTypes)
如果是访问指定的方法,需要根据该方法的名称和入口参数的类型来访问。例如,访问一个名称为print、入口参数类型依次为String型和int型的方法,通过下面两种方式均可实现:
objectClass.getDeclaredMethod("print",String.class, int.class);
objectClass.getDeclaredMethod("print", new Class[] {String.class, int.class });
Method 类中提供的常用方法
例题. 反射一个类的所有成员方法
16.2 Annotation注解功能
该功能可用于类、构造方法、成员变量、成员方法、参数等的声明中。该功能并不会影响程序的运行,但是会对编译器警告等辅助工具产生影响
16.2.1 定义Annotation类型
内置注解:
@Override :限定重写父类方法作用范围成员方法
@SuppressWarnings :抑制编译器警告作用范围类、成员属性、成员方法
@Deprecated :标示已过时作用范围类、成员属性、成员方法
在定义Annotation 类型时,也需要用到用来定义接口的interface 关键字,但需要在interface关键字前加一个“@”符号,即定义Annotation 类型的关键字为@interface,这个关键字的隐含意思是继承了 java.lang.annotation.Annotation 接口。例如,下面的代码就定义了一个 Annotation 类型:
public @interface NoMemberAnnotation{
}
上面定义的Annotation类型@NoMemberAnnotation未包含任何成员,这样的Annotation类型被称为marker annotation。下面的代码定义了一个只包含一个成员的Annotation类型:
public @interface OneMemberAnnotation {
String value();
}
String:成员类型。可用的成员类型有 String、Class、primitive、enumerated和annotation,以及所列类型的数组
value:成员名称。如果在所定义的Annotation 类型中只包含一个成员,通常将成员名称命名为value
下面的代码定义了一个包含多个成员的Annotation类型:
public @interface MoreMemberAnnotation {
String describe();
Class type();
}
在为Annotation 类型定义成员时,也可以为成员设置默认值。例如,下面的代码在定义Annotation型时就为成员设置了默认值:
public @interface DefaultValueAnnotation
String describe() default "<默认值>";
Class type() default void.class;
}
@Override :限定重写父类方法作用范围成员方法
@SuppressWarnings :抑制编译器警告作用范围类、成员属性、成员方法
@Deprecated :标示已过时作用范围类、成员属性、成员方法
在定义Annotation 类型时,也需要用到用来定义接口的interface 关键字,但需要在interface关键字前加一个“@”符号,即定义Annotation 类型的关键字为@interface,这个关键字的隐含意思是继承了 java.lang.annotation.Annotation 接口。例如,下面的代码就定义了一个 Annotation 类型:
public @interface NoMemberAnnotation{
}
上面定义的Annotation类型@NoMemberAnnotation未包含任何成员,这样的Annotation类型被称为marker annotation。下面的代码定义了一个只包含一个成员的Annotation类型:
public @interface OneMemberAnnotation {
String value();
}
String:成员类型。可用的成员类型有 String、Class、primitive、enumerated和annotation,以及所列类型的数组
value:成员名称。如果在所定义的Annotation 类型中只包含一个成员,通常将成员名称命名为value
下面的代码定义了一个包含多个成员的Annotation类型:
public @interface MoreMemberAnnotation {
String describe();
Class type();
}
在为Annotation 类型定义成员时,也可以为成员设置默认值。例如,下面的代码在定义Annotation型时就为成员设置了默认值:
public @interface DefaultValueAnnotation
String describe() default "<默认值>";
Class type() default void.class;
}
在定义Annotation 类型时,还可以通过 Annotation 类型@Target 来设置Annotation类型适用的程序元素种类。如果未设置@Target,则表示适用于所有程序元素。枚举类 ElementType 中的枚举常量用来设置@Targer
通过 Amotaion 类型@Retenion 可以设置Amnotation 的有效范围。枚举类RetentioPolicy 中的枚举常量用来设置@Rctention, 如表所示。如果未设置@Retention,Annotation 的有效范围为枚举常量CLASS 表示的范围
16.2.2 访问Annotation 信息
十七、数据库操作
一、数据库内操作
1.搜索栏内输入cmd,以管理员身份运行。
2.登入MySQL
3.创建数据库和表
二、java内部操作
三、连接数据库
1.注册驱动
//注册驱动 获取链接
public void getConnection() throws SQLException{
//第一步:注册驱动
DriverManager.registerDriver(new Driver());
public void getConnection() throws SQLException{
//第一步:注册驱动
DriverManager.registerDriver(new Driver());
2.获取链接
coonection = DriverManager.getConnection("jdbc:mysql://localhost:3306/school_java","root","1234");
3.获取statment对象
PreparedStatement prepareStatedment = coonection.prepareStatement("insert into course values (?,?)");
4. 执行SQL语句返回结果集
ResultSet resultSet=prepareStatedment.executeQuery();
5.遍历结果集
while(resultSet.next()) {
System.out.print(resultSet.getInt("id"));
System.out.println(resultSet.getString("name"));
}
System.out.print(resultSet.getInt("id"));
System.out.println(resultSet.getString("name"));
}
6.关闭连接释放资源
```java
resultSet.close();
prepareStatedment.close();
```//关闭连接
private void close() throws SQLException{
coonection.close();
}
resultSet.close();
prepareStatedment.close();
```//关闭连接
private void close() throws SQLException{
coonection.close();
}
7.整体代码
十八、Swing程序设计
18.1 Swing概述
String包的层次结构和继承关系如下
常用的Swing组件如下表:
18.2 Swing常用窗体
18.2.1 JFrame 窗体
JFrame 类的常用构造方法包括以下两种形式:
public JFrame():创建一个初始不可见、没有标题的窗体。
public JFrame(String title):创建一个不可见、具有标题的窗体。
例如,创建一个不可见、具有标题的窗体,关键代码如下:
JFrame jf = new JFrame(“登录系统”);
Container container = jf.getContentPane();
在创建窗体后,先调用getContentPaneO方法将窗体转换为容器,再调用addO方法或者removeO方法向容器中添加组件或者删除容器中的组件。向容器中添加按钮,关键代码如下:
JButton okBtn= new JButton(“确定“)
container.add(okBtn);
删除容器中的按钮,关键代码如下:
container.remove(okBtn);
public JFrame():创建一个初始不可见、没有标题的窗体。
public JFrame(String title):创建一个不可见、具有标题的窗体。
例如,创建一个不可见、具有标题的窗体,关键代码如下:
JFrame jf = new JFrame(“登录系统”);
Container container = jf.getContentPane();
在创建窗体后,先调用getContentPaneO方法将窗体转换为容器,再调用addO方法或者removeO方法向容器中添加组件或者删除容器中的组件。向容器中添加按钮,关键代码如下:
JButton okBtn= new JButton(“确定“)
container.add(okBtn);
删除容器中的按钮,关键代码如下:
container.remove(okBtn);
创建窗体后,要对窗体进行设置,如设置窗体的位置、大小、是否可见等。JFrame 类提供的相应方法可实现上述设置操作,具体如下:
setBounds(int x, int y, int width, int leight):设置窗体左上角在屏幕中的坐标为(x,y),窗体的宽度为width,窗体的高度为height。
setLocation(int x,int y):设置窗体左上角在屏幕中的坐标为(x,y)。
setSize(int width, int height):设置窗体的宽度为width,高度为height。
setVisibale(boolean b):设置窗体是否可见。b为true时,表示可见;b为false时,表示不可见。setDefaultCloseOperation(int operation):设置窗体的关闭方式,默认值为DISPOSE_ON_CLOSE
setBounds(int x, int y, int width, int leight):设置窗体左上角在屏幕中的坐标为(x,y),窗体的宽度为width,窗体的高度为height。
setLocation(int x,int y):设置窗体左上角在屏幕中的坐标为(x,y)。
setSize(int width, int height):设置窗体的宽度为width,高度为height。
setVisibale(boolean b):设置窗体是否可见。b为true时,表示可见;b为false时,表示不可见。setDefaultCloseOperation(int operation):设置窗体的关闭方式,默认值为DISPOSE_ON_CLOSE
Java 语言提供了多种窗体的关闭方式,常用的有4种,如表所示。
例题.. 第一个窗体程序
18.2.2 JDialog 对话框
JDialog 类常用的构造方法如下:
public JDialogO:创建一个没有标题和父窗体的对话框。
public JDialog(Frame f):创建一个没有标题,但指定父窗体的对话框。
public JDialog(Frame f, boolean model):创建一个没有标题,但指定父窗体和模式的对话框。如果model为true,那么弹出对话框后,用户无法操作父窗体。
public JDialog(Frame f, String title):创建一个指定标题和父窗体的对话框.。
public JDialog(Frame f, String title, boolean model):创建一个指定标题、父窗体和模式的对话框。
public JDialogO:创建一个没有标题和父窗体的对话框。
public JDialog(Frame f):创建一个没有标题,但指定父窗体的对话框。
public JDialog(Frame f, boolean model):创建一个没有标题,但指定父窗体和模式的对话框。如果model为true,那么弹出对话框后,用户无法操作父窗体。
public JDialog(Frame f, String title):创建一个指定标题和父窗体的对话框.。
public JDialog(Frame f, String title, boolean model):创建一个指定标题、父窗体和模式的对话框。
例题.. 在窗体中弹出对话框
18.2.3 JOptionPane 小型对话框
JOptionPane提供了4种创建对话框的方法
1.自定义对话框
参数说明如下:
parentComponent:指明对话框在哪个窗体上显示,如果传入具体的窗体对象,对话框会在该窗体居中位置显示,如果传入null则在屏幕中间弹出对话框。
message:提示的信息。
title:对话框的标题。
optionType:指定可用于对话框的选项的整数:DEFAULT_OPTION、YES NO_OPTION.YES NO_CANCEL_OPTION 或 OK_CANCEL_OPTION。
messageType:指定消息种类的整数,主要用于确定来自可插入外观的图标ERRORMESSAGE、INFORMATION_MESSAGE、WARNING_MESSAGE、QUESTION_MESSAGE 或 PLAIN_MESSAGE。
icon:在对话框中显示的图标。
options:指示用户可能选择的对象组成的数组。如果对象是组件,则可以正确呈现,非String对象使用其toString方法呈现;如果此参数为null,则由外观确定选项。
initialValue:表示对话框的默认选择的对象,只有在使用options 时才有意义,可以为null。
参数说明如下:
parentComponent:指明对话框在哪个窗体上显示,如果传入具体的窗体对象,对话框会在该窗体居中位置显示,如果传入null则在屏幕中间弹出对话框。
message:提示的信息。
title:对话框的标题。
optionType:指定可用于对话框的选项的整数:DEFAULT_OPTION、YES NO_OPTION.YES NO_CANCEL_OPTION 或 OK_CANCEL_OPTION。
messageType:指定消息种类的整数,主要用于确定来自可插入外观的图标ERRORMESSAGE、INFORMATION_MESSAGE、WARNING_MESSAGE、QUESTION_MESSAGE 或 PLAIN_MESSAGE。
icon:在对话框中显示的图标。
options:指示用户可能选择的对象组成的数组。如果对象是组件,则可以正确呈现,非String对象使用其toString方法呈现;如果此参数为null,则由外观确定选项。
initialValue:表示对话框的默认选择的对象,只有在使用options 时才有意义,可以为null。
例题. 弹出对话框并1询问
2.确认框
调出带有选项 Yes、No 和Cancel的对话框;标题为 Select an Option。
static int showConfirmDialog(Component parentComponent, Object message)
调出一个由optionType参数确定其中选项数的对话框。
static int showConfirmDialog(Component parentComponent, Object message, String title, int optionType)
调用一个由optionType参数确定其中选项数的对话框,messageType参数确定要显示的图标。
static int showConfirmDialog(Component parentComponent,
Object message,
String title,
int optionType,
int messageType)
调出一个带有指定图标的对话框,其中的选项数由optionType 参数确定。
static int showConfirmDialog(Component parentComponent,
Object message,
String title,
int optionType,
int messageType,
Icon icon)
调出带有选项 Yes、No 和Cancel的对话框;标题为 Select an Option。
static int showConfirmDialog(Component parentComponent, Object message)
调出一个由optionType参数确定其中选项数的对话框。
static int showConfirmDialog(Component parentComponent, Object message, String title, int optionType)
调用一个由optionType参数确定其中选项数的对话框,messageType参数确定要显示的图标。
static int showConfirmDialog(Component parentComponent,
Object message,
String title,
int optionType,
int messageType)
调出一个带有指定图标的对话框,其中的选项数由optionType 参数确定。
static int showConfirmDialog(Component parentComponent,
Object message,
String title,
int optionType,
int messageType,
Icon icon)
例题.. 弹出对话框并询问
3.输入框
输入框已经封装好了一套外观样式,弹出后要求用户在文本框中输入文本,用户完成输入操作后,输入框可以返回用户输入的结果。创建输入框的方法有以下几种重载形式:
显示请求用户输入内容的问题消息对话框,它以parentComponent为父级。
static String showlnputDialog(Component parentComponent, Object message)
显示请求用户输入内容的问题消息对话框,它以parentComponent为父级。
static String showlnputDialog(Component parentComponent, Object message, Object initialSelectionValue)
显示请求用户输入内容的对话框,它以parentComponent为父级,该对话框的标题为title,消息类型为messageType。
static String showlnputDialog(Component parentComponent, Object message, String title, int messageType)
提示用户在可以指定初始选择、可能选择及其他所有选项的模块化的对话框中输入内容。
static Object showInputDialog(Component parentComponent,
Object message,
String title,
int messageType,
Icon icon,
Objectü selectionValues,
Object initialSelectionValue)
显示请求用户输入的问题消息对话框
static String showInputDialog(Object message)
显示请求用户输入的问题消息对话框,它带有已初始化为initialSelectionValue的输入值。
static String showInputDialog(Object message, Object initialSelectionValue)
输入框已经封装好了一套外观样式,弹出后要求用户在文本框中输入文本,用户完成输入操作后,输入框可以返回用户输入的结果。创建输入框的方法有以下几种重载形式:
显示请求用户输入内容的问题消息对话框,它以parentComponent为父级。
static String showlnputDialog(Component parentComponent, Object message)
显示请求用户输入内容的问题消息对话框,它以parentComponent为父级。
static String showlnputDialog(Component parentComponent, Object message, Object initialSelectionValue)
显示请求用户输入内容的对话框,它以parentComponent为父级,该对话框的标题为title,消息类型为messageType。
static String showlnputDialog(Component parentComponent, Object message, String title, int messageType)
提示用户在可以指定初始选择、可能选择及其他所有选项的模块化的对话框中输入内容。
static Object showInputDialog(Component parentComponent,
Object message,
String title,
int messageType,
Icon icon,
Objectü selectionValues,
Object initialSelectionValue)
显示请求用户输入的问题消息对话框
static String showInputDialog(Object message)
显示请求用户输入的问题消息对话框,它带有已初始化为initialSelectionValue的输入值。
static String showInputDialog(Object message, Object initialSelectionValue)
例题.. 弹出对话框,让用户输入自己的姓名
4.通知框
创建通知框方法有以下几种重载形式:
调出标题为Message的信息消息对话框。
static void showMessageDialog(Component parentComponent, Object message)
调出对话框,它显示使用由messageType 参数确定的默认图标的message。
static void showMessageDialog(Component parentComponent,
Object message,
String title,
int messageType)
调出一个显示信息的对话框,为其指定了所有参数。
static void showMessageDialog(Component parentComponent,
Object message,
String title,
int messageType,
Icon icon)
创建通知框方法有以下几种重载形式:
调出标题为Message的信息消息对话框。
static void showMessageDialog(Component parentComponent, Object message)
调出对话框,它显示使用由messageType 参数确定的默认图标的message。
static void showMessageDialog(Component parentComponent,
Object message,
String title,
int messageType)
调出一个显示信息的对话框,为其指定了所有参数。
static void showMessageDialog(Component parentComponent,
Object message,
String title,
int messageType,
Icon icon)
例题..弹出警告对话框
18.3 常用布局管理器
18.3.1 null绝对布局
特点:硬性指定组件在容器中的位置和大小,组件的位置通过绝对坐标的方式来指定。
例题..使用绝对布局定位按钮的大小和位置
18.3.2 FlowLayout 流布局管理器
FlowLayout类具有以下常用的构造方法:
public FlowLayout()。
public FlowLayout(int alignment)。
public FlowLayout(int alignment,int horizGap,int vertGap)。
public FlowLayout()。
public FlowLayout(int alignment)。
public FlowLayout(int alignment,int horizGap,int vertGap)。
例题.. 使用流布局排序按钮
18.3.3 BorderLayout 边界布局管理器
addo方法被用于实现向容器中添加组件的功能,它可以设置组件的摆放位置。addO方法常用的语
法格式如下:
public void add(Component comp, Object constraints)
comp:被添加的组件。
constraints:被添加组件的布局约束对象。
法格式如下:
public void add(Component comp, Object constraints)
comp:被添加的组件。
constraints:被添加组件的布局约束对象。
例题.. 使用边界布局排列按钮
18.3.4 GridLayout 网络布局管理器
网格布局管理器主要有以下两个常用的构造方法:
public GridLayout(int rows, int columns)。
public GridLayout(int rows, int columns, int horizGap, int vertGap)。
其中,参数rows 和columns分别代表网格的行数和列数,这两个参数只允许有一个参数可以为0,被用于表示一行或一列可以排列任意多个组件;参数horizGap和vertGap分别代表网格之间的水平间距和垂直间距。
public GridLayout(int rows, int columns)。
public GridLayout(int rows, int columns, int horizGap, int vertGap)。
其中,参数rows 和columns分别代表网格的行数和列数,这两个参数只允许有一个参数可以为0,被用于表示一行或一列可以排列任意多个组件;参数horizGap和vertGap分别代表网格之间的水平间距和垂直间距。
例题. 使用网格布局排列按钮
18.4 常用面板
18.4.1 JPanel 面板
18.4.2 JScrollPane 滚动面板
JScrollPane 滚动面板 不能使用布局管理器,且只能容纳一个组件
例题.. 为窗体添加上下滚动条
18.5 文字标签组件与图标
18.5.1 JLable 标签
JLabel类常用的构造方法如下:
public JLabel0:创建一个不带图标或文本的标签。
public JLabel(Icon icon):创建一个带图标的标签。
public JLabel(Icon icon, int aligment):创建一个带图标的标签,并设置图标的水平对齐方式。
public JLabel(String text, int aligment):创建一个带文本的标签,并设置文本的水平对齐方式。
public JLabel(String text, Icon icon, int aligment):创建一个带文本和图标的JLabel对象,并设置文本和图标的水平对齐方式。
public JLabel0:创建一个不带图标或文本的标签。
public JLabel(Icon icon):创建一个带图标的标签。
public JLabel(Icon icon, int aligment):创建一个带图标的标签,并设置图标的水平对齐方式。
public JLabel(String text, int aligment):创建一个带文本的标签,并设置文本的水平对齐方式。
public JLabel(String text, Icon icon, int aligment):创建一个带文本和图标的JLabel对象,并设置文本和图标的水平对齐方式。
18.5.2 图标的使用
在Swing 程序设计中,图标经常被添加到标签、按钮等组件,使用javax.swing.Imagelcon类可以依据现有的图片创建图标。ImageIcon类实现了Icon接口,它有多个构造方法,常用的如下:
public ImagelconO:创建一个 Imagelcon 对象,创建 ImageIcon对象后,使用其调用 setImage(Image image)方法设置图片。
public Imagelcon(Image image):依据现有的图片创建图标。
public ImageIcon(URL url):依据现有图片的路径创建图标。
public ImagelconO:创建一个 Imagelcon 对象,创建 ImageIcon对象后,使用其调用 setImage(Image image)方法设置图片。
public Imagelcon(Image image):依据现有的图片创建图标。
public ImageIcon(URL url):依据现有图片的路径创建图标。
18.6 按钮组件
18.6.1 JButton 按钮
Swing 按钮由JButton对象表示,JButton常用的构造方法如下:
public JButtonO:创建一个不带文本或图标的按钮。
public JButton(String text):创建一个带文本的按钮。
public JButton(Icon icon):创建一个带图标的按钮。
public JButton(String text, Icon icon):创建一个带文本和图标的按钮。
创建JButon 对象后,如果要对JButton 对象进行设置,那么可以使用JButton类提供的方法。
public JButtonO:创建一个不带文本或图标的按钮。
public JButton(String text):创建一个带文本的按钮。
public JButton(Icon icon):创建一个带图标的按钮。
public JButton(String text, Icon icon):创建一个带文本和图标的按钮。
创建JButon 对象后,如果要对JButton 对象进行设置,那么可以使用JButton类提供的方法。
Button 类的常用方法及其说明
18.6.2 JRadinButton 单选按钮
1.单选按钮
创建JRadioButton 对象需要使用JRadioButton 类的构造方法。JRadioButton类常用的构造方法如下:
public JRadioButton():创建一个未被选中、文本未被设定的单选按钮。
public JRadioButton(Icon icon):创建一个未被选中、文本未被设定,但具有指定图标的单选按钮。
public JRadioButton(Icon icon, boolean selected):创建一个具有指定图标、选择状态,但文本区未被设定的单选按钮。
public JRadioButton(String text):创建一个具有指定文本,但未被选中的单选按钮。
public JRadioButton(String text, Icon icon):创建一个具有指定文本、指定图标,但未被选中的
单选按钮。
public JRadioButton(String text, Icon icon, boolean selected):创建一个具有指定的文本、指定图标和选择状态的单选按钮。
根据上述构造方法的相关介绍,不难发现,单选按钮的图标、文本和选择状态等属性能够被同时设定。例如,使用JRadioButton 类的构造方法创建一个文本为“选项 A”的单选按钮,关键代码如下:
JRadioButton rbtn = new JRadioButton("选项 A");
创建JRadioButton 对象需要使用JRadioButton 类的构造方法。JRadioButton类常用的构造方法如下:
public JRadioButton():创建一个未被选中、文本未被设定的单选按钮。
public JRadioButton(Icon icon):创建一个未被选中、文本未被设定,但具有指定图标的单选按钮。
public JRadioButton(Icon icon, boolean selected):创建一个具有指定图标、选择状态,但文本区未被设定的单选按钮。
public JRadioButton(String text):创建一个具有指定文本,但未被选中的单选按钮。
public JRadioButton(String text, Icon icon):创建一个具有指定文本、指定图标,但未被选中的
单选按钮。
public JRadioButton(String text, Icon icon, boolean selected):创建一个具有指定的文本、指定图标和选择状态的单选按钮。
根据上述构造方法的相关介绍,不难发现,单选按钮的图标、文本和选择状态等属性能够被同时设定。例如,使用JRadioButton 类的构造方法创建一个文本为“选项 A”的单选按钮,关键代码如下:
JRadioButton rbtn = new JRadioButton("选项 A");
2.按钮组
Swing 按钮组由 ButtonGroup对象表示,多个单选按钮被添加到按钮组后,能够实现“选项有多个,
但只能选中一个”的效果。ButtonGroup 对象被创建后,可以使用add()方法把多个单选按钮添加到
ButtonGroup对象中。
Swing 按钮组由 ButtonGroup对象表示,多个单选按钮被添加到按钮组后,能够实现“选项有多个,
但只能选中一个”的效果。ButtonGroup 对象被创建后,可以使用add()方法把多个单选按钮添加到
ButtonGroup对象中。
18.6.3 JCheckBox 复选框
JCheckBox的常用构造方法如下:
public JCheckBox():创建一个文本、图标未被设定且默认未被选中的复选框。
public JCheckBox(Icon icon, Boolean checked):创建一个具有指定图标、指定初始时是否被选中,但文本未被设定的复选框。
public JCheckBox(String text, Boolean checked):创建一个具有指定文本、指定初始时是否被选中,但图标未被设定的复选框。
public JCheckBox():创建一个文本、图标未被设定且默认未被选中的复选框。
public JCheckBox(Icon icon, Boolean checked):创建一个具有指定图标、指定初始时是否被选中,但文本未被设定的复选框。
public JCheckBox(String text, Boolean checked):创建一个具有指定文本、指定初始时是否被选中,但图标未被设定的复选框。
18.7 列表组件
18.7.1 JComboBox 下拉列表框
JComboBox 类的常用构造方法如下:
public JComboBox(ComboBoxModeldataModel):创建一个 JComboBox对象,下拉列表中的列表项使用ComboBoxModel中的列表项,ComboBoxModel 是一个用于组合框的数据模型。
public JComboBox(Object[]arrayData):创建一个包含指定数组中的元素的JComboBox对象。
public JComboBox(Vector vector):创建一个包含指定 Vector 对象中的元素的JComboBox 对象.Voetor对象中的元素可以通过整数索引进行访问,而且 Vector 对象中的元素可以根据需求被添加或者移除。
public JComboBox(ComboBoxModeldataModel):创建一个 JComboBox对象,下拉列表中的列表项使用ComboBoxModel中的列表项,ComboBoxModel 是一个用于组合框的数据模型。
public JComboBox(Object[]arrayData):创建一个包含指定数组中的元素的JComboBox对象。
public JComboBox(Vector vector):创建一个包含指定 Vector 对象中的元素的JComboBox 对象.Voetor对象中的元素可以通过整数索引进行访问,而且 Vector 对象中的元素可以根据需求被添加或者移除。
JComboBox类的常用方法及其说明
18.7.2 JList 列表框
JList类的常用构造方法如下:
public void JList():创建一个空的JList对象。
public void JList(Object[] listData):创建一个显示指定数组中的元素的JList对象。
public void JList(Vector listData):创建一个显示指定 Vector 中的元素的JList对象。
public void JList(ListModel dataModel):创建一个显示指定的非 null模型的元素的JList对象。
public void JList():创建一个空的JList对象。
public void JList(Object[] listData):创建一个显示指定数组中的元素的JList对象。
public void JList(Vector listData):创建一个显示指定 Vector 中的元素的JList对象。
public void JList(ListModel dataModel):创建一个显示指定的非 null模型的元素的JList对象。
18.8 文本组件
18.8.1 JTextField文本框
文本框组件由JTextField对象表示。JTextField类的常用构造方法如下:
public JTextFieldO:创建一个文本未被指定的文本框。
public JTextField(String text):创建一个指定文本的文本框。
public JTextField(int fieldwidth):创建一个指定列宽的文本框。
public JTextField(String text, int fieldwidth):创建一个指定文本和列宽的文本框。
public JTextField(Document docModel, String text, int fieldWidth):创建一个指定文本模型、本内容和列宽的文本框。
如果要为一个文本未被指定的文本框设置文本内容,那么需要使用 setTextO方法。setText0方法的语法如下:
public void setText(String t)
其中,t表示文本框要显示的文本内容。
public JTextFieldO:创建一个文本未被指定的文本框。
public JTextField(String text):创建一个指定文本的文本框。
public JTextField(int fieldwidth):创建一个指定列宽的文本框。
public JTextField(String text, int fieldwidth):创建一个指定文本和列宽的文本框。
public JTextField(Document docModel, String text, int fieldWidth):创建一个指定文本模型、本内容和列宽的文本框。
如果要为一个文本未被指定的文本框设置文本内容,那么需要使用 setTextO方法。setText0方法的语法如下:
public void setText(String t)
其中,t表示文本框要显示的文本内容。
18.8.2 JPasswordField 密码框
密码框组件由JPasswordField对象表示,其作用是把用户输入的字符串以某种符号进行加密。JPasswordField类的常用构造方法如下:
public JPasswordFieldO:创建一个文本未被指定的密码框。
public JPasswordFiled(String text):创建一个指定文本的密码框。
public JPasswordField(int fieldwidth):创建一个指定列宽的密码框。
public JPasswordField(String text, int fieldwidth):创建一个指定文本和列宽的密码框。
public JPasswordField(Document docModel, String text, int fieldWidth):创建一个指定文本模型和列宽的密码框。
JPasswordField 类提供了setEchoCharO方法,这个方法被用于改变密码框的回显字符。setEchoCharO方法的语法如下:
public void setEchoChar(char c)
其中,c表示密码框要显示的回显字符
public JPasswordFieldO:创建一个文本未被指定的密码框。
public JPasswordFiled(String text):创建一个指定文本的密码框。
public JPasswordField(int fieldwidth):创建一个指定列宽的密码框。
public JPasswordField(String text, int fieldwidth):创建一个指定文本和列宽的密码框。
public JPasswordField(Document docModel, String text, int fieldWidth):创建一个指定文本模型和列宽的密码框。
JPasswordField 类提供了setEchoCharO方法,这个方法被用于改变密码框的回显字符。setEchoCharO方法的语法如下:
public void setEchoChar(char c)
其中,c表示密码框要显示的回显字符
18.8.3 JTextArea 文本域
文本城组件曲 JTextArea 对象表示,其作用是接受用户的多行文本输入。JTextArea类的常用构造方法如下:
patie TextArea0:创建一个文本未被指定的文本域。
publie NTtextArea(String text):创建一个指定文本的文本域。
pabic leatAesfint rows,int columns):创建一个指定行高和列宽,但文本未被指定的文本域。
public JTextArea(Document doc): 创建一个指定文档模型的文本域。
public JTextArea(Document doc,String Text,int rows,int columns):创建内容以及行高和列宽的文本域
patie TextArea0:创建一个文本未被指定的文本域。
publie NTtextArea(String text):创建一个指定文本的文本域。
pabic leatAesfint rows,int columns):创建一个指定行高和列宽,但文本未被指定的文本域。
public JTextArea(Document doc): 创建一个指定文档模型的文本域。
public JTextArea(Document doc,String Text,int rows,int columns):创建内容以及行高和列宽的文本域
18.9 表格组件
18.9.1 创建表格
JTable 类除提供了默认的构造方法外,还提供了被用于显示二维数组中的元素的构造方法,这个
构造方法的语法如下:
JTable(Object[][] rowData, Objectl columnNames)
rowData:存储表格数据的二维数组。
columnNames:存储表格列名的一维数组。
构造方法的语法如下:
JTable(Object[][] rowData, Objectl columnNames)
rowData:存储表格数据的二维数组。
columnNames:存储表格列名的一维数组。
18.9.2 DefaultTableModel 表格数据模型
Swing 使用 TableModel 接口定义了一个表格模型,AbstractTableModel 抽象类实现了 TableModel接口的大部分方法,只有以下3个抽象方法没有实现:
public int getRowCountO);
public int getColumnCountO);
public Object getValueAt(int rowIndex, int columnIndex);
为了实现使用表格模型创建表格的功能,Swing 提供了表格模型类,即DefaultTableModel类。DefaultTableModel 类继承了 AbstractTableModel 抽象类且实现了上述3个抽象方法。
public int getRowCountO);
public int getColumnCountO);
public Object getValueAt(int rowIndex, int columnIndex);
为了实现使用表格模型创建表格的功能,Swing 提供了表格模型类,即DefaultTableModel类。DefaultTableModel 类继承了 AbstractTableModel 抽象类且实现了上述3个抽象方法。
DefaultTableModel类提供的常用构造方法
18.9.3 维护表格模型
18.10 事件监听器
18.10.1 ActionEvent动作事件
动作事件( ActionEvent)监听器是Swing中比较常用的事件监听器,很多组件的动作都会使用它监听,如按钮被单击等。下表描述了动作事件监听器的接口与事件源等。
18.10.2 KeyEvent键盘事件
当向文本框中输入内容时,将发生键盘事件。KeyEvent类负责捕获键盘事件,可以通过为组件添加实现了KeyListener接口的监听器类来处理相应的键盘事件。
KeyListener接口共有三个抽象方法,分别在发生击键事件(按下并释放键)、按键被按下(手指按下键但不松开)和按键被释放(手指从按下的键松开)时被触发,具体如下:
public interface KeyListener extends EventListener {
public void keyTyped(KeyEvent e); //发生击键事件时被触发
public void keyPressed(KeyEvent e); //按键被按下时被触发
public void keyReleased(KeyEvent e); //按键被释放时被触发
}
KeyListener接口共有三个抽象方法,分别在发生击键事件(按下并释放键)、按键被按下(手指按下键但不松开)和按键被释放(手指从按下的键松开)时被触发,具体如下:
public interface KeyListener extends EventListener {
public void keyTyped(KeyEvent e); //发生击键事件时被触发
public void keyPressed(KeyEvent e); //按键被按下时被触发
public void keyReleased(KeyEvent e); //按键被释放时被触发
}
18.10.3 MouseEvent 鼠标事件
MouseEvent鼠标事件
所有组件都能发生鼠标事件,MouseEvent类负责捕获鼠标事件,可以通过为组件添加实现MouseListener接口的监听器来处理相应的鼠标事件。
MouseListener接口共有5个抽象方法,分别在光标移入或者移出组件、鼠标按键被按下或释放和发生单击事件时被触发。所谓单击事件,就是按键被按下并释放。需要注意的是,如果按键是在移出组件之后才被释放,则不会触发单击事件。MouseListener接口的具体定义如下:
public interface MouseListener extends EventListener {
public void mouseEntered(MouseEvent e); //光标移入组件时被触发
public void mousePressed(MouseEvent e); //鼠标按键被按下时被触发
public void mouseReleased(MouseEvent e); //鼠标按键被释放时被触发
public void mouseClicked(MouseEvent e); //发生单击事件时被触发
public void mouseExited(MouseEvent e); //光标移出组件时被触发
}
所有组件都能发生鼠标事件,MouseEvent类负责捕获鼠标事件,可以通过为组件添加实现MouseListener接口的监听器来处理相应的鼠标事件。
MouseListener接口共有5个抽象方法,分别在光标移入或者移出组件、鼠标按键被按下或释放和发生单击事件时被触发。所谓单击事件,就是按键被按下并释放。需要注意的是,如果按键是在移出组件之后才被释放,则不会触发单击事件。MouseListener接口的具体定义如下:
public interface MouseListener extends EventListener {
public void mouseEntered(MouseEvent e); //光标移入组件时被触发
public void mousePressed(MouseEvent e); //鼠标按键被按下时被触发
public void mouseReleased(MouseEvent e); //鼠标按键被释放时被触发
public void mouseClicked(MouseEvent e); //发生单击事件时被触发
public void mouseExited(MouseEvent e); //光标移出组件时被触发
}
在上述每个抽象方法中,均传入了MouseEvent类的对象。MouseEvent类中比较常用的方法
当 需要判断触发此次事件的按键时,可以通过表18.12中的静态常量判断由getButton()方法返回的int型值代表的键。
十九、Java绘图
19.1 绘图类
19.1.1 Graphics 类
Grapics 类是所有图形上下文的抽象基类,它允许应用程序在组件以及闭屏图像上进行绘制。Graphics 类封装了Java 支持的基本绘图操作所需的状态信息,主要包括颜色、字体、画笔、文本、图像等。
Graphics 类提供了绘图常用的方法,利用这些方法可以实现直线、钜形、多边形、椭面、圆弧等形状和文本、图片的绘制操作。另外,在执行这些操作之前,还可以使用相应的方法设置给图的颜色和字体等状态属性。
Graphics 类提供了绘图常用的方法,利用这些方法可以实现直线、钜形、多边形、椭面、圆弧等形状和文本、图片的绘制操作。另外,在执行这些操作之前,还可以使用相应的方法设置给图的颜色和字体等状态属性。
19.1.2 Graphics2D类
使用Graphics 类可以完成简单的图形绘制任务,但是它所实现的功能非常有限,如无法改变线条的粗细、不能对图片使用旋转和模糊等过滤效果。
Graphics2D 类继承Graphics 类,实现了功能更加强大的绘图操作的集合。由子Graphies2D类是Graphics 类的扩展,也是推荐使用的Java 绘图类。
Graphics2D 类继承Graphics 类,实现了功能更加强大的绘图操作的集合。由子Graphies2D类是Graphics 类的扩展,也是推荐使用的Java 绘图类。
19.2 绘制图形
Java 可以分别使用Graphics 类和 Graphics2D 类绘制图形,Graphics类使用不同的方法实现不同图形的给制。例如,drawLine0方法可以绘制直线,drawRect()方法用于绘制矩形,drawOval0方法用于绘制椭圓形等。
Graphics2D类是在继承Graphics 类的基础上编写的,它包含了Graphics类的绘图方法并添加了更强的功能,在创建绘图类时推荐使用该类。Graphics2D类可以分别使用不同的类来表示不同的形状,Line2D类、Rectangle2D类等。
要绘制指定形状的图形,需要先创建并初始化该图形类的对象,且这些图形类必须是Shape接口药实现类;然后使用Graphics2D类的draw0方法绘制该图形对象,或者使用610方法填充该图形对象。看法格式如下:
draw(Shape form)
或
fill(Shape form)
其中,form 是指实现Shape 接口的对象。
java.awt.geom 包中提供了如下常用的图形类,这些图形类都实现了Shape 接口:
Arc2D类
CubicCurve2D类
Ellipse2D类
Line2D类
Point2D类
QuadCurve2D类
Rectangle2D类
RoundRectangle2D类
要绘制指定形状的图形,需要先创建并初始化该图形类的对象,且这些图形类必须是Shape接口药实现类;然后使用Graphics2D类的draw0方法绘制该图形对象,或者使用610方法填充该图形对象。看法格式如下:
draw(Shape form)
或
fill(Shape form)
其中,form 是指实现Shape 接口的对象。
java.awt.geom 包中提供了如下常用的图形类,这些图形类都实现了Shape 接口:
Arc2D类
CubicCurve2D类
Ellipse2D类
Line2D类
Point2D类
QuadCurve2D类
Rectangle2D类
RoundRectangle2D类
19.3 绘图颜色与画笔属性
19.3.1 设置颜色
使用Color 类可以创建任意颜色的对象,不用担心平台是否支持该颜色,因为Java以跨平台和与硬件无关的方式支持颜色管理。创建Color 对象的构造方法有如下两种:
Color col = new Color(int r, int g, int b)
Color col = new Color(int rgb
rgb:颜色值,该值是红、绿、蓝三原色的总和。
r:该参数是三原色中红色的取值。
g:该参数是三原色中绿色的取值。
b:该参数是三原色中蓝色的取值。
Color col = new Color(int r, int g, int b)
Color col = new Color(int rgb
rgb:颜色值,该值是红、绿、蓝三原色的总和。
r:该参数是三原色中红色的取值。
g:该参数是三原色中绿色的取值。
b:该参数是三原色中蓝色的取值。
绘图类可以使用setColor()方法设置当前颜色。语法如下:
setColor(Color color)
其中,参数color是Color对象,代表一个颜色值,如红色、黄色或默认的黑色
setColor(Color color)
其中,参数color是Color对象,代表一个颜色值,如红色、黄色或默认的黑色
19.3.2 设置画笔
默认情况下,Graphics 类使用的画笔属性是粗细为1个像素的正方形,而Graphics2D类可以调用setStrokeO方法设置画笔的属性,如改变线条的粗细、虚实,定义线段端点的形状、风格等。语法格式如下:
setStroke(Stroke stroke)
其中,参数stroke是Stroke 接口的实现类对象。
setStroke0方法必须接受一个 Stroke 接口的实现类对象作参数,java.awrt包中提供了BasisSrke类它实现了Stroke接口,并且通过不同的构造方法创建画笔属性不同的对象。这些构造方法如下:
setStroke(Stroke stroke)
其中,参数stroke是Stroke 接口的实现类对象。
setStroke0方法必须接受一个 Stroke 接口的实现类对象作参数,java.awrt包中提供了BasisSrke类它实现了Stroke接口,并且通过不同的构造方法创建画笔属性不同的对象。这些构造方法如下:
- BasicStroke()
- BasicStroke(float width)
- BasicStroke(float width, int cap, int join)
- BasicStroke(float width, int cap, int join, float miterlimit)
- BasicStroke(float width, int cap, int join, float miterlimit, float[] dash, float dash_phase)
19.4 绘制文本
19.4.1 设置字体
Java 使用Font 类封装了字体的大小、样式等属性,该类在java.awt包中定义,其构造方法可以指定字体的名称、大小和样式3个属性。语法如下:
Font(String name, int style, int size)
name:字体的名称
style:字体的样式
size:字体的大小
设置绘图类的字体可以使用绘图类的setFontO方法。设置字体以后在图形上下文中绘制的所有文字都使用该字体,除非再次设置其他字体。语法如下:
setFont(Font font)
其中,参数font 是Font 类的字体对象。
Font(String name, int style, int size)
name:字体的名称
style:字体的样式
size:字体的大小
设置绘图类的字体可以使用绘图类的setFontO方法。设置字体以后在图形上下文中绘制的所有文字都使用该字体,除非再次设置其他字体。语法如下:
setFont(Font font)
其中,参数font 是Font 类的字体对象。
19.4.2 显式文字
Graphics2D类提供了drawString0方法,使用该方法可以实现图形上下文的文本绘制,从而实现在图片上显示文字的功能。语法格式有如下两种:
drawString(String str, int x, int y)
drawString(String str, float x, float y)
str:要绘制的文本字符串。
x:绘制字符串的水平起始位置。
y:绘制字符串的垂直起始位置。
这两个方法唯一不同的就是x和y的参数类型不同。
drawString(String str, int x, int y)
drawString(String str, float x, float y)
str:要绘制的文本字符串。
x:绘制字符串的水平起始位置。
y:绘制字符串的垂直起始位置。
这两个方法唯一不同的就是x和y的参数类型不同。
19.5 显示图片
绘图类不仅可以绘制图形和文本,还可以使用drawImageO方法将图片资源显示到绘图上下文中,而且可以实现各种特效处理,如图片的缩放、翻转等。有关图像处理的知识将在19.6节讲解,本节主要讲解如何显示图片。语法如下:
drawimage(lmage img, int x, int y, ImageObserver observer)
drawimage(lmage img, int x, int y, ImageObserver observer)
19.6 图像处理
19.6.1 放大与缩小
在显示图片时,使用了drawImageO方法将图片以原始大小显示在窗体中,要想实现图片的放大与缩小,则需要使用它的重载方法。语法如下:
drawlmage(lmage img, int x, int y, int width, int height, ImageObserver observer)
drawlmage(lmage img, int x, int y, int width, int height, ImageObserver observer)
19.6.2 图片翻转
图像的翻转需要使用drawImage()方法的另一个重载方法。语法如下:
drawimage(lmage img, int dx1, int dy1, int dx2, int dy2, int sx1, int sy1, int sx2, int sy2, ImageObserver observer)
此方法总是用非缩放的图像来呈现缩放的矩形,并动态地执行所需的缩放。此操作不使用缓存的缩放图像。执行图像从源到目标的缩放,要将源矩形的第一个坐标映射到目标矩形的第一个坐标,源矩形的第二个坐标映射到目标矩形的第二个坐标,按需要缩放和翻转子图像,以保持这些映射关系。
drawimage(lmage img, int dx1, int dy1, int dx2, int dy2, int sx1, int sy1, int sx2, int sy2, ImageObserver observer)
此方法总是用非缩放的图像来呈现缩放的矩形,并动态地执行所需的缩放。此操作不使用缓存的缩放图像。执行图像从源到目标的缩放,要将源矩形的第一个坐标映射到目标矩形的第一个坐标,源矩形的第二个坐标映射到目标矩形的第二个坐标,按需要缩放和翻转子图像,以保持这些映射关系。
子主题
19.6.3 图像旋转
图像旋转需要调用Graphics2D类的rotateO方法,该方法将根据指定的弧度旋转图像。语法如下:
rotate(double theta)
其中,theta 是指旋转的弧度
rotate(double theta)
其中,theta 是指旋转的弧度
19.6.4 图像倾斜
可以使用Graphics2D类提供的shearO方法设置绘图的倾斜方向,从而使图像实现倾斜的效果。语法如下:
shear(double shx, double shy)
shx:水平方向的倾斜量
shy : 垂直方向的倾斜量
shear(double shx, double shy)
shx:水平方向的倾斜量
shy : 垂直方向的倾斜量
二十、多线程
20.1 线程简介
在Java中,并发机制非常重要,程序员可以在程序中执行多个线程,每个线程完成一个功能,并与其他线程并发执行,这种机制被称为多线程。但是,并不是所有编程语言都支持多线程。
线程的特点:
1.进程是资源分配的最小单位,线程是最小的执行单位
2.一个进程可以有多个线程
3.线程共享进程资源
Windows操作系统是多任务操作系统,它以进程为单位。一个进程是一个包含有自身地址的程序,每个独立执行的程序都称为进程。也就是说每个正在执行的程序都是一个进程。系统可以分配给每一个进程有一段有限的使用CPU的时间(也可以称为CPU时间片),CPU在这段时间中执行某个进程,然后下一个时间片又跳至另一个进程中去执行。由于CPU转换比较快,所以使得每个进程好像是同时执行一样。
线程的特点:
1.进程是资源分配的最小单位,线程是最小的执行单位
2.一个进程可以有多个线程
3.线程共享进程资源
Windows操作系统是多任务操作系统,它以进程为单位。一个进程是一个包含有自身地址的程序,每个独立执行的程序都称为进程。也就是说每个正在执行的程序都是一个进程。系统可以分配给每一个进程有一段有限的使用CPU的时间(也可以称为CPU时间片),CPU在这段时间中执行某个进程,然后下一个时间片又跳至另一个进程中去执行。由于CPU转换比较快,所以使得每个进程好像是同时执行一样。
20.2 创建线程
20.2.1 继承Thread类
Thread 类时 java.lang 包中的一个类,从类中实例化的对象代表线程,程序员启动一个新线程需要建立 Thread 实例。
Thread类中常用的两个构造方法如下:
public Thread():创建一个新的线程对象。
public Thread(String threadName):创建一个名称为threadName的线程对象。
继承Thread类创建一个新的线程的语法如下:
public class ThreadTest extends Threadf {
}
完成线程真正功能的代码放在类的run0方法中,当一个类继承Thread类后,就可以在该类中覆盖run0方法,将实现该线程功能的代码写入runO方法中,然后调用 Thread类中的start0方法执行线程也就是调用run0方法。
Thread 对象需要一个任务来执行,任务是指线程在启动时执行的工作,该工作的功能代码被写在run0方法中。run0方法必须使用以下语法格式:
public void run() {
}
当执行一个线程程序时,就自动产生一个线程,主方法正是在这个线程上运行的。当不再启动其他线程时,该程序就为单线程程序,如本章以前的程序都是单线程程序。主方法线程启动由Java 虚拟机负责,程序员负责启动自己的线程。代码如下:
public static void main(String[] args){
new ThreadTest().start();
}
Thread类中常用的两个构造方法如下:
public Thread():创建一个新的线程对象。
public Thread(String threadName):创建一个名称为threadName的线程对象。
继承Thread类创建一个新的线程的语法如下:
public class ThreadTest extends Threadf {
}
完成线程真正功能的代码放在类的run0方法中,当一个类继承Thread类后,就可以在该类中覆盖run0方法,将实现该线程功能的代码写入runO方法中,然后调用 Thread类中的start0方法执行线程也就是调用run0方法。
Thread 对象需要一个任务来执行,任务是指线程在启动时执行的工作,该工作的功能代码被写在run0方法中。run0方法必须使用以下语法格式:
public void run() {
}
当执行一个线程程序时,就自动产生一个线程,主方法正是在这个线程上运行的。当不再启动其他线程时,该程序就为单线程程序,如本章以前的程序都是单线程程序。主方法线程启动由Java 虚拟机负责,程序员负责启动自己的线程。代码如下:
public static void main(String[] args){
new ThreadTest().start();
}
20.2.2 实现Runnable 接口
实现Runnable接口的语法如下:
public class Thread extends Object implements Runnable
实现Runnable 接口的程序会创建一个Thread对象,并将 Runnable 对象与Thread对象相关联。Thread类中有以下两个构造方法:
public Thread(Runnable target)
public Thread(Runnable target,String name)
这两个构造方法的参数中都存在Runnable 实例,使用以上构造方法就可以将Runnable实例与Thread实例相关联。
使用Runnable 接口启动新的线程的步骤如下:
建立Runnable对象
使用参数为Runnable对象的构造方法创建Thread实例
调用startO方法启动线程
通过Runnable 接口创建线程时,程序员首先需要编写一个实现Runnable接口的类,然后实例化该类的对象,这样就建立了Runnable对象;接下来使用相应的构造方法创建Thread 实例;最后使用该实例调用Thread类中的startO方法启动线程。
public class Thread extends Object implements Runnable
实现Runnable 接口的程序会创建一个Thread对象,并将 Runnable 对象与Thread对象相关联。Thread类中有以下两个构造方法:
public Thread(Runnable target)
public Thread(Runnable target,String name)
这两个构造方法的参数中都存在Runnable 实例,使用以上构造方法就可以将Runnable实例与Thread实例相关联。
使用Runnable 接口启动新的线程的步骤如下:
建立Runnable对象
使用参数为Runnable对象的构造方法创建Thread实例
调用startO方法启动线程
通过Runnable 接口创建线程时,程序员首先需要编写一个实现Runnable接口的类,然后实例化该类的对象,这样就建立了Runnable对象;接下来使用相应的构造方法创建Thread 实例;最后使用该实例调用Thread类中的startO方法启动线程。
子主题
20.3 线程的生命周期
虽然多线程看起来像同时执行,但事实上在同一时间点上只有一个线程被执行,只是线程之间切换较快,所以才会使人产生线程是同时进行的假象。在Windows操作系统中,系统会为每个线程分配一小段CPU时间片,一旦 CPU时间片结束就会将当前线程换为下一个线程,即使该线程没有结束。要使线程处于就绪状态,有以下几种方法:
调用sleep()方法
调用wait()方法。
等待输入/输出完成。
当线程处于就绪状态后,可以用以下几种方法使线程再次进入运行状态:
线程的休眠时间结束
输入\输出结束
调用sleep()方法
调用wait()方法。
等待输入/输出完成。
当线程处于就绪状态后,可以用以下几种方法使线程再次进入运行状态:
线程的休眠时间结束
输入\输出结束
20.4 操作线程的方法
20.4.1 线程的休眠
一种能控制线程行为的方法是调用sleep()方法,sleep()方法需要一个参数用于指定该线程休眠的时间,该时间以毫秒为单位。sleep()方法语法如下
try{
Thread.sleep(2000);
}catch(InterruptedException e){
e.printStackTrace(();
}
try{
Thread.sleep(2000);
}catch(InterruptedException e){
e.printStackTrace(();
}
20.4.2线程的加入
当某一个线程使用join()方法加入另外一个线程时,另一个线程会等待该线程执行完毕后再继续执行
20.4.3线程的中断
以往有的时候会使用stop()方法停止线程,但当前版本的JDK早己废除了stop()方法,不建议使用stop()方法来停止一个线程的运行。现在提倡在run()方法中使用无限循环的形式,然后使用一个布尔型标记控制循环的停止。
如果线程是因为使用了slcep()或wait()方法进入了就绪状态,可以使用Thread 类中 interrupt()方法使线程离开run()方法,同时结束线程,但程序会抛出InterruptedException异常,用户可以在处理该异常时完成线程的中断业务处理,如终止while循环。
下面的实例演示了某个线程使用interrupted()方法,同时程序抛出了InterruptedException异常,在异常处理时结束了while 循环。在项目中,经常在这里执行关闭数据库连接和关闭Socket连接等操作。
如果线程是因为使用了slcep()或wait()方法进入了就绪状态,可以使用Thread 类中 interrupt()方法使线程离开run()方法,同时结束线程,但程序会抛出InterruptedException异常,用户可以在处理该异常时完成线程的中断业务处理,如终止while循环。
下面的实例演示了某个线程使用interrupted()方法,同时程序抛出了InterruptedException异常,在异常处理时结束了while 循环。在项目中,经常在这里执行关闭数据库连接和关闭Socket连接等操作。
20.4.4 线程的礼让
Thread 类中提供了一种礼让方法,使用yield()方法表示,它只是给当前正处于运行状态的线程个提醒,告知它可以将资源礼让给其他线程,但这仅是一种暗示,没有任何一种机制保证当前线程会将资源礼让。
yield()方法使具有同样优先级的线程有进入可执行状态的机会,在当前线程放弃执行权时会再度回到就绪状体。对于支持多任务的操作系统来说,不需要调用yield()方法,因为操作系统会为线程自动分配CPU时间片来执行。
yield()方法使具有同样优先级的线程有进入可执行状态的机会,在当前线程放弃执行权时会再度回到就绪状体。对于支持多任务的操作系统来说,不需要调用yield()方法,因为操作系统会为线程自动分配CPU时间片来执行。
20.5 线程的优先级
每个线程都具有各自的优先级,线程的优先级可以表明在程序中该线程的重要性,如果有很多线程处于就绪状态,系统会根据优先级来决定首先使哪个线程进入运行状态。但这并不意味着低优先级的线程得不到运行,而只是它运行的概率比较小,如垃圾回收线程的优先级就较低。
Thread类中包含的成员变量代表了线程的某些优先级,如Thread.MIN_PRIORITY(常数1)、Thread.MAXPRIORITY(常数10)、Thread.NORM PRIORITY(常数5)。其中,每个线程的优先级都在 Thread.MIN_PRIORITY~Thread.MAX_PRIORITY,在默认情况下其优先级都是Thread.NORM PRIORITY。每个新产生的线程都继承了父线程的优先级。
在多任务操作系统中,每个线程都会得到一小段CPU时间片运行,在时间结束时,将轮换另一个线程进入运行状态,这时系统会选择与当前线程优先级相同的线程予以运行。系统始终选择就绪状态下优先级较高的线程进入运行状态。处于各个优先级状态下的线程的运行顺序
Thread类中包含的成员变量代表了线程的某些优先级,如Thread.MIN_PRIORITY(常数1)、Thread.MAXPRIORITY(常数10)、Thread.NORM PRIORITY(常数5)。其中,每个线程的优先级都在 Thread.MIN_PRIORITY~Thread.MAX_PRIORITY,在默认情况下其优先级都是Thread.NORM PRIORITY。每个新产生的线程都继承了父线程的优先级。
在多任务操作系统中,每个线程都会得到一小段CPU时间片运行,在时间结束时,将轮换另一个线程进入运行状态,这时系统会选择与当前线程优先级相同的线程予以运行。系统始终选择就绪状态下优先级较高的线程进入运行状态。处于各个优先级状态下的线程的运行顺序
,优先级为5的线程A首先得到CPU时间片;当该时间结束后,轮换到与线程A相同优先级的线程B;当线程 B的运行时间结束后,会继续轮换到线程A,直到线程A与线程B都执行完毕,才会轮换到线程C;当线程C结束后,才会轮换到线程D。
线程的优先级可以使用 setPriority()方法调整,如果使用该方法设置的优先级不在1~10,将产生IllegalArgumentException异常。
线程的优先级可以使用 setPriority()方法调整,如果使用该方法设置的优先级不在1~10,将产生IllegalArgumentException异常。
20.6 线程同步
在单线程程序中,每次只能做一件事情,后面的事情需要等待前面的事情完成后才可以进行,但是如果使用多线程程序,就会发生两个线程抢占资源的问题,如两个人同时说话、两个人同时过同个独木桥等。所以,在多线程编程中需要防止这些资源访问的冲突。Java 提供了线程同步的机制来防止资源访问的冲突。
20.6.1 线程安全
例如,在项目中创建ThreadSafeTest类,该类实现了Rummable接口,在未考虑到线程安全问题的基础上,模拟火车站售票系统的功能的代码如上:
20.6.2 线程同步机制
1.同步块
Java 中提供了同步机制,可以有效地防止资源冲突。同步机制使用synchronized关键字,使用该关键字包含的代码块称为同步块,也称为临界区,语法如下:
synchronized(Object) {
}
通常将共享资源的操作放置在 synchronized 定义的区域内,这样当其他线程获取到这个锁时,就必须等待锁被释放后才可以进入该区域。Object 为任意一个对象,每个对象都存在一个标志位,并具有两个值,分别为0和1。一个线程运行到同步块时首先检查该对象的标志位,如果为0状态,表明此同步块内存在其他线程,这时当期线程处于就绪状态,直到处于同步块中的线程执行完同步块中的代码后,这时该对象的标识位设置为1,当期线程才能开始执行同步块中的代码,并将Object对象的标识位设置为0,以防止其他线程执行同步块中的代码。
Java 中提供了同步机制,可以有效地防止资源冲突。同步机制使用synchronized关键字,使用该关键字包含的代码块称为同步块,也称为临界区,语法如下:
synchronized(Object) {
}
通常将共享资源的操作放置在 synchronized 定义的区域内,这样当其他线程获取到这个锁时,就必须等待锁被释放后才可以进入该区域。Object 为任意一个对象,每个对象都存在一个标志位,并具有两个值,分别为0和1。一个线程运行到同步块时首先检查该对象的标志位,如果为0状态,表明此同步块内存在其他线程,这时当期线程处于就绪状态,直到处于同步块中的线程执行完同步块中的代码后,这时该对象的标识位设置为1,当期线程才能开始执行同步块中的代码,并将Object对象的标识位设置为0,以防止其他线程执行同步块中的代码。
2.同步方法
同步方法就是在方法前面用synchronized关键字修饰的方法,其语法如下:
synchronized void f(){}
当某个对象调用了同步方法时,该对象上的其他同步方法必须等待该同步方法执行完毕后才能被
执行。必须将每个能访问共享资源的方法修饰为synchronized,否则就会出错。
同步方法就是在方法前面用synchronized关键字修饰的方法,其语法如下:
synchronized void f(){}
当某个对象调用了同步方法时,该对象上的其他同步方法必须等待该同步方法执行完毕后才能被
执行。必须将每个能访问共享资源的方法修饰为synchronized,否则就会出错。
修改例题20.7的代码,将共享资源操作放置在用同一个同步方法中
二十一、网络通信
21.1 网络程序设计基础
21.1.1 局域网与互联网
为了实现两台计算机的通信,必须用一个网络线路连接两台计算机。如下图所示
21.1.2 网络协议
1.IP协议
IP是Internet Protocol的简称,是一种网络协议。Internet 网络采用的协议是TCP/IP协议,其全称是Transmission Control Protocol/Internet Protocol。Internet 依靠TCP/IP协议,在全球范围内实现了不同硬件结构、不同操作系统、不同网络系统间的互联。在Internet 网络上存在着数以亿计的主机,每台主机都用网络为其分配的 Internet 地址代表自己,这个地址就是I地址。到目前为止,I地址用4个字节,也就是32位的二进制数来表示,称为IPv4。为了便于使用,通常取用每个字节的十进制数,并且每个字节之间用圆点隔开来表示I地址,如192.168.1.1。现在人们正在试验使用16个字节来表示I地址,这就是IPv6,但IPv6还没有投入使用。
TCP/IP 模式是一种层次结构,共分为4层,分别为应用层、传输层、互联网层和网络层。各层实现特定的功能,提供特定的服务和访问接口,并具有相对的独立性,
IP是Internet Protocol的简称,是一种网络协议。Internet 网络采用的协议是TCP/IP协议,其全称是Transmission Control Protocol/Internet Protocol。Internet 依靠TCP/IP协议,在全球范围内实现了不同硬件结构、不同操作系统、不同网络系统间的互联。在Internet 网络上存在着数以亿计的主机,每台主机都用网络为其分配的 Internet 地址代表自己,这个地址就是I地址。到目前为止,I地址用4个字节,也就是32位的二进制数来表示,称为IPv4。为了便于使用,通常取用每个字节的十进制数,并且每个字节之间用圆点隔开来表示I地址,如192.168.1.1。现在人们正在试验使用16个字节来表示I地址,这就是IPv6,但IPv6还没有投入使用。
TCP/IP 模式是一种层次结构,共分为4层,分别为应用层、传输层、互联网层和网络层。各层实现特定的功能,提供特定的服务和访问接口,并具有相对的独立性,
2. TCP与UDP协议
在TCPAIP 协议栈中,有两个高级协议是网络应用程序编写者应该了解的,即传输控制协议(Transmission Control Protocol,TCP)与用户数据报协议(User Datagram Protocol, UDP)。
TCP 协议是一种以固接连线为基础的协议,它提供两台计算机间可靠的数据传送。TCP可以保证数据从一端送至连接的另一端时,能够确实送达,而且抵达的数据的排列顺序和送出时的顺序相同。因此,TCP协议适合可靠性要求比较高的场合。就像拨打电话,必须先拨号给对方,等两端确定连接后,相互才能听到对方说话,也知道对方回应的是什么。
HTTP、FTP 和Telnet 等都需要使用可靠的通信频道。例如,HTTP从某个URL读取数据时,如果收到的数据顺序与发送时不相同,可能就会出现一个混乱的HTML文件或是一些无效的信息。
UDP是无连接通信协议,不保证数据的可靠传输,但能够向若干个目标发送数据,或接收来自若干个源的数据。UDP以独立发送数据包的方式进行。这种方式就像邮递员送信给收信人,可以寄出很多信给同一个人,且每一封信都是相对独立的,各封信送达的顺序并不重要,收信人接收信件的顺序也不能保证与寄出信件的顺序相同。
UDP 协议适合于一些对数据准确性要求不高,但对传输速度和时效性要求非常高的网站,如网络聊天室、在线影片等。这是由于TCP协议在认证上存在额外耗费,可能使传输速度减慢,而UDP协议即使有一小部分数据包遗失或传送顺序有所不同,也不会严重危害该项通信。
在TCPAIP 协议栈中,有两个高级协议是网络应用程序编写者应该了解的,即传输控制协议(Transmission Control Protocol,TCP)与用户数据报协议(User Datagram Protocol, UDP)。
TCP 协议是一种以固接连线为基础的协议,它提供两台计算机间可靠的数据传送。TCP可以保证数据从一端送至连接的另一端时,能够确实送达,而且抵达的数据的排列顺序和送出时的顺序相同。因此,TCP协议适合可靠性要求比较高的场合。就像拨打电话,必须先拨号给对方,等两端确定连接后,相互才能听到对方说话,也知道对方回应的是什么。
HTTP、FTP 和Telnet 等都需要使用可靠的通信频道。例如,HTTP从某个URL读取数据时,如果收到的数据顺序与发送时不相同,可能就会出现一个混乱的HTML文件或是一些无效的信息。
UDP是无连接通信协议,不保证数据的可靠传输,但能够向若干个目标发送数据,或接收来自若干个源的数据。UDP以独立发送数据包的方式进行。这种方式就像邮递员送信给收信人,可以寄出很多信给同一个人,且每一封信都是相对独立的,各封信送达的顺序并不重要,收信人接收信件的顺序也不能保证与寄出信件的顺序相同。
UDP 协议适合于一些对数据准确性要求不高,但对传输速度和时效性要求非常高的网站,如网络聊天室、在线影片等。这是由于TCP协议在认证上存在额外耗费,可能使传输速度减慢,而UDP协议即使有一小部分数据包遗失或传送顺序有所不同,也不会严重危害该项通信。
21.1.3 端口与套接字
一般而言,一台计算机只有单一的连到网络的物理连接(Physical Connection),所有的数据都通过此连接对内、对外送达特定的计算机,这就是端口。网络程序设计中的端口(port)并非真实的物理存在,而是一个假想的连接装置。端口被规定为一个在0~65535的整数。HTTP服务一般使用80端口,FTP 服务使用21端口。假如一台计算机提供了HTTP、FTP等多种服务,那么客户机会通过不同的端口来确定连接到服务器的哪项服务上
通常,0~1023的端口数用于一些知名的网络服务和应用,用户的普通网络应用程序应该使用1024以上的端口数,以避免端口号与另一个应用或系统服务所用端口冲突。
网络程序中的套接字(Socket)用于将应用程序与端口连接起来。套接字是一个假想的连接装置,就像插座一样可连接电器与电线,
网络程序中的套接字(Socket)用于将应用程序与端口连接起来。套接字是一个假想的连接装置,就像插座一样可连接电器与电线,
21.2 TCP程序
TCP网络程序设计是指利用Socket 类编写通信程序。利用TCP协议进行通信的两个应用程序是有主次之分的,一个称为服务器程序,另一个称为客户机程序,两者的功能和编写方法大不一样。
21.2.1 InetAddress 类
ava.net包中的InetAddress类是与IP地址相关的类,利用该类可以获取IP地址、主机地址等信息。
21.2.2 ServerSocket 类
- ServerSocker 类的构造方法通常会抛出1OException异常,具体有以下几种形式:
- ServerSocket():创建非绑定服务器套接字。
- ServerSocket(int port):创建绑定到特定端口的服务器套接字。
- ServerSocket(int port, int backlog):利用指定的backlog创建服务器套接字,并将其绑定到指定的本地端口号上。
- ServerSocket(int port, int backlog, InetAddress bindAddress):使用指定的端口、侦听backlog和要绑定到的本地IP地址创建服务器。这种情况适用于计算机上有多块网卡和多个I地址的情况,用户可以明确规定ServerSocket在哪块网卡或哪个IP地址上等待客户的连接请求。
21.2.3 TCP网络程序设计
编写客户端程序,将用户在文本框中输入的信息发送至服务端,并将文本框中输入的信息显示再客户端的文本域中。
21.3 UDP程序
基于 UDP通信的基本模式如下:
将数据打包(称为数据包),然后将数据包发往目的地。
接收别人发来的数据包,然后查看数据包。
发送数据包的步骤如下:
(1)使用DatagramSocketO创建一个数据包套接字。
(2)使用DatagramPacket(byte[] buf,int offset, int length,InetAddress address,int port)创建要发送的数据包。
(3)使用DatagramSocket 类的sendO方法发送数据包。
接收数据包的步骤如下:
(1)使用DatagramSocket(int port)创建数据包套接字,绑定到指定的端口。
(2)使用 DatagramPacket(byte buf, int length)创建字节数组来接收数据包。
(3)使用DatagramPacket 类的receive0方法接收UDP包。
将数据打包(称为数据包),然后将数据包发往目的地。
接收别人发来的数据包,然后查看数据包。
发送数据包的步骤如下:
(1)使用DatagramSocketO创建一个数据包套接字。
(2)使用DatagramPacket(byte[] buf,int offset, int length,InetAddress address,int port)创建要发送的数据包。
(3)使用DatagramSocket 类的sendO方法发送数据包。
接收数据包的步骤如下:
(1)使用DatagramSocket(int port)创建数据包套接字,绑定到指定的端口。
(2)使用 DatagramPacket(byte buf, int length)创建字节数组来接收数据包。
(3)使用DatagramPacket 类的receive0方法接收UDP包。
21.3.1DatagramPacket类
java.net 包的DatagramPacket 类用来表示数据包。DatagramPacket 类的构造方法如下:
DatagramPacket(byte[] buf, int length)
DatagramPacket(bytel] buf, int length, InetAddress address, int port)
第一种构造方法在创建DatagramPacket 对象时,指定了数据包的内存空间和大小。
第二种构造方法不仅指定了数据包的内存空间和大小,还指定了数据包的目标地址和端口
DatagramPacket(byte[] buf, int length)
DatagramPacket(bytel] buf, int length, InetAddress address, int port)
第一种构造方法在创建DatagramPacket 对象时,指定了数据包的内存空间和大小。
第二种构造方法不仅指定了数据包的内存空间和大小,还指定了数据包的目标地址和端口
21.3.2 DatagramSocker 类
java.net 包中的()
DatagramSocket(int port)
DatagramSocket(int port, InetAddress addr)
第一种构造方法创建DatagramSocket对象,构造数据报套接字,并将其绑定到本地主机任何可用的端口上。
第二种构造方法创建DatagramSocket对象,创建数据报套接字,并将其绑定到本地主机的指定端口上。
第三种构造方法创建DatagramSocket对象,创建数据报套接字,并将其绑定到指定的端口和指定的本地地址上。第三种构造函数适用于有多块网卡和多个I地址的情况。
DatagramSocket(int port)
DatagramSocket(int port, InetAddress addr)
第一种构造方法创建DatagramSocket对象,构造数据报套接字,并将其绑定到本地主机任何可用的端口上。
第二种构造方法创建DatagramSocket对象,创建数据报套接字,并将其绑定到本地主机的指定端口上。
第三种构造方法创建DatagramSocket对象,创建数据报套接字,并将其绑定到指定的端口和指定的本地地址上。第三种构造函数适用于有多块网卡和多个I地址的情况。
21.3.3 UDP网络程序设计
收藏
0 条评论
下一页