Java核心技术 笔记——第3章

第3章 Java的基本程序设计结构

概述

  • 简单Java程序
  • 注释
  • 数据类型
  • 变量和常量
  • 运算符
  • 字符串
  • 输入与输出
  • 控制流程
  • 大数
  • 数组

一、 一个简单的Java程序

public class HelloWorld {
    public static void main(String[] args) {
        /* println方法输出后换行,print方法输出后不换行 */
        System.out.println("Hello World!");
    }
}

知识点:

第一行,public称为访问修饰符(access modifier),用于控制程序的访问级别。class称为
,类是所有Java应用构建模块。

源代码的文件名必须与公共类的类名相同

Java虚拟机总是从指定类中的main方法开始执行,且main方法必须声明为public

Java程序中main方法的声明格式:

public class ClassName {
    public static void main(String[] args) {
        //program statements
    }
}

二、注释

注释分为三种:

  1. 单行注释:// ...
  2. 多行注释:/*... */
  3. 文档注释 /** ... */
// this is a single-line comment

/* this is a multi-line comment */

/**
 * @date 2023/5/10 上午12:56
 * @description
 *  this is a document comment
 * @param
 */

注意

注释是不能够嵌套使用的

三、数据类型

Java是强类型语言。

补充

强类型语言即强制类型定义的语言,一旦某变量类型已经定义,那么如果不经强制转换,那么它永远都是该数据类型。例如:C++、Java

与之相反的弱类型语言则是某一个变量被定义类型,该变量可以根据环境变化自动进行转换,不需要经过强制转换。例如:JavaScript、PHP

Java中共有8基本类型(primitive type),4中整型、2种浮点型、1中字符型char和一种用于表示真值的boolean类型。

相较于C++“见机行事”的基本数据类型大小,Java明确规定具体的大小:

类型名称 存储需求 取值范围
int 4字节 -2 147 483 648到2 147 483 647(略高于20亿)
short 2字节 -32 768到32 767
long 8字节 -9 223 372 036 854 775 808到9 223 372 036 854 775 807
byte 1字节 -128到127

一般常用到int类型,其基本能够满足需求,byte和short类型主要运用在特定的应用环境下,比如:底层的文件处理或存储空间较小的数组中。

前文提到,Java中基本类型是固定的,所以很好解决了整型等基本数据类型溢出的问题,因为其数据类型范围与执行Java代码的机器无关。

补充

  • 长整型拥有后缀L或l,例如:4000000000000L
  • 十六进制数拥有前缀0x或0X,例如:0x1P-7
  • 八进制数拥有前缀-1,例如:033(但是由于此表示方法易混淆,所以很少使用八进制数)
  • 二进制数拥有前缀0b或0B,例如:0b10110101,还可以写成0b1011_0101(下画线仅帮助阅读,javac会去除这些下画线)

注意

Java并不存在无符号(unsigned)形式的数据类型

浮点型用于表示含有小数部分数值,Java中的浮点型有:

类型名称 存储需求 取值范围
float 4字节 -3.40E+38到3.40E+38(6~8位有效数字)
double 8字节 -1.797 693E+308到1.797 693E308 (15位有效数字)

在大多数情况下,float类型并不能够满足日常需求,所以在大多数情况下都是使用double类型。

补充

float类型具有后缀f或F,若没有此后缀默认为double类型

double类型具有后缀d或D,当然没有后缀也是可以的

特殊的字符和转义序列

转义序列 名称
\b 退格
\t 制表
\n 换行
\r 回车
\f 换页
" 双引号
' 单引号
\ 反斜杠
\s 空格
\newline 只在文本块中使用:连接上一行和下一行

建议

由于在Java中,char类型描述为UTF-16编码的一个代码单元

所以强烈建议不要在程序中使用char类型,除非确实需要处理UTF-16代码单元,最好的方式是将字符串作为抽象数据类型来处理

注意

在C++中可以使用数值或指针来代替布尔值,例如:值0表示false,但是在Java中则不会。

四、变量和常量

Java声明变量和变量的规则与C++类似。需要注意的是:Java对“字母”、“数字”等其他符号的范围更大,例如:在Java中可以使用中文作为变量名,但是在C++下不行。但是,强烈建议
不要使用中文作为变量名

补充

想要知道哪些Unicode字符可以作为标识符,可以使用Character.isJavaIdentifierStart
Character.isJavaIdentifierPart方法检查

区别

从Java 10开始,对于局部变量可以通过关键字var声明作为变量的“类型”,编译器会通过其变量的初始值推断出它的类型,而无需声明类型。

例如:

var test_variable=12;  /* this variable type is int */

同时Java并不会像C++一样区分声明和定义,在C++中:

int i ;   /* 这是一个定义 */
extern int j ; /* 这是一个声明 */

在Java中使用final关键词来只是常量。若某个常量需要在一个类中多个方法中使用,则需要创建类常量
,关键词为:static final

五、运算符

常见的+、-、*、/就不必说,注意点:①、当除数与被除数都为整数时,进行整数除法,其余都进行浮点除法;②、当除数为零时,将会得到无穷大或NaN的结果。

@startuml

left to right direction
[byte] --> [short]
[short] --> [int]
[int]->[long]
[char]->[int]
[int] -> [float] #line.dashed;
[int]->[double]
[float]->[double]
[long]->[float] #line.dashed;
[long]->[double] #line.dashed;

@enduml

总体上,从小到大数据是不会丢失的,特殊为:int -> float、long->float、long->
double。其次,若使用二元运算符连接两个数,总体上遵守转换为精度更高的数。

强制类型转换通过截断方式进行,例如:

        double number=9.997;
        int number_1=(int)number;   /* number_1 is 9 */
        int number_2=Math.round(number); /* number_2 is 10 */

若想通过舍入的方式获取更为精确的值,可以使用Math.round方法,其返回类型为long。

注意

不要将boolean类型进行强制类型转换,如有要求请使用:b?1:0

赋值其实是一个表达式(expression),所以以下赋值正确的:

        int x=1;
        int y=x+=3; /* y is 4 */

当然,这样的方式颇具恶趣味,O(∩_∩)O哈哈~

为了帮助理解赋值是表达式这个观念,上述的方式赋值无疑是冗余的,勿模仿。🐱

六、字符串

从概念上讲:Java字符串就是Unicode字符序列,例如:“Java\u2122”由“J”、“a”、“v”、“a”和“™”组成。

子串

    String string="Hello!";
        String substring=string.substring(0,3); /* the result is Hel */

substring(x,y)方法用于生成子串,其x表示开始复制的第一个索引,y表示第一个不想复制的索引。

注意

Java字符串大致类似与char*指针,而非char数组

比较两字符串可以使用equals方法,若不区分大小写,则可以使用equalsIgnoreCase方法

        String string_1="this is good!";
        String string_2="this is Good!";
        boolean result_1=string_1.equals(string_2);   /* false */
        boolean result_2=string_1.equalsIgnoreCase(string_2); /* true */

区别

在C++中比较两个字符串使用strcmp函数,当然Java也有类似的方法:compareTo,但是equals方法显得更为清晰

在Java中字符串的空串Null串是两个概念,空串是一个Java对象,有自己的串长度(0)和内容(空)但是Null串则表示没有任何对象与该变量关联。

Java在Java 15新增了文本块(text block)特性:

String text_block="""
This is a block of text.
and It wraps automatically.\
cool!
"""

实现效果:

This is a block of text.
and It wraps automatically.cool!

该特性特别适合用于包含其他语言编写的代码(例如:HTML、SQL)。

注意

在文本块中一般不需要对引号转义(除非:①、文本块以一个引号结尾;②、文本块中包含三个及以上的引号)

注意:所有的反斜杠都需要转义(😕),若在文本块行尾添加“\”,则表示将上下两行连接起来。

七、输入与输出

首先介绍更简单的输出:“标准输出流”System.out.println,这很简单:

    /*  会自动换行 */
	System.out.println("Hello World!");

            /* 不会换行 */
            System.out.print("Hello World!");

😄,是不是很简单?

相较于输出,输入就复杂一些。

想要实现读取控制台的输入,必须先构造一个与“标准输入流”System.in关联的Scanner对象。

Scanner in=new Scanner(System.in);

第3章 Java的基本程序设计结构

概述

  • 简单Java程序
  • 注释
  • 数据类型
  • 变量和常量
  • 运算符
  • 字符串
  • 输入与输出
  • 控制流程
  • 大数
  • 数组

一、 一个简单的Java程序

public class HelloWorld {
    public static void main(String[] args) {
        /* println方法输出后换行,print方法输出后不换行 */
        System.out.println("Hello World!");
    }
}

知识点:

第一行,public称为访问修饰符(access modifier),用于控制程序的访问级别。class称为
,类是所有Java应用构建模块。

源代码的文件名必须与公共类的类名相同

Java虚拟机总是从指定类中的main方法开始执行,且main方法必须声明为public

Java程序中main方法的声明格式:

public class ClassName {
    public static void main(String[] args) {
        //program statements
    }
}

二、注释

注释分为三种:

  1. 单行注释:// ...
  2. 多行注释:/*... */
  3. 文档注释 /** ... */
// this is a single-line comment

/* this is a multi-line comment */

/**
 * @date 2023/5/10 上午12:56
 * @description
 *  this is a document comment
 * @param
 */

注意

注释是不能够嵌套使用的

三、数据类型

Java是强类型语言。

补充

强类型语言即强制类型定义的语言,一旦某变量类型已经定义,那么如果不经强制转换,那么它永远都是该数据类型。例如:C++、Java

与之相反的弱类型语言则是某一个变量被定义类型,该变量可以根据环境变化自动进行转换,不需要经过强制转换。例如:JavaScript、PHP

Java中共有8基本类型(primitive type),4中整型、2种浮点型、1中字符型char和一种用于表示真值的boolean类型。

相较于C++“见机行事”的基本数据类型大小,Java明确规定具体的大小:

类型名称 存储需求 取值范围
int 4字节 -2 147 483 648到2 147 483 647(略高于20亿)
short 2字节 -32 768到32 767
long 8字节 -9 223 372 036 854 775 808到9 223 372 036 854 775 807
byte 1字节 -128到127

一般常用到int类型,其基本能够满足需求,byte和short类型主要运用在特定的应用环境下,比如:底层的文件处理或存储空间较小的数组中。

前文提到,Java中基本类型是固定的,所以很好解决了整型等基本数据类型溢出的问题,因为其数据类型范围与执行Java代码的机器无关。

补充

  • 长整型拥有后缀L或l,例如:4000000000000L
  • 十六进制数拥有前缀0x或0X,例如:0x1P-7
  • 八进制数拥有前缀-1,例如:033(但是由于此表示方法易混淆,所以很少使用八进制数)
  • 二进制数拥有前缀0b或0B,例如:0b10110101,还可以写成0b1011_0101(下画线仅帮助阅读,javac会去除这些下画线)

注意

Java并不存在无符号(unsigned)形式的数据类型

浮点型用于表示含有小数部分数值,Java中的浮点型有:

类型名称 存储需求 取值范围
float 4字节 -3.40E+38到3.40E+38(6~8位有效数字)
double 8字节 -1.797 693E+308到1.797 693E308 (15位有效数字)

在大多数情况下,float类型并不能够满足日常需求,所以在大多数情况下都是使用double类型。

补充

float类型具有后缀f或F,若没有此后缀默认为double类型

double类型具有后缀d或D,当然没有后缀也是可以的

特殊的字符和转义序列

转义序列 名称
\b 退格
\t 制表
\n 换行
\r 回车
\f 换页
" 双引号
' 单引号
\ 反斜杠
\s 空格
\newline 只在文本块中使用:连接上一行和下一行

建议

由于在Java中,char类型描述为UTF-16编码的一个代码单元

所以强烈建议不要在程序中使用char类型,除非确实需要处理UTF-16代码单元,最好的方式是将字符串作为抽象数据类型来处理

注意

在C++中可以使用数值或指针来代替布尔值,例如:值0表示false,但是在Java中则不会。

四、变量和常量

Java声明变量和变量的规则与C++类似。需要注意的是:Java对“字母”、“数字”等其他符号的范围更大,例如:在Java中可以使用中文作为变量名,但是在C++下不行。但是,强烈建议
不要使用中文作为变量名

补充

想要知道哪些Unicode字符可以作为标识符,可以使用Character.isJavaIdentifierStart
Character.isJavaIdentifierPart方法检查

区别

从Java 10开始,对于局部变量可以通过关键字var声明作为变量的“类型”,编译器会通过其变量的初始值推断出它的类型,而无需声明类型。

例如:

var test_variable=12;  /* this variable type is int */

同时Java并不会像C++一样区分声明和定义,在C++中:

int i ;   /* 这是一个定义 */
extern int j ; /* 这是一个声明 */

在Java中使用final关键词来只是常量。若某个常量需要在一个类中多个方法中使用,则需要创建类常量
,关键词为:static final

五、运算符

常见的+、-、*、/就不必说,注意点:①、当除数与被除数都为整数时,进行整数除法,其余都进行浮点除法;②、当除数为零时,将会得到无穷大或NaN的结果。

@startuml

left to right direction
[byte] --> [short]
[short] --> [int]
[int]->[long]
[char]->[int]
[int] -> [float] #line.dashed;
[int]->[double]
[float]->[double]
[long]->[float] #line.dashed;
[long]->[double] #line.dashed;

@enduml

总体上,从小到大数据是不会丢失的,特殊为:int -> float、long->float、long->
double。其次,若使用二元运算符连接两个数,总体上遵守转换为精度更高的数。

强制类型转换通过截断方式进行,例如:

        double number=9.997;
        int number_1=(int)number;   /* number_1 is 9 */
        int number_2=Math.round(number); /* number_2 is 10 */

若想通过舍入的方式获取更为精确的值,可以使用Math.round方法,其返回类型为long。

注意

不要将boolean类型进行强制类型转换,如有要求请使用:b?1:0

赋值其实是一个表达式(expression),所以以下赋值正确的:

        int x=1;
        int y=x+=3; /* y is 4 */

当然,这样的方式颇具恶趣味,O(∩_∩)O哈哈~

为了帮助理解赋值是表达式这个观念,上述的方式赋值无疑是冗余的,勿模仿。🐱

六、字符串

从概念上讲:Java字符串就是Unicode字符序列,例如:“Java\u2122”由“J”、“a”、“v”、“a”和“™”组成。

子串

        String string="Hello!";
        String substring=string.substring(0,3); /* the result is Hel */

substring(x,y)方法用于生成子串,其x表示开始复制的第一个索引,y表示第一个不想复制的索引。

注意

Java字符串大致类似与char*指针,而非char数组

比较两字符串可以使用equals方法,若不区分大小写,则可以使用equalsIgnoreCase方法

        String string_1="this is good!";
        String string_2="this is Good!";
        boolean result_1=string_1.equals(string_2);   /* false */
        boolean result_2=string_1.equalsIgnoreCase(string_2); /* true */

区别

在C++中比较两个字符串使用strcmp函数,当然Java也有类似的方法:compareTo,但是equals方法显得更为清晰

在Java中字符串的空串Null串是两个概念,空串是一个Java对象,有自己的串长度(0)和内容(空)但是Null串则表示没有任何对象与该变量关联。

Java在Java 15新增了文本块(text block)特性:

String text_block="""
This is a block of text.
and It wraps automatically.\
cool!
"""

实现效果:

This is a block of text.
and It wraps automatically.cool!

该特性特别适合用于包含其他语言编写的代码(例如:HTML、SQL)。

注意

在文本块中一般不需要对引号转义(除非:①、文本块以一个引号结尾;②、文本块中包含三个及以上的引号)

注意:所有的反斜杠都需要转义(😕),若在文本块行尾添加“\”,则表示将上下两行连接起来。

七、输入与输出

首先介绍更简单的输出:“标准输出流”System.out.println,这很简单:

        System.out.println("Hello World!");/* 会自动换行 */
        System.out.print("Hello World!");/* 不会换行 */

😄,是不是很简单?

相较于输出,输入就复杂一些。

想要实现读取控制台的输入,必须先构造一个与“标准输入流”System.in关联的Scanner对象。

Scanner in=new Scanner(System.in);

这样我们就可以开始读取控制台的输入了:

        System.out.print("Enter a line of text:");
        String text=in.nextLine();    /* 读取一行输入 */
        String word=in.next();    /* 读取一个单词(以空白符作为分隔 )*/

除了读取文本外,还可以使用nextIntnextDouble读取整数和浮点数。

补充

由于Scanner类是直接明文输入,并不适合用于输入密码等需要隐藏的信息。可以使用Console类解决:

Console console=System.console();
String user_name=console.readLine("Username: ");
char[] password=console.readPassword("Password: ");

注意:由于Console类会调用控制台输入,所以无法在IDE中使用它(如IDEA、Eclipse),需要自行在控制台编译运行

文件的输入与输出

若想要读取一个文件,首先需要构建一个Scanner对象:

		Scanner in=new Scanner(Path.of("data.txt"),StandardCharsets.UTF_8);

注意

在上述示例中,我们指明了使用的字符编码集为UTF-8,若不添加该参数,那么Java程序会使用默认的编码(那么这可能导致程序出现不同的效果,我们应当避免)。

同时我们不能这样写:Scanner("data.txt"),这样会将字符串解释为数据,而不是文件名。

若想要写入文件,则需要构建PrintWriter对象,类似于上述的Scanner对象写法:

		PrintWriter out=new PrintWriter(Path.of("data.txt"),StandardCharsets.UTF_8);	

补充

有些时候我们并不能准确的找到需要输入/输出文件的相对路径,可以通过方法System.getProperty("user.dir")获取启动目录,从而借此找到所需文件的相对路径。

除此之外,我们使用输入/输出文件需要考虑文件是否存在情况,Java编译器认为异常比“被零除”更为严重。所以,需要采用throwstry-catch-finally语法来捕捉异常,并根据情况选择处理。

当然也有可以避免此类异常的方法:通过利用shell的重定向语法将任意文件关联到输入/输出中。

java test < input.txt > output.txt

< input.txt 代表重定向输入,即从input.txt文件中读入数据作为程序的输入;

> output.txt 代表重定向输出,即将程序的输出存入output.txt文件;

八、控制流程

条件语句:

  • ①、if(condition) statement;
  • ②、if(condition) statement1; else statement2;

循环语句:

  • ①、while(condition) statement;
  • ②、do statement while(condition);

确定性循环语句:

  • ①、for(init;cond;inc) statement; init通常是对计数器的初始化;cond给出每次新一轮循环执行前要检测的循环条件;inc指定如何更新计数器。

注意

在进行两个浮点数是否相等需要格外小心(由于存在舍入误差),例如:for(double x=0;x!=10;x+=0.1)就永远不可能达到最终值(因为0.1无法精确用二进制表示)。

总的来说,for循环仅是while循环的一种简单形式。

多重选择语句:

  • ①、switch(expr) { case value1: statement1; case value2: statement2;...; default: statementn }

补充

若使用switch语句时对每个分支不添加break语句,那么接下来的分支依旧会被执行。并且IDE会给出警告,若需要这种效果,则可以添加注解@SuppressWarnings("fallthrough")

Java 14新特性:case value ->yield value

使用switch标准方式编写代码太多的break造成代码冗余可读性不高,所以采用->代替。同样,为了可读性采用yield方式终止执行并返回表达式值。具体实现

中断控制流程语句:

Java并未存在goto,通常程序员使用goto语句会被认为是一种拙劣的程序设计风格。但是万物皆有其存在理由。Structured Programming with goto statements

Java也存在这种设计风格:

read_data:
while(...){
	for(...){
       break read_data;/* 执行带标签的break会跳转到带标签的语句块的末尾 */
    }    
}

具体实现参照代码示例

除此之外,还可以使用continue

while(condition){
    statements;
    continue;	/* 越过此次循环后面部分,直接回到循环首部 */
}

当然,continue也可以带上匹配标签,将跳转到匹配标签的循环的首部。

但是无论如何,这些语句也仅是可选项,也有其他实现方式。笔者曾经在回答“是否在C++中使用goto语句”问题上一位读者告诉我不一样的答案:goto语句会导致CPU进程的混乱。

最后,存在即有道理。合理使用即可~

posted @ 2023-05-10 20:42  木木亚伦  阅读(11)  评论(0编辑  收藏  举报