入门篇-其之二-Java基础知识
对第一个Java程序的思考
前面我们已经写过一个使用Java语言输出四行诗句的代码:
public class Huanghelou {
public static void main(String[] args) {
System.out.println("昔人已乘黄鹤去,此地空余黄鹤楼。");
System.out.println("黄鹤一去不复返,白云千载空悠悠。");
System.out.println("晴川历历汉阳树,芳草萋萋鹦鹉洲。");
System.out.println("日暮乡关何处是?烟波江上使人愁。");
}
}
外层结构——类
观察这段代码的结构,它的外层是由public
、class
、文件名称(即Huanghelou
)和一对大括号组成。
public class Huanghelou {
}
public
和class
是Java内置的关键字(本文后面会讲到关键字),也就是说,这两个关键字是Java语言本身就规定的,小白在写代码的时候不能随意更改(例如:将public
写成Public
,class
一不小心写成了cLass
等都是错误写法)。
class
本意是“类”,class
后面的标识符Huanghelou
是当前这个类的名称,也就是说,这个类的类名是Huanghelou
;
public
是权限修饰符(后续文章会讲到这个关键字的具体使用,这里小白有一个印象就可以了)。
一个Java文件至多只能有一个由public
修饰的类,并且这个类的类名必须和Java
文件名保持一致。
由上述规定我们可以推断出:不由public
修饰的类不必和当前java文件名保持一致。这里我创建一个名为MyThirdProgram
的Java文件,其内部代码如下:
class Dog {
}
执行了javac
命令时,我们发现它并没有生成MyThirdProgram.class
文件,而是生成了Dog.class
文件。这是因为前面我们的MyThirdProgram.java
文件中只有一个Dog
类,并不包含由public
修饰的MyThirdProgram
类。
当然,我们的代码中既可以由public
修饰的类和不由public
修饰的类共存。这里我创建一个名为MyFourthProgram
的Java文件,其内部代码如下:
public class MyFourthProgram {
}
class Cat {
}
class Sheep {
}
class Duck {
}
我们使用java
命令进行编译,此时就会出现MyFourthProgram
、Cat
、Sheep
和Duck
四个.class
文件:
由此可以说明,一个Java文件中,如果有多个类,那么对这个Java文件执行编译命令时,就会生成多个相对应的字节码文件。
内层结构——main方法
在MySecondProgram
类的内部,包含一个这样的结构:
public static void main(String[] args) {
}
前三个public
、static
、void
是Java的关键字(固定写法)。这个结构在Java中称作方法,这个方法称作main
方法(因为方法名叫做main
方法),main
方法是Java程序的入口,也就是说,程序在运行时,会先执行main
方法。
main
方法必须定义成public static void main(String[] args) {...}
的结构,这是Java的规范。
输出语句
这段代码中,按行输出的语句是System.out.println();
。也就是说,Java在执行这条语句的时候,会向控制台输出内容并换行。
当然,我们也可以选择不换行输出,System.out.print();
语句就能保证输出的内容不换行。以下是示例代码:
public class PrintWithoutLine {
public static void main(String[] args) {
System.out.print("昔人已乘黄鹤去,此地空余黄鹤楼。");
System.out.print("黄鹤一去不复返,白云千载空悠悠。");
System.out.print("晴川历历汉阳树,芳草萋萋鹦鹉洲。");
System.out.print("日暮乡关何处是?烟波江上使人愁。");
}
}
以下是使用javac encoding PrintWithoutLine.java
和java PrintWithoutLine
命令的执行结果:
注释
注释是用来向代码中添加解释和说明,编写注释可以让我们更好地阅读和理解代码。在代码上写注释是一个好习惯,今天我写了50行的代码,但是过了三个月以后,如果我再看这段代码,会有种不知所措的感觉:这代码是我写的吗?它要实现的功能是什么?如果在编写代码以后写了注释,以后在阅读代码的时候这种窘境会大大减少,提高我们对代码的理解😄。
注释不会影响程序的运行,Java编译器会将注释忽略。
在Java编程语言中,有三种类型的注释:单行注释、多行注释和文档注释。
单行注释
单行注释,顾名思义,就是只能在某一行上写注释,使用两个斜杠//
表示,格式为:// 单行注释内容
。
以前面写过的代码为例,如果我想在输出语句上方中添加一句注释:
// 输出一行内容
System.out.println("晴川历历汉阳树,芳草萋萋鹦鹉洲。");
当然,你也可以在这个输出语句后面所在行写注释:
System.out.println("晴川历历汉阳树,芳草萋萋鹦鹉洲。"); // 输出一行内容
扩展:《阿里巴巴Java开发手册》对单行注释内容的说明
1. 【强制】方法内部的单行注释,在被注释的语句上方另起一行,使用
//
注释。也就是说,在我们日常开发的时候,编写注释时,推荐使用上述第一种注释风格。
2. 【强制】注释的双斜线与注释内容之间有且仅有一个空格。
正例:
3. 【推荐】与其“半吊子”英文来注释,不如用中文注释把问题说清楚。专有名词与关键字保持英文原文即可。
反例:“TCP 连接超时”解释成“传输控制协议连接超时”,理解反而费脑筋。
多行注释
多行注释使用/* */
进行表示,在/*
和*/
之间你可以写多行注释。
/*
这是一段多行注释
println()方法用于换行输出
print()方法用与不换行输出
*/
System.out.println("黄鹤一去不复返,白云千载空悠悠。");
System.out.print("晴川历历汉阳树,芳草萋萋鹦鹉洲。");
多行注释之间不要使用嵌套。
/*/*这是一段多行注释,这样嵌套多行注释的方式是错误的*/*/
System.out.println("黄鹤一去不复返,白云千载空悠悠。");
这样嵌套是错误的。以上述代码为例,Java编译器认为多行注释最开头的是/*
,能和它配对的是最近的*/
,也就是说,这段多行注释的内容是:/*这是一段多行注释,这样嵌套多行注释的方式是错误的
。最外层的*/
无法识别为多行注释符号而导致编译错误。
文档注释
文档注释是Java特有的一种注释,它用于对类、方法、变量等进行说明。
文档注释使用/**
作为开头,*/
作为结尾。
/**
* 这个类中由一个main方法组成
* 这个类的主要作用是通过控制台输出两句话
*
* @author iCode504
* @version 1.0
*/
public class MyJavaDoc {
/**
* main方法用于输出两行诗句
*/
public static void main(String[] args) {
System.out.println("杨花落尽子规啼,闻道龙标过五溪。");
System.out.println("我寄愁心与明月,随君直到夜郎西。");
}
}
文档注释常用标签
在这段代码中,我们发现类上有一些特殊标签,它们以@
作为开头,后面跟随一个指定的名字,例如:@author
、@version
等。
@author
用于指明当前代码的作者或所属组织,如果有多个作者可以加多个此标签,适用于类、接口等。例如:
/**
* @author iCode504
* @author Zhangsan
* @author Lisi
*/
@version
用于指明当前代码的版本号,适用于类、接口等。例如:
/**
* @version 1.1.0
*/
@return
标签作用于方法的文档注释上,表明当前方法的返回值类型。例如:
/**
* main方法用于输出两行诗句
* @return 不返回任何内容,因为返回值类型为void
*/
public static void main(String[] args) {
System.out.println("杨花落尽子规啼,闻道龙标过五溪。");
System.out.println("我寄愁心与明月,随君直到夜郎西。");
}
@param
标签用于描述方法的参数信息。以main
方法为例,它的参数是字符串数组类型的。
/**
* main方法用于输出两行诗句
* @param args是main方法的参数,类型为字符串数组类型
*/
public static void main(String[] args) {
System.out.println("杨花落尽子规啼,闻道龙标过五溪。");
System.out.println("我寄愁心与明月,随君直到夜郎西。");
}
@throws
和@exception
标签用于描述方法可能会抛出的异常,例如:
/**
* main方法用于输出两行诗句
* @param args是main方法的参数,类型为字符串数组类型
* @throws IOException 可能会抛出文件IO异常
*/
public static void main(String[] args) throws IOException {
System.out.println("杨花落尽子规啼,闻道龙标过五溪。");
System.out.println("我寄愁心与明月,随君直到夜郎西。");
}
使用javadoc命令生成网页风格的文档
我们可以使用javadoc
命令对代码中的文档注释进行解析,生成一套网页形式的文档。命令格式为:
javadoc -d 文件路径 -encoding UTF-8 --label1 -label2 文件名.java
这里的label1
和label2
是指文档注释中由@
开头的标签,如果执行命令中写了那个标签,就会在网页中显示。当然,你的java
文件中写了多少个不同类型的标签,你就可以在命令中写多少个--标签
。
以上述内容为例,如果我想输出所有文档注释和标签到网页,可以执行如下命令:
此时我们进入G:\Code\MyWorkspace\day02\MyFirstDoc
路径中,我们可以看到如下内容,直接使用浏览器打开index.html
:
此时我们就能在网页中更加直观地看到我们写的文档注释内容了:
阿里巴巴Java开发手册关于文档注释的规范
1. 【强制】类、类属性、类方法的注释必须使用 Javadoc 规范,使用
/**内容*/
格式,不得使用// xxx
方式。说明:在 IDE 编辑窗口中,Javadoc 方式会提示相关注释,生成 Javadoc 可以正确输出相应注释;在 IDE中,工程调用方法时,不进入方法即可悬浮提示方法、参数、返回值的意义,提高阅读效率。
2. 【强制】所有的类都必须添加创建者和创建日期。
说明:在设置模板时,注意 IDEA 的@author 为
${USER}
,而 eclipse 的@author 为`${user}`,大小写有区别,而日期的设置统一为 yyyy/MM/dd 的格式。正例:
/** * @author iCode504 * @date 2023/08/31 */
3. 【推荐】代码修改的同时,注释也要进行相应的修改,尤其是参数、返回值、异常、核心逻辑等的修改。
说明:代码与注释更新不同步,就像路网与导航软件更新不同步一样,如果导航软件严重滞后,就失去了导航的意义。
关键字
Java关键字是由Java语言预先定义的保留的标识符,关键字不能用作变量名、方法名、类名等。这些关键字在Java语言中具有特殊的含义和用途,以下是Java常见的关键字(不需要记忆,因为这些关键字的用法会在后续文章中陆续讲到):
- 数据类型相关的关键字:
byte
、short
、char
、int
、long
、float
、double
、boolean
、void
。 - 流程控制相关的关键字:
if
、else
、switch
、case
、default
、for
、while
、do
、break
、continue
、return
- 权限控制关键字:
public
、protected
、private
- 类和对象相关关键字:
class
、new
、extends
、interface
、implements
、this
、super
、instanceof
、static
、abstract
、final
、enum
- 异常处理关键字:
try
、catch
、finally
、throw
、throws
、assert
- 包相关的关键字:
import
、package
- 多线程及同步相关的关键字:
synchronized
、volatile
- 序列化相关的关键字:
transient
- 保留字:
goto
、const
- 其他关键字:
native
、var
(JDK 10新增关键字)、null
(不推荐做变量名)、strictfp
所有关键字的名称全部是小写,不是小写的一定不是关键字。
标识符
Java中类名、方法名、变量名(关于变量名会在后面讲到)都称作标识符。以前面的代码为例:
public class MyJavaDoc {
public static void main(String[] args) {
System.out.println("");
System.out.println("");
}
}
这个类的类名叫做MyJavaDoc
,方法名称作main
。
关于Java标识符,需要遵守如下规范(必须遵守,否则无法通过编译):
1. 标识符由大小写英文字母、数字、美元符号$
、下划线组成。例如:ABC
、_MyProgram
、$Sheep
都是正确写法;-Sheep
、ABC+
等都是非法的。
2. 关键字不能作为标识符。例如:static
关键字不可以做类名和方法名。
3. Java对标识符大小写是敏感的。例如:sheepCount
和SheepCount
就是两个不同的标识符。
4. 数字不能作为标识符的开头,例如:标识符4Sheep
就是错误写法。
扩展:《阿里巴巴Java开发手册》对标识符相关内容做出如下规范:
1. 【强制】代码中的命名均不能以下划线或美元符号开始,也不能以下划线或美元符号结束。
反例:
_name / __name / $name / name_ / name$ / name__
2. 【强制】所有编程相关的命名严禁使用拼音与英文混合的方式,更不允许直接使用中文的方式。
说明:正确的英文拼写和语法可以让阅读者易于理解,避免歧义。注意,纯拼音命名方式更要避免采用。
正例:
ali / alibaba / taobao / cainiao / aliyun/ youku / hangzhou
等国际通用的名称,可视同英文。反例:
DaZhePromotion [打折] / getPingfenByName() [评分] / int 某变量 = 3
3. 【强制】类名使用 UpperCamelCase 风格(大驼峰命名方式,每个单词首字母大写),但以下情形例外:DO / BO / DTO / VO / AO / PO / UID 等。
正例:
ForceCode / UserDO / HtmlDTO / XmlService / TcpUdpDeal / TaPromotion
反例:
forcecode / UserDo / HTMLDto / XMLService / TCPUDPDeal / TAPromotion
4. 【强制】方法名、参数名、成员变量、局部变量都统一使用 lowerCamelCase(除了第一个单词首字母小写以外,其他单词首字母大写)风格。
正例:
localValue / getHttpMessage() / inputUserId
5. 【强制】杜绝完全不规范的缩写,避免望文不知义。
反例:AbstractClass“缩写”命名成 AbsClass;condition“缩写”命名成 condi,此类随意缩写严重降低了代码的可阅读性。
变量
在Java编程语言中,变量是一种存储数据的“容器”,它们能存储各种类型的数据,例如:整数、浮点数、字符、布尔类型等。
变量的概念
变量是内存中的一个存储区域,正如其名:变量,变量存储的数据是可以变化的。
变量三要素:数据类型、变量名和变量值。在内存中的关系图如下:
变量主要用于在内存中存储数据。
定义并初始化变量
创建Java变量的一般语法是:数据类型 变量名 = 变量值
- 变量名可以自定义,但是需要遵守标识符命名规范。
- 数据类型分为基础数据类型和引用数据类型,这里举例使用整数类型
int
,更多关于数据类型的内容详见下一篇文章。
这里以存储整数类型的int
来举例:变量number
的值为22
,那么可以定义成:
int number = 22;
当然我们也可以先定义变量number
,在对变量进行赋值。
int number;
number = 22;
以下是变量在代码中的使用案例:
public class MyVariable {
public static void main(String[] args) {
// 变量的定义和赋值都在同一行
int age = 20;
System.out.println(age);
// 先定义变量,再为变量进行赋值
int number;
number = 22;
System.out.println(number);
// 变量是可以变化的:给number再次赋值为24,这个值会将原有的22进行覆盖
number = 24;
System.out.println(number);
}
}
运行结果:
使用变量的注意事项
1. 变量必须先声明,后使用。凭空出现的变量是无法通过编译的。以下是错误写法:
public static void main(String[] args) {
number = 1; // 编译不通过,因为number并没有被声明
}
2. 使用变量名来访问这块区域的内存数据。以上述MyVariable
类为例,当我们输出结果的时候,并没有直接使用变量值20
和22
进行输出,而是使用变量名age
和number
进行输出,因为通过变量名可以访问到这块区域的内存,存储的值是多少。
3. 变量的作用域:作用域在最近的外层大括号内,变量只有定义在作用域内才有效。以上述MyVariable
类为例,变量age
和number
的作用域只能在main
方法中,因为两个变量最近的外层大括号就是在main
方法的范围,出了main
方法会导致Java将无法识别这个变量而出现编译错误。
4. 同一个作用域内,不能定义重名的变量。下面代码是错误写法:
public static void main(String[] args) {
int number = 23;
int number = 29; // 错误写法,因为作用域内只能定义一个名为number的变量
}