编码规范

命名规范

  • 命名方法

    • 匈牙利命名
      • 一般值命名变量
      • 原则:变量名=类型前缀+描述
      • 例如:bFoo(布尔型变量)、pFoo(指针类型变量)
    • 驼峰命名(最常用)
      • 混合使用大小写字母命名
      • 小驼峰法:第一个单词小写,其他单词首字母大写,例如:myRoomCount
      • 大驼峰法:单词首字母都大写,例如:ClassRoom
  • 包名:全小写,中间可以用点(.)分隔开,

    • 作为命名空间,报名应具有唯一性,可以采用公司或组织域名倒置
    • java 核心库报名不采用域名倒置,例如:java.awt.event
  • 类和接口名:采用大驼峰法

  • 文件名:大驼峰法

  • 变量:小驼峰法

  • 常量名:全大写,由多个单词组成的用下划线(_)分隔开,例如:YEAR、WEEK_OF_MONTH

  • 方法名:小驼峰法

注释规范

  • 单行注释(//)
  • 多行注释(/* … */)
  • 文档注释(/** … */)

文件注释

在每一个文件开头添加注释

通常包含版权信息、文件名、所在模块、作者信息、历史版本信息、文件内容、作用

1
2
3
4
5
6
7
8
/*
*版权所有....
*许可证信息....
*描述:
* ....
*历史版本:
* ....
*/

文档注释

能生成 API 帮助文档

JDK 中 javadoc 命令能提取这些注释信息并生成 HTML 文件

文档注释主要对类(或接口)、实例变量、静态变量、实例方法、静态方法进行注释

  • 文档注释标签

    标签 功能
    @author 说明类或接口的作者
    @deprecated 说明类、接口或成员已经废弃
    @param 说明方法参数
    @return 说明返回值
    @see 参考另一个主题的链接
    @exception 说明方法所抛出的异常类
    @throws 同@exception
    @version 类或接口版本
  • 生成 API 帮助文档,可以使用 javadoc 命令

代码注释

  • 单行://
  • 多行:/* … */

地标注释

  • // TODO:此处由待处理任务,或未完成的代码
  • // FIXME:此处代码是错误的,需要修正
  • // XXX:此处代码已经完成,但是实现的方法还有待商讨

排版

空行

  • 类声明和接口之间保留两个空行
  • 两个方法之间保留一个空行
  • 方法的第一条语句之前保留一个空行
  • 代码注释(尾端注释除外)之前保留一个空行
  • 一个方法内的两个逻辑段之间保留一个空行

空格

  • 赋值符号 = 前后各一个空格

    • 例如

      1
      a = b;
  • 所有二元运算符有应该使用空格与操作数分开

    • 例如

      1
      a = b + c;
  • 一元操作符(负号、自增、自减等)与操作数之间没有空格

    • 例如

      1
      2
      a++;
      --b;
  • 左小括号 ( 之后,右小括号 ) 之前不能有空格

  • 左大括号 { 之前应有一个空格

    • 例如

      1
      2
      3
      public static void main(String[] args) {

      }
  • 方法参数列表左小括号 ( 之前没有空格,右小括号 ) 之后有一个空格

    • 例如

      1
      2
      3
      public static void test(int a) {

      }
  • 关键字之后紧跟着左小括号 ( ,关键字之后应该有一个空格

    • 例如

      1
      2
      3
      while (1) {

      }

缩进

  • 通常将4个空格作为缩进排版的一个单位

  • 一般默认一个制表符(Tab)等于8个空格

  • 不同 IDE 工具制表符与空格对应个数可能不同,IDEA 中默认一个制表符对应4个空格

  • 方法、Lambda、控制语句等包含大括号 “ {} ” 的代码块中,代码块的内容相对于首行缩进一个制表符(Tab)

    • 例如

      1
      2
      3
      4
      5
      public class Date {
      public void time() {
      int year = super.getYear() + 1900;
      }
      }
  • if 语句中条件表达式的断行,新的一行应相对于上一行缩进两个指标都(Tab),再往后的断行应与第一次断行对齐

    • 例如

      1
      2
      3
      4
      5
      if ((a == b)
      || (c > d) && (e != f)
      && (g <= h)) {

      }

断行

  • 一行代码最好不要超过80个字符
  • 断行规范
    • 在一个逗号后断开
    • 在一个操作符前断开,要选择较高级别的运算符
    • 新的一行应相对于上一行索引两个制表符

其他规范

  • 声明变量的时候最好一行声明一个

  • 左大括号(“ { ”)位于声明语句同行的末尾,右大括号(“ } ”)另起一行,与相对应声明语句对齐;除非是一个空语句右大括号(“ } ”)应紧跟左大括号(“ { ”)之后

    • 例如

      1
      2
      3
      4
      5
      6
      7
      public static void main(String[] args) {
      while (1) {

      }
      }

      public static void setString() {}
  • 每行最多包含一条语句

    • 例如

      1
      2
      3
      4
      5
      a++;
      b--;

      // 不推荐
      a++; b--;
  • if、for 等控制语句在只有一行代码的情况下最好不要省略两个大括号

JAVA基础

JAVA基础语法

  • 对象:类的一个实例,有状态和行为。例如:狗是一个对象,它的状态有颜色、名字、品种,行为有叫、吃、摇尾巴
  • 类:类是一个模板,描述一类对象的行为和状态
  • 方法:方法是行为,一个类可以有很多方法。逻辑运算以及所有动作都是在方法中完成的
  • 实例变量:每个对象都有独特的实例变量,对象的状态由这些实例变量的值决定

第一个JAVA程序

1
2
3
4
5
public class Test {
public static void main(String[] args) {
System.out.println("Hello World!");
}
}
  • public:访问修饰符
  • static:关键字
  • void:返回类型
  • main:方法名
  • **String[]**:String类
  • args:字符串数组

JAVA标识符

  • 以字母、美元符($)、下划线(_)开始
  • 首字母后可以是字母、美元符($)、下划线(_)或数字
  • 关键字不能用作标识符
  • 区分大小写

类和对象

  • 对象:类的一个实例,有状态和行为。例如:狗是一个对象,它的状态有颜色、名字、品种,行为有叫、吃、摇尾巴
  • 类:类是一个模板,描述一类对象的行为和状态

JAVA中的类

类可以看成是创建 Java 对象的模板

创建一个简单的类来理解下 Java 中类的定义:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
public class Dog {
String breed;
int size;
String colour;
int age;

void eat() {
}

void run() {
}

void sleep(){
}

void name(){
}
}

一个类可以包含以下类型变量:

  • 局部变量:在方法、构造方法或语句块中定义的变量为局部变量。变量声明和初始化都是在方法中,方法结束后,变量会自动销毁
  • 成员变量:成员变量是定义在类中,方法体之外的变量。这种变量在创建对象的时候实例化。成员变量可以被类中方法、构造方法和特定类的语句块访问
  • 类变量:类变量也声明在类中,方法体之外,但必须声明static类型

构造方法

  • 每个类都有构造方法
  • 如果没有显式的为类定义构造方法,编译器会为该类提供一个默认的构造方法
  • 创建一个对象的时候,至少要调用一个构造方法
  • 构造方法的名称必须与类同名,一个类可以有多个构造方法
1
2
3
4
5
6
7
8
public class Puppy{
public Puppy(){
}

public Puppy(String name){
// 这个构造器仅有一个参数:name
}
}

创建对象

  • 步骤:
    1. 声明:声明一个对象,包括对象名称和对象类型
    2. 实例化:用关键字 new 创建一个对象
    3. 初始化:使用 new 创建对象时,会调用构造方法初始化对象
1
2
3
4
5
6
7
8
9
10
public class Object {
public Object(String name) {
System.out.println("name:" + name);
}

public static void main(String[] args) {
// 创建一个Object对象
Object myObject = new Object("Tony");
}
}

结果:

1
name:Tony

访问实例变量和方法

1
2
3
4
5
6
/* 实例化对象 */
Object referenceVariable = new Constructor();
/* 访问类中的变量 */
referenceVariable.variableName;
/* 访问类中的方法 */
referenceVariable.methodName();

实例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
public class Puppy{
int puppyAge;
public Puppy(String name){
// 这个构造器仅有一个参数:name
System.out.println("小狗的名字是 : " + name );
}

public void setAge( int age ){
puppyAge = age;
}

public int getAge( ){
System.out.println("小狗的年龄为 : " + puppyAge );
return puppyAge;
}

public static void main(String[] args){
/* 创建对象 */
Puppy myPuppy = new Puppy( "tommy" );
/* 通过方法来设定age */
myPuppy.setAge( 2 );
/* 调用另一个方法获取age */
myPuppy.getAge( );
/*你也可以像下面这样访问成员变量 */
System.out.println("变量值 : " + myPuppy.puppyAge );
}
}

结果:

1
2
3
小狗的名字是 : tommy
小狗的年龄为 : 2
变量值 : 2

源文件声明规则

  • 一个源文件只能有一个public类
  • 一个源文件可以有多个非public类
  • 源文件的名称应该和 public 类的类名保持一致
  • 如果一个类定义在某个包中,那么 package 语句应该在源文件的首行
  • 如果源文件包含 import 语句,那么应该放在 package 语句和类定义之间;如果没有 package 语句,那么 import 语句应该在源文件中最前面
  • import 语句和 package 语句对源文件中定义的所有类都有效
  • 在同一源文件中,不能给不同的类不同的包声明

包主要用来对类和接口进行分类。当开发 Java 程序时,可能编写成百上千的类,因此很有必要对类和接口进行分类

import语句

  • 在 Java 中,如果给出一个完整的限定名,包括包名、类名,那么 Java 编译器就可以很容易地定位到源代码或者类
  • import 语句就是用来提供一个合理的路径,使得编译器可以找到某个类

下面的命令行将会命令编译器载入 java_installation/java/io 路径下的所有类

1
import java.io.*;

实践一下

  • 创建两个类:Employee和EmployeeTest
  • 程序都是从main方法开始执行。为了能运行这个程序,必须包含main方法并且创建一个实例对象
  • EmployeeTest类,该类实例化2个 Employee 类的实例,并调用方法设置变量的值
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
import java.io.*;

public class Employee {
String name; // 名字
int age; // 年龄
String designation; // 职位
int salary; // 薪资
// Employee类的构造器
public Employee(String name) {
this.name = name;
}
// 设置age值
public void empAge(int empAge) {
age = empAge;
}
// 设置designation值
public void empDesignation(String empDesignation) {
designation = empDesignation;
}
// 设置salary值
public void empSalary(int empSalary) {
salary = empSalary;
}
public void printEmployee() {
System.out.println("姓名:" + name);
System.out.println("年龄:" + age);
System.out.println("职位:" + designation);
System.out.println("薪资:" + salary);
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
import java.io.*;

public class EmployeeTest {
public static void main(String[] args) {
/* 使用构造器构造两个对象 */
Employee empOne = new Employee("One");
Employee empTwo = new Employee("Two");
// 调用这两个对象的成员方法
empOne.empAge(30);
empOne.empDesignation("快秃完的程序员");
empOne.empSalary(300000);
empOne.printEmployee();
empTwo.empAge(21);
empTwo.empDesignation("刚毕业头发茂盛的程序员");
empTwo.empSalary(10000);
empTwo.printEmployee();
}
}
1
2
3
4
5
6
7
8
姓名:One
年龄:30
职位:快秃完的程序员
薪资:300000
姓名:Two
年龄:21
职位:刚毕业头发茂盛的程序员
薪资:10000

基本数据类型

整型

byte、short、int、long

  • byte
    • byte 数据类型是8位、有符号的,以二进制补码表示的整数
    • 默认值是0
    • byte 类型用在大型数组中节约空间,主要代替整数,因为 byte 变量占用的空间只有 int 类型的四分之一
  • short
    • short 数据类型是 16 位、有符号的以二进制补码表示的整数
    • short 数据类型也可以像 byte 那样节省空间。一个short变量是int型变量所占空间的二分之一
    • 默认值是0
  • int
    • int 数据类型是32位、有符号的以二进制补码表示的整数
    • 一般地整型变量默认为 int 类型
    • 默认值是0
  • long
    • long 数据类型是 64 位、有符号的以二进制补码表示的整数

    • 这种类型主要使用在需要比较大整数的系统上

    • 默认值是 0L

    • 声明

      1
      2
      long var1 = 16L;
      long var2 = 16l;

浮点型

float、double

  • float
    • float 数据类型是单精度、32位、符合 IEEE 754 标准的浮点数
    • float 在储存大型浮点数组的时候可节省内存空间
    • 默认值是 0.0f
    • 浮点数不能用来表示精确的值,如货币
    • 声明的时候要在数值后家 F 或 f
  • double
    • double 数据类型是双精度、64 位、符合 IEEE 754 标准的浮点数
    • 浮点数的默认类型为 double 类型
    • double 类型同样不能表示精确的值,如货币
    • 默认值是 0.0d
    • 声明是数值后可以加上 D 或 d

布尔型

boolean

  • boolean
    • boolean 数据类型表示一位的信息
    • 只有两个取值:true 和 false
    • 这种类型只作为一种标志来记录 true/false 情况
    • 默认值是 false

字符型

char

  • char

    • char 类型是一个单一的 16 位 Unicode 字符
    • char 数据类型可以储存任何字符
    • 声明时字符常量必须是用单引号(“ ‘’ ”)括起来的单个字符
  • 转义字符

数值表示方式

进制数值

  • 二进制数:以 0b 或 0B 为前缀
  • 八进制数:以 0 为前缀
  • 十六进制数:以 0x 或 0X 为前缀
  • 0 均为数字 0

指数

  • 用 e 或 E 表示幂

  • 幂前为底数,幂后为指数

  • e2 表示10的平方

  • 例如

    1
    double myMoney = 3.36e2;

引用类型

  • 在Java中,引用类型的变量非常类似于 C/C++ 的指针。引用类型指向一个对象,指向对象的变量是引用变量。这些变量在声明时被指定为一个特定的类型
  • 对象、数组都是引用数据类型
  • 所有引用类型的默认值都是null
  • 一个引用变量可以用来引用任何与之兼容的类型

如:

1
Employee empOne = new Employee("One");

引用类型比较

  • Java 引用类型比较时,有 “ == ” 和 “ equals ” 两种方法
  • “ == ” 比较的是两个引用是否指向同一个对象
  • “ equals ” 比较的是对象内容是否相同
  • 在枚举类型中 “ == ” 和 “ equals ” 是一样的,都是比较两个引用是否指向同一个实例,枚举类中每个枚举常量无论怎样都只有一个实例

常量

  • 常量在程序运行时是不能被修改的

  • Java 中使用 final 关键字来修饰常量

    1
    final double PI = 3.14159;
  • 通常使用大写字母表示常量

  • 字符串常量和字符常量都可以包含任何Unicode字符

自动类型转换

  • 转换从低级到高级

    1
    2
    3
    低  ----------------------------------------->  高
    byte -> short -> int -> long -> float -> double
    char -> int -> long -> float -> double
  • 数据类型转换必须满足:

    • 不能对boolean类型进行类型转换
    • 不能把对象类型转换成不相关类的对象
    • 在把容量大的类型转换为容量小的类型时必须使用强制类型转换
    • 转换过程中可能导致溢出或损失精度
    • 浮点数到整数的转换是通过舍弃小数得到,而不是四舍五入
  • 自动类型转换

    • 必须满足转换前的数据类型的位数要低于转换后的数据类型

    • 
      

    public class ZiDongLeiZhuan{
    public static void main(String[] args){
    char c1=’a’;//定义一个char类型
    int i1 = c1;//char自动类型转换为int
    System.out.println(“char自动类型转换为int后的值等于”+i1);
    char c2 = ‘A’;//定义一个char类型
    int i2 = c2+1;//char 类型和 int 类型计算
    System.out.println(“char类型和int计算后的值等于”+i2);
    }
    }

    1


    char自动类型转换为int后的值等于97
    char类型和int计算后的值等于66
    1
    2
    3
    4
    5
    6
    7
    8
    9

    - 强制类型转换

    - 条件是转换的数据类型必须是兼容的

    - 格式:

    ```java
    (type) value

      - type 是要强制类型转换后的数据类型
    
    • 
      

    public class QiangZhiZhuanHuan{
    public static void main(String[] args){
    int i1 = 123;
    byte b = (byte)i1;//强制类型转换为byte
    System.out.println(“int强制类型转换为byte后的值等于”+b);
    }
    }

    1


    int强制类型转换为byte后的值等于123
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16

    - 隐含强制类型转换

    - 整数的默认类型是 int
    - 小数默认是 double 类型浮点型,在定义 float 类型时必须在数字后面跟上 F 或者 f



    ### 变量类型

    - 所有的变量在使用前必须声明

    声明变量的基本格式:

    ```java
    type identifier [ = value][, identifier [= value] ...] ;

  • type 为 Java 数据类型

  • identifier 是变量名

Java语言支持的变量类型:

  • 类变量:独立于方法之外的变量,用 static 修饰
  • 实例变量:独立于方法之外的变量,不过没有 static 修饰
  • 局部变量:类的方法中的变量

局部变量

  • 局部变量声明在方法、构造方法或者语句块中
  • 局部变量在方法、构造方法、或者语句块被执行的时候创建,当它们执行完成后,变量将会被销毁
  • 访问修饰符不能用于局部变量
  • 局部变量只在声明它的方法、构造方法或者语句块中可见
  • 局部变量是在栈上分配的
  • 局部变量没有默认值,所以局部变量被声明后,必须经过初始化,才可以使用

实例变量

  • 实例变量声明在一个类中,但在方法、构造方法和语句块之外
  • 当一个对象被实例化之后,每个实例变量的值就跟着确定
  • 实例变量在对象创建的时候创建,在对象被销毁的时候销毁
  • 实例变量的值应该至少被一个方法、构造方法或者语句块引用,使得外部能够通过这些方式获取实例变量信息
  • 实例变量可以声明在使用前或者使用后
  • 访问修饰符可以修饰实例变量
  • 实例变量对于类中的方法、构造方法或者语句块是可见的。一般情况下应该把实例变量设为私有。通过使用访问修饰符可以使实例变量对子类可见
  • 实例变量具有默认值。数值型变量的默认值是0,布尔型变量的默认值是false,引用类型变量的默认值是null。变量的值可以在声明时指定,也可以在构造方法中指定
  • 实例变量可以直接通过变量名访问。但在静态方法以及其他类中,就应该使用完全限定名:ObejectReference.VariableName
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
public class Employee{
// 这个实例变量对子类可见
public String name;
// 私有变量,仅在该类可见
private double salary;
// 在构造器中对name赋值
public Employee (String empName) {
name = empName;
}
// 设定salary的值
public void setSalary(double empSal) {
salary = empSal;
}
// 打印信息
public void printEmp(){
System.out.println("名字 : " + name );
System.out.println("薪水 : " + salary);
}

public static void main(String[] args) {
Employee empOne = new Employee("RUNOOB");
empOne.setSalary(1000.0);
empOne.printEmp();
}
}
1
2
名字 : RUNOOB
薪水 : 1000.0

类变量(静态变量)

  • 在类中以 static 关键字声明,但必须在方法之外
  • 无论一个类创建了多少个对象,类只拥有类变量的一份拷贝
  • 静态变量除了被声明为常量外很少使用,静态变量是指声明为 public/private,final 和 static 类型的变量。静态变量初始化后不可改变
  • 静态变量储存在静态存储区。经常被声明为常量,很少单独使用 static 声明变量
  • 静态变量在第一次被访问时创建,在程序结束时销毁
  • 与实例变量具有相似的可见性。但为了对类的使用者可见,大多数静态变量声明为 public 类型
  • 默认值和实例变量相似。数值型变量默认值是 0,布尔型默认值是 false,引用类型默认值是 null。变量的值可以在声明的时候指定,也可以在构造方法中指定。此外,静态变量还可以在静态语句块中初始化
  • 静态变量可以通过:ClassName.VariableName的方式访问
  • 类变量被声明为 public static final 类型时,类变量名称一般建议使用大写字母。如果静态变量不是 public 和 final 类型,其命名方式与实例变量以及局部变量的命名方式一致
1
2
3
4
5
6
7
8
9
10
public class Employee {
// salary是静态的私有变量
private static double salary;
// DEPARTMENT是一个常量
public static final String DEPARTMENT = "开发人员";
public static void main(String[] args){
salary = 10000;
System.out.println(DEPARTMENT+"平均工资:"+salary);
}
}
1
开发人员平均工资:10000.0

修饰符

修饰符用来定义类、方法或变量,通常放在语句最前端

访问控制修饰符

  • default:在同一包内可见,不使用任何修饰符。使用对象:类、接口、变量、方法
  • private:在同一页内可见。适用对象:变量、方法。
  • public:对所有类可见。使用对象:类、接口、变量、方法
  • protected:对同一包内的类和所有子类可见。使用对象:变量、方法

默认访问修饰符–default

  • 对同一个包内的类可见。

  • 接口内的变量隐式声明为 public static final,接口内方法默认情况下访问权限为 public

1
2
3
4
5
/* 变量和类的声明都没有加修饰符 */
String version = "1.5.1";
boolean processOrder() {
return true;
}

私有访问修饰符–private

  • 方法、变量和构造方法只能被所属类访问
  • 类和接口不能声明为 private
  • 声明为私有访问类型的变量只能通过类中公共的 getter 方法被外部类访问
1
2
3
4
5
6
7
8
9
10
11
public class Logger {
private String format; // 私有变量,其他类不能直接得到和改变他的值
// 定义方法返回format值
public String getFormat() {
return this.format;
}
// 定义方法设置format值
public void setFormat(String format) {
this.format = format;
}
}

公有访问修饰符–public

  • 类、方法、构造方法和接口能被任何其他类访问
  • 如果几个相互访问的 public 类分布在不同的包中,则需要导入相应 public 类所在的包
  • 类所有的公有方法和变量都能被其子类继承
  • main() 方法必须设置为公有的

受保护的访问修饰符–protected

  • 子类与基类在同一包中:被声明为 protected 的变量、方法和构造器能被同一个包中的任何其他类访问

  • 子类与基类不在同一包中:在子类中,子类实例可以访问其从基类继承而来的 protected 方法,而不能访问基类实例的 protected 方法

  • protected 可以修饰数据成员,构造方法、方法成员,不能修饰类(除内部类)

  • 接口及接口的成员变量和成员方法不能声明为 protected

  • 子类能访问 protected 修饰符声明的方法和变量,这样就能保护不相关的类使用这些方法和变量

  • 下面的父类使用了 protected 访问修饰符,子类重写了父类的 openSpeaker() 方法

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    class AudioPlayer {
    protected boolean openSpeaker(Speaker sp) {
    // 实现细节
    }
    }

    class StreamingAudioPlayer extends AudioPlayer {
    protected boolean openSpeaker(Speaker sp) {
    // 实现细节
    }
    }
    • 如果把 openSpeaker() 方法声明为 private,那么除了 AudioPlayer 之外的类将不能访问该方法
    • 如果把 openSpeaker() 声明为 public,那么所有的类都能够访问该方法
    • 如果我们只想让该方法对其所在类的子类可见,则将该方法声明为 protected

访问控制和继承

  • 父类中声明为 public 的方法在子类中也必须为 public
  • 父类中声明为 protected 的方法在子类中要么声明为 protected,要么声明为 public,不能声明为 private
  • 父类中声明为 private 的方法,不能被子类继承

非访问修饰符

  • static 修饰符,用来修饰类方法和类变量
  • final修饰符,用来修饰类、方法和变量,final 修饰的类不能够被继承,修饰的方法不能被继承类重新定义,修饰的变量为常量,是不可修改的
  • abstract 修饰符,用来创建抽象类和抽象方法
  • synchronizedvolatile 修饰符,主要用于线程的编程

static 修饰符

  • 静态变量:static 关键字用来声明独立于对象的静态变量,无论一个类实例化多少对象,它的静态变量只有一份拷贝。静态变量也被称为类变量。局部变量不能被声明为static变量
  • 静态方法:static 关键字用来声明独立于对象的静态方法。静态方法不能使用类的非静态变量。静态方法从参数列表得到数据。然后计算这些数据

final 修饰符

  • final 变量

    • 变量一旦赋值后,不能被重新赋值,被 final 修饰的实例变量必须显式指定初始值
    • final 修饰符通常和 static 修饰符一起使用来创建类常量
  • final 方法

    • 父类中的 final 方法可以被子类继承,但是不能被子类重写
    • 声明 final 方法的主要目的是防止该方法的内容被修改
  • final 类

    • final 类不能被继承,没有类能够继承 final 类的任何特性

abstract 修饰符

  • 抽象类
    • 抽象类不能用来实例化对象,声明抽象类的唯一目的是为了将来对该类进行扩充
    • 一个类不能同时被 abstract 和 final 修饰
    • 如果一个类包含抽象方法,那么该类一定要声明为抽象类
    • 抽象类可以包含抽象方法和非抽象方法
  • 抽象方法
    • 抽象方法是一种没有任何实现的方法,该方法的具体实现由子类提供
    • 抽象方法不能被声明成 final 和 static
    • 任何继承抽象类的子类必须实现父类的所有抽象方法,除非该子类也是抽象类
    • 如果一个类包含若干个抽象方法,那么该类必须声明为抽象类
    • 抽象方法的声明以分号结尾,例如:public abstract sample();

synchronized 修饰符

  • synchronized 关键字声明的方法同一时间只能被一个线程访问
  • synchronized 修饰符可以应用于四个访问修饰符

transient 修饰符

  • 序列化的对象包含被 transient 修饰的实例变量时,java 虚拟机(JVM)跳过该特定的变量
  • 该修饰符包含在定义变量的语句中,用来预处理类和变量的数据类型

volatile 修饰符

  • volatile 修饰的成员变量在每次被线程访问时,都强制从共享内存中重新读取该成员变量的值
  • 当成员变量发生变化时,会强制线程将变化值回写到共享内存
  • 在任何时刻,两个不同的线程总是看到某个成员变量的同一个值

运算符

算数运算符

运算符 功能
+
-
*
/
% 取模
++ 自加1
自减1

关系运算符

运算符 功能
== 等于
!= 不等于
> 大于
< 小于
>= 大于等于
<= 小于等于

位运算符

运算符 功能
& 如果相对应位都是1,结果为1,否则为0
| 如果相对应位都是0,结果位0,否则为1
^ 如果相对应位值相同,结果为0,否则为1
~ 按位取反运算符翻转操作数的每一位
<< 按位左运算符,左操作数按位左移右操作数指定的位数
>> 按位右移运算符,左操作数按位右移右操作数指定的位数
>>> 按位右移补零操作符,左操作数的值按右操作数指定的位数右移,移动得到的空位以零填充

逻辑运算符

运算符 功能 说明
! 逻辑非 !a => a 为 true,结果为 false,a 为 false,结果为 true
& 逻辑与 a&b => a、b 均为 true,结果为 true,否则为 false
| 逻辑或 a|b => a、b 均为 false,结果为 false,否则为 true
&& 短路与 a&&b => a、b 均为 true,结果为 true,否则为 false;如果 a 为 false,则不计算 b,结果都为 false
|| 短路或 a||b => a、b 均为 false,结果为 false,否则为 true;如果 a 为 true,则不计算 b,结果都为true

赋值运算符

运算符 功能
= 赋值
+= A+=B => A=A+B
-= A-=B => A=A-B
*= A * =B => A=A*B
/= A/=B => A=A/B
(%)= A%=B => A=A%B
<<= A<<=B => A=A<<B
>>= A>>=B => A=A>>B
&= A&=B => A=A&B
^= A^=B => A=A^B
|= A|=B => A=A|B

条件运算符

1
variable x = (expression) ? value if true : value if false

instanceof 运算符

用于操作对象实例,检查该对象是否是一个特定类型(类类型或接口类型)
如果运算符左侧变量所指的对象,是操作符右侧类或接口(class/interface)的一个对象,那么结果为真

1
( Object reference variable ) instanceof  (class/interface type)

例:

1
2
String name = "James";
boolean result = name instanceof String; // 由于 name 是 String 类型,所以返回真

如果被比较的对象兼容于右侧类型,该运算符仍然返回 true:

1
2
3
4
5
6
7
8
9
10
11
class Vehicle {}

public class Car extends Vehicle {
public static void main(String[] args){
Vehicle a = new Car();
boolean result = a instanceof Car;
System.out.println( result);
}
}

// 返回结果为 true

循环

for 循环

1
2
3
for(初始化;布尔表达式;更新) {
// 代码块
}

while 循环

1
2
3
while(布尔表达式) {
// 代码块
}

do … while 循环

1
2
3
do {
// 代码块
} while(布尔表达式)

增强 for 循环

主要用于数组

1
2
3
for(声明语句:表达式) {
// 代码块
}
  • 声明语句:声明新的局部变量,该变量的类型必须和数组元素的类型匹配。其作用域限定在循环语句块,其值与此时数组元素的值相等

  • 表达式:表达式是要访问的数组名,或者是返回值为数组的方法

  • 实例:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    public class Test {
    public static void main(String[] args){
    int [] numbers = {10, 20, 30, 40, 50};

    for(int x : numbers ){
    System.out.print( x );
    System.out.print(",");
    }
    System.out.print("\n");
    String [] names ={"James", "Larry", "Tom", "Lacy"};
    for( String name : names ) {
    System.out.print( name );
    System.out.print(",");
    }
    }
    }
    1
    2
    10,20,30,40,50,
    James,Larry,Tom,Lacy,

continue 关键字

适用于任何循环控制结构中
让程序立刻跳转到下一次循环的迭代

break 关键字

主要用在循环语句或者 switch 语句中
用来跳出整个语句块
break 跳出最里层的循环,并且继续执行该循环下面的语句

条件语句

if 语句

1
2
3
if(布尔表达式) {
// 表达式为true时运行的代码块
}

if … else 语句

1
2
3
4
5
6
if(布尔表达式) {
// 表达式为true时运行的代码块
}
else {
// 表达式为false时运行的代码块
}

if … else if … else 语句

1
2
3
4
5
6
7
8
9
10
if(布尔表达式1) {
// 表达式1为true时运行的代码块
}
else if(布尔表达式) {
// 表达式2为true时运行的代码块
}
[...]
else {
// 表达式都为false时运行的代码块
}

switch 语句

1
2
3
4
5
6
7
8
9
10
11
switch(value) {
case value1:
// 语句
break;
case value2:
// 语句
break;
[...]
default: // 可选
// 语句
}
  • switch case 执行时,一定会先进行匹配,匹配成功返回当前 case 的值,再根据是否有 break,判断是否继续输出,或是跳出判断
  • 当遇到 break 语句时,switch 语句终止。程序跳转到 switch 语句后面的语句执行。case 语句不必须要包含 break 语句。如果没有 break 语句出现,程序会继续执行下一条 case 语句,直到出现 break 语句
  • 如果 case 语句块中没有 break 语句时,JVM 并不会顺序输出每一个 case 对应的返回值,而是继续匹配,匹配不成功则返回默认 case
  • 如果 case 语句块中没有 break 语句时,匹配成功后,从当前 case 开始,后续所有 case 的值都会输出
  • 如果当前匹配成功的 case 语句块没有 break 语句,则从当前 case 开始,后续所有 case 的值都会输出,如果后续的 case 语句块有 break 语句则会跳出判断

Number 和 Math 类

Number 类

所有的包装类(Integer、Long、Byte、Double、Float、Short)都是抽象类 Number 的子类

  • 这种由编译器特别支持的包装称为装箱
  • 当内置数据类型被当作对象使用的时候,编译器会把内置类型装箱为包装类
  • 编译器也可以把一个对象拆箱为内置类型
  • Number 类属于 java.lang 包

Math 类

包含了用于执行基本数学运算的属性和方法,如初等指数、对数、平方根和三角函数

Math 的方法都被定义为 static 形式,通过 Math 类可以在主函数中直接调用

实例:

1
2
3
4
5
6
7
8
9
10
11
public class Test {  
public static void main (String []args)
{
System.out.println("90 度的正弦值:" + Math.sin(Math.PI/2));
System.out.println("0度的余弦值:" + Math.cos(0));
System.out.println("60度的正切值:" + Math.tan(Math.PI/3));
System.out.println("1的反正切值: " + Math.atan(1));
System.out.println("π/2的角度值:" + Math.toDegrees(Math.PI/2));
System.out.println(Math.PI);
}
}
1
2
3
4
5
6
90 度的正弦值:1.0
0度的余弦值:1.0
60度的正切值:1.7320508075688767
1的反正切值: 0.7853981633974483
π/2的角度值:90.0
3.141592653589793

Number 和 Math 类方法

方法 功能
xxxValue() 将 Number 对象转换为xxx数据类型的值并返回
compareTo() 将number对象与参数比较
equals() 判断number对象是否与参数相等
valueOf() 返回一个 Number 对象指定的内置数据类型
toString() 以字符串形式返回值
parselInt() 将字符串解析为int类型
abs() 返回参数的绝对值
ceil() 返回大于等于( >= )给定参数的的最小整数,类型为双精度浮点型
floor() 返回小于等于(<=)给定参数的最大整数
rint() 返回与参数最接近的整数(返回值类型为double)
round() 它表示四舍五入,算法为 **Math.floor(x+0.5)**,即将原来的数字加上 0.5 后再向下取整,所以,Math.round(11.5) 的结果为12,Math.round(-11.5) 的结果为-11
min() 返回两个参数中的最小值
max() 返回两个参数中的最大值
exp() 返回自然数底数e的参数次方
log() 返回参数的自然数底数的对数值
pow() 返回第一个参数的第二个参数次方
sqrt() 求参数的算术平方根
sin() 求指定double类型参数的正弦值
cos() 求指定double类型参数的余弦值
tan() 求指定double类型参数的正切值
asin() 求指定double类型参数的反正弦值
acos() 求指定double类型参数的反余弦值
atan() 求指定double类型参数的反正切值
atan2() 将笛卡尔坐标转换为极坐标,并返回极坐标的角度值
toDegress() 将参数转化为角度
toRadians() 将角度转换为弧度
random() 返回一个随机数

Math 的 floor,round 和 ceil 方法

参数 Math.floor() Math.round() Math.ceil()
1.4 1 1 2
1.5 1 2 2
1.6 1 2 2
-1.4 2 -1 -1
-1.5 2 -1 -1
-1.6 2 -2 -1

Character 类

用于对单个字符进行操作

在对象中包装一个基本类型 char 的值

  • 实例:

    1
    2
    3
    4
    5
    6
    7
    char ch = 'a';

    // Unicode 字符表示形式
    char uniChar = '\u039A';

    // 字符数组
    char[] charArray ={ 'a', 'b', 'c', 'd', 'e' };
  • 为了解决需要使用对象,而不是内置数据类型的情况,java 语言为内置数据类型 char 提供了包装类 Character 类

  • Character 类提供了一系列方法来操纵字符。你可以使用 Character 的构造方法创建一个 Character 类对象

    1
    Character ch = new Character('a');
  • 在某些情况下,Java 编译器会自动创建一个 Character 对象

    • 例如,将一个 char 类型的参数传递给需要一个 Character 类型参数的方法时,那么编译器会自动地将char类型参数转换为Character 对象

    • 这种特征称为装箱,反过来称为拆箱

    • 实例:

      1
      2
      3
      4
      5
      6
      // 原始字符 'a' 装箱到 Character 对象 ch 中
      Character ch = 'a';

      // 原始字符 'x' 用 test 方法装箱
      // 返回拆箱的值到 'c'
      char c = test('x');

转义序列

转义序列 功能
\t 在文中该处插入一个tab键
\b 在文中该处插入一个后退键
\n 在文中该处换行
\r 在文中该处插入回车
\f 在文中该处插入换页符
\ ‘ 在文中该处插入单引号
\ “ 在文中该处插入双引号
\ \ 在文中该处插入反斜杠

Character 方法

方法 功能
isLetter() 是否是一个字母
isDigit() 是否是一个数字字符
isWhitespace() 是否是一个空白字符
isUpperCase() 是否是大写字母
isLowerCase() 是否是小写字母
toUpperCase() 指定字母的大写形式
toLowerCase() 指定字母的小写形式
toString() 返回字符的字符串形式,字符串的长度仅为1

字符串

用双引号括起来的多个字符

1
2
3
4
5
6
"Hello World!"
"你好世界"
"\u0048\u0057"
"\n\t"
"a" // 虽然只有一个字符,但这也是个字符串
"" // 空字符串
  • 空字符串不是 null ,空字符串是分配内存空间,null 是没有分配内存空间

不可变字符串

String

  • 创建字符串

    1
    String strName="str";
  • 用构造函数创建字符串

    1
    2
    3
    4
    5
    // 使用空字符串创建并初始化一个新的 String 对象
    String strName=new String();

    // 使用另外一个字符串创建并初始化一个新的 String 对象
    String staName = new String(String original);
    • String(StringBuffer buffer):使用可变字符串对象(StringBuffer)创建并初始化一个新的 String 对象

    • String(StringBuilder builder):使用可变字符串对象(StringBuilder)创建并初始化一个新的 String 对象

    • String(byte[] bytes):使用平台默认的字符集解码指定的 byte 数组,通过 byte 数组创建并初始化一个新的 String 对象

    • String(char[] value):通过字符数组创建并初始化一个新的 String 对象

    • String(char[] calue, int offset, int count):通过字符数组的子数组创建并初始化一个新的 String 对象

      • offset:子数组第一个字符的索引

      • count:指定子数组的长度

    • 实例

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15
      16
      17
      18
      19
      20
      // 创建字符串对象
      String str1 = new String();
      String str2 = new String("Hello World");
      String str3 = new String("\u0048\u0065\u006c\u006c\u006f");
      System.out.println("str2 = " + str2);
      System.out.println("str3 = " + str3);

      char[] chars = {'a', 'b', 'c', 'd', 'e', 'f', 'g'};
      // 通过字符数组创建字符串对象
      String str4 = new String(chars);
      // 通过子字符数组创建字符串对象
      String str5 = new String(chars, 1, 4);
      System.out.println("str4 = " + str4);
      System.out.println("str5 = " + str5);

      byte[] bytes = { 97, 98, 99 };
      // 通过 byte 数组创建字符串对象
      String str6 = new String(bytes);
      System.out.println("str6 = " + str6);
      System.out.println("str6 的长度:" + str6.length());
      1
      2
      3
      4
      5
      6
      str2 = Hello World
      str3 = Hello
      str4 = abcdefg
      str5 = bcde
      str6 = abc
      str6 的长度:3

字符串池

1
2
3
4
5
6
7
8
9
String str1 = "Hello";    // 字符串常量
String str2 = "Hello";
String str3 = new String("Hello"); // 使用 new 关键字创建
String str4 = new String("Hello");

System.out.printf("str1 == str2 : %b%n", str1 == str2);
System.out.printf("str3 == str4 : %b%n", str3 == str4);
System.out.printf("str1 == str3 : %b%n", str1 == str3);
System.out.printf("str2 == str3 : %b%n", str2 == str3);
1
2
3
4
str1 == str2 : true
str3 == str4 : false
str1 == str3 : false
str2 == str3 : false
image-20221227152916430

字符串长度

1
strName.length();

连接字符串

  • 使用 “ + ” 拼接

    • 优势:可以拼接任何类型的数据成字符串

      1
      str1 + str2;
  • 使用 contact(String str) 拼接

    • 是能拼接 String 型数据

      1
      str1.contact(str2);

创建格式化字符串

可以使用 printf() 和 format() 方法

  • String 类使用静态方法 format() 返回一个String 对象而不是 PrintStream 对象

  • String 类的静态方法 format() 能用来创建可复用的格式化字符串,而不仅仅是用于一次打印输出

  • 使用 printf() 方法

    1
    2
    3
    4
    System.out.printf("浮点型变量的值为 " +
    "%f, 整型变量的值为 " +
    " %d, 字符串变量的值为 " +
    "is %s", floatVar, intVar, stringVar);
  • 使用 format() 方法

    1
    2
    3
    4
    5
    String fs;
    fs = String.format("浮点型变量的值为 " +
    "%f, 整型变量的值为 " +
    " %d, 字符串变量的值为 " +
    " %s", floatVar, intVar, stringVar);

StringBuffer 和 StringBuilder 类

在对字符串进行修改时使用

StringBuffer 和 StringBuilder 类的对象能够被多次的修改,并且不产生新的未使用对象

image-20221227153506748
  • 在使用 StringBuffer 类时,每次都会对 StringBuffer 对象本身进行操作,而不是生成新的对象,所以如果需要对字符串进行修改推荐使用 StringBuffer

  • StringBulider 和 StringBuffer 之间的最大不同在于 StringBuilder 的方法不是线程安全的(不能同步访问)

  • 由于 StringBuilder 相较于 StringBuffer 有速度优势,所以多数情况下建议使用 StringBuilder 类

  • 实例

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    public class RunoobTest{
    public static void main(String args[]){
    StringBuilder sb = new StringBuilder(10);
    sb.append("Runoob..");
    System.out.println(sb);
    sb.append("!");
    System.out.println(sb);
    sb.insert(8, "Java");
    System.out.println(sb);
    sb.delete(5,8);
    System.out.println(sb);
    }
    }
    1
    2
    3
    4
    Runoob..
    Runoob..!
    Runoob..Java!
    RunooJava!
    image-20221227153645974
  • 在应用程序要求线程安全的情况下,则必须使用 StringBuffer 类

数组

声明数组

1
2
3
4
5
// 方法一(首选)
dataType[] arrayName;

// 方法二
dataType arrayName[];

数组初始化

  • 静态初始化

    • 例如

      1
      2
      int[] intArray = {1,2,3,4};
      String[] strArray = {'a','b','c','d'};
  • 动态初始化

    • 使用 new 操作符创建数组
    1
    new dataType[arraySize]
    • 用一条语句完成数组声明和创建
    1
    2
    3
    4
    dataType[] arrayName = new dataType[arraySize];

    // 也可以这样创建数组
    dataType[] arrayName = {value0,value2,[...,]valuen};

for-each 循环

可以在不使用下标的情况下遍历数组

1
2
3
4
for(type element: array)
{
System.out.println(element);
}

多维数组

多维数组可以看成是数组的数组

比如二维数组就是一个特殊的一维数组,其每一个元素都是一个一维数组

二维数组声明

1
2
3
4
5
6
7
8
// 方法一,最常用
dataType[][] arrayName;

// 方法二
dataType arrayName[][];

// 方法三
dataType[] arrayName[];

初始化

  • 静态初始化

    • 例如

      1
      int[][] intArray = { {1,2,3}, {4,5,6}, {7,8,9} };
  • 动态初始化

    • 使用 new 操作符初始化

      1
      new dataType[rowsNum][colsNum]
    • 用一条语句完成声明和初始化

      1
      dataType[][] arrayName = new dataType[rowsNum][colsNum];

Array 类

能方便地操作数组,它提供的所有方法都是静态的

  • 功能
    • 给数组赋值:通过 fill 方法
    • 对数组排序:通过 sort 方法,按升序
    • 比较数组:通过 equals 方法比较数组中元素值是否相等
    • 查找数组元素:通过 binarySearch 方法能对排序好的数组进行二分查找法操作

方法

方法 功能
public static int binarySearch(Object[] a, Object key) 用二分查找算法在给定数组中搜索给定值的对象(Byte,Int,double等)。数组在调用前必须排序好的。如果查找值包含在数组中,则返回搜索键的索引;否则返回 (-(插入点) - 1)
public static boolean equals(long[] a, long[] a2) 如果两个指定的 long 型数组彼此相等,则返回 true。如果两个数组包含相同数量的元素,并且两个数组中的所有相应元素对都是相等的,则认为这两个数组是相等的。换句话说,如果两个数组以相同顺序包含相同的元素,则两个数组是相等的。同样的方法适用于所有的其他基本数据类型(Byte,short,Int等)
public static void fill(int[] a, int val) 将指定的 int 值分配给指定 int 型数组指定范围中的每个元素。同样的方法适用于所有的其他基本数据类型(Byte,short,Int等)
public static void sort(Object[] a) 对指定对象数组根据其元素的自然顺序进行升序排列。同样的方法适用于所有的其他基本数据类型(Byte,short,Int等)