Java: 基本语法
Java基本语法
包管理
包的声明
Java包的功能类似C++的命名空间,减少类名冲突;但它并不是随意声明和引用的:包名必须是当前文件/目录的父目录相对于项目根目录的路径,用
.运算符表明父子关系 例如,若.为根目录,当前文件的路径为./test/math,则声明如下:1
package test.math;
一个文件除非直接在项目文件夹下,否则必须声明包,且必须在文件开头(在
import前)
- 一个
.java文件只能有一个public类或接口,且类名必须和文件名相同 - 不同
.java文件在同一个包体内,指的是它们处于同一个目录下,声明的package路径相同 - 命名规范:所有包名均应小写
外部包的引用
引用外部包的类或接口需要使用
import关键字,用于减少包名冗余导致的可读性下降1
2import pkg1.pkg2.MyClass; // 可快捷使用MyClass
import pkg1.*; // 可快捷使用pkg1下的所有公有类或接口, 但不包含子包下的公有类或接口引用外部包的类的静态成员或静态方法时需要使用
import static1
import static java.lang.Math.*;
实践时,引入外部包类等情形不推荐使用通配符
*,引用静态成员等可酌情使用,推荐按以下顺序引入:1
2
3
4
5
6
7import java.util.?; // 先引入java标准库
import org.springframework.?; // 再引入java扩展的第三方库, 按照依赖顺序, 每个不同的库之间隔一空行
import jakarta.persistence.?; // 第三方库
import dlut.?; // 最后引入自己开发的模块实践时,推荐使用格式化插件
javac命令
javac用于编译.java文件,生成可被JVM执行的.class文件最常用的编译命令如下(多个文件使用
:分隔,Windows下是;):1
2-d(destination)参数表示保留文件的包路径信息,并生成到目标目录下
javac -d 目标目录 待编译的.java文件其它参数:
-encoding,指定文件编码实践中,推荐使用
IDE插件提供的脚本服务自动编译
java命令
java用于运行.class文件最常用的命令如下:
1
2
3
4-cp(classpath)参数标明`JVM`应从哪些路径下查找
主类名必须包含`main`,链接由JVM在运行时进行,被链接的类同样是在指定的目录下查找
注意主类名不是文件名,不能包含`.class`
java -cp 目录 主类名java的main函数模板:1
2
3public class MainClass {
public static void main(String[] args) {}
}
jar命令
jar命令与tar命令极其相似,用于归档常用参数如下:
-v:verbose,显示归档/解压详情-c:create,创建归档文件-f:file,指明归档文件名-u:update,更新归档文件-x:extract,解压归档文件
常用语句如下:
1
2
3jar -cf a.jar 类列表
jar -uf a.jar 新加入类列表
jar -xf a.jar 解压a.jar归档后,可以通过
java -cp xxx.jar MainClass运行主类MainClass,所有需要链接的类都在归档文件中找到
关键字及声明型语句
访问控制修饰符
本节不讨论内部类
java有四个访问控制权限,分别对应public、protected、default、private四个修饰符public:可以修饰类、接口、方法、属性,表示所有包可访问,是最常用的修饰符protected:可以修饰方法、属性,表示同包内均可访问,外部包中仅子孙类可通过this(自己或子孙类的对象)访问,例如1
2
3
4
5
6
7
8
9package a;
import b.A; // 假设含有protected void methodA() {}方法
class B extends A {
void func() {
methodA(); // 正确
A a = new A();
a.methodA(); // 错误
}
}default:实际上不存在这个关键字,当类或方法或属性没有显式地声明访问控制修饰符时,含有default权限,常称为包级私有,仅包内所有类可访问private:可以修饰方法、属性,仅类内可访问
static、abstract、final、record
static:声明静态对象或方法或内部类,和cpp类似abstract:声明抽象方法或抽象类,和cpp的virtual定义类似final:- 修饰类时:表明该类不能被继承
- 修饰方法时:表明该方法不能被重写
- 修饰变量时:声明常变量,注意只是限制在栈中的值不能改变
abstract不能和final或private或static同时出现,因为没有意义final不能修饰接口,因为没有意义修饰符的顺序对程序没有影响,但规范是先是访问控制修饰符,然后是其它修饰符
final修饰引用对象时只能限制该变量不能改变指向,但没有限制用户通过该变量改变其指向的实例因为
final修饰方法只代表该方法不能被重写,所以做不到cpp那样用一个类型声明可变或不可变对象在
java中,一个类要么是可变类,要么是不可变类,不可变类的所有属性都被final修饰且不提供setter方法,例如String就是典型的不可变类,不要把实例方法和引用赋值搞混:1
2
3
4String s = ""; // 引用赋值
s = s.trim(); // 实际上是改变了s的指向使其指向s.trim()的返回值,而没有改变原来指向堆中的实例
StringBuilder sb = new StringBuilder(""); // 引用赋值
sb.append("a"); // StringBuilder是一个可变类, append()修改了sb指向的实例的属性重写后的方法的访问控制权不能比父类的该方法低
record关键字可用于修饰类,表示一个类是不可变类,自动添加final等修饰符、自动实现equals(), hashCode()方法、自动实现getter方法
synchronized、transient、volatile、sealed、permits
synchronized用于同步transient修饰表示无法被序列化volatile修饰表示每次读写都对主存读写,但仍不能保证原子性sealed和permits是JDK 17及以上提供的继承修饰符,与final相区分,sealed修饰的类只能被其permits的类继承1
2public sealed SuperClass permits SubClass {}
class SubClass extends SuperClass {} // 允许
标识符声明
声明变量:仅支持用
=初始化新变量,且需要指明类型1
String obj = "";
声明类:
java没有函数,所有函数体都在类内,抽象类不能被实例化1
modifiers class ClassName {ClassBody} // 不需要';'
声明方法:抽象方法所属类必须为抽象类
1
modifiers returnType methodName(paramList) {methodBody}
声明接口:
java提供所谓接口,是一系列抽象方法的集合,是其它模块访问你编写的模块的入口,编译时会自动在接口的所有方法前加上public修饰符1
2
3
4public interface InterfaceName {
// 接口内的方法默认为public,且没有实现
returnType methodName(paramList);
}声明一个实现了某个接口的类,一个类可以实现多个接口:
1
2
3public class ClassName implements InterfaceName {
// 必须重写所有该接口的方法
}声明一个继承了某个类的类,或一个继承了某个接口的接口,只能单继承:
1
2public class ClassName extends SuperClass {}
public interface InterfaceName extends SuperInterface {}extends应该在implements之前
标识符规范
- 包名规范:应全小写
- 变量名和方法名规范:构成标识符的所有单词,首单词全小写,其余单词仅首字母大写
- 类名和接口名规范:构成标识符的所有单词首字母均大写
- 常量名规范:应全大写
protected权限的解释
- 在引入类(链接在
.class文件中的字节码)时,JVM会加载类/接口的元数据进方法区,并构建方法表来区分不同的访问控制域 - 在创建对象时,
JVM会申请一段内存,并创建对象的方法表,用于单独存储所有非静态成员 类、对象的方法表是不同的 - 每个类都会维护一个引用,指向允许访问的类或对象的方法表
- 这个引用能指向所有同一包的类及其对象、所有引入的外包类的方法表
- 能指向,同时符合访问修饰符的范围,才能正常调用
- 因此
protected是极其特殊的:- 包外子类不能通过基类的对象访问保护型方法,因为包外的子类不能指向对象的方法表
- 包外子类可以通过基类访问保护型静态方法,因为包外子类能指向类的方法表,同时符合
protected的范围 - 包内子类可以通过基类及其对象访问保护型方法,因为包内类能指向类及其对象的方法表,同时符合
protected的范围
java的语法糖
java不支持运算符重载,仅有部分特殊的类含有类似的语法糖(String支持+拼接,但没有[]运算符)java不支持默认参数java支持函数重载,重载要求方法名相同但参数列表不同java支持变长参数,java变长参数的语法如下:1
2// paramList可以是零或多个String参数
void method(String... paramList) {}java不支持多继承java不支持常方法,cpp支持用const修复一个方法保证不能被非常量调用java和cpp均支持类型自动推断,在cpp中是auto而在java中是varjava的Type[]整体表示一个数组类型,元素的类型为指定的Type
结构型语句
if-else if-elsewhere-continue-breakfor(;;)-continue-breakfor(type e : c)语法糖try-catch-finallytry-with-resourceswitch-case-breakswitch-case -> {yield}