Java学习笔记之八 Java基本的程序设计结构
现在,我已经成功地安装了JDK,并且已经能够运行《Java核心技术卷I》(原书第8版)中给出的例子程序。
程序按照交互方式,主要有3类:一类是控制台程序。一类是图形化程序。另一类是Web程序。
这份笔记记录的是《Java核心技术卷I》第3章:Java基本的程序设计结构。里面的程序时控制台程序。
简单的Java应用程序
public class FirstSample
{
public static void main(String[] args)
{
System.out.println("We will not use 'Hello, World!'");
}
}
Java对大小写敏感。
public被称为访问修饰符,access modifier。它用于控制程序的其他部分对这部分代码的访问级别。
class表明全部内容都包含在类中。可以将类视为一个加载程序逻辑的容器。
Java应用程序的全部内容,都必须放在类中。
class后面跟的是类名。Java类名规则很宽松。名字必须以字母开头,后面可以接字母和数字的任意组合。长度基本上没有限制。类名不能使用Java的保留字。
不知道新版本的Java类名是不是支持Unicode字符。另外,类名应该不支持下划线、连字符。
类名的标准命名规范为驼峰命名法。类名是以大写字母开头的单词。如果类名由多个单词组成,则每个单词的第一个字母也应该大写。CamelCase。
源代码的文件名必须与公有类的名字相同,并用.java
作为扩展名。
上述代码应该保存为FirstSample.java
。大小写非常重要。
编译源代码文件后,会得到字节码文件。Java编译器自动将字节码文件命名为FirstSample.class,并存放在源文件相同的文件夹下。
运行Java程序,使用java命令:
java FirstClass
这里不加.class
扩展名。
当用java ClassName
运行编译程序时,Java虚拟机从指定类的main方法开始执行。方法类似于其他语言中的函数。为了让代码执行,类的源文件中必须有一个main方法。
根据Java语言规范,main方法必须声明为public。
源代码中的括号{}
用来划分程序的各个部分。这样的部分成为块。
Java中的任何方法都以{
开始,以}
结束。
花括号的具体对齐位置颇具争议。我将匹配的花括号上下对齐。
空白字符会被Java编译器忽略。所以可以使用任何自己喜欢的风格。
static void暂且不理。
每个Java应用程序都必须有一个main方法。其格式为:
public class ClassName
{
public static void main(String[] args)
{
program statements
}
}
在Java中,每个句子都必须用分号;
来表示句子的结束。回车不是语句结束的标志。一个句子可以写在好多行上,也可以在在一行上。多个句子也可以写在一行上。
System.out.println("We will not use 'Hello, World!'");
是一个语句。这个语句的功能是输出一系列字符到控制台上。
这里使用了对象System.out,并调用了它的println方法。点号用于调用方法。
Java调用方法的通用语法是object.method(parameters)
。
Java用双引号分割字符串。
println方法输出字符串,并换行。
Java的方法可以没有参数,也可以有一个或多个参数。没有参数也需要用圆括号书写。例如:
System.out.println();
注释
Java中有三种注释:
- //
- /* */
- /** */
这是注释的三种书写方式。第一种,双斜线,它的注释内容从//开始,直到行尾。
第二种是块注释。可以用来注释多行,或一行中的一部分。这种注释以/*
开头,以*/
结束。
第三种用于自动生成文档。这种注释以/**
开头,以*/
结束。
Java种的/* */
注释不能嵌套。如果代码本身包含:
*/
则不能用/* */
将它包起来。
注释的例子:
/**
* This is the first sample program in Core Java Chapter 3
* @version 1.01 1997-03-22
* @author Gary Cornell
*/
public class FirstSample
{
public static void main(String[] args)
{
System.out.println("We will not use 'Hello, World!'");
}
}
数据类型
Java种的每一个变量,都必须有一种类型。
Java是一种强类型语言。
在Java种,一共有8种基本数据类型。primitive types。
8种基本数据类型:4种整形、2种浮点类型、1种表示unicode字符单元的char、1种表示真值的boolean类型。
- 整数类型。见整数类型学习笔记。
- 浮点类型。见浮点类型学习笔记。
- char类型。见char类型学习笔记。
- boolean类型。见boolean类型学习笔记。
变量
Java种,每个变量都有一个类型。type。声明变量时,变量所属的类型位于变量名之前。
例如:
double salary;
int vacationDays;
long eartchPopulation;
boolean done;
每个声明以分号;
结束。声明是一条完整的语句,以分号结束。
变量名必须是一个以字母开头的,由字母和数字组成的序列。
Java种的字母包括:A-Z
、a-z
、_
、在某些语言种代表字母的任何Unicode字符。
Java中的数字包括:0-9
、在某些语言中代表数字的任何Unicode字符。
Java中字母和数字的范围更大。
变量名中所有的字符都是有意义的,并且大小写敏感。
变量名的长度没有限制。
不能将变量命名为Java保留字。
可以在一行中声明多个变量:
int i, j;
运算符
Java中的算术运算符:+、-、*、/表示加、减、乘、除运算。
当参与 / 运算的两个操作数都是整数时,表示整数除法;否则,表示浮点数除法。
整数的求余(或被称作取模)操作用 % 表示。
整数被0除会产生异常。浮点数被0除会得到无穷大或NaN。
二元算术运算符在赋值语句中可以简写:
x += 4
等价于 x = x + 4
。
移植性是Java的设计目标。无论在哪个虚拟机上运行,同一运算都该得到相同的结果。但是对于浮点数的算术运算,实现移植性是非常困难的。这和某些处理器的浮点寄存器的精度有关。
由于移植性问题和CPU的设计,Java的浮点数在不同平台的算术结果可能不同。
- Java中的浮点数算术精度问题。见Java中的浮点数算术精度问题学习笔记。
- 自增运算符和自减运算符。见自增运算符和自减运算符学习笔记。
- 关系运算符和boolean运算符。见关系运算符和boolean运算符学习笔记。
- 位运算符。见位运算符学习笔记。
- 数学函数与常量。见数学函数与常量学习笔记。
- 数值类型之间的转换。见数值类型之间的转换学习笔记。
- 强制类型转换。见强制类型转换的学习笔记。
- 括号与运算符级别。见括号与运算符级别的学习笔记。
- 枚举类型。见枚举类型的学习笔记。
字符串
Java字符串是Unicode字符序列。
Java没有内置的字符串类型。
Java标准类库中提供了一个预定义的类String。
每个用双引号括起来的字符串都是String类的一个实例。
- 字串。String类的substring方法可以从一个较大的字符串提取出一个子串。substring的第2个参数是不想复制的第一个位置。substing从0开始计数。substring容易计算子串的长度。s.substring(a, b)的长度为 b - a。
- 拼接。在Java中,用+好连接或拼接两个字符串。将一个字符串与一个非字符串的值拼接时,非字符串的值会被转为字符串,再拼接。在今后将学到,任何一个Java对象都可以转换为字符串。
- 不可变字符串。String类没有提供修改字符串的方法。如果需要修改字符串,需要使用substring提取子字符串,再行拼接。不能修改Java字符串中的字符。因此Java String类对象被称为不可变字符串。
- 检测字符串是否相等。使用equals方法来检测两个字符串是否相等。s.equals(t)。如果相等,返回true,否则,返回false。如若比较字符串是否相等,但忽略大小写,使用equalsIgnoreCase方法。不能使用==来检测两个字符串是否相等。这个运算符仅用来确定两个字符串是否放在同一个位置上。
- 代码点与代码单元。
- 字符串API。Java中的string类包含了50多个方法。
- 阅读联机API文档。要想记住所有的类和方法几乎是一件不可能的事情。所以需要查看Java API文档。
- 构建字符串。有时候,需要用较短的字符串构建字符串。字符串拼接的方式耗时、占用空间大。使用StringBuilder类可以避免这种问题。
StringBuilder builder = new StringBuilder();
builder.append(ch); // appdends a single character
builder.append(str); // appends a string
String complatedString = builder.toString();
首先构建一个空的字符串构建器。
每次需要添加一部分内容时,调用append方法。
在需要构建字符串时,调用toString方法,得到一个String对象。
StringBuffer和StringBuilder两个类的API是相同的。StringBuffer效率略微有些低,被用于多线程中。在单线程中的操作,应该使用StringBuidler类。
输入和输出
现代的程序使用图形化用户界面收集用户的输入。编写图形化用户界面的程序需要使用较多的工具和技术。
目前使用简单的控制台的输入和输出。
读取输入。
要想通过控制台进行输入,需要构造一个Scanner对象,并于标准输入流System.in关联。
Scanner in = new Scanner(System.in);
之后,利用Scanner类的各种方法实现输入。
例如,nextLine方法将输入下一行。
System.out.print("What is your name?");
String name = in.nextLine();
使用nextLine方法,是因为输入行中有可能包含由空格。要想读取一个单词(以空白符作为分隔符),就调用:
String firstName = in.next();
要想读取一个整数,就调用:
System.out.print("How old are you?");
int age = in.nextInt();
类似的,读取浮点数,用nextDouble方法。
最后,需要在最开始加上一行:
import java.util.*;
Scanner类定义在java.util包中。
当使用的类不是定义在基本的java.lang包中时,一定要用import指示字将相应的包加载进来。
Scanner类不适用于从控制台读取密码。
Java SE 6特别引入了Console类,来实现这个目的。
采用Console对象处理输入没有Scanner方便。
按格式输出。
文件输入和输出。
控制流程
Java使用条件语句和循环结构确定控制流程。
Java中没有goto语句,但break语句可以带标签,可以利用它实现从内层循环跳出的目的。
块作用域。
块,即复合语句,是由一对花括号括起来的若干简单的Java语句。
块决定了变量的作用域。
一个块可以嵌套在另一个块中。
不能再嵌套的两个块中声明同名的变量。
条件语句。
再Java中,条件语句的格式为:
if (condition) statement
条件必须用括号括起来。
当条件为真时,需要执行多个语句时,应该使用块语句。
if (condition)
{
statement1
statement2
}
另一种条件语句的格式
if (condition) statement1 else statement2
else部分时可选的。else子句与最邻近的if构成一组。
使用括号将使代码更加清晰。
重复地交替出现 if... else if...是一种常见情况。
循环。
当条件为true时,while循环执行一条语句(也可以是一个块)。
常用格式:
while (condition) statement
如果最开始地循环条件地值为false,则while循环体一次也不执行。
如果希望循环体至少执行一次,则应将检测条件放在最后。使用do/while循环语句。
它地语法格式为:
do statement while (condition);
确定循环。
for循环语句是支持迭代地一种通用结构。利用每次迭代之后更新地计数器或类似地变量控制迭代次数。
for语句的3个部分应该对同一个计数器变量进行初始化、检测和更新。
再循环中,检测两个浮点数是否相等一定要非常小心。
多种选择:switch语句。
不建议再程序中使用switch语句。
中断控制流程语句。
使用break和continue来中断控制流程。
break和continue语句完全是可选的,不使用它们也可以表达同样的逻辑含义。
大数值
基本的整数和浮点数精度不够时,可以使用java.math包中的两个很有用的类BigInteger和BigDecimal。
这两个类用于处理包含任意长度数字序列的数值。
BigInteger类实现了任意精度的整数运算。
BigDecimal类实现了任意精度的浮点数运算。
使用静态方法valueOf可以将普通的数值转换为大数值。
BigInteger a = BigInteger.valueOf(100);
不能使用算术运算符处理大数值。需要使用大数值类提供的运算方法。
Java没有提供运算符重载功能。Java确实重载了字符串链接运算符+,但没有重载其他运算符,也没有给Java程序员自己重载运算符的权利。
数组
数组是一种数据结构,用来存储同一类型值的集合。
通过整型下标可以访问数组中的每一个值。
声明数组时,需要指出数组的类型和数组变量的名字。数组类型用数据元素类型紧跟[]表示。
int[] a;
应该使用new运算符创建数组。
int[] a = new int[100];
声明数组由两者方法,一种是:
int[] a;
另一种是:
int a[];
大多数Java应用程序员采用第一种风格。它将类型和变量名分开了。
获取数组中的元素个数,用array.length。
一旦创建了数组,就不能改变它的大小。
如果经常需要在运行的过程中扩展数组的大小,就应该使用另一种数据结构——数组列表,array list。
- For each循环。
语法:
for (variable: collection) statement
如果需要处理一个集合中的所有元素,for each语句更适合。
如果不希望遍历集合中的每个元素,或在循环内部需要使用下标值,则需要使用传统循环。
- 数组初始化及匿名数组
创建数组并赋予初始值的简化写法:
int[] smallPrimes = { 2, 3, 5, 7, 11, 13 };
在使用这种语句的时候,不需要调用new。
初始化匿名数组:
int[] { 17, 19, 23, 29, 31, 37 }
- 数组拷贝
将数组变量拷贝给另一个数组变量。两个变量引用同一个数组。
如果需要将一个数组的所有值拷贝到另一个新的数组中去,则需要使用Arrays类的copyOf方法。
- 命令行参数
每一个Java应用程序都有一个带String args[]参数的main方法。这个参数表明main方法将接收一个字符串数组,也就是命令行参数。
java Message -g cruel world
args数组将包含下述内容:
args[0]: "-g"
args[1]: "cruel"
args[2]: "world"
Java应用程序的main方法中,程序名并没有存储在args数组中。
- 数组排序
使用Arrays.sort方法。
- 多维数组
多维数组将使用多个下标访问数组元素。它适用于表示表格或更复杂的排列形式。
- 不规则数组
Java实际上没有多维数组,只有一位数组。多维数组被解释为”数组的数组“。
所以可以方便地构造一个”不规则“数组。即数组的每一行有不同的长度。