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类型。

变量

Java种,每个变量都有一个类型。type。声明变量时,变量所属的类型位于变量名之前。

例如:

double salary;
int vacationDays;
long eartchPopulation;
boolean done;

每个声明以分号;结束。声明是一条完整的语句,以分号结束。

变量名必须是一个以字母开头的,由字母和数字组成的序列。

Java种的字母包括:A-Za-z_、在某些语言种代表字母的任何Unicode字符。

Java中的数字包括:0-9、在某些语言中代表数字的任何Unicode字符。

Java中字母和数字的范围更大。

变量名中所有的字符都是有意义的,并且大小写敏感。

变量名的长度没有限制。

不能将变量命名为Java保留字。

可以在一行中声明多个变量:

int i, j;

运算符

Java中的算术运算符:+、-、*、/表示加、减、乘、除运算。

当参与 / 运算的两个操作数都是整数时,表示整数除法;否则,表示浮点数除法。

整数的求余(或被称作取模)操作用 % 表示。

整数被0除会产生异常。浮点数被0除会得到无穷大或NaN。

二元算术运算符在赋值语句中可以简写:

x += 4 等价于 x = x + 4

移植性是Java的设计目标。无论在哪个虚拟机上运行,同一运算都该得到相同的结果。但是对于浮点数的算术运算,实现移植性是非常困难的。这和某些处理器的浮点寄存器的精度有关。

由于移植性问题和CPU的设计,Java的浮点数在不同平台的算术结果可能不同。

字符串

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实际上没有多维数组,只有一位数组。多维数组被解释为”数组的数组“。

所以可以方便地构造一个”不规则“数组。即数组的每一行有不同的长度。