精通JBuilder 2005
2.2.6 数组
一个数组即为基本数据类型或对象引用的有序集合,一个数组的元素也可以是数组。Java数组中的元素必须是相同类型的,不能将一个整数和一个浮点数放入相同的数组中。对于类对象的数组来说,情况有点特殊,只要它们能够“归为同一类”的对象就可以放在相同的数组中。
初始化数组必须经过三个阶段:
— 声明数组
— 构造数组
— 初始化数组
声明数组完成的工作是告诉编译器数组的名字及数组元素的类型,如代码清单2-7所示。
代码清单2-7 数组声明
1.int[] ints;
2.double[] dubs;
3.Object[] obj;
4.short[][] shts;
5.short shts[];
第1行和第2行声明一个基本数据类型的数组,第3行声明一个对象引用的数据,而第4行声明一个short型的二维数据,也可以看成是元素是short数组的数组。中括号可以放在数组变量名的前面,也可以放在数据变更名的后面,如第5行的short数组,尽管可以将[]放在变量名的后面,但建议采用第1~4行的声明方法,因为这样符合前面是数据类型而后面是变量名的习惯。一个接受整数数组作为入参的方法可以这样定义:foo(int[] ints)。
需要注意的是,声明数据变量时不可以在左边指定数组的大小,数组的大小只能在运行期通过new关键字分配指定,如代码清单2-8所示。
代码清单2-8 数组声明及构造
1.int[] ints;
2.ints = new int[10];
3.int[] ints2 = new int[10];
4.int[4] ints1;//错误
第1行声明了整数数组,第2行构造这个整数数组,第3行其实做了两步工作,声明一个整数数组并构造这个整数数组,而第4行的声明是错误的。
当一个数组构造完成时,数组中的元素初始化为该数组数据类型的默认值,算术数据类型的默认值为0,而非算术数据类型的默认值为“类零值”,所有数据类型的默认值如表2-3所示。
表2-3 数据类型的默认值
数据类型 | 默 认 值 | 数据类型 | 默 认 值 |
byte | 0 | short | 0 |
int | 0 | long | 0L |
float | 0.0f | double | 0.0d |
char | ‘\u0000’ | boolean | false |
对象类型 | null |
|
|
提示:
在Java中数组其实就是对象,虽然不能继承数组产生子类,但数组确实是对象,你可以执行数组的方法。此外,数据的初始化和对象的初始化是一样的。
如果你希望将数组初始化为非默认的值,你可以将声明、构造及初始化三个步骤组合到一步骤中。下面的代码以指定的数据初始化一个double的数组:
double[] dbls = {2.3,4.5,6.7,1.0};
用这种方式初始化的数组,数组大小由元素个数决定,上例中的double数据的大小为4。当然数组的初始化也可以拆分成三步进行,如代码清单2-9所示。
代码清单2-9 为数组填充元素
1.int[] ints ;
2.ints = new int[100];
3.for(int i = 0 ; i < 100 ; i++)
4.{
5. int[i] = i*i;
6.}
第2行执行后,ints数组中的所有元素都是0,其后的循环体内的赋值语句覆盖原先的默认值。上面的代码是可以工作的,但不是最好的。假设数组的大小发生了变化,将第2行的100变为150,则第3行的代码中的100也必须做相应的调整,如果不小心忽略了这个操作,则数组的一部分元素将得不到期望的值。可以调整为如代码清单2-10所示。
代码清单2-10 优化的数组值填充代码
1.int[] ints ;
2.ints = new int[100];
3.for(int i = 0 ; i <ints. length; i++)
4.{
5. int[i] = i*i;
6.}
第3行利用数组的length属性获取数组的大小,这样第2行的数组大小变化后循环语句代码无须调整。需要提醒的是Java数组的索引是从0开始的。
2.2.7 运算符和表达式
Java提供了丰富的运算符,其中许多与C/C++的运算符相似。Java的运算符列在表2-4中。
表2-4 Java的运算符
类 型 | 运 算 符 |
一元运算符 | ++ -- + - ! ~ () |
算术运算符 | * / % + - |
移位运算符 | << >> >>> |
关系运算符 | < <= < >= instanceof = = != |
位逻辑运算符 | & ^ | |
短路逻辑运算符 | && || |
条件运算符 | ?: |
赋值运算符 | = += -= *= /= %= |
1.一元运算符和表达式
++和--分别是对一个数递增或递减1。这两个运算符放在操作数前面还是后面是有区别的:放在操作数前面时,先完成递增或递减再进行其他的操作,而放在操作数的后面则先完成其他的操作再对操作数执行递增或递减。相信在看完下面的代码(如代码清单2-11所示)后,你对这两个操作符会有更深的理解。
代码清单2-11 一元运行符示例
1.int i = 0 ,j = 0 ;
2.int k1 = ++i;//执行完后k1为1
3.int k2 = j++;//执行完后k2为0
4.if(i== j) System.out.println("相等");//此时i和j都为1
5.if(++i== 2) System.out.println("相等");//i先加1再比较所以相等
6.if( !(j++== 2)) System.out.println("不相等");//j先比对再加1所以不相等
正值运算符+放在操作数或者变量的前面,有没有这个运算符的效果是一样的,只是为了显式的说明一个数是正数而已。如+23和23是一样的。而负值运算符表示对操作数进行负值运算,如-(-23)即为23,--23则表示递减运算。
!表示对boolean值取非,它的操作数类型只能是boolean值。如!isTrue表示对boolean 变量isTrue执行取非操作,这个运算符往往应用于逻辑比较操作表示式中,如:
!(a== b )&& k。
~运算符对数据的每个二进制位取反,即把1变成0,将0变成1。注意~运算符和-运算符是不同的,~34 ¹-34。
()为转型运算符,它显式地将一种类型的数据转为另外一种类型的数据,但开发人员必须保证这两种数据类型本质上可以进行这样的转换。转型运算符除可以对基本数据类型进行转换外,还可对对象进行类型的转换,请看代码清单2-12。
代码清单2-12 转型
1.float diameter = 2.3f;
2.int circum = (int)(Math.PI * diameter);//基本数据类型转换
3.List list = new ArrayList();
4.list.add("Hello");
5.String s = (String)list.get(0);//对象类型转换
第2行代码计算圆的周长,返回值为double类型,通过(int) 进行强制数据类型转换,将double类型转换为int类型,返回给circum变量,这样即小数点后的数据将丢失。
而第3~5行的代码对一个对象进行类型转换,list.get(0)获取列表中的一个对象,这个对象的类型为Object,而String是Object的子类,第5行的代码将其转换为String类型。
2.算术运算符和表达式
在所有的算术运算符中,用户可能对取模运算符%不太熟悉。取模运算就是求出被模数除所得的余数。如10%5=0,因为10能够被5整除。而11%5=1,因为11/5的余数为1。与C、C++语言不同的一点是,Java中可以对浮点数进行取模的操作,如39.3%10.0 =9.3。
对负数进行取模的运算常令人迷惑,这里给出一个计算的技巧:a%b可以这样计算,首先将a和b都变成正数进行取模运算,得到的结果添加上和a相同的正负符号即可。举个例子:
-10%-3= -10 % 3= -(10%3) = -1 ,而10%-3 = 10 % 3 = 1;
Java对于加法的运算进行了扩展,使它能够对两字符串执行连接运算,如:"abcd"+"ef"="abcdef"。
3.移位运算符
Java使用补码来表示二进制数,无符号右移时,最高位添0,下面是3个移位的运算符:
<< 左移 符号位保持不变
>> 右移
>>> 无符号右移
4.关系运算符
关系运算符分为两类,一类对数据值大小进行比较:< 、<=、<、>=、== 、!=;而另一类用于对象关系的比较:instanceof。如代码清单2-13所示。
代码清单2-13 逻辑运算
1.int p = 10;
2.int q = 64;
3.int r = -13;
4.float f = 9.0 F;
5.char c = 'A';//65
6.
7.//下列所有的测试都是true
8.p < q
9.f < q
10.f <= c
11.c > r
12.c >= q
instanceof运算符在运行期测试一个对象的类型,运算符左边是一个对象实例,而右边是一个类或接口的名字,如果左边的对象实例是属于右边类或其子类的实例,或者是实现了接口类的实例则返回true。为了说明这个运算符,我们先举一个简单的类继承例子,如代码清单2-14所示。
代码清单2-14 instanceof运算符
1.public class Fruit
2.{
3. double weigth;
4.}
5.public class Apple extends Fruit
6.{
7. public static void main(String[] args)
8. {
9. Apple c = new Apple();
10. if (c instanceof Fruit)//这个测试为true
11. {
12. System.out.println("apple is fruit!");
13. }
14. }
15.}
在上例中Apple类继承了Fruit类,第10行代码利用instanceof判断c实例和Fruit类关系,因为Apple类继承了Fruit类,所以第10行逻辑判断结果为true。关于类和接口的详细讲解请参见本章后面的内容。
5.位逻辑运算符和表达式
位逻辑运算符对基本数据类型比特位进行操作。位运算符两边的数据类型可以是byte、char、short、int、long、boolean,但不能是浮点数据类型float和double。其中boolean数据类型的操作数只能和boolean数据类型的操作数做位逻辑运算。而byte、char、short、int、long可任意组合进行位运算。
(1)& 按位与
按位与示例如表2-5所示。
表2-5 按位与示例
操作数a | 操作数b | a & b |
0 | 0 | 0 |
1 | 0 | 0 |
1 | 1 | 1 |
1010 0011 | 1100 0101 | 1000 0001 |
false | true | false |
(2)| 按位或
按位或示例如表2-6所示。
表2-6 按位或示例
操作数a | 操作数b | a | b |
0 | 0 | 0 |
1 | 0 | 1 |
1 | 1 | 1 |
1010 0011 | 1100 0101 | 1110 0111 |
false | true | true |
(3)^ 按位异或
按位异或示例如表2-7所示。
表2-7 按位异或示例
操作数a | 操作数b | a ^ b |
0 | 0 | 0 |
1 | 0 | 1 |
1 | 1 | 0 |
1010 0011 | 1100 0101 | 0110 0110 |
false | true | true |
6.短路逻辑运算符和表达式
短路逻辑运算符两边的操作数只能是boolean类型,一般情况下短路逻辑运算符两边都是关系表达式,如:(a>b) && ( k>100) || ( m-234),和关系运算符一起组成了逻辑关系表达式。
(1)&& 逻辑与
当逻辑关系表达式前面的表达项有一个是false时,后面的关系运算将被忽略,因为不管后面返回的是true或false整个表达式的值都为false,这种运算规则被称为短路运算,如代码清单2-15所示。
代码清单2-15 短路逻辑与运算
1.int i = 100;
2.int k = 0;
3.if( i < 90 && k== 0)
4.{
5. System.out.println("hello");
6.}
第3行的逻辑关系表达式先对i < 90的关系式进行判断,得到false,程序直接跳过对k==0的测试直接返回false。当i < 90改为i == 100时,前面的测试值为true,程序继续对k == 0进行测试,然后将两结果做与运算。
当需要同时测试多个关系式项,并且后面的关系式项基于前面的关系式项满足后才可正确执行时,用短路与再适合不过了。代码清单2-16为未用短路逻辑与运算。
代码清单2-16 未用短路逻辑与运算
1.if( arr != null)
2.{
3. if(arr.length >20)
4. {
5. System.out.println(arr.length);
6. }
7.}
第3行的arr.length只有在arr是一个已实例化的数组对象时才可正确执行,否则程序会抛出NullPointerException异常,我们可以通过&&将上面的代码改写成更简洁的形式,如代码清单2-17所示。
代码清单2-17 改写为短路逻辑与运算
1.if(arr != null && arr.length > 20)
2.{
3. System.out.println(arr.length);
4.}
(2)|| 逻辑或
逻辑或和逻辑与的区别是当多个关系式项联合判断时,仅当前面的关系式项返回false时才继续对后面的表示式项进行运算,否则忽略后面表示项的运算,可以用 || 改写上一例的代码,如代码清单2-18所示。
代码清单2-18 短路逻辑或运算
1.if( arr== null || arr.length <= 20)
2.{
3. System.out.println("is not match");
4.}
5.else
6.{
7. System.out.println(arr.length);
8.}
7.条件运算符表达式
典型的条件运算符表达式为:a = x ? b:c;这个表达式当x为true时返回b值给a,否则返回c值给a,它实现的逻辑相当于代码清单2-19所实现的逻辑。
代码清单2-19 条件运算符表达式
1.if(x )
2.{
3. a = b;
4.}
5.else
6.{
7. a = c;
8.}
其中x、b、c都可以是一个表达式,但a、b、c必须是相同类型或者是兼容的数据类型。如代码清单2-20所示。
代码清单2-20 灵活的条件运算符表达式
1.int a = 1;
2.int b = 20;
3.int c = 50;
4.short s = 90;
5.a = s -12 < 100 ? b + 100 : c +20;//a 为120
8.赋值运算符和表达式
= 是赋值运算符,而算术运算符和赋值运算符的组合运算符是运算并赋值的简化版,例如:
byte b = 2;
b += 2;
相当于:
byte b = 2;
b = (byte)(b + 2);
另一种比较复杂的赋值操作是连环赋值,下面的代码将a、b、c赋值为3,如代码清单2-21所示。
代码清单2-21 复杂逻辑运算符
1.int a , b , c;
2.a = b = c = 3;
3.//下面是另一种赋值方法
4.int d = 3 ,e = 3 ,f = 3;
导入论坛 引用链接 收藏 分享给好友 推荐到圈子 管理 举报
TAG:

