简单资料型别的取值范围
byte
:8 位,1 字节,最大资料存盘量是 255,数值范围是 ?128 ~ 127,short
:16 位,2 字节,最大资料存盘量是 65536,数值范围是 ?32768 ~ 32767,int
:32 位,4 字节,最大资料存盘容量是 2^32 - 1,数值范围是 ?2^31 ~ 2^31 - 1,long
:64 位,8 字节,最大资料存盘容量是 2^64 - 1 数值范围是 ?2^63 ~ 2^63 - 1,float
:32 位,4 字节,数值范围是 3.4e?45 ~ 1.4e38,直接赋值时必须在数字后加上f
或F
,double
:64 位,8 字节,数值范围在 4.9e?324 ~ 1.8e308,赋值时可以加 d 或 D,也可以不加,boolean
:只有true
和false
两个取值,char
:16 位,2 字节,存盘 Unicode 码,用单引号'
赋值,
字符型
关系运算子和逻辑运算子
在 Java 程序设计中,关系运算子(Relational Operator)和逻辑运算子(Logical Operator)显得十分重要,关系运算子定义值与值之间的相互关系,逻辑(logical)运算子定义可以用真值和假值连接在一起的方法,
关系运算子
在数学运算中有大于、小于、等于、不等于关系,在程序中可以使用关系运算子来表示上述关系,下图中列出了 Java 中的关系运算子,通过这些关系运算子会产生一个结果,这个结果是一个布林值,即 true
或 false
,在 Java 中,任何型别的资料,都可以用 ==
比较是不是相等,用 !=
比较是否不相等,只有数字才能比较大小,关系运算的结果可以直接赋予布尔变量,
逻辑运算子
布尔逻辑运算子是最常见的逻辑运算子,用于对布尔型操作数进行布尔逻辑运算,Java 中的布尔逻辑运算子如下图示,
逻辑运算子与关系运算子运算后得到的结果一样,都是布尔型别的值,在 Java 程序设计中,&&
和 ||
布尔逻辑运算子不总是对运算子右边的表达式求值,如果使用逻辑与 &
和逻辑或 |
,则表达式的结果可以由运算子左边的操作数单独决定,通过下表,同学们可以了解常用逻辑运算子 &&
、||
、!
运算后的结果,
位逻辑运算子
位逻辑运算子在 Java 程序设计中,使用位逻辑运算子来操作二进制资料,读者必须注意,位逻辑运算子只能操作二进制资料,如果用在其他进制的资料中,需要先将其他进制的资料转换成二进制资料,位逻辑运算子(Bitwise Operator)可以直接操作整数型别的位,这些整数型别包括 long
、int
、short
、char
和 byte
,Java 语言中位逻辑运算子的具体说明如下表所示,
因为位逻辑运算子能够在整数范围内对位操作,所以这样的操作对一个值产生什么效果是很重要的,具体来说,了解 Java 如何存盘整数值并且如何表示负数是非常有用的,下表中演示了操作数 A 和操作数 B 按位逻辑运算的结果,
移位运算子把数字的位向右或向左移动,产生一个新的数字,Java 的右移运算子有两个,分别是 >>
和 >>>
,
>>
运算子:把第一个操作数的二进制码右移指定位数后,将左边空出来的位以原来的符号位填充,即,如果第一个操作数原来是正数,则左边补 0;如果第一个操作数是负数,则左边补 1,>>>
:把第一个操作数的二进制码右移指定位数后,将左边空出来的位以 0 填充,
条件运算子
条件运算子是一种特殊的运算子,也被称为三目运算子,它与前面所讲的运算子有很大不同,Java 中提供了一个三目运算子,其实这跟后面讲解的 if
陈述句有相似之处,条件运算子的目的是决定把哪个值赋给前面的变量,在 Java 语言中使用条件运算子的语法格式如下所示,
变量 = (布尔表达式) ? 为 true 时赋予的值 : 为 false 时赋予的值;
赋值运算子
赋值运算子是等号 =
,Java 中的赋值运算与其他计算机语言中的赋值运算一样,起到赋值的作用,在 Java 中使用赋值运算子的格式如下所示,
+=
:对于x+=y
,等效于x=x+y
,-=
:对于x-=y
,等效于x=x?y
,*=
:对于x*=y
,等效于x=x*y
,/=
:对于x/=y
,等效于x=x/y
,%=
:对于x%=y
,等效于x=x%y
,&=
:对于x&=y
,等效于x=x&y
,|=
:对于x|=y
,等效于x=x|y
,^=
:对于x^=y
,等效于x=x^y
,<<=
:对于x<<=y
,等效于x=x<<y
,>>=
:对于x>>=y
,等效于x=x>>y
,>>>=
:对于x>>>=y
,等效于x=x>>>y
,
其中,变量 var
的型别必须与表达式 expression
的型别一致, 赋值运算子有一个有趣的属性,它允许我们对一连串变量进行赋值,请看下面的代码, 在上述代码中,使用一条赋值陈述句将变量 x
、y
、z
都赋值为 100,这是由于 =
运算子表示右边表达式的值,因此 z = 100
的值是 100,然后该值被赋给 y
,并依次被赋给 x
,使用字符串赋值是给一组变量赋予同一个值的简单办法,在赋值时型别必须匹配,否则将会出现编译错误,
运算子的优先级
数学中的运算都是从左向右运算的,在 Java 中除了单目运算子、赋值运算子和三目运算子外,大部分运算子也是从左向右结合的,单目运算子、赋值运算子和三目运算子是从右向左结合的,也就是说,它们是从右向左运算的,乘法和加法是两个可结合的运算,也就是说,这两个运算子左右两边的运算子可以互换位置而不会影响结果,
运算子有不同的优先级,所谓优先级,就是在表达式运算中的运算顺序,下表中列出了包括分隔符在内的所有运算子的优先级,上一行中的运算子总是优先于下一行的,
字符串的初始化
在 Java 程序中,使用关键字 new
来创建 String 实体,具体格式如下所示,
String a = new String();
上面这行代码创建了一个名为 a 的 String 类的实体,并把它赋给变量,但它此时是一个空的字符串,接下来就为这个字符串复制,赋值代码如下所示,
a = "I am a person.";
在 Java 程序中,我们将上述两句代码合并,就可以产生一种简单的字符串表示方法,
String s = new String("I am a person.");
除了上面的表示方法,还有表示字符串的如下一种形式,
String s = ("I am a person.");
String 类
在 Java 程序中可以使用 String 类来操作字符串,在该类中有许多方法可以供程序员使用,
索引
在 Java 程序中,通过索引函式 charAt()
可以回传字符串中指定索引的位置,读者需要注意的是,这里的索引数字从零开始,使用格式如下所示,
public char charAt(int index)
追加字符串
追加字符串函式 concat()
的功能是在字符串的末尾添加字符串,追加字符串是一种比较常用的操作,具体语法格式如下所示,
public String concat(String s)
StringBuffer 类
StringBuffer 类是 Java 中另一个重要的操作字符串的类,当需要对字符串进行大量的修改时,使用 StringBuffer 类是最佳选择,接下来将详细讲解 StringBuffer 类中的常用方法,
追加字符
在 StringBuffer 类中实作追加字符功能的方法的语法格式如下所示,
public synchronized StringBuffer append(char b)
插入字符
前面的字符追加方法总是在字符串的末尾添加内容,倘若需要在字符串中添加内容,就需要使用方法 insert()
,语法格式如下所示,
public synchronized StringBuffer insert(int offset, String s)
上述语法格式的含义是:将第 2 个自变量的内容添加到第 1 个自变量指定的位置,换句话说,第 1 个自变量表示要插入的起始位置,第 2 个自变量是需要插入的内容,可以是包括 String 在内的任何资料型别,
颠倒字符
字符颠倒方法能够将字符颠倒,例如 "我是谁",颠倒过来就变成 "谁是我",很多时候需要颠倒字符,字符颠倒方法 reverse()
的语法格式如下所示,
public synchronized StringBuffer reverse()
自动型别转换
如果系统支持把某种基本型别的值直接赋给另一种基本型别的变量,这种方式被称为自动型别转换,当把一个取值范围小的数值或变量直接赋给另一个取值范围大的变量时,系统可以进行自动型别转换,
Java 中所有数值型变量之间可以进行型别转换,取值范围小的可以向取值范围大的进行自动型别转换,就好比有两瓶水,当把小瓶里的水倒入大瓶时不会有任何问题,Java 支持自动型别转换的型别如下图所示,
在上图所示的型别转换图中,箭头左边的数值可以转换为箭头右边的数值,当对任何基本型别的值和字符串进行连接运算时,基本型别的值将自动转换为字符串型别,尽管字符串型别不再是基本型别,而是参考型别,因此,如果希望把基本型别的值转换为对应的字符串,可以对基本型别的值和一个空字符串进行连接,
Java 11 新特性:新增的 String 函式
在新发布的 JDK 11 中,新增了 6 个字符串函式,下面介绍各个字符串函式,
-
String.repeat(int)
函式
String.repeat(int)
的功能是根据 int 自变量的值重复 String, -
String.lines()
函式
String.lines()
的功能是回传从该字符串中提取的行,由行终止符分隔,行要么是零个或多个字符的序列,后面跟着一个行结束符;要么是一个或多个字符的序列,后面是字符串的结尾,一行不包括行终止符,在 Java 程序中,使用函式String.lines()
回传的流包含该字符串中出现的行的顺序, -
String.strip()
函式
String.strip()
的功能是回传一个字符串,该字符串的值为该字符串,其中所有前导和尾部空白均被洗掉,如果该 String 物件表示空字符串,或者如果该字符串中的所有代码点是空白的,则回传一个空字符串,否则,回传该字符串的子字符串,该字符串从第一个不是空白的代码点开始,直到最后一个不是空白的代码点,并包括最后一个不是空白的代码点,在 Java 程序中,开发者可以使用此函式去除字符串开头和结尾的空白, -
String.stripLeading()
函式
String.stripLeading()
的功能是回传一个字符串,其值为该字符串,并且洗掉字符串前面的所有空白,如果该 String 物件表示空字符串,或者如果该字符串中的所有代码点是空白的,则回传空字符串, -
String.stripTrailing()
函式
String.stripTrailing()
的功能是回传一个字符串,其值为该字符串,并且洗掉字符串后面的所有空白,如果该 String 物件表示空字符串,或者如果该字符串中的所有代码点是空白的,则回传空字符串, -
String.isBlank()
函式
String.isBlank()
的功能是判断字符串是否为慷训仅包含空格,如果字符串为慷训仅包含空格则回传true
;否则,回传false
,
定义常量时的注意事项
在 Java 语言中,主要利用 final
关键字(在 Java 类中灵活使用 static
关键字)来进行 Java 常量的定义,当常量被设定后,一般情况下就不允许再进行更改,在定义常量时,需要注意如下 3 点,
- 在定义 Java 常量的时候,就需要对常量进行初始化,也就是说,必须在宣告常量时就对它进行初始化,跟区域变量或类成员变量不同,在定义一个常量的时候,进行初始化之后,在应用程序中就无法再次对这个常量进行赋值,如果强行赋值的话,编译器会弹出错误信息,并拒绝接受这一新值,
- 需要注意
final
关键字的使用范围,final
关键字不仅可以用来修饰基本资料型别的常量,还可以用来修饰物件的参考或方法,比如阵列就是物件参考,为此,可以使用final
关键字定义一个常量的阵列,这是 Java 语言中的一大特色,一个阵列物件一旦被final
关键字设置为常量阵列之后,它就只能恒定地指向一个阵列物件,无法将其指向另一个物件,也无法更改阵列中的值, - 需要注意常量的命名规则,在定义变量或常量时,不同的语言,都有自己的一套编码规则,这主要是为了提高代码的共享程度与易读性,在 Java 中定义常量时,也有自己的一套规则,比如在给常量取名时,一般都用大写字母,在 Java 语言中,区分大小写字母,之所以采用大写字母,主要是为了跟变量进行区分,虽然说给常量取名时采用小写字母,也不会有语法上的错误,但是为了在撰写代码时能够一目了然地判断变量与常量,最好还是能够将常量设定为大写字母,另外,在常量中,往往通过下划线来分隔不同的字符,而不像物件名或类名那样,通过首字母大写的方式来进行分隔,这些规则虽然不是强制性的,但是为了提高代码的友好性,方便开发团队中的其他成员阅读,这些规则还是需要遵守的, 总之,Java 开发人员需要注意,被定义为
final
的常量需要采用大写字母命名,并且中间最好使用下划线作为分隔符来连接多个单词,定义为final
的资料不论是常量、物件参考还是阵列,在主函式中都不可以改变,否则会被编辑器拒绝并提示错误信息,
char 型别中单引号的意义
char
型别使用单引号括起来,而字符串使用双引号括起来,关于 String 类的具体用法以及对应的各个方法,读者可以参考查阅 API 档案中的信息,其实 Java 语言中的单引号、双引号和反斜线都有特殊的用途,如果在一个字符串中包含这些特殊字符,应该使用转义字符,
例如希望在 Java 程序中表示绝对路径 c:\daima
,但这种写法得不到我们期望的结果,因为 Java 会把反斜线当成转义字符,所以应该写成 c:\\daima
的形式,只有同时写两个反斜线,Java 才会把第一个反斜线当成转义字符,与后一个反斜线组成真正的反斜线,
正无穷和负无穷的问题
Java 还提供了 3 个特殊的浮点数值——正无穷大、负无穷大和非数,用于表示溢位和出错,
例如,使用一个正浮点数除以 0 将得到正无穷大,使用一个负浮点数除以 0 将得到负无穷大,用 0.0 除以 0.0 或对一个负数开方将得到一个非数,
正无穷大通过 Double 或 Float 的 POSITIVE_INFINITY
表示,负无穷大通过 Double 或 Float 的 NEGATIVE_INFINITY
表示,非数通过 Double 或 Float 的 NaN
表示,
请注意,只有用浮点数除以 0 才可以得到正无穷大或负无穷大,因为 Java 语言会自动把和浮点数运算的 0(整数)当成 0.0(浮点数)来处理,如果用一个整数除以 0,则会抛出 “ArithmeticException:/by zero”(除以 0 例外)
,
移位运算子的限制
Java 移位运算子只能用于整型,不能用于浮点型,也就是说,>>、>>>和<<这 3 个移位运算子并不适合所有的数值型别,它们只适合对 byte
、short
、char
、int
和 long
等整型数进行运算,除此之外,进行移位运算时还有如下规则:
- 对于低于
int
型别(如byte
、short
和char
)的操作数来说,总是先自动型别转换为int
型别后再移位, - 对于
int
型别的整数移位,例如a >> b
,当b > 32
时,系统先用b
对 32 求余(因为int
型别只有 32 位),得到的结果才是真正移位的位数,例如,a >> 33
和a >> l
的结果完全一样,而a >> 32
的结果和a
相同, - 对
long
型别的整数移位时,例如a >> b
,当b > 64
时,总是先用b
对 64 求余(因为long
型别是 64 位),得到的结果才是真正移位的位数, 当进行位移运算时,只要被移位的二进制码没有发生有效位的数字丢失现象(对于正数而言,通常指被移出的位全部都是 0),不难发现左移 n 位就相当于乘以 2n,右移则相当于除以 2n,这里存在一个问题:左移时,左边舍弃的位通常是无效的,但右移时,右边舍弃的位常常是有效的,因此通过左移和右移更容易看出这种运行结果,并且位移运算不会改变操作数本身,只是得到一个新的运算结果,原来的操作数本身是不会改变的,
if 陈述句
if 陈述句由保留字 if
、条件陈述句和位于后面的陈述句组成,条件陈述句通常是一个布尔表达式,结果为 true
和 false
,如果条件为 true
,则执行陈述句并继续处理其后的下一条陈述句;如果条件为 false
,则跳过陈述句并继续处理紧跟整个 if 陈述句的下一条陈述句,例如在下图中,当条件(condition)为 true
时,执行 statement1 陈述句;当条件为 false
时,执行 statement2 陈述句,
if 陈述句的语法格式如下所示,
if (条件表达式)
语法说明:if
是该陈述句中的关键字,后续紧跟一对小括号,这对小括号任何时候都不能省略,小括号的内部是具体的条件,语法上要求条件表达式的结果为 boolean
型别,后续为功能代码,也就是当条件成立时执行的代码,在书写程序时,一般为了直观地表达包含关系,功能代码需要缩进,
例如下面的演示代码,
int a = 10; //定义 int 型变量 a 的初始值是 10
if (a >= 0)
System.out.println("a 是正数"); //a 大于或等于 0 时的输出内容
if ( a % 2 == 0)
System.out.println("a 是偶数"); //a 能够整除 2 时的输出内容
在上述演示代码中,第一个条件判断变量 a
的值是否大于或等于零,如果该条件成立,输出 "a 是正数";第二个条件判断变量 a
是否为偶数,如果成立,也输出 "a 是偶数",
再看下面的代码的执行流程,
int m = 20; //定义 int 型变量 m 的初始值是 20
if ( m > 20) //如果变量 m 的值大于 20
m += 20; //将 m 的值加上 20
System.out.println(m); //输出 m 的值
按照前面的语法格式说明,只有 m += 20
这行代码属于功能代码,而后续的输出陈述句和前面的条件形成顺序结构,所以该程序执行以后输出的结果为 20,当条件成立时,如果需要执行的陈述句有多句,可以使用陈述句块来进行表述,具体语法格式如下所示,
if (条件表达式) {
功能代码块;
}
这种语法格式中,使用功能代码块来代替前面的功能代码,这样可以在代码块内部书写任意多行代码,而且也使整个程序的逻辑比较清楚,所以在实际的代码撰写中推荐使用这种方式,
if陈述句的延伸
在第一种 if 陈述句中,大家可以看到,并不对条件不符合的内容进行处理,因为这是不允许的,所以 Java 引入了另外一种条件陈述句 if…else
,基本语法格式如下所示,
if (condition) // 设定条件 condition
statement1; // 如果条件 condition 成立,执行 statement1 这一行代码
else // 如果条件 condition 不成立
statement2; // 执行 statement2 这一行代码
if…else
陈述句的执行流程如下图所示,
有多个条件判断的 if 陈述句
if 陈述句实际上是一种功能十分强大的条件陈述句,可以对多种情况进行判断,可以判断多个条件的陈述句是 if-else-if
,语法格式如下所示,
if (condition1)
statement1;
else if (condition2)
statement2;
else
statement3;
上述语法格式的执行流程如下,
- 判断第一个条件 condition1,当为
true
时执行 statement1,并且程序运行结束,当 condition1 为false
时,继续执行后面的代码, - 当 condition1 为
false
时,接下来先判断 condition2 的值,当 condition2 为true
时执行 statement2,并且程序运行结束,当 condition2 为false
时,执行后面的 statement3,也就是说,当前面的两个条件 condition1 和 condition2 都不成立(为false
)时,才会执行 statement3,
if-else-if
的执行流程如下图所示,
在 Java 陈述句中,if…else
可以嵌套无限次,可以说,只要遇到值为 true
的条件,就会执行对应的陈述句,然后结束整个程序的运行,
switch 陈述句的形式
switch 陈述句能够对条件进行多次判断,具体语法格式如下所示,
switch(整数选择因子) {
case 整数值 1 : 陈述句; break;
case 整数值 2 : 陈述句; break;
case 整数值 3 : 陈述句; break;
case 整数值 4 : 陈述句; break;
case 整数值 5 : 陈述句; break;
//..
case 整数值 n : 陈述句; break;
default: 陈述句;
}
其中,整数选择因子
必须是 byte
、short
、int
和 char
型别,每个整数必须是与 整数选择因子
型别兼容的一个常量,而且不能重复,整数选择因子
是一个特殊的表达式,能产生整数,switch 能将整数选择因子的结果与每个整数做比较,发现相符的,就执行对应的陈述句(简单或复合陈述句),没有发现相符的,就执行 default
陈述句,
在上面的定义中,大家会注意到每个 case
均以一个 break
结尾,这样可使执行流程跳转至 switch 主体的末尾,这是构建 switch 陈述句的一种传统方式,但 break
是可选的,若省略 break
,将会继续执行后面的 case
陈述句的代码,直到遇到 break
为止,尽管通常不想出现这种情况,但对有经验的程序员来说,也许能够善加利用,注意,最后的 default
陈述句没有 break
,因为执行流程已到达 break
的跳转目的地,当然,如果考虑到编程风格方面的原因,完全可以在 default
陈述句的末尾放置一个 break
,尽管它并没有任何实际用处,
switch 陈述句的执行流程如下图所示,
无 break 的情况
多次出现了 break
陈述句,其实在 switch 陈述句中可以没有 break
这个关键字,一般来说,当 switch 遇到一些 break
关键字时,程序会自动结束 switch 陈述句,如果把 switch 陈述句中的 break
关键字去掉了,程序将继续向下执行,直到整个 switch 陈述句结束,
case 陈述句后没有执行陈述句
当 case 陈述句后没有执行陈述句时,即使条件为 true
,也会忽略掉不执行,
default 可以不在结尾
通过前面的学习,很多初学者可能会误认为 default
一定位于 switch
的结尾,其实不然,它可以位于 switch
中的任意位置
for 回圈
在 Java 程序中,for 陈述句是最为常见的一种回圈陈述句,for 回圈是一种功能强大且形式灵活的结构,下面对它进行讲解,
书写格式
for 陈述句是一种十分常见的回圈陈述句,语法格式如下所示,
for(initialization;condition;iteration){
statements;
}
从上面的语法格式可以看出,for 回圈陈述句由如下 4 部分组成,
initialization
:初始化操作,通常用于初始化回圈变量,condition
:回圈条件,是一个布尔表达式,用于判断回圈是否持续,iteration
:回圈迭代器,用于迭代回圈变量,statements
:要回圈执行的陈述句(可以有多条陈述句),
上述每一部分间都用分号分隔,如果只有一条陈述句需要重复执行,大括号就没有必要有了,
在 Java 程序中,for 回圈的执行程序如下,
- 当回圈启动时,先执行初始化操作,通常这里会设定一个用于主导回圈的回圈变量,重要的是要理解初始化表达式仅被执行一次,
- 计算回圈条件,
condition
必须是一个布尔表达式,它通常会对回圈变量与目标值做比较,如果这个布尔表达式为真,则继续执行回圈体statements
;如果为假,则回圈终止, - 执行回圈迭代器,这部分通常是用于递增或递级训圈变量的一个表达式,以便接下来重新计算回圈条件,判断是否继续回圈,
while 回圈陈述句
在 Java 程序里,除了 for 陈述句以外,while 陈述句也是十分常见的回圈陈述句,其特点和 for 陈述句十分类似,while 回圈陈述句的最大特点,就是不知道回圈多少次,在 Java 程序中,当不知道某个陈述句块或陈述句需要重复运行多少次时,通过使用 while 陈述句可以实作这样的回圈功能,当回圈条件为真时,while 陈述句重复执行一条陈述句或某个陈述句块,while 陈述句的基本使用格式如下所示,
while (condition) // condition 表达式是回圈条件,其结果是一个布林值
{
statements;
}
while 陈述句的执行流程如下图所示,
do...while 回圈陈述句
许多软件程序中会存在这种情况:当条件为假时也需要执行陈述句一次,初学者可以这幺理解,在执行一次回圈后才测验回圈的条件表达式,在 Java 语言中,我们可以使用 do…while
陈述句实作上述回圈,
书写格式
在 Java 语言中,do…while
回圈陈述句的特点是至少会执行一次回圈体,因为条件表达式在回圈的最后,do…while
回圈陈述句的使用格式如下所示,
do{
statements;
}
while (condition) // condition 表示回圈条件,是一个布林值
在上述格式中,do…while 陈述句先执行 statement
一次,然后判断回圈条件,如果结果为真,回圈继续;如果为假,回圈结束,
do…while
回圈陈述句的执行流程如下图所示,
break 陈述句的应用
在本小节前面的内容中,我们事实上已经接触过 break 陈述句,了解到它在 switch 陈述句里可以终止一条陈述句,其实除这个功能外,break 还能实作其他功能,例如退出回圈,break 陈述句根据用户使用的不同,可以分为无标号退出回圈和有标号退出回圈两种,
无标号退出回圈是指直接退出回圈,当在回圈陈述句中遇到 break 陈述句时,回圈会立即终止,回圈体外面的陈述句也将会重新开始执行,
return 陈述句的使用
在 Java 程序中,使用 return 陈述句可以回传一个方法的值,并把控制权交给呼叫它的陈述句,return 陈述句的语法格式如下所示,
return [expression];
expression
表示表达式,是可选自变量,表示要回传的值,它的资料型别必须同方法宣告中回传值的型别一致,这可以通过强制型别转换实作,
在撰写 Java 程序时,return 陈述句如果被放在方法的最后,它将用于退出当前的程序,并回传一个值,如果把单独的 return 陈述句放在一个方法的中间,会出现编译错误,如果非要把 return 陈述句放在方法的中间,可以使用条件陈述句 if,然后将 return 陈述句放在这个方法的中间,用于实作将程序中未执行的全部陈述句退出,
continue 陈述句
在 Java 语言中,continue 陈述句不如前面几种跳转陈述句应用得多,其作用是强制当前这轮迭代提前回传,也就是让回圈继续执行,但不执行当前迭代中 continue 陈述句生效之后的陈述句,
使用 for 回圈的技巧
控制 for 回圈的变量经常只用于该回圈,而不用在程序的其他地方,在这种情况下,可以在回圈的初始化部分宣告变量,当我们在 for 回圈内宣告变量时,必须记住重要的一点:该变量的作用域在 for 回圈执行后就结束了(因此,该变量的作用域仅限于 for 回圈内),由于回圈控制变量不会在程序的其他地方使用,因此大多数程序员都在 for 回圈中宣告它,
另外,初学者经常以为,只要在 for 后面的括号中控制了回圈迭代陈述句,就万无一失了,其实不是这样的,请看下面的代码,
public class TestForError {
public static void main(String[] args) {
// 回圈的初始化条件、回圈条件、回圈迭代陈述句都在下面一行
for (int count = 0; count < 10; count++) {
System.out.println(count);
// 再次修改了回圈变量
count *= 0.1;
}
System.out.println("回圈结束!");
}
}
在上述代码中,我们在回圈体内修改了 count
变量的值,并且把这个变量的值乘以 0.1,这会导致 count
的值永远都不超过 10,所以上述程序是一个死回圈,
其实在使用 for 回圈时,还可以把初始化条件定义在回圈体之外,把回圈迭代陈述句放在回圈体内,把 for 回圈的初始化陈述句放在回圈之前定义还有一个好处,那就是可以扩大初始化陈述句中定义的变量的作用域,在 for 回圈里定义的变量,其作用域仅在该回圈内有效,for 回圈终止以后,这些变量将不可被访问,
跳转陈述句的选择技巧
由此可见,continue
的功能和 break
有点类似,区别在于 continue
只是中止当前迭代,接着开始下一次迭代;而 break
则完全终止回圈,我们可以将 continue
的作用理解为:略过当前迭代中剩下的陈述句,重新开始新一轮的迭代,
宣告一维阵列
阵列本质上就是某类元素的集合,每个元素在阵列中都拥有对应的索引值,只需要指定索引值就可以取出对应的资料,在 Java 中宣告一维阵列的格式如下所示,
int[] arrar;
也可以用下面的格式,
int array[];
虽然这两种格式的形式不同,但含义是一样的,各个自变量的具体说明如下,
int
:阵列型别,array
:阵列名称,[]
:一维阵列的内容通过这个符号括起来,
除上面宣告的整型阵列外,还可以宣告多种资料型别的阵列,例如下面的代码,
boolean[] array; // 宣告布尔型阵列
float[] array; // 宣告浮点型阵列
double[] array; // 宣告双精度型阵列
创建一维阵列
创建阵列实质上就是为阵列申请相应的存盘空间,阵列的创建需要用大括号 {}
括起来,然后将一组相同型别的资料放在存盘空间里,Java 编译器负责管理存盘空间的分配,创建一维阵列的方法十分简单,具体格式如下所示,
int[] a = {1,2,3,5,8,9,15};
上述代码创建了一个名为 a
的整型阵列,但是为了访问阵列中的特定元素,应指定阵列元素的位置序号,也就是索引(又称下标),一维阵列的内部结构如下图所示,
上面这个阵列的名称是 a
,方括号的数值表示阵列元素的索引,这个序号通常也被称为下标,这样就可以很清楚地表示每一个阵列元素,阵列 a
的第一个值就用 a[0]
表示,第 2 个值就用 a[1]
表示,以此类推,
初始化一维阵列
在 Java 程序里,一定要将阵列看作一个物件,它的资料型别和前面的基本资料型别相同,很多时候我们需要对阵列进行初始化处理,在初始化的时候需要规定阵列的大小,当然,也可以初始化阵列中的每一个元素,下面的代码演示了 3 种初始化一维阵列的方法,
int[] a = new int[8]; // 使用 new 关键字创建一个含有 8 个元素的 int 型别的阵列 a
int[] a = new int{1,2,3,4,5,6,7,8}; // 初始化并设定阵列 a 中的 8 个阵列元素
int[] a = {1,2,3,4}; // 初始化并设定阵列 a 中的 4 个阵列元素
对上面代码的具体说明如下所示,
int
:阵列型别,a
:阵列名称,new
:物件初始化陈述句,
在初始化阵列的时候,当使用关键字 new
创建阵列后,一定要明白它只是一个参考,直到将值赋给参考,开始进行初始化操作后才算真正结束,在上面 3 种初始化阵列的方法中,同学们可以根据自己的习惯选择一种初始化方法,
宣告二维阵列
在前面已经学习了宣告一维阵列的知识,宣告二维阵列也十分简单,因为它与宣告一维阵列的方法十分相似,很多程序员习惯将二维阵列看作一种特殊的一维阵列,其中的每个元素又是一个阵列,宣告二维阵列的语法格式如下所示,
float A[][]; //float 型别的二维阵列 A
char B[][]; //char 型别的二维阵列 B
int C[][]; //int 型别的二维阵列 C
上述代码中各个自变量的具体说明如下所示,
float
、char
和int
:表示阵列和型别,A
、B
和C
:表示阵列的名称,[][]
:二维阵列的内容通过这个符号括起来,
创建二维阵列的程序,实际上就是在计算机上申请一块存盘空间的程序,例如下面是创建二维阵列的代码,
int A[][]={
{1,2,3,4},
{5,6,7,8},
{9,10,11,12},
};
上述代码创建了一个二维阵列,A
是阵列名,实质上这个二维阵列相当于一个 3 行 4 列的矩阵,当需要获取二维阵列中的值时,可以使用索引来显示,具体格式如下所示,
array[i - 1][j - 1];
上述代码中各个自变量的具体说明如下所示,
i
:阵列的行数,j
:阵列的列数,
下面以一个二维阵列为例,看一下 3 行 4 列的阵列的内部结构,如下图所示,
初始化二维阵列
初始化二维阵列的方法非常简单,可以看作是由多个一维阵列构成,也是使用下面的语法格式实作的,
array = new int[][]{
{第一个阵列第一个元素的值,第一个阵列第二个元素的值,第一个阵列第三个元素的值},
{第二个阵列第一个元素的值,第二个阵列第二个元素的值,第二个阵列第三个元素的值},
};
或者使用 new
关键字,
array = new int[3][4]; // 创建一个 3 行 4 列的阵列,
使用 new
关键字初始化的阵列,其所有元素的值都默认为该阵列的型别的默认值,这里是 int
型别阵列,则默认值为 0.
上述代码中各个自变量的具体说明如下所示,
array
:阵列名称,new
:物件实体化陈述句,int
:阵列型别,
宣告三维阵列
宣告三维阵列的方法十分简单,与宣告一维、二维阵列的方法相似,具体格式如下所示,
float a[][][];
char b[][][];
上述代码中各个自变量的具体说明如下所示,
float
和char
:阵列型别,a
和b
:阵列名称,
创建三维阵列的方法
在 Java 程序中,创建三维阵列的方法也十分简单,例如下面的代码,
int [][][] a = new int[2][2][3];
初始化三维阵列
初始化三维阵列的方法十分简单,例如可以用下面的代码初始化一个三维阵列,
int[][][]a={
//初始化三维阵列
{{1,2,3}, {4,5,6}}
{{7,8,9},{10,11,12}}
}
通过上述代码,可以定义并且初始化三维阵列中元素的值,
复制阵列
复制阵列是指复制阵列中的数值,在 Java 中可以使用 System
的方法 arraycopy()
实作阵列复制功能,方法 arraycopy()
有两种语法格式,其中第一种语法格式如下所示,
System.arraycopy(arrayA,indexA,arrayB,indexB,a.length);
arrayA
:来源阵列名称,indexA
:来源阵列的起始位置,arryaB
:目的阵列名称,indexB
:要从来源阵列复制的元素个数,
上述阵列复制方法 arraycopy()
有一定局限,可以考虑使用方法 arraycopy()
的第二种格式,使用第二种格式可以复制阵列内的任何元素,第二种语法格式如下所示,
System.arraycopy(arrayA,2,arrayB,3,3);
arrayA
:来源阵列名称,2
:来源阵列从起始位置开始的第2
个元素,arrayB
:目的阵列名称,3
:目的阵列从其实位置开始的第3
个元素,3
:从来源阵列的第 2 个元素开始复制3
个元素,
比较阵列
比较阵列就是检查两个阵列是否相等,如果相等,则回传布林值 true
;如果不相等,则回传布林值 false
,在 Java 中可以使用方法 equals()
比较阵列是否相等,具体格式如下所示,
Arrays.equals(arrayA,arrayB);
arrayA
:待比较阵列的名称,arrayB
:待比较阵列的名称,
如果两个阵列相等,就会回传 true
;否则回传 false
,
排序阵列
排序阵列是指对阵列内的元素进行排序,在 Java 中可以使用方法 sort()
实作排序功能,并且排序规则是默认的,方法 sort()
的语法格式如下所示,
Arrays.sort(array);
自变量 array
是待排序阵列的名称,
搜索阵列中的元素
在 Java 中可以使用方法 binarySearch()
搜索阵列中的某个元素,语法格式如下所示,
int i = binarySearch(a,"abcde");
a
:要搜索的阵列名称,abcde
:需要在阵列中查找的内容,
填充阵列
在 Java 程序设计里,可以使用 fill()
方法向阵列中填充元素,fill()
方法的功能十分有限,只能使用同一个数值进行填充,使用 fill()
方法的语法格式如下所示,
int a[] = new int[10];
Arrays.fill(array,11);
其中,自变量 a
是将要填充的阵列的名称,上述格式的含义是将数值 11 填充到阵列 a
中,
遍历阵列
在 Java 语言中,foreach 陈述句是从 Java 1.5 开始出现的新特征之一,在遍历阵列和遍历集合方面,foreach 为开发人员提供极大的方便,从实质上说,foreach 陈述句是 for 陈述句的特殊简化版本,虽然 foreach 陈述句并不能完全取代 for 陈述句,但是任何 foreach 陈述句都可以改写为 for 陈述句版本,
foreach 并不是一个关键字,习惯上将这种特殊的 for 陈述句称为 foreach
陈述句,从英文字面意思理解,foreach 就是「为每一个」的意思,foreach 陈述句的语法格式如下所示,
for(type 变量 x : 遍历物件 obj){
参考了 x 的 Java 陈述句;
}
其中,type
是阵列元素或集合元素的型别,变量 x
是一个形参,foreach 回圈自动将阵列元素、集合元素依次赋给变量 x
,
动态初始化阵列的规则
在执行动态初始化时,程序员只需要指定阵列的长度即可,即为每个阵列元素指定所需的存储器空间,系统将负责为这些阵列元素分配初始值,在指定初始值时,系统按如下规则分配初始值,
- 阵列元素的型别是基本型别中的整数型别(
byte
、short
、int
和long
),阵列元素的值是 0, - 阵列元素的型别是基本型别中的浮点型别(
float
、double
),阵列元素的值是 0.0, - 阵列元素的型别是基本型别中的字符型别(
char
),阵列元素的值是 '\u0000', - 阵列元素的型别是基本型别中的布尔型别(
boolean
),阵列元素的值是false
, - 阵列元素的型别是参考型别(类、界面和阵列),阵列元素的值是
null
,
参考型别
如果存储器中的一个物件没有任何参考的话,就说明这个物件已经不再被使用了,从而可以被垃圾回收,不过由于垃圾回收器的运行时间不确定,可被垃圾回收的物件实际被回收的时间是不确定的,对于一个物件来说,只要有参考存在,它就会一直存在于存储器中,如果这样的物件越来越多,超出 JVM 中的存储器总数,JVM 就会抛出 OutOfMemory 错误,虽然垃圾回收器的具体运行是由 JVM 控制的,但是开发人员仍然可以在一定程度上与垃圾回收器进行互动,目的在于更好地帮助垃圾回收器管理好应用的存储器,这种互动方式就是从 JDK 1.2 开始引入的 java.lang.ref
包,
强参考
在一般的 Java 程序中,见到最多的就是强参考(strong reference),例如 Date date = new Date()
,其中的 date 就是一个物件的强参考,物件的强参考可以在程序中到处传递,很多情况下,会同时有多个参考指向同一个物件,强参考的存在限制了物件在存储器中的存活时间,假如物件 A 中包含物件 B 的一个强参考,那么一般情况下,物件 B 的存活时间就不会短于物件 A,如果物件 A 没有显式地把物件 B 的参考设为 null
的话,那么只有当物件 A 被垃圾回收之后,物件 B 才不再有参考指向它,才可能获得被垃圾回收的机会, 除了强参考之外,java.lang.ref
包还提供了对一个物件的另一种不同的参考方式,JVM 的垃圾回收器对于不同型别的参考有不同的处理方式,
软参考
软参考(soft reference)在强度上弱于强参考,通过类 SoftReference 来表示,它的作用是告诉垃圾回收器,程序中的哪些物件不那么重要,当存储器不足的时候是可以被暂时回收的,当 JVM 中的存储器不足时,垃圾回收器会释放那些只被软参考指向的物件,如果全部释放完这些物件之后,存储器仍不足,则会抛出 OutOfMemory 错误,软参考非常适合于创建快取,当系统存储器不足时候,快取中的内容是可以被释放的,比如考虑一个影像编辑器的程序,该程序会把影像档案的全部内容读取到存储器中,以方便进行处理,用户也可以同时打开多个档案,当同时打开的档案过多时,就可能造成存储器不足,如果使用软参考来指向影像档案的内容,垃圾回收器就可以在必要的时候回收这些存储器,
阵列的初始化
在 Java 中不存在只分配存储器空间而不赋初始值的情况,因为一旦为阵列的每个阵列元素分配存储器空间,存储器空间里存盘的内容就是阵列元素的值,即使存储器空间存盘的内容为空,「空」也是值,用 null
表示,不管以哪一种方式初始化阵列,只要为阵列元素分配了存储器空间,阵列元素就有了初始值,获取初始值的方式有两种:一种由系统自动分配;另一种由程序员指定,
Java 面向物件的几个核心概念
类
只要是一门面向物件的编程语言(例如 C++、C#等),那么就一定有类这个概念,类是指将相同属性的东西放在一起,类是一个模板,能够描述一类物件的行为和状态,请看下面两个例子,
- 在现实生活中,可以将人看成一个类,这类称为人类,
- 如果某个男孩想找一个物件(女朋友),那么所有的女孩都可能是这个男孩的女朋友,所有的女孩就是一「类」,
Java 中的每一个源程序至少都会有一个类,在
0 评论