《Java 核心技术卷一:基础知识》读书笔记(二)

本文介绍了Java的基本程序设计结构,包括类的定义、变量的声明与初始化、数据类型如整型、浮点型、字符型和布尔型,以及运算符的使用。此外,还涵盖了字符串操作、数组、输入输出和控制流程如条件语句和循环。文章强调了Java的强类型特性,并讨论了变量的生命周期和作用域。
摘要由CSDN通过智能技术生成

Java 的基本程序设计结构

一个简单的 Java 应用程序

  • 下面看一个最简单的 Java 应用程序,它只发送一条消息到控制台窗口中:
    /*
     * output We will not use 'Hello, World!'
     */
    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 保留字。
  • 类名是以大写字母开头的名词
    • 如果名字由多个单词组成,每个单词的第一个字母都应该大写(这种在一个单词中间使用大写字母的方式称为骆驼命名法 (camel case) 。
    • 源代码的文件名必须与公共类的名字相同,并用 . java 作为扩展名。
    • Java 中任何方法的代码都用 " { " 开始,用 " }" 结束。
  • 在这里,我们使用 System.out 对象并调用了它的 println 方法。注意,点号(.)用于调用方法。
    • Java 使用的通用语法是 object.method(parameters),这等价于函数调用。
    • Java 中的方法可以没有参数,也可以有一个或多个参数(有的程序员把参数叫做实参)。
    • 即使一个方法没有参数,也需要使用空括号。

注释

  • 在 Java 中,有 3 种标记注释的方式。
    • 最常用的方式是使用 “//”, 其注释内容从 “//” 开始到本行结尾。
    • 当需要更长的注释时,既可以在每行的注释前面标记 “//”, 也可以使用 /* 和 */ 注释界定符将一段比较长的注释括起来。
    • 最后,第 3 种注释可以用来自动地生成文档,这种注释以 /** 开始,以 **/ 结束。

数据类型

  • Java 是一种强类型语言,这就意味着必须为每一个变量声明一种类型。
  • 在 Java 中,共有 8 种基本类型 (primitive type),其中有 4 种整型、2 种浮点类型、1 种字符类型 char 和 1 种用于表示真值的 boolean 类型。

整型

  • 整型用于表示没有小数部分的数值,允许是负数。
  • Java 提供了 4 种整型:byte(1 字节)、short(4 字节)、int(4 字节)、long(8 字节)

浮点类型

  • 浮点类型用于表示有小数部分的数值。
  • 在 Java 中有两种浮点类型:float(4 字节)和 doubble(8字节)
    • double 表示这种类型的数值精度是 float 类型的两倍(双精度数值)。
    • float 类型的数值有一个后缀 F 或 f。
    • 没有后缀 F 的浮点数值总是默认为 double 类型。
    • 当然,也可以在浮点数值后面添加后缀 D 或 d。
  • 下面是用于表示溢出和出错清况的三个特殊的浮点数值:
    • 正无穷大
    • 负无穷大
    • NaN (不是一个数字)
    • 一个正整数除以 0 的结果为正无穷大。
    • 计算 0/0 或者负数的平方根结果为 NaN。

char 类型

  • char 类型原本用于表示单个字符。
    • 如今,有些 Unicode 字符可以用一个 char 值描述,另外一些 Unicode 字符则需要两个 char 值。
    • char 类型的字面量值要用单引号括起来。
    • ’ A ’ 是编码值为 65 的 字符常量。
  • 我们强烈建议不要在程序中使用 char 类型,除非确实需要处理 UTF-16 代码单元。最好将字符串作为抽象数据类型处理。

boolean 类型

  • boolean (布尔)类型有两个值:false 和 true,用来判定逻辑条件。整型值和布尔值之间不能进行相互转换。
  • 在 C++ 中,数值甚至指针可以代替 boolean 值。值 0 相当于布尔值 false, 非 0 值相 当 于布尔值 true。在 Java 中则不是这样。

变量与常量

声明变量

  • 在 Java 中,每个变量都有一个类型 (type)。
    • 在声明变量时,先指定变量的类型,然后是变量名。
  • 变量名必须是一个 以字母开头并由字母或数字构成的序列。
    • 需要注意,与大多数程序设计语言相比,Java 中 ”字母”和“数字”的范围更大。
    • 字母包括 ’ A’ ~ ’ Z’ 、 ’ a’ ~ ‘z’ 、 ’ _ ’ 、 I $’ 或在某种语言中表示字母的任何 Unicode 字符。
  • **变量名中所有的字符都是有意义的,并且大小写敏感。**变量名的长度基本上没有限制。
  • 逐一声明每一个变量可以提高程序的可读性。

变量初始化

  • 声明一个变量之后,必须用赋值语句对变量进行显式初始化,千万不要使用未初始化的变量的值。
    • 也可以将变量的声明和初始化放在同一行中。
    • 在 Java 中,变量的声明尽可能地靠近变量第一次使用的地方,这是一种良好的程序编写风格。
  • 从 Java 10 开始,对于局部变量,如果可以从变量的初始值推断出它的类型,就不再需要声明类型。
  • 只需要使用关键宇 var 而无须指定类型:
    • var vacationDays = 12; // vacationDays is an int
    • var greeting = "Hello"; // greeting is a String

常量

  • 在 Java 中,利用关键字 final 指示常量。
    • 关键字 final 表示这个变量只能被赋值一次。
    • 一旦被赋值之后,就不能够再更改了。
    • 习惯上, 常量名使用全大写。
  • 在 Java 中,经常希望某个常量可以在一个类的多个方法中使用,通常将这些常量称为类常量 ( class constant)。
    • 可以使用关键字 static final 设置一个类常量。
    • 需要注意,类常量的定义位于 main 方法的外部。

枚举类型

  • 有时候,变量的取值只在一个有限的集合内。
    • 针对这种情况,可以自定义枚举类型。
    • 枚举类型包括有限个命名的值。
  • 例如,enum Size { SMALL, MEDIUM, LARGE, EXTRA_LARGE };
    • 现在,可以声明这种类型的变量:Size s = Size.MEDIUM;
    • Size 类型的变量只能存储这个类型声明中给定的某个枚举值,或者特殊值 null, null 表示这个变量没有设置任何值。

运算符

算术运算符

  • 在 Java 中,使用算术运算符 +、-、*、/ 表示加、减、乘、除运算。
    • 当参与除法运算的两个操作数都是整数时,表示整数除法;
    • 否则,表示浮点除法。
  • 整数的求余操作(有时称为取模)用 % 表示。
  • 需要注意,整数被 0 除将会产生一个异常,而浮点数被 0 除将会得到无穷大或 NaN 结果。

数学函数与常量

  • 在 Math 类中,包含了各种各样的数学函数。
    • 要想计算一个数值的平方根,可以使用 sqrt 方法;
    • 在 Java 中,没有幂运算,因此需要借助于 Math 类的 pow 方法。
    • floorMod 方法的目的是解决一个长期存在的有关整数余数的问题。
  • 在 Math 类中,为了达到最佳的性能,所有的方法都使用计算机浮点单元中的例程。如果得到一个完全可预测的结果比运行速度更重要的话,那么就应该使用 StrictMath 类。

数值类型之间的转换

  • 当用一个二元运算符连接两个值时(例如 n + f, n 是整数,f 是浮点数),先要将两个操作数转换为同一种类型,然后再进行计算。
    • 如果两个操作数中有一个是 double 类型,另 一个操作数就会转换为 double 类型。
    • 否则,如果其中一个操作数是 float 类型,另一个操作数将会转换为 float 类型。
    • 否则,如果其中一个操作数是 long 类型,另一个操作数将会转换为 long 类型。
    • 否则,两个操作数都将被转换为 int 类型。

强制类型转换

  • 在必要的时候,int 类型的值将会自动地转换为 double 类型。
  • 但另一方面,有时也需要将 double 转换成 int。
  • 在 Java 中,允许进行这种数值之间的类型转换,当然,有可能会丢失一些信息。
    • 这种可能损失信息的转换要通过强制类型转换 (cast) 来完成。
    • 强制类型转换的语法格式是在圆括号中给出想要转换的目标类型,后面紧跟待转换的变量名。
  • 如果想对浮点数进行舍入运算,以便得到最接近的整数,那就需要使用 Math. round 方法。
  • 如果试图将一个数值从一种类型强制转换为另一种类型,而又超出了目标类型的表示范围,结果就会截断成一个完全不同的值。

自增与自减运算符

  • n++ 将变量 n 的当前值加 1, n- - 则将 n 的值减 1。
  • 实际上,这些运算符有两种形式:
    • 运算符放在操作数后面的”后缀”形式。
    • 还有一种“前缀”形式:++n。
    • 后缀和前缀形式都会使变量值加 1 或减 1。
    • 前缀形式会先完成加 1; 而后缀形式会使用变量原来的值。
  • 建议不要在表达式中使用 ++, 因为这样的代码很容易让人困惑,而且会带来烦人的 bug。

关系和 boolean 运算符

  • 要检测相等性,可以使用两个等号 ==。
  • 另外可以使用 != 检测不相等。
  • 最后,还有经常使用的 <(小于)、 >(大于)、<=(小于等于)和 >=(大于等于)运算符。
  • Java 沿用了 C++ 的做法,使用 && 表示逻辑”与“运算符,使用 || 表示逻辑”或“运算符。
    • 感叹号 !就是逻辑非运算符。
    • && 和 || 运算符是按照“短路”方式来求值的:如果第一个操作数已经能够确定表达式的值,第二个操作数就不必计算了。
  • Java 支持三元操作符 ? :。
    • 如果条件为 true,表达式 condition ? expression1 : expression2 就为第一个表达式的值。
    • 否则计算为第二个表达式的值。

位运算符

  • 处理整型类型时,可以直接对组成整数的各个位完成操作,这意味着可以使用掩码技术得到整数中的各个位。
  • 位运算符包括:& (“and”) \ (“or”) ^ (“xor”) - (“not”),这些运算符按位模式处理。
    • 另外,还有 >> 和 << 运算符可以将位模式左移或右移。
    • “>>>” 运算符会用 0 填充高位,这与 >> 不同,它会用符号位填充高位。不存在 <<< 运算符。
    • 位运算符没有短路操作。
  • 在 C++ 中,不能保证 >> 是完成算术移位(扩展符号位)还是逻辑移位(填充 0)。
    • 这意味着 C++ 中的 >> 运算符对于负数生成的结果可能会依赖于具体的实现。
    • Java 则消除了这种不确定性。

字符串

  • Java 没有内置的字符串类型,而是在标准 Java 类库中提供了 一个预定义类,很自然地叫做 String。
  • 每个用双引号括起来的字符串都是 String 类的一个实例。

子串

  • String 类的 substring 方法可以从一个较大的字符串提取出一个子串:
    String greeting = "Hello";
    String s = greeting.substring(0, 3);
    
    • substring 方法的第二个参数是不想复制的第一个位置。
    • 这里要复制位置为 0、1 和 2 (从 0 到 2, 包括 0 和 2) 的字符。
    • 在 substring 中从 0 开始计数,直到 3 为止,但不包含 3。

拼接

  • 与绝大多数程序设计语言一样,Java 语言允许使用 + 号拼接两个字符串。
    • 当将一个字符串与一个非字符串的值进行拼接时,后者会转换成字符串。
  • 如果需要把多个字符串放在一起,用一个界定符分隔,可以使用静态 join 方法:String all = String.join("/", "S", "M", "L", "XL"); // all is the string "S/M/L/XL
  • 在 Java 11 中, 还提供了一个 repeat 方法:String repeated = "Java".repeat(3); // repeated is "JavaJavaJava"

不可变字符串

  • String 类没有提供修改字符串中某个字符的方法。
    • 由于不能修改 Java 字符串中的单个字符,所以在 Java 文档中将 String 类对象称为是不可变的 (immutable),
    • 不可变字符串却有一个优点:编译器可以让字符串共享。

检测字符串是否相等

  • 可以使用 equals 方法检测两个字符串是否相等。
    • 要想检测两个字符串是否相等,而不区分大小写,可以使用 equalslgnoreCase 方法。
    • 一定不要使用 == 运算符检测两个字符串是否相等!
    • 这个运算符只能够确定两个字符串是否存放在同一个位置上。
    • 当然,如果字符串在同一个位置上,它们必然相等。
    • 但是,完全有可能将内容相同的多个字符串副本放置在不同的位置上。

空串与 Null 串

  • 空串 “” 是长度为 0 的字符串。
    • 空串是一个 Java 对象,有自己的串长度 (0) 和内容(空)。
    • 不过,String 变量还可以存放一个特殊的值,名为 null, 表示目前没有任何对象与该变量关联。

码点与代码单元

  • length() 方法将返回采用 UTF-16 编码表示给定字符串所需要的代码单元数量。
  • 调用 s.charAt(n) 将返回位置 n 的代码单元, n 介于 0 ~ s.length() -1 之间。
  • 虚拟机不 一定把字符串实现为代码单元序列。在 Java 9 中,只包含单字节代码单元的字符串使用 byte 数组实现,所有其他字符串使用 char 数组。

构建字符串

  • 如果需要用许多小段的字符串来构建一个字符串,那么应该按照下列步骤进行。
    • 首先,构建一个空的字符串构建器:StringBuilder builder= new StringBuilder();
    • 当每次需要添加一部分内容时,就调用 append 方法:
      builder.append(ch) ; // appends a single character
      builder.append(str); // appends a string
      
    • 在字符串构建完成时就调用 toString() 方法,将可以得到一个 String 对象,其中包含了构建器中的字符序列:String completedString = builder.toString();

输入与输出

读取输入

  • 要想通过控制台进行输入,首先需要构造一个标准输入流 System.in 关联的 Scanner 对象:Scanner in = new Scanner(System.in);
  • 现在,就可以使用 Scanner 类的各种方法读取输入了。
    • 例如,nextline 方法将读取一行输入。
    • 要想读取一个单词(以空白符作为分隔符),可以调用String firstName = in.next ();
    • 要想读取一个整数,就调用 nextlnt 方法。
    • 要想读取下一个浮点数,就调用 nextDouble 方法。

格式化输出

  • 可以为 printf 提供多个参数:System.out.printf("Hello, %s. Next year, you'll be %d", name, age);
    • 每一个以 % 字符开始的格式说明符都用相应的参数替换。
    • 格式说明符尾部的转换符指示要格式化的数值的类型:f 表示浮点数,s 表示字符串,d 表示十进制整数。
    • 可以使用静态的 String.format() 方法创建一个格式化的字符串,而不打印输出:String message = String.format("Hello, %s. Next year, you'll be %d", name, age);

文件输入与输出

  • 要想读取一个文件, 需要构造一个 Scanner 对象:Scanner in = new Scanner(Path.of("myfile.txt"), StandardCharsets.UTF_8);
  • 如果文件名中包含反斜杠符号 ,就要记住在每个反斜杠之前再加一个额外的反斜杠转义:"c:\\mydirectory\\myfile.txt"
  • 要想写入文件,就需要构造一个 PrintWriter 对象。
    • 在构造器 (constructor) 中 ,需要提供文件名和字符编码:PrintWriter out = new PrintWriter("myfile.txt", StandardCharsets.UTF_8);
    • 如果文件不存在,创建该文件。
    • 可以像输出到 System.out 一样使用 print、println 以及 printf 命令。

控制流程

块作用域

  • 块(即复合语句)是指由若干条 Java 语句组成的语句,并用一对大括号括起来。
  • 块确定了变量的作用域,一个块可以嵌套在另一个块中,但是不能在嵌套的两个块中声明同名的变量。
  • 在 C++ 中,可以在嵌套的块中重定义一个变量。在内层定义的变量会覆盖在外层定义的变量。这就有可能带来编程错误,因此 Java 中不允许这样做。

条件语句

  • 在 Java 中,条件语句的形式为 if (condition) statement,这里的条件必须用小括号括起来。
  • 与绝大多数程序设计语言一样,Java 常常希望在某个条件为真时执行多条语句。在这种情况下,就可以使用块语句 (block statement),形式为:
    if (condition) {
    	statement1;
    	statement2;
    	......
    }
    
  • 在 Java 中,更一般的条件语句如下所示:if (condition) statement1 else statement2else 子句与最邻近的 if 构成一组

循环

  • 当条件为 true 时,while 循环执行一条语句(也可以是一个块语句)。
    • 一般形式如下:while (condition) statement
    • 如果开始时循环条件的值就为 false , 那么 while 循环一次也不执行。
    • while 循环语句在最前面检测循环条件。因此,循环体中的代码有可能一次都不执行。
  • 如果希望循环体至少执行一 次,需要使用 do/while 循环将检测放在最后。
    • 它的语法如下:do statement while (condition);
    • 这种循环语句先执行语句(通常是一个语句块),然后再检测循环条件。
    • 如果为 true, 就重复执行语句,然后再次检测循环条件,以此类推。

确定循环

  • for 循环语句是支持迭代的一种通用结构,由一个计数器或类似的变量控制迭代次数,每次迭代后这个变量将会更新。
    for (int i = 1; i <= 10; i++)
    	System.out.println(i) ;
    
    • for 语句的第 1 部分通常是对计数器初始化;
    • 第 2 部分给出每次新一轮循环执行前要检测的循环条件;
    • 第 3 部分指定如何更新计数器。
  • 如果在 for 语句 内部定义一个变量,这个变量就不能在循环体之外使用。

多重选择:switch 语句

  • 在处理多个选项时,使用 if/else 结构显得有些笨拙。
  • Java 有一个与 C/C++ 完全一样的 switch 语句。
    • switch 语句将 从 与选项值相匹配的 case 标签开始执行,直到遇到 break 语句,或者执行到 switch 语句的结束处为止。
    • 如果没有相匹配的 case 标签,而有 default 子句,就执行这个子句。
  • case 标签可以是:
    • 类型为 char、 byte、 short 或 int 的常量表达式。
    • 枚举常量。
    • case 标签还可以是字符串字面量。

中断控制流程的语旬

  • 不带标签的 break 语句与用于退出 switch 语句的 break 语句一样,它也可以用于退出循环语句。
    • 与 C++ 不同,Java 还提供了 一种带标答的 break 语句,用千跳出多重嵌套的循环语句。
    • 有时候,在嵌套很深的循环语句中会发生一些不可预料的事情。
    • 此时可能更加希望完全跳出所有嵌套循环之外。
  • 还有一个 continue 语句。
    • 与 break 语句一样,它将中断正常的控制流程。continue 语句将控制转移到最内层循环的首部。
    • 如果将 continue 语句用千 for 循环中,就可以跳到如循环的”更新”部分。

大数

  • 如果基本的整数和浮点数精度不能够满足需求,那么可以使用 java.math 包中两个很有用的类:Biglnteger 和 BigDecimal。
    • 这两个类可以处理包含任意长度数字序列的数值。
    • Biglnteger类实现任意精度的整数运算,BigDecimal 实现任意精度的浮点数运算。
    • 使用静态的 valueOf 方法可以将普通的数值转换为大数:Biglnteger a= Biglnteger.value0f(l00);
    • 对于更大的数,可以使用一个带字符串参数的构造器:BigInteger reallyBig = new BigInteger("222232244629420445529739893461909967206666939096499764990979600");
    • 遗憾的是,不能使用人们熟悉的算术运算符(如 + 和 * )处理大数,而需要使用大数类中的 add 和 multiply 方法。

数组

声明数组

  • 数组是一种数据结构,用来存储同一类型值的集合。
    • 通过一个整型下标 (index, 或称索引)可以访问数组中的每一个值。
    • 在声明数组变量时,需要指出数组类型(数据元素类型紧跟 [ ])和数组变量的名字:int[ ] a;
    • 这条语句只声明了变量 a , 并没有将 a 初始化为一个真正的数组,应该使用 new 操作符创建数组:int[] a= new int[100]; // or var a= new int[100];
    • 这条语句声明并初始化了一个可以存储 100 个整数的数组。
  • 数组长度不要求是常量:new int[n] 会创建一个长度为 n 的数组。
    • 一旦创建了数组,就不能再改变它的长度。
    • 如果程序运行中需要经常扩展数组的大小,就应该使用另一种数据结构一一数组列表(Arraylist)。
  • 在 Java 中,提供了一种创建数组对象并同时提供初始值的简写形式:
    int[] smallPrimes = { 2, 3, 5, 7, 11, 13 };
    
    • 请注意,这个语法中不需要使用 new,甚至不用指定长度。
    • 最后一个值后面允许有逗号,如果你要不断为数组增加值,这会很方便:
      String[] authors= {
      	"James Gosling",
      	"Bill Joy",
      	"Guy Steele",
      	// add more names here and put a comma after each name
      };
      
  • 还可以声明一个匿名数组:new int[] { 17, 19, 23, 29, 31, 37 }
    • 这会分配一个新数组并填入大括号中提供的值。
    • 它会统计初始值个数,并相应地设置数组大小。
    • 可以使用这种语法重新初始化一个数组而无须创建新变量。

访问数组元素

  • 创建一个数字数组时,所有元素都初始化为 0。
    • boolean 数组的元素会初始化为 false。
    • 对象数组的元素则初始化为一个特殊值 null , 表示这些元素还未存放任何对象。
  • 要想获得数组中的元素个数,可以使用 array.length。

for each 循环

  • Java 有一种功能很强的循环结构,可以用来依次处理数组(或者其他元素集合)中的每个元素,而不必考虑指定下标值。
    • 这种增强的 for 循环的语句格式为:for (variable : collection) statement
    • 它定义一个变量用于暂存集合中的每一个元素,并执行相应的语句(当然,也可以是语句块)。
    • collection 这一集合表达式必须是一个数组或者是一个实现了 Iterable 接口的类对象(Arraylist)。

数组拷贝

  • 在 Java 中,允许将一个数组变量拷贝到另一个数组变量。这时,两个变量将引用同一个数组。
  • 如果希望将一个数组的所有值拷贝到一个新的数组中去, 就要使用 Arrays 类的 copyOf 方法:int[] copiedluckyNumbers = Arrays.copyOf(luckyNumbers, luckyNumbers.length);
  • 第 2 个参数是新数组的长度。
    • 这个方法通常用来增加数组的大小:luckyNumbers = Arrays .,:opyOf (luckyNumbers, 2 * luckyNumbers .length);
    • 如果数组元素是数值型,那么额外的元素将被赋值为 0;
    • 如果数组元素是布尔型,则将赋值为 false。
    • 相反,如果长度小于原始数组的长度,则只拷贝前面的值。

数组排序

  • 要想对数值型数组进行排序, 可以使用 Arrays 类中的 sort 方法,这个方法使用了优化的快速排序 (QuickSort) 算法。

多维数组

  • 多维数组将使用多个下标访问数组元素,它适用千表示表格或更加复杂的排列形式。
  • 在 Java 中, 声明一个二维数组相当简单。
    • 例如:double[][] balances;
    • 对数组进行初始化之前是不能使用的,在这里可以如下初始化:
      balances = new double[NYEARS][NRATES];
      
  • 一旦数组初始化,就可以利用两个中括号访问各个元素,例如 balances[i][j]。
  • for each 循环语句不能自动处理二维数组的每一个元素。
    • 它会循环处理行,而这些行本身就是一维数组。
    • 要想访问 二 维数组 a 的所有元素,需要使用两个嵌套的循环。

不规则数组

  • Java 实际上没有多维数组,只有一维数组。
    • 多维数组被解释为 “数组的数组”。
    • 还可以方便地构造一个“不规则“数组,即数组的每一行有不同的长度。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值