一、分支结构
1、if条件语句
第一种形式:
if(logic expression)
{
statement...
}
第二种形式:
if(logic expression)
{
statement...
}
else
{
statement...
}
第三种形式:
if(logic expression)
{
statement...
}
else if(logic expression)
{
statement...
}
...//可以有零个或者多个else if语句
else//最后一个else可以省去
{
statements...
}
注意:在if语句中表面上看else后面没有任何条件,或者else if后面只有一个条件,但这不是真相:因为else本身就是一个条件!else的含义是“否则”,其隐含条件是对前面条件取反。而不是仅仅是表象中非此即彼的感觉。
在使用if...else语句时应遵循一条基本原则:总是优先把包含范围小的条件放在前面处理。如age>60和age>20两个条件,明显age>60的范围更小,所以应该先处理age>60的情况。
2、switch语句
switch (expression)
{
case condition1:
{
statement(s)
break;
}
case condition2:
{
statement(s)
break;
}
...
case conditionN:
{
statement(s)
break;
}
default:
{
statement(s)
}
}
default的含义是expression表达式的值不能与前面任何一个case标签后面的值相等。
1、while循环语句
[init_statement]//初始化语句
while(test_expression)
{
statement;
[iteration_statment]//迭代语句
}
while循环每次执行循环体之前,先对test_expression循环条件求值,如果循环条件为true,则运行循环体部分。
2、do while循环语句
[init_statement]//初始化语句
do
{
statement;
[iteration_statment]//迭代语句
}while(test_expression);
do while循环语句与while的区别在于do while先执行循环体,然后才判断循环条件,如果循环条件为真,则执行下一次循环,否则终止循环。do while循环的循环条件后必须有一个分号,这个分号表明循环结束。值得注意的是do while 循环的循环体至少执行一次,即使判断条件为假。
for([init_statement];[test_statement];[iteration_statement])
{
statement
}
for循环圆括号里面只有两个分号是必需的,初始化语句、循环条件、迭代语句部分都是可以省略的,如果省略了循环条件,则这个循环默认为true,将会产生一个死循环。
三、控制循环结构
1、使用break结束循环
break用于完全结束一个循环,跳出一个循环体。不管是哪种循环,一旦在循环体中遇到break,系统将完全结束该循环,开始执行循环之后的代码。
其实break不仅可以结束其所在的循环,还可以直接结束其外层循环。此时需要在break后面紧跟着一个标签,这个标签用于标识一个外层循环。
Java中的标签就是一个紧跟着一个英文冒号的标识符。java中的标签只有放在循环语句之前才有作用。
public class BreakTest2
{
public static void main(String[] args)
{
//外层循环,outer作为标识符
outer:
for(int i=0;i<5;i++){
//内层循环
for(int j=0;j<3;j++){
System.out.println("i的值为: "+i+" j的值为:"+j);
if(j==1){
//跳出outer标签所标识的循环体
break outer;
//break;
}
}
}
}
}
2、使用continue忽略本次循环剩下语句
continue和break的区别在于,continue只是忽略本次循环剩下语句,并不会终止循环;而break则是完全终止循环的本身。continue后面也可以紧跟一个标签,用于直接跳过标签所标识循环的当次循环的剩下语句,重新开始下一次循环。
public class ContinueTest2
{
public static void main(String[] args)
{
//外层循环,outer作为标识符
outer:
for(int i=0;i<5;i++){
//内层循环
for(int j=0;j<3;j++){
System.out.println("i的值为: "+i+" j的值为:"+j);
if(j==1){
//忽略outer标签所指定的循环中本次循环所剩下语句
continue outer;
}
}
}
}
}
3、使用return结束方法
return关键字的功能是结束一个方法,并不是专门用于结束循环。当一个方法执行到break语句时(return关键字后还可以跟变量、常量和表达式),这个方法将被结束。
与continue和break不同的是return直接结束整个方法,不管这个return处于多少循环之内。
四、数组类型
Java的数组要求所有的数组元素具有相同的数据类型。
数组本身是一种引用类型。一旦数组初始化完成,数组在内存中所占的空间将被固定下来,因此数组的长度是不可变的。即使把某个数组元素的数据清空,但它所占的空间依然被保留,依然属于该数组,数组的长度依然不变。
1、定义数组
type[] arrayName;
type arayName[];
对于这两种语法格式而言,通常推荐使用第一种格式。
数组是一种引用类型的变量,因此使用它定义一个变量时,仅仅是表示定义了一个引用变量,这个引用变量还没有指向任何有效的内存,因此定义数组时不能指定数组的长度。
2、数组的初始化
数组的初始化有两种方式:
静态初始化:初始化由程序员显示指定每个数组元素的初始值,由系统决定数组的长度。
动态初始化:初始化时程序员只指定数组长度,由系统为数组元素分配初始值。
2.1 静态初始化
语法格式:
arrayName=new type[]{element1,element2,element3...}
执行静态初始化时,显示指定的数组元素值的类型必须与new关键字后的type类型相同,或者是其子类的实例。
// 定义一个int数组类型的变量,变量名为intArr.
int[] intArr;
// 使用静态初始化,初始化数组时只指定数组元素的初始值,不指定数组长度。
intArr = new int[]{5, 6, 8 , 20};
// 定义一个Object数组类型的变量,变量名为objArr.
Object[] objArr ;
// 使用静态初始化,初始化数组时数组元素的类型是
// 定义数组时所指定的数组元素类型的子类
objArr = new String[]{"Java" , "李刚"};
Object[] objArr2 ;
// 使用静态初始化
objArr2 = new Object[] {"Java" , "李刚"};
除此之外,静态初始化还有下面格式:
type[] arrayName={element1,element2,element3...}
2.2 动态初始化语法格式如下:
arrayName=new type[length]
语法格式中的type必须与定义数组时使用的type类型相同,或者是定义数组时使用的type类型的子类。
//数组的定义和初始化同时完成,使用动态初始化语法
int[] prices = new int[5];
// 数组的定义和初始化同时完成,初始化数组时元素的类型是定义数组时元素类型的子类
Object[] books = new String[4];
执行动态初始化时,程序员指定数组长度,由系统为这些数组元素分配初始值:
数组元素的类型如果是整数类型(byte、short、int和long),则数组元素的值为0;如果是浮点类型(float、double),数组元素的值为0.0;如果是字符类型(char),数组元素的值为‘\u0000’;如果是布尔类型(boolean),则数组元素的值为false;如果是引用类型(类、接口、数组),则数组元素的值为null。
注意:不要同时使用静态初始化和动态初始化,也就是说,不要在进行数组初始化时,既指定数组的长度,也为每个数组元素分配初始值。
3、foreach循环
使用foreach循环遍历数组和集合元素时,无需获得数组和集合的长度,无需根据索引来访问数组元素和集合元素,foreach循环自动遍历数组和集合中的每个元素。语法格式如下:
for(type variableName : arry|collection)
{
//variableName自动迭代访问每个元素...
}
上面语法中type是数组元素或集合元素的类型,variableName是一个形参名,foreach循环将自动将数组元素、集合元素依次赋给该变量。
public class ForEachErrorTest
{
public static void main(String[] args)
{
String[] books = {"轻量级Java EE企业应用实战" ,
"疯狂Java讲义",
"疯狂Android讲义"};
// 使用foreach循环来遍历数组元素,其中book将会自动迭代每个数组元素
for (String book : books)
{
book = "疯狂Ajax讲义";
System.out.println(book);
}
System.out.println(books[0]);
}
}
使用foreach循环迭代数组时,并不能改变数组元素的值,因此不要对foreach的循环变量进行赋值。
1、内存中的数组
引用变量是访问真是对象的根本方式。也就是说,如果希望在程序中访问数组对象本身,则只能通过这个数组的引用变量来访问它。实际上数组对象存在堆内存中;如果引用该数组对象的数组引用变量是一个局部变量,则它被存储在栈内存中。数组在内存中的存储如下图:
所有在方法中定义的局部变量都放在栈内存中;在程序中创建一个对象时,这个对象被保存到堆内存中。只有当一个对象没有任何引用变量引用它时,系统的垃圾回收器才会在合适的时候回收它。
因此,为了让垃圾回收机制回收一个数组所占用的内存空间,可以将该数组变量赋值为null,也就切断了数组引用变量和实际数组之间的引用关系,实际的数组也就成了垃圾。
2、基本类型数组的初始化
基本类型数组初始化时,先为该数组分配内存空间,然后直接将数组元素的值存入对应数组元素中。
public class PrimitiveArrayTest
{
public static void main(String[] args)
{
// 定义一个int[]类型的数组变量
int[] iArr;
// 动态初始化数组,数组长度为5
iArr = new int[5];
// 采用循环方式为每个数组元素赋值。
for (int i = 0; i
上面代码流程用内存存储表示为:
class Person
{
public int age; // 年龄
public double height; // 身高
// 定义一个info方法
public void info()
{
System.out.println("我的年龄是:" + age
+ ",我的身高是:" + height);
}
}
public class ReferenceArrayTest
{
public static void main(String[] args)
{
// 定义一个students数组变量,其类型是Person[]
Person[] students;
// 执行动态初始化
students = new Person[2];
// 创建一个Person实例,并将这个Person实例赋给zhang变量
Person zhang = new Person();
// 为zhang所引用的Person对象的age、height赋值
zhang.age = 15;
zhang.height = 158;
// 创建一个Person实例,并将这个Person实例赋给lee变量
Person lee = new Person();
// 为lee所引用的Person对象的age、height赋值
lee.age = 16;
lee.height = 161;
// 将zhang变量的值赋给第一个数组元素
students[0] = zhang;
// 将lee变量的值赋给第二个数组元素
students[1] = lee;
// 下面两行代码的结果完全一样,因为lee
// 和students[1]指向的是同一个Person实例。
lee.info();
students[1].info();
}
}
上述代码执行过程的示意图如下:
type[][] arrName;
因为在java中数组类型是引用类型,也就是说type[]是一种引用类型。上述的语法中的实质还是一维数组,只是其数组元素也是引用,数组元素里保存的引用指向一维数组(type[]是引用类型,第二个[]存入引用元素)。
arrName=new type[length][]
初始化多维数组时可以只指定最左边维的大小,也可以一次指定每一维的大小,如:
//同时初始化二维数组的两个维度
int[][] b=new int[3][4];