大家好,我是栗筝i,这篇文章是我的 “栗筝i 的 Java 技术栈” 专栏的第 003 篇文章,在 “栗筝i 的 Java 技术栈” 这个专栏中我会持续为大家更新 Java 技术相关全套技术栈内容。专栏的主要目标是已经有一定 Java 开发经验,并希望进一步完善自己对整个 Java 技术体系来充实自己的技术栈的同学。与此同时,本专栏的所有文章,也都会准备充足的代码示例和完善的知识点梳理,因此也十分适合零基础的小白和要准备工作面试的同学学习。当然,我也会在必要的时候进行相关技术深度的技术解读,相信即使是拥有多年 Java 开发经验的从业者和大佬们也会有所收获并找到乐趣。
–
上一篇文章中,我们详细介绍了 Java 环境的安装、配置、编译与运行,帮助大家成功搭建了 Java 开发的基础环境。在这篇文章中,我们将深入探讨 Java 程序的基本结构,了解 Java 语言中的变量、方法、运算符与注释。这些知识是学习和掌握 Java 编程的基石,对于编写高效、可维护的代码至关重要。
最后在前言的末尾我补充一下,如果这篇文章,对大家有所帮助或收获一定的乐趣和想法,那么非常欢迎大家能够,点赞、评论、收藏、订阅。这些也将是我持续更新的最大动力。
文章目录
- 1、Java 程序基本结构
- 1.1、一个简单的 Java 应用程序
- 1.2、解读简单的 Java 应用程序
- 1.2.1、代码解读-1
- 1.2.2、代码解读-2
- 1.2.3、代码解读-3
- 2、Java 变量&常量
- 2.1、声明变量
- 2.2、变量初始化
- 2.3、声明常量
- 2.4、枚举变量
- 3、Java 中的方法
- 3.1、方法构成
- 3.2、方法传参
- 3.3、方法重载
- 4、Java 运算符
- 4.1、算数运算符
- 4.2、数学函数 Math 类
- 4.3、关系运算符
- 4.4、逻辑运算符
- 4.5、位运算符
- 5、Java 注释
- 5.1、单行注释
- 5.2、多行注释
- 5.3、文档注释
1、Java 程序基本结构
1.1、一个简单的 Java 应用程序
下面看一个最简单的 Java 应用程序,它只发送一条 “Hello World!!!” 消息到控制台窗口中:
public class FirstSample
{
public static void main(String[] args) {
System.out.println("Hello World!!!");
}
}
这个程序虽然很简单,但因为所有的 Java 应用程序都具有这种结构,所以值得花一些时间对它进行研究。首先,Java 对大小写敏感。如果出现了大小写拼写错误(例如,将 main
拼写成了 Main
),程序就无法运行。
1.2、解读简单的 Java 应用程序
1.2.1、代码解读-1
下面逐行地查看一下这段源代码,我们先看第一行:
public class FirstSample {
这段代码定义了一个名为 FirstSample
的公共类:
-
public
是一个访问修饰符,表示这个类可以被任何其他类访问。这是控制程序的其他部分对这段代码的访问级别的一种方式; -
class
关键字用于声明一个类。在 Java 程序中,所有的内容都需要包含在类中,类是加载程序逻辑的容器,定义了应用程序的逻辑和行为; -
FirstSample
是这个类的名称。在 Java 中定义类名的规则很宽松。类名应以字母开头,后面可以跟字母和数字的任意组合。长度基本上没有限制。但是不能使用 Java 保留字。
Ps: 标准的命名规范为(类名
FirstSample
就遵循了这个规范): 类名是以大写字母开头的名词。如果名字由多个单词组成,每个单词的第一个字母都应该大写(这种在一个单词中间使用大写字母的方式称为骆驼命名法。以其自身为例,应该写成CamelCase
)。
Ps: 源代码的文件名必须与公共类的名字相同,并用
.java
作为扩展名。因此,存储这段源代码的文件名必须为FirstSample.java
(再次提醒大家注意,大小写是非常重要的,千万不能写成firstsample.java
)。如果已经正确地命名了这个文件,并且源代码中没有任何录入错误,在编译这段源代码之后就会得到一个包含这个类字节码的文件。Java 编译器将字节码文件自动地命名为
FirstSample. class
,并与源文件存储在同一个目录下。最后,使用下面这行命令运行这个程序:Java FirstSample
。
1.2.2、代码解读-2
运行已编译的程序时,Java 虚拟机将从指定类中的 main
方法开始执行(这里的 “方法” 就是 Java 中所说的 “函数”),因此为了代码能够执行,在类的源文件中必须包含一个 main
方法。当然,也可以将用户自定义的方法添加到类中,并且在 main
方法中调用它们:
{
public static void main(String[] args) {
System.out.println("Hello World!!!");
}
}
-
Java 代码中的
{}
是用来划分程序的各个部分的,通常称为块。在 Java 中,任何方法的代码都用{
开始,用}
结束; -
关于
static void
,我们暂时可以将它们视为编译 Java 应用程序所必需的一部分。具体的含义和用法,可以在学习了更多 Java 基础知识后再进行理解。
Ps: 如果
main
方法正常退出,那么 Java 应用程序的退出代码为 “0”,表示成功地运行了程序。如果希望在终止程序时返回其他的代码,那就需要调用System.exit
方法。
1.2.3、代码解读-3
接下来,让我们研究一下这段代码:
System.out.println("Hello World!!!");
在上面这个 main
方法体中只包含了一条语句,其功能是: 将一个文本行输出到控制台上
-
{}
表示方法体的开始与结束,在这个方法中只包含一条语句。Java 语句可以看作是这种语言的句子,每个句子必须用分号结束。需要注意的是,回车并不是语句的结束标志,因此,一条语句可以写在多行上; -
这个方法体中的唯一一条语句的功能是将一个文本行输出到控制台上。这里使用了
System.out
对象并调用了它的println()
方法。在 Java 中,点号用来调用一个方法,通用的语法是object.method(parameters)
; -
这个例子中调用了
println()
方法并传递给它一个字符串参数。这个方法将传递给它的字符串参数显示在控制台上,然后终止这个输出行,以便每次调用println()
都会在新的一行上显示输出; -
与其他程序设计语言一样,在 Java 的方法中,可以没有参数,也可以有零个、一个或多个参数。对于一个方法,即使没有参数也需要书写圆括号。
2、Java 变量&常量
Java 变量的本质上就是代表一个可操作的 “存储空间” 的标识符,这个 “存储空间” 的位置是确定的,但是里面放置什么值是不确定。我们可以通过变量名来访问对应的 “存储空间”,从而操作这个 “存储空间” 存储的值。
而 Java 常量则是一种特殊的变量,其值在定义后就不能再改变。
2.1、声明变量
在 Java 中,每个变量都有一个类型(type)。在声明变量时,变量的类型位于变量名之前。例如:
int num;
这行代码声明了一个名为 num
的整型变量。
关于变量名的命名规则。变量名不能以数字开头,可以包含字母、数字、下划线 _
和美元符号 $
。虽然 Java 支持 Unicode,因此理论上可以使用包括汉字在内的任何字符来命名变量,但是为了代码的可读性和可维护性,通常不建议使用汉字或其他非 ASCII 字符来命名变量。
Ps: 在 Java 中,变量的声明尽可能地靠近变量第一次使用的地方,这是一种良好的程序编写风格。
2.2、变量初始化
在 Java 中,变量的初始化是非常重要的,它可以确保变量在使用前已经被赋予了一个明确的值。
初始化变量有两种方式:
- 声明时直接赋值。例如:
int num = 10;
这行代码声明了一个名为 num
的整型变量,并立即将其初始化为 10。
- 先声明,后赋值。例如:
int num;
num = 10;
这两行代码先声明了一个名为 num
的整型变量,然后在下一行将其初始化为 10。
使用未初始化的变量是非常危险的,因为它的值是不确定的,可能会导致程序行为不可预测。因此,我们应该尽量避免使用未初始化的变量。
2.3、声明常量
在 Java 中,final
关键字用于声明常量,这意味着一旦给常量赋值后,其值就不能再被改变。例如:
final int NUM = 10;
这行代码声明了一个名为 NUM
的常量,并将其初始化为 10。之后就不能再改变 NUM
的值了。
习惯上,常量名是使用全大写字母。
另外,如果你希望一个常量可以在一个类中的多个方法中使用,那么可以使用 static final
关键字来声明一个类常量。例如:
public class MyClass {
static final double PI = 3.14;
// ...
}
这行代码声明了一个名为 PI
的类常量,其值为 3.14。这个常量可以在 MyClass
类的所有方法中使用。
2.4、枚举变量
有时候,变量的取值只在一个有限的集合内。例如,销售的服装或披萨只有小、中、大和超大这四种尺寸。当然,可以将这些尺寸分别编码为 1、2、3、4 或 S、M、L、X。但这种设置很容易出错。很可能在变量保存的是一个错误的值(例如 0 或 m).
针对这种情况,可以自定义枚举类型。枚举类型包括有限个命名的值。例如:
enum Size { SMALL, MEDIUM, LARGE, EXTRA_LARGE };
这段代码定义了一个名为 Size
的枚举类型,它包含了四个常量:SMALL
、MEDIUM
、LARGE
和 EXTRA_LARGE
。
然后,你可以声明这种类型的变量,并给它赋值:
public class Main {
public static void main(String[] args) {
Size s = Size.SMALL;
}
enum Size {SMALL, MEDIUM, LARGE, EXTRA_LARGE}
}
这行代码声明了一个 Size
类型的变量 s
,并将其初始化为 Size.MEDIUM
。
Size
类型的变量只能存储这个类型声明中给定的某个枚举值,或者 null
值。null
表示这个变量没有设置任何值。
3、Java 中的方法
Java 中的方法,在其他语言中也可能被称为过程或函数,是为执行一个操作而组合在一起的语句组。如果一个操作会被多次执行,则可以将该操作定义成一个方法,执行该操作的时候调用方法即可。
3.1、方法构成
在 Java 中方法包括 “方法头” 和 “方法体”,方法头又可以分成修饰符、返回值类型、方法名和参数列表,因此方法包括 5 个部分:
-
方法头–修饰符:修饰符是可选的,告诉编译器如何调用该方法。例如
public
、private
、protected
、static
、final
等; -
方法头–返回值类型:方法可以返回一个值,此时返回值类型是方法要返回的值的数据类型。方法也可以没有返回值,此时返回值类型是
void
; -
方法头–方法名:方法的实际名称;
-
方法头–参数列表:定义在方法头中的变量称为形式参数或参数,简称形参。当调用方法时,需要给参数传递一个值,称为实际参数,简称实参。参数列表指明方法中的参数类型、次序和数量。参数是可选的,方法可以不包含参数;
-
方法体:方法体包含具体的语句集合,用大括号
{}
包围。
例如:
public static int add(int a, int b) {
return a + b;
}
这个方法的修饰符是 public static
,返回值类型是 int
,方法名是 add
,参数列表是 (int a, int b)
,方法体是 { return a + b; }
。
3.2、方法传参
在 Java 中,方法的参数传递有两种方式:值传递(实参)和引用传递(形参)。
形参:全名叫形式参数,出现在方法定义中,形参只是用来占位的,用来代表未来调用时传递过来的数据。
实参:全名叫实际参数,出现在方法调用中,实参是方法执行时真正要用到的数据。在方法调用时,会把实参传递给形参,在执行方法过程中用于参与运算。
实参到形参只是单向的值拷贝过程。如果实参是个数据,会把数据拷贝给形参;如果实参是个地址,会把地址拷贝给形参。实参和形参是 2 个变量,只是值相等,实参的值拷贝给了形参。
Java 中方法参数传递的规则:
- 如果实参是基本类型(包括包装类型)或者 String,则实参不会变(传的是值);
- 如果实参是对象集合或者数组,则实参会改变(传的是引用)。
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
class Solution {
public static void main(String[] args) {
Integer a = 0;
Integer[] array = {0};
List<Integer> list = new ArrayList<>();
add(a);
// 输出结果:"0"
System.out.println(a);
add(array);
// 输出结果:"[1]"
System.out.println(Arrays.toString(array));
add(list);
// 输出结果:"[1]"
System.out.println(list);
}
public static void add(Integer a) {
a = a + 1;
}
public static void add(Integer[] array){
array[0] = array[0] + 1;
}
public static void add(List<Integer> list){
list.add(1);
}
}
3.3、方法重载
在同一个类中,如果多个方法具有相同的方法名,但参数类型或者参数个数不相同(或都不相同),这就是方法的重载。
方法重载和返回值没有关系,不看返回值,只看方法名以及参数。
public static void main(String[] args) {
System.out.println(sum(10, 20));
System.out.println(sum(3.5, 2.0));
System.out.println(sum(1, 2, 3));
}
public static double sum(double x, double y) {
return x + y;
}
public static int sum(int x, int y) {
return x + y;
}
public static int sum(int x, int y, int z) {
return x + y + z;
}
其中需要注意的有两点:
- 同一个类中的同名方法,这个是与后面要学到的方法重写的一个重要的区分方法;
- 与返回值无关。
4、Java 运算符
运算符用于连接值。Java 提供了一系列丰富的算数和逻辑运算符以及数学函数。
4.1、算数运算符
在 Java 中,算术运算符包括 +
、-
、*
、/
和 %
,分别用于加法、减法、乘法、除法和求余运算。此外,Java 还提供了自增运算符 ++
和自减运算符 --
,用于将变量的值加 1 或减 1。
以下是一些注意事项:
- 当
+
运算符用于字符串时,它表示字符串连接。只有直接与字符串相加才会转成字符串;
// 输出:Hello, World!
System.out.println("Hello, " + "World!");
- 当
/
运算符的两个操作数都是整数时,表示整数除法,结果为整数。否则,表示浮点除法,结果为浮点数; - 当
%
运算符用于求余数。结果的符号与被除数的符号相同; - 在进行整数除法运算时,0 不能作为除数,否则会抛出
ArithmeticException
异常;
// 抛出异常:java.lang.ArithmeticException
System.out.println(1 / 0);
- 在进行浮点数除法运算时,除以 0 的结果为
Infinity
,对 0 取模的结果为NaN
。
// 输出:Infinity
System.out.println(1.0 / 0);
// 输出:NaN
System.out.println(1.0 % 0);
Ps: 在 JDK1.2 版本中,Java 引入了 strictfp 关键字。
strictfp,即 strict float point (精确浮点),其作用就是规范 Java 中的浮点类型的计算让计算结果更加精确,因为 Java 的底层默认计算方式不是很精确,在不同的平台会得到不同的结果,结果就会有所差异,但是默认的这种方式是为了运算速度而言,运算速度会更快。
该关键字可以确保在任何平台中的计算结果都相同都精确精确,只不过是速度会稍微慢一点儿,具体用哪一种情况需要我们根据自己的项目中按需求而定。
该关键字可以修饰在接口、类或者是方法上面,修饰在不同的部位,它的应用作用范围也是不同的。使用方法例如,可以把 main 方法标记为:
public static strictfp void main(String[] args)
,那么,main 方法中所有指令都要使用严格的浮点计算,对精确率类型较高且跨平台的计算结果要求比较严格的清醒的话,建议使用该 strictfp 关键词。
4.2、数学函数 Math 类
在 Math 类中,包含了各种各样的数学函数。在编写不同类别的程序时,可能需要的函数也不同。
例如: 要想计算一个数值的平方根,可以使用 sqrt
方法:
public class Main {
public static strictfp void main(String[] args) {
double x = 4;
double y = Math.sqrt(x);
// 输出结果为 2.0
System.out.println(y);
}
}
下面的汇总了一部分 Math 类最常用的方法:
//********** 算术运算 **********
// 取绝对值
abs(double a){...}
Math.abs(a);
// 取平方根
abs(double a){...}
Math.sqrt(a);
// 取立方根
abs(double a){...}
Math.cbrt(a);
// 取最大值
max(double a, double b){...}
Math.max(a, b) ;
// 取最小值
min(double a, double b){...}
Math.min(a, b);
// 取 a 的 b 次幂
pow(double a, double b){...}
Math.pow(a, b);
//********** 算术进位 **********
// 取大于等于 a 的最小整数(返回 double 值)
ceil(double a){...}
Math.ceil(a);
// 取小于等于 a 的最大整数(返回 double 值)
floor(double a){...}
Math.floor(a);
// 四舍五入(返回 double 值)
rint(double a){...}
Math.rint(a);
// 四舍五入(double 时返回 long 值,float 时返回 int 值)
round(double a){...}
round(float a){...}
Math.round(a);
//********** 三角函数 **********
// 计算角度 a 的正弦值(sin)
sin(double a){...}
Math.sin(a);
// 计算角度 a 的余弦值(cos)
cos(double a){...}
Math.cos(a);
// 计算角度 a 的正切值 (tan)
tan(double a){...}
Math.tan(a);
// 计算正弦值为 a 的角度
asin(double a){...}
Math.asin(a);
// 计算余弦值为 a 的角度
acos(double a){...}
Math.acos(a);
// 计算正切值为 a 的角度
atan(double a){...}
Math.atan(a);
//返回从 X 轴到点(x, y)的角度(以弧度为单位)
atan2(double a, double b){...}
Math.atan2(a, b);
// 弧度转角度,用于将角度从弧度转换为角度值
toDegrees(double a){...}
Math.toDegrees(a);
// 角度转弧度,用于将角度从角度值转换为弧度
tan(double a){...}
toRadians.ttoRadiansan(a);
//********** 其他 **********
// 随机数,在范围 [0.0,1.0) 内随机取一个值
random(){...}
Math.random();
此外,Math 类中还包含 Math.E 和 Math.PI 两个静态常量,正如它们名字所暗示的,它们的值分别等于 e(自然对数)和 π(圆周率)
4.3、关系运算符
在 Java 中,关系运算符包括 ==
、!=
、<
、>
、<=
和 >=
,分别用于检测等于、不等于、小于、大于、小于等于和大于等于。
以下是一些注意事项:
- 关系运算符的结果只能是
true
或false
; - 当关系运算符用于字符时,比较的是字符的 ASCII 值;
- 当浮点数和整数进行比较时,只要它们的值相等,结果就为
true
。
4.4、逻辑运算符
在 Java 中,逻辑运算符包括 &&
、||
和 !
,分别用于逻辑与、逻辑或和逻辑非运算。此外,Java 还提供了 &
和 |
运算符,用于无条件的逻辑与和逻辑或运算,以及 ^
运算符,用于逻辑异或运算。
以下是一些注意事项:
-
&&
和||
运算符,是短路运算符,例如&&
,也称为短路与。如果第一个表达式的值为false
,那么就不会继续计算第二个表达式的值。对于A && B
,如果A
为false
,则不会计算B
的值,直接返回false
。对于A || B
,如果A
为true
,则不会计算B
的值,直接返回true
; -
&
和|
运算符,不具短路功能,是无条件的逻辑与和逻辑或运算符。无论操作数的值如何,都会计算所有操作数的值; -
^
运算符是逻辑异或运算符。如果两个操作数的值不同,结果为true
;如果两个操作数的值相同,结果为false
。
此外,Java 支持三元操作符 condition ?expression1 : expression2
,这个操作符有时很有用。如果条件 condition 为 true,就为第一个表达式的值 expression1,否则计算为第二个表达式的值 expression2。
4.5、位运算符
在 Java 中,处理整型类型时,可以直接对组成整型数值的各个位完成操作。这意味着可以使用掩码技术得到整数中的各个位。位运算符包括: &
、|
、~
、^
、>>
、<<
和 >>>
,分别用于位与、位或、位非、位异或、右移、左移和无符号右移运算。
以下是一些注意事项:
-
&
运算符是位与运算符。只有两个位都为 1 时,结果才为 1。
// 输出:1,因为 5 的二进制表示为 101,3 的二进制表示为 011,它们的位与运算结果为 001,即 1
System.out.println(5 & 3);
-
|
运算符是位或运算符。只有两个位都为 0 时,结果才为 0。
// 输出:7,因为 5 的二进制表示为 101,3 的二进制表示为 011,它们的位或运算结果为 111,即 7
System.out.println(5 | 3);
-
~
运算符是位非运算符。它将操作数的每一位取反。
// 输出:-6,因为 5 的二进制表示为 101,取反后为 010,即 -6
System.out.println(~5);
-
^
运算符是位异或运算符。如果两个位的值不同,结果为 1;如果两个位的值相同,结果为 0。
// 输出:6,因为 5 的二进制表示为 101,3 的二进制表示为 011,它们的位异或运算结果为 110,即 6
System.out.println(5 ^ 3);
-
>>
运算符是右移运算符。它将操作数的二进制表示向右移动指定的位数。对于正数,高位补 0;对于负数,高位补 1。
// 输出:2,因为 5 的二进制表示为 101,右移 1 位后为 010,即 2
System.out.println(5 >> 1);
-
<<
运算符是左移运算符。它将操作数的二进制表示向左移动指定的位数。高位超出的部分被舍弃,低位补 0。
// 输出:10,因为 5 的二进制表示为 101,左移 1 位后为 1010,即 10
System.out.println(5 << 1);
-
>>>
运算符是无符号右移运算符。它将操作数的二进制表示向右移动指定的位数。无论操作数是正数还是负数,高位都补 0。
// 输出:2147483645,因为 -5 的二进制表示为 11111111111111111111111111111011,无符号右移 1 位后为 01111111111111111111111111111101,即 2147483645
System.out.println(-5 >>> 1);
5、Java 注释
与大多数程序设计语言一样,Java 中的注释也不会出现在可执行程序中。因此,可以在源程序中根据需要添加任意多的注释,而不必担心可执行代码会膨胀。在 Java 中,有 3 种标记注释的方式: 单行注释、多行注释、文档注释。
5.1、单行注释
最常使用的方式是 //
,其注释内容从 //
开始到本行结尾。一般注释少量的代码或者说明内容。
// 这是一个单行注释
System.out.println("Hello, World!");
5.2、多行注释
当需要使用更长的注释时,既可以在每行的注释前面标记 //
,也可以使用 /*
和 */
注释一段较长的注释。
/*
这是一个多行注释
可以包含多行
*/
System.out.println("Hello, World!");
5.3、文档注释
最后,第三种注释可以用来自动地生成文档,这种注释以 /**
开始,以 */
结束,用于对类和方法进行功能说明。
/**
* 这是一个文档注释
* 可以用来生成 JavaDoc 文档
*/
public class MyClass {
// ...
}
Ps: 在 Java 中,
/* */
注释不能嵌套。也就是说,不能简单地把代码用/*
和*/括
起来作为注释,