[关闭]
@Darcy 2017-08-11T11:14:12.000000Z 字数 10238 阅读 2883

第四章 Java 编程基础

JavaForKids

你可以为你程序中一行特定的代码、方法或类添加任意的文本作为注释。因为有时人们会忘记自己以前为什么 写下这些代码,同时也可帮助别人理解你的代码。

1. 程序注释

Java里,共有三种不同的注释:

  1. 如果你的注释只想出现在同一行,可以用两个斜杠//开头:
  1. // 这个方法用来计算距离
  1. 更长的注释跨越多行,它必须放在于 /* 和 */ 之间,例如:
  1. /*接下来的 3 行用来存储
  2. 鱼的位置
  3. */
  1. Java有一个叫做 javadoc 的特殊程序,它可以提取你程序中的注释到一个单独的帮助文件。这个文件可以作为你的程序的技术文档。这一类型的注释放在符号/** 和 */ 中。这一类型的注释应该只在描述类或方法等这些比较重要代码时才使用。
  1. /**
  2. 这个方法根据价格来计算折扣
  3. 如果价格超过100元,那么折扣就是 20%
  4. 其他情况下,则只有 10%
  5. */

从现在起,我会在代码示例中加入注释,好让你了解怎样使用和在哪里使用它们。

2. 用 if 条件语句做判断

生活中,我们经常需要做出某些判断:如果她告诉我这个,我就会回答她,否则,我将做其他一些事。Java用 if 语句来检查一个特定的表达式成立与否。成立是 true,否则是false

根据表达式的结果,程序将会分叉执行。
分叉
例如,如果表达式我要不要去奶奶那?计算结果是 true,那么转左;否则转右。

如果一个表达式返回true,JVM将执行第一个大括号中的代码,否则执行else后的语句。举个例子,如果价格(price)超过100元,则给予20%的折扣,否则只有10%。代码实现如下:

  1. // 价格超过100元的物品给20%的折扣
  2. if (price > 100){
  3. price=price*0.8;
  4. System.out.println("Youll get a 20% discount”);
  5. }else{
  6. price=price*0.9;
  7. System.out.println("Youll get a 10% discount”);
  8. }

让我们修改一下Fish中的方法 dive(),以确保我们的鱼不会潜入超过100英尺深:

  1. public class Fish extends Pet{
  2. int currentDepth=0;
  3. public int dive(int howDeep){
  4. currentDepth=currentDepth + howDeep;
  5. if (currentDepth > 100){
  6. System.out.println("I am a little fish and " + " can't dive below 100 feet");
  7. currentDepth=currentDepth - howDeep;
  8. }else{
  9. System.out.println("Diving for " + howDeep + " feet");
  10. System.out.println("I'm at " + currentDepth +" feet below the sea level");
  11. }
  12. return currentDepth;
  13. }
  14. public String say(String something){
  15. return "Don't you know that fish do not talk?";
  16. }
  17. }

现在,对FishMaster做些小小的修改并让我们的鱼潜入深海:

  1. public class FishMaster {
  2. public static void main(String[] args) {
  3. Fish myFish = new Fish();
  4. //试着让鱼下潜到比100尺更深的地方
  5. myFish.dive(2);
  6. myFish.dive(97);
  7. myFish.dive(3);
  8. myFish.sleep();
  9. }
  10. }

运行程序,它将打印如下信息:

Diving for 2 feet
I'm at 2 feet below the sea level
Diving for 97 feet
I'm at 99 feet below the sea level
I am a little fish and can't dive below 100 feet
Good night, see you tomorrow

3. 逻辑操作符

有时候,你需要检查多个条件来做出决定,比如,如果州 (state)名是Texas或者California的话,那么就为商店的每一件商品加上州税。这是一个逻辑‘或’(or)的例子 - Texas 或者 California。在Java中,逻辑‘或’的符号是一根或者两根的竖线。它工作原理是这样子的:如果其中的一个条件为true,那么整个结果就是true。在下面的例子中,我会使用String类型的变量来进行比较,它有一个equals()方法,可以比较两个字符串是否相等,在这里用它来比较州名否等于Texas或者California:

  1. if (state.equals("Texas") | state.equals("California"))

你也可以在if语句里面使用两条竖线:

  1. if (state.equals("Texas") || state.equals("California"))

它们两者的区别在于:如果你使用两条竖线,那么只要第一个表达式(state.equals("Texas"))的结果为true,那么第二个表达式就不会执行检查了。如果是单条竖线的方式,那么JVM会对这两个表达式都进行检查。

逻辑‘与’(and)是用一个或者两个的&符号来表示的,它工作原理是这样子的:如果其中所有的表达式的结果为true,那么整个结果就是true。举个例子:当州名(state)是New York 并且 价格(price)大于110美元的时候,需要交纳销售税。也就是这两个条件要同时成立:

  1. if (state.equals("New York") && price >110)

或者

  1. if (state.equals("New York") & price >110)

如果你使用的是两个&符号的方式,那么当第一个表达式结果是false时,则第二个表达式就不用执行检查了,因为无论第二个表达式的结果如何,它总的结果反正都是false的。如果是单个符号&的方式,就算第一个结果是false,那么第二个表达式还是会执行的。

逻辑‘非’是用感叹号!来表示的,它的作用是会使结果相反。例如:如果你想当州名不是New York的情况执行一些操作,那么你可以使用下面的语句:

  1. if (!state.equals("New York"))

这里展示的另外一个例子 - 下面的两个表达式的效果是一样的:

  1. if (price < 50)
  2. if (!(price >=50))

4. 条件操作符

if语句还有另外一种表示方法条件操作符( conditional operator) 。这种语句用于给一个变量赋值, 其中问号会紧跟在判断表达式的后面。如果这个表达式成立,那么就给在左边的这个变量赋予跟在问号?后面的值,否则就给它赋予跟在冒号:后面的值:

  1. discount = price > 50 ? 10 : 5;

如果price比50大,那么赋予discount这个变量10的值,否则为5。这其实就是用更简短的方式代替了一个常规的if语句:

  1. if (price > 50){
  2. discount = 10;
  3. } else {
  4. discount = 5;
  5. }

5. 使用 else if

你也可以通过使用一些else if语句块来构建更多复杂的if语句。这次我们将创建一个新的类叫做ReportCard。这个类必须有main()方法以及一个只带单个参数的方法,这个数值类型的参数代表你要传入的成绩。根据数字的不同,它会把你的成绩用A,B,C,D或F来表示。我们将这个方法命名为convertGrades()

  1. public class ReportCard {
  2. /**
  3. 这个方法带了一个int类型的参数testResult:该方法返回的字母是A、B、C还是D取决于这个参数的值。
  4. */
  5. public char convertGrades( int testResult){
  6. char grade;
  7. if (testResult >= 90){
  8. grade = 'A';
  9. }else if (testResult >= 80 && testResult < 90){
  10. grade = 'B';
  11. }else if (testResult >= 70 && testResult < 80){
  12. grade = 'C';
  13. }else {
  14. grade = 'D';
  15. }
  16. return grade;
  17. }
  18. public static void main(String[] args){
  19. ReportCard rc = new ReportCard();
  20. char yourGrade = rc.convertGrades(88);
  21. System.out.println("Your first grade is " + yourGrade);
  22. yourGrade = rc.convertGrades(79);
  23. System.out.println("Your second grade is " + yourGrade);
  24. }
  25. }

除了使用else if条件,这个例子还告诉你怎么使用char类型的变量。在上面的例子中,你能看到,用 && 操作符你可以确定一个数字是否落在一定范围内。在Java里,你不能就直接写if(80<=testResult<90),而应写成if( 80<=testResult && testResult<90 )

  1. testResult >= 80 && testResult < 89

思考一下:在这里我们为什么不能使用 || 操作符 ?

6. 使用switch语句做选择

switch语句有时可作为if语句的替代。程序将会根据在switch后面括号中的值来选择和它相同值的case代码块来执行:

  1. public static void main(String[] args){
  2. ReportCard rc = new ReportCard();
  3. char yourGrade = rc.convertGrades(88);
  4. switch (yourGrade){
  5. case 'A':
  6. System.out.println("Excellent work!");
  7. break;
  8. case 'B':
  9. System.out.println("Good job!");
  10. break;
  11. case 'C':
  12. System.out.println("You have to work more!");
  13. break;
  14. case 'D':
  15. System.out.println("Change your attitude!");
  16. break;
  17. }
  18. }

可别忘了在每个case后面加上关键字break哦,如果没有它,那么接下来的case都会被执行,直到下个break出现或直到语句结束。例如,在没有加break的情况下,yourGrade的值为'C' , 那么下面的case 'D'里面的代码也会被执行。
switch
在Java里switch语句有一个限制条件--所有需要赋值的变量都必须是以下类型中的其中一种:

char
int
byte
short。

7. 变量会存活多久?

ReportCard在方法convertGrades()里面声明了一个变量--grade。如果你声明的一个变量在任意一个方法里,那么这个变量就叫做本地变量(local variable)。这意味着只有在这个方法里的代码才能使用这个变量。当这个方法结束,这个变量会自动从内存中清除。程序员通常用作用域(scope)这个词来表示一个变量会存活多久,比如,你可以说在一个方法里被声明的变量有一个局部作用域。

如果一个变量必须被数个方法重复使用,或者它必须出现在同一个类里的不止一个方法里,你应该把这类变量声明在任何一个方法之外。在Fish这个类里,currentDepth是一个成员变量。只要Fish这个对象的实例还驻留在内存里,这些变量都是“活着的”,所以它们也被称为实例变量(instance variables)。它们可以被在这个类里的所有方法共享并使用,而且在某些情况下,它们甚至能出现在外部的类里,比如,在我们构建的类里,System.out.println() 这个 语句中使用了被声明在System这个类里的out这个变量。

等一下! 如果我们还未曾为System类构建一个实例,是否还可以用它里面的成员变量呢?没错,当然可以,只要我们用static这个关键词来声明这个变量。如果一个成员变量或一个方法的声明以static开头,你就不必给这个类构建一个实例来使用它。类的静态变量(也称为类变量)将被这个类所有的实例共享,也就是说,这个变量在所有实例中的值都是一样的,在一个实例中改变这个变量的值会直接影响到另外一个实例。

比如在下面的代码中,Fish有一个静态的类变量,Fish创建了两个实例fish1fish2,当currentDepthfish2的实例中的值被改为3时,fish1中的currentDepth也跟着变成3了。

  1. public class Fish extends Pet{
  2. static int currentDepth = 0;
  3. public static void main(String[] args){
  4. Fish fish1 = new Fish();
  5. fish1.currentDepth = 2;
  6. Fish fish2 = new Fish();
  7. fish2.currentDepth = 3;
  8. //这里的fish1.currentDepth的值是什么呢? 答案就是3啦 :)
  9. System.out.println("the Fish's currentDepth is : "+fish1.currentDepth);
  10. }
  11. }

好了,下面让我们来看看静态的方法吧。

比如,我们把ReprotCard这个类里的方法convertGrades()声明为static类型的,因为它里面的代码并没有使用到类的成员变量,注意,类的成员变量是不能在静态方法中使用的。看看下面这个例子是如何调用一个static方法的:

  1. char yourGrade = ReportCard.convertGrades(88);

这里有另外一个例子:在Java里有个类叫Math,它包含了几十种数学方法,比如 sqrt(), sin(), abs()等等。所有的这些方法都是static类型的,你不需要给Math这个类构建一个实例来调用它们,比如:

  1. double squareRoot = Math.sqrt(4.0);

8. 特殊的方法:构造方法

Java用new这个操作符在内存里构建对象的实例,比如:

  1. Fish myFish = new Fish();

Fish这个词后面的圆括号告诉我们这个类里有个方法叫做Fish()。是的,这里有一些特殊的方法叫做构造方法( constructors),它们有如下特征:

任何一个类都可以有不止一个构造方法。如果你不给这个类构建一个构造方法,那么Java编译器会为你自动生成一个默认的无参构造方法。所以即使Fish这个类没有任何的构造方法,Java编译器也不会在诸如new Fish() 此类的语句上出问题的。

通常,构造方法用于给一个类里的成员变量赋予初始值,比如,在下面版本的Fish类中包含一个带有单个参数的构造方法,它只赋予实例变量currentDepth这个参数的值,为下一步所用。

  1. public class Fish extends Pet{
  2. int currentDepth;
  3. Fish(int startingPosition){
  4. currentDepth = startingPosition;
  5. }
  6. }

现在FishMaster这个类可以构建Fish的一个实例并给这个它赋予一个初始位置。下面这个例子构建了Fish的一个“潜入”海底20英尺的一个实例:

  1. Fish myFish = new Fish (20) ;

如果在一个类里,一个带有参数的构造方法已经被定义了,你就不能再使用默认无参数构造方法了。如果你想要一个没有参数的构造方法--那就多写一个吧。

  1. public class Fish extends Pet{
  2. int currentDepth;
  3. //没有参数的构造方法
  4. Fish(){
  5. }
  6. //有参数的构造方法
  7. Fish(int startingPosition){
  8. currentDepth = startingPosition;
  9. }
  10. }

9. 关键词this

当你需要表示某个对象的实例时,关键词this就能派上用场。看看下面的这个例子:

  1. class Fish{
  2. int currentDepth;
  3. Fish(int currentDepth){
  4. this.currentDepth = currentDepth;
  5. }
  6. }

一个this关键词就能有效阻止名称重叠导致的冲突,比如,this.currentDepth指的是Fish中的成员变量currentDepth,而currentDepth指的是参数值。

换句话说, this就是对Fish的实例对象自己的引用。
this
在[第六章: 如何在类之间传递数据]这个章节里,你会看到关于使用关键词this的另一个重要例子。

8. 数组

假设你的程序必须储存4个游戏玩家的名字。你可以声明一个含有4个元素( element)的String 数组( array String) ,而不是声明4个不同的String变量。

我们是通过在变量名称或数据类型后面加上方括号来标记数组的:

  1. String[] players;
  2. or
  3. String players[];

这几行其实就是要告诉Java编译器,你将在players这个数组里储存几个字符串。每一个元素都有它自己的索引,都从0开始。下面这个例子就构建了一个数组的一个实例,它可以储存4个String元素且给这个数组的所有元素赋值:

  1. players = new String[4];
  2. players[0] = "David";
  3. players[1] = "Daniel";
  4. players[2] = "Anna";
  5. players[3] = "Gregory";

在给一个数组的元素赋值之前你必须知道这个数组的大小。如果你不能事先确定这个数组将有多少元素,你就不能使用数组,而应观察其他的Java的类,比如Vector,不过现在我们还是先来讨论数组的问题吧。

任何一个数组都有一个叫做length的属性,可用于“记住”这个数组的元素的数量,因此你总能知道这里一共有多少元素:

  1. int totalPlayers = players.length;

如果在你声明这个数组时,就已经知道所有将被储存在这个数组里的值,你可以一次性声明并初始化这样的数组:

  1. String [] players = {"David", "Daniel", "Anna", "Gregory"};

Array

假设第二个游戏玩家是赢家,而你想要对这个孩子送出祝贺词。如果游戏玩家的名字都被储存在一个数组里,我们就要在代码里写它的第二个元素:

  1. String theWinner = players[1];
  2. System.out.println("Congratulations, " + theWinner + "!");

下面是这个代码的输出结果:

Congratulations, Daniel!

你知道为什么第二个元素的索引是[1]吗?你当然知道,因为第一个元素的索引永远都是[0]。

在这个例子里游戏玩家的这个数组是一维的,因为我们把他们储存在一行里。如果我们想把这些值储存在一个矩阵里,我们可以构建一个二维数组。Java允许构建多维数组。你可以在数组里储存任何对象,在第十章里我会告诉你怎么做。

9. 用循环重复动作

循环用于多次重复一个相同的动作,比如,我们需要对多个游戏赢家发出祝贺词。

如果你知道循环重复的次数,那么可以用关键词for来使用循环:

  1. int totalPlayers = players.length;
  2. int counter;
  3. for (counter=0; counter<totalPlayers; counter++){
  4. String thePlayer = players[counter];
  5. System.out.println("Congratulations," + thePlayer+"!");
  6. }

Java虚拟机(JVM)执行在大括号之间的每一行代码,然后返回到循环的第一行,给counter变量增加1并判断条件表达式是否成立。以上代码表达的含义如下:

输出编号和counter的当前值相同的数组元素的值。从编号为0的元素(counter=0)开始,给counter的值增加1(counter++)。一直重复此动作,直到counter等于totalPlayers为止(coutner=totalPlayers)。

在编写循环代码时还可以用另一个关键词--while。在这些循环里你不必知道一个动作被重复的确切次数,但你必须知道什么时候该停止循环。下面我们来看看,我们怎么使用while循环来祝贺游戏赢家,当变量counter的值跟totalPlayers的值相等时,这个循环就会停止:

  1. int totalPlayers = players.length;
  2. int counter=0;
  3. while (counter< totalPlayers){
  4. String thePlayer = players[counter];
  5. System.out.println("Congratulations, "+ thePlayer + "!");
  6. counter++;
  7. }

在第九章你将会学习如何在磁盘上储存数据并把它们读取到内存中。如果你从磁盘文件里读取游戏分数,你就不能事先确认被储存在那儿的分数有多少。那么,你很可能会用while循环来读取分数。

使用循环时,你也可以使用两个重要的关键词:breakcontinue

当某些特定条件成立(true)的时候,关键词break可用于跳出循环。假设不管我们有多少个游戏玩家,我们最多只想送出3次祝贺词。在下面的例子中,在显示了数组元素0、1、2之后,break会让代码跳出此循环,而程序将继续执行大括号后面的代码。

下面的这个代码在if语句中有一个双重等号符(==)。这意味着你在判断变量counter的值是否等于3 。在这里,一个等号(=)意味着给变量counter赋予3的值。在if语句里用=代替==是个会带来棘手的麻烦的错误,它可以导致不可预测的程序错误,且不容易被查找出来。

  1. int counter =0;
  2. while (counter< totalPlayers){
  3. if (counter == 3){
  4. break; // 跳出循环
  5. }
  6. String thePlayer = players[counter];
  7. System.out.println("Congratulations, "+thePlayer+ "!");
  8. counter++;
  9. }

关键词continue能让代码跳过下面的代码并返回到循环的开头。假设你想祝贺除了David以外的每一个游戏玩家--关键词continue会让程序返回到循环的开头:

  1. while (counter< totalPlayers){
  2. counter++;
  3. String thePlayer = players[counter];
  4. if (thePlayer.equals("David"){
  5. continue;
  6. }
  7. System.out.println("Congratulations, "+ thePlayer+ !");
  8. }

while循环还有另一种表示方式,是以do开头的,例如:

  1. do {
  2. // 要循环的代码
  3. } while (counter< totalPlayers);

这种循环会在执行大括号之间的代码之后再进行判断一个表达式是否成立,这意味着在循环里的代码会被执行至少一次。而以关键字while开头的循环,如果一开始表达式不成立,那么循环体里面的代码就一次都不会被执行了。

10. 扩展阅读

  1. jGuru:语言概要.短课程:
    http://java.sun.com/developer/onlineTraining/JavaIntro/contents.html

  2. 变量的作用域:
    http://java.sun.com/docs/books/tutorial/java/nutsandbolts/scope.html

11. 练习

  1. 构建一个叫做TemperatureConverter的新的类,而且它的一个方法有下面这样的签名:
  1. public String convertTemp(int temperature, char convertTo)
如果参数convertTo的值是F,那么温度就必须被转换为华氏温度,同理,如果它的值是C,那么就转换为摄氏温度。当你调用这个方法的时候,可以用加上单引号为char类型的参数传值,如 'C'。 

2. 声明类ReportCard的方法convertGrades()为类型,并从main()方法中删除初始化这个类的代码。

12. 进一步的练习

  1. 不知道你注意到了没有,在有关键词continue的例子里,我们把counter++移到上面去了。
    如果我们把这行代码留在循环的最后,就像在有关键词break的例子里一样,会发生什么事情呢?

創用 CC 授權條款
本著作係採用創用 CC 姓名標示-非商業性-禁止改作 2.5 中國大陸 授權條款授權.

添加新批注
在作者公开此批注前,只有你和作者可见。
回复批注