前言
以前做东西都赶时间需要什么百度什么,很多时候因为这种方式导致学的东西太片面,总体下来反而花了很多冤枉时间,在语法方面这个情况更加明显。这次趁着项目中再一次用到Java,就花点时间对相关语法做个记录,方便自己后期查阅。
测试环境搭建
- 系统:
Windows
- 环境:
JDK
下载地址:https://www.oracle.com/java/technologies/downloads/
我这里下载的是Java 19 2022-09-20版本 - 编辑器:
VS Code
下载地址:https://code.visualstudio.com/
下载安装后需要装Java扩展,见下图:
Java 8 语法
我这里用到Java是用于安卓原生开发,目前安卓支持Java版本为Java 8,所以这里就以这个版本进行记录,当然大概也不会详细的记录所有语法,详细内容可以参考官方文档。
Java 8 官方页面如下:
https://docs.oracle.com/javase/8/
语法教程如下:
https://docs.oracle.com/javase/tutorial/java/index.html
基础示例
// 这是单行注释
/* 这是单行或多行注释 */
/** 这是文档注释,可以单行或多行
* Java程序最基础的就是class(类),这里的Test是类名
*/
class Test {
public static void main(String[] args) { // main方法是程序的主入口点
System.out.println("Hello World!"); // 打印输出字符串
}
}
Language Basics(基础语法)
Variables and Arrays(变量和数组)
下面是Java中基本的变量类型及默认值:
byte varByte = 0;
short varShort = 0;
int varInt = 0;
long varLong = 0L;
float varFloat = 0.0f;
double varDouble = 0.0d;
char varChar = '\0';
boolean varBoolean = false;
String varString = null; // 所有对象的默认值均为null
变量通常以骆驼式命名法命名: 第一个单词以小写字母开始;从第二个单词开始以后的每个单词的首字母都采用大写字母 。
变量值可以有多种表达方式:
byte var1 = 0b00001111; // 二进制表示
byte var2 = 0b0000_1111; // 带下划线分割
int var3 = 0xff; // 十六进制表示
int var4 = 1_0000_0000; // 带下划线分割
double d2 = 1.0E2; // 用科学计数法表达
使用 final
修饰的变量赋值后就不可修改,相当于其它语言中的常量,常量名称一般使用全大写和下划线的形式:
final String MY_NAME = "Naisu";
下面是Java中数组的声明和创建方式:
int[] array1; // 声明数组
int array2[]; // 声明数组,不推荐
byte[][] array3; // 声明二维数组
array1 = new int[4]; // 创建数组
array3 = new byte[4][8]; // 创建数组
char[] array4 = new char[8]; // 声明并创建数组
boolean[] array5 = { true, false, true, false }; // 声明并创建数组
System.out.println(array5.length) // 打印数组长度
下面是一些数组操作方法:
// 数组很多操作都在java.util.Arrays中,下面演示其中部分方法
String[] array1 = new String[3];
java.util.Arrays.fill(array1, "la"); // 填充数组
for (String item : array1) { // 遍历数组
System.out.print(item);
}
System.out.println();
char[] array2 = { 'H', 'e', 'l', 'l', 'o', ' ', 'N', 'a', 'i', 's', 'u', '!' };
char[] array3 = java.util.Arrays.copyOfRange(array2, 6, 11); // 从一个数组中截取复制
for (char item : array3) {
System.out.print(item);
}
System.out.println();
System.out.println(java.util.Arrays.equals(array2, array3)); // 比较数组是否相同
String[] array4 = { "la", "la", "la" };
System.out.println(java.util.Arrays.equals(array1, array4));
java.util.Arrays.sort(array2); // 对数组元素进行排序
for (char item : array2) {
System.out.print(item);
}
System.out.println();
System.out.println(java.util.Arrays.binarySearch(array2, 'i')); // 查找元素返回位置
System.out.println(java.util.Arrays.binarySearch(array2, 'l')); //
System.out.println(java.util.Arrays.binarySearch(array2, 'x')); // 查找不存在的元素
Operators(运算符)
类型 | 符号 |
---|---|
算术运算 | + - * / % |
自增自减 | expr++ ++expr expr-- --expr |
赋值运算 | = += -= *= /= %= &= ^= |= <<= >>= >>>= |
位运算 | & | ^ ~ << >> >>> |
逻辑运算 | && || ! |
比较与判断 | < > <= >= == != instanceof(判断左边对象是否为右边类的实例) |
三元运算 | ? : |
Control Flow Statements(流程控制语句)
下面是Java中各种条件选择语句一般用法:
if (condition) { ... }
if (condition) { ... }
else { ... }
if (condition) { ... }
else if (condition) { ... }
else { ... }
switch (key) {
case value1:
...
break;
case value2:
...
break;
default:
break;
}
下面是Java中各种循环语句一般用法:
while (expression) {
...
}
for (initialization; termination; increment) {
...
}
循环语句中使用 break
跳出循环,使用 continue
跳过本次循环进入下一次循环。
Numbers and Strings(数值和字符串)
数值和字符串是编程中最主要操作的内容,这里稍微描述下,有时间再进行 详细说明。
Java语言自带或是官方的类库中有非常多的数值和字符串操作的方法:
- 对于数值来说比较常用的有各种数值类型间的转换、数值的数学运算、数值间的比较等;
- 对于字符串来说比较常用的有字符串的查找、替换、截取、比较等;
- 字符串和数值之间还有相互转换的各种方法;
Classes and Objects(类和对象)
类、成员、方法基础说明
Java作为面向对象编程语言(OOPL),最核心的特征就是类。类是对具体对象特征的抽象,类中主要包含变量和方法(函数)等,都称为类的成员:
class MyClass {
// 成员变量
// 用private修饰的成员只允许类内部访问
private int number = 233;
// 成员方法
// 用public修饰的成员允许外部访问
public int getNumber() {
return number;
}
// 同名的方法可以有不同的输入参数,称为方法的重载
public int getNumber(int add) {
return number + add;
}
}
类通常以骆驼式命名法命名:每个单词首字母大写。
文件中直接的类(顶级类)的前面可以不加修饰符,或是有且只有其中一个类可以加上public修饰符,如果加了该修饰符那么该类名必须和文件名相同。
方法通常以骆驼式命名法命名,并且第一个单词一般为动词。
和类名相同的方法称为构造方法,会在该类型变量创建时运行构造方法:
class MyClass {
// 构造方法没有返回值
public MyClass() {
System.out.println("Hello World !");
}
// 构造方法也可以重载
public MyClass(String name) {
System.out.println("Hello " + name + " !");
}
}
传入方法的参数最后一个可以是任意长度参数,该参数在方法内部会被视为数组:
注意传参时传值和传引用:
class Test {
public static void main(String[] args) {
int data = 200;
modify(data); // 简单类型传递的是值,内部修改不会影响原始数据
System.out.println(data);
int[] array = { 200 };
modify(array); // 数组和对象等复杂类型传递的是引用,内部修改会影响原始数据
System.out.println(array[0]);
}
public static void modify(int data) {
data += 33;
}
public static void modify(int[] array) {
array[0] += 33;
}
}
可以使用 static
来修饰成员,这些成员被称为静态成员,在所有该类的对象中共享,并且不需要创建对象就能使用:
Nested Classes(嵌套类)
类的内部还可以嵌套类:
class OuterClass {
...
class InnerClass {
...
}
}
Enum Types(枚举类型)
Java中也有枚举类型,比如下面样子:
enum Week {
SUNDAY, MONDAY, TUESDAY, WEDNESDAY, THURSDAY, FRIDAY, SATURDAY
}
Interfaces and Inheritance(接口和继承)
Interfaces(接口)
接口算是Java中除了类以外最重要的一个概念了。接口有点像C/C++中的头文件,但又强大很多。
接口和类定义上有一点点像,使用 interface
关键词,接口中只需要声明变量和方法,不需要去实现它:
interface CommInterface {
// 在Java9前接口内的成员前面不能加限定范围的关键词,默认都是public的
void setName(String str);
String getName();
...
}
接口是给两边人合作的中间点,一边需要实现接口具体的方法,另一边拿来使用。
实现接口是通过创建类来进行的:
class MyClass implements CommInterface {
// 类中真正实现了接口中声明的方法
public void setName(String str) { ... }
public String getName() { ... }
...
}
如果接口被实现过,就可以使用了:
// 注意这里声明的对象类型是接口的类型
CommInterface inter = new MyClass();
inter.setName("Naisu");
System.out.println(inter.getName());
使用接口的好处是使用的人完全不需要关系实现接口的细节,只要知道接口中有哪些东西就能拿来用了。一个接口可以有各种各样的实现,更换实现时不需要更改使用的代码。
一个类可以同时实现多个接口:
class Class implements Interface1, Interface2 ... {
...
}
Java8开始接口中可以有静态方法和默认方法了:
interface CommInterface {
// 静态方法,不需要实现它,直接用CommInterface.func1()即可使用
public static void func1() { ... }
// 默认方法,实现该接口的类中不写该方法也可以有默认操作
default void func2() { ... }
}
Inheritance(继承)
Java中一个类可以继承自另一个类:
class SubClass extends MainClass {
...
}
继承的意义是一个类可以在编写时直接获得它继承的父类的内容,提高代码的复用:
class MainClass {
public String str1 = "main-str1";
private String str2 = "main-str2"; // private修饰的成员是不会被继承的
public MainClass() {
System.out.println("main-class");
}
public void print() {
System.out.println("main-print");
}
}
class SubClass extends MainClass {
// 什么都不写也会获得父类的成员
}
public class Test {
public static void main(String[] args) {
SubClass obj = new SubClass(); // 子类没有自己的“无参数构造方法”,那么就会调用父类的“无参数构造方法”
System.out.println(obj.str1);
// System.out.println(obj.str2); // private修饰的成员是不会被继承的
obj.print();
}
}
子类可以有和父类相同名称的变量和方法:
class MainClass {
public String str1 = "main-str1";
public void print() {
System.out.println("main-print");
}
}
class SubClass extends MainClass {
public String str1 = "sub-str1";
// 重写父类的print方法
public void print() {
System.out.println("sub-print");
}
}
public class Test {
public static void main(String[] args) {
SubClass obj = new SubClass();
System.out.println(obj.str1);
obj.print();
}
}
子类中可以用 this
来指代自己,使用 super
来指代父类:
class MainClass {
public String str1 = "main-str1";
public void print() {
System.out.println("main-print");
}
}
class SubClass extends MainClass {
public String str1 = "sub-str1";
public void print() {
System.out.println("sub-print");
}
public void printAll() {
System.out.println(this.str1);
System.out.println(super.str1);
this.print();
super.print();
}
}
public class Test {
public static void main(String[] args) {
SubClass obj = new SubClass();
obj.printAll();
}
}
可以使用 final
来修饰类,这种类无法被继承;如果用 final
来修饰方法,那么该方法无法被子类重写。
可以使用 abstract
来修饰类,叫做抽象类,其中方法不需要实现,而是由继承它的子类来实现,有点类似与接口。
接口也可以继承别的接口,并且接口可以多继承:
interface CommInterface extends Interface1, Interface2 ... {
...
}
类可以同时继承其它类并实现接口:
class MyClass extends Class implements Interface {
...
}
Generics(泛型)
Java的基础变量类型都是强类型的,这在有些时候不怎么方便,比如下面情况:
String test(String str) { return str; }
int test(int i) { return i; }
这两二方法其实功能是一样的,唯一的区别就是参数类型不一样。这种情况其实挺常见的,如果遇到这种情况有一种通用的处理方式就可以减少很多代码量。这就是泛型了:
// 用<T>声明了一个名称为T的类型
// 通常泛型声明类型都用单个的大写字母,比如E K N T V S U等,虽然可以任意指定,但通常规则如下
// E:Element (在集合中使用,因为集合中存放的是元素)
// T:Type(Java 类)
// K:Key(键)
// V:Value(值)
// N:Number(数值类型)
// ?:表示不确定的java类型
<T> T test(T t) {
return t;
}
泛型会在使用时根据传入或接收的对象类型来确定其真正的类型:
在类或接口中也可以使用泛型:
Packages(包)
前面讲到了对Java程序来说最基本的是的类,这有个问题,对于大型程序来说类名有可能重复,这就有冲突了。所以又搞了个包出来,包名通常很长,比如 com.example.naisu
,这样使用这个包下面的类其实就会变成这样 com.example.naisu.MyClass
,包名通常用组织的域名加具体的子名称组成,这样可以在最大可能上避免重复产生。
包的方式不光是名称而已,文件目录上也是根据包名组织的,使用开发工具的话一般会自动处理相关事务:
包之间可以用 import
来导入使用:
Annotations(注解)
Java的代码中很多类和方法的前面经常会有 @
开有后跟文本的内容,这个是Java中的Annotations(注解)。
- 注解的基本功能就是一些提示性的语句,比如下面这些:
@Author 标示作者信息
@Override 标示方法是重写的方法 - 在上面基础上这些注解还可以给编译器看,比如下面一些:
@Override 如果父类中没有该方法则发出警告
@SuppressWarnings 忽略某些警告 - 再进一步的有些注解可以给其它的工具看,用来配置生成代码等。