目录
- 基本语法操作
- 函数入口
- 打印输出
- 终端输入
- 数据类型
- 运算符优先级顺序
- 方法
- 方法的定义
- 方法重载
- 数组
- 数组的定义
- 初始化
- 二维数组
- 内存分配
- 区域划分
- 面向对象
- 封装
- private
- this
- 构造方法
- 类初始化
- static
- 继承
- super
- 重写
- final
- 多态
- abstract
- 接口 interface
- implements
- 内部类
- 局部内部类
- 匿名内部类
- 包
- 定义
- 导包
- 权限修饰符
- 常用类
- Scanner
- String
- StringBuffer
- StringBuilder
- Arrays
- 其他基本数据类型
- Date \& DateFormat
- calendar
- 异常
- 分类
- 线程
- 生命周期
- 多线程的实现
基本语法操作
函数入口
public class test {
public static void main(String[] args) {
System.out.println("Hello World!");
}
}
打印输出
System.out.println("Hello World");
终端输入
- 导包
java
import java.util.Scanner;
- 创建对象
java
Scanner sc = new Scanner(System.in);
- 输入
java
int a = sc.nextInt();
- 关闭
java
sc.close();
数据类型
- 整型
| 中文 | 英文 | 大小 | 数据范围 |
| —— | —– | —– | ———————- |
| 字节 | byte | 1字节 | $-2^7$ ~ $2^7-1$ |
| 短整型 | short | 2字节 | $-2^{15}$ ~ $2^{15}-1$ |
| 整数 | int | 4字节 | $-2^{31}$ ~ $2^{31}-1$ |
| 长整型 | long | 8字节 | $-2^{63}$ ~ $2^{63}-1$ |
整型字面量(如
1
)默认为int
类型
- 浮点型
| 中文 | 英文 | 大小 | 数据范围 |
| —— | —— | —– | ————————– |
| 单精度 | float | 4字节 | $-3.403E38$ ~ $3.403E38$ |
| 双精度 | double | 8字节 | $-1.798E308$ ~ $1.798E308$ |
浮点型字面量(如
1.0
)默认为double
类型
- 字符型
| 中文 | 英文 | 大小 | 数据范围 |
| —- | —- | —– | ——— |
| 字符 | char | 2字节 | 0 ~ 65535 |
- 布尔值
| 中文 | 英文 | 大小 | 数据范围 |
| —- | ——- | —– | ———- |
| 布尔 | boolean | 1字节 | true/false |
注意!
byte,short,char
相互之间补转换,他们参与运算首先转换为int类型
java
byte b1=3,b2=4,b;
b=b1+b2;
b=3+4;这段代码中
b1+b2
会报错,因为b1+b2
会自动转换为int
类型,而int
类型不能赋值给byte
类型,所以会报错
java
System.out.println('a'); // a
System.out.println('a'+1); // 9
System.out.println("hello"+'a'+1); // helloa1
System.out.println('a'+1+"hello"); // 98hello
System.out.println("5+5="+5+5); // 5+5=55
System.out.println(5+5+"=5+5"); // 10=5+5
运算符优先级顺序
| 优先级 | 描述 | 运算符 |
| —— | ———— | ————————- |
| 1 | 括号 | ()、[]
|
| 2 | 正负号 | +、-
|
| 3 | 自增自减,非 | ++、--、!
|
| 4 | 乘除,取余 | *、/、%
|
| 5 | 加减 | +、-
|
| 6 | 移位运算 | <<、>>、>>>
|
| 7 | 大小关系 | >、>=、<、<=
|
| 8 | 相等关系 | ==、!=
|
| 9 | 按位与 | &
|
| 10 | 按位异或 | ^
|
| 11 | 按位或 | \|
|
| 12 | 逻辑与 | &&
|
| 13 | 逻辑或 | \|\|
|
| 14 | 条件运算 | ?:
|
| 15 | 赋值运算 | =、+=、-=、*=、/=、%=
|
| 16 | 位赋值运算 | &=、\|=、<<=、>>=、>>>=
|
方法
方法的定义
修饰符 返回值类型 方法名(参数类型 参数名1,参数类型 参数名2…) {
函数体;
return 返回值;
}
方法重载
在同一个类中,允许存在一个以上的同名方法,只要它们的参数个数或者参数类型不同即可。
数组
数组的定义
数据类型[] 数组名;
数据类型 数组名[];
两种方式等价
初始化
Java中的数组必须先初始化,然后才能使用
初始化:就是为数组中的数组元素分配内存空间,并为每个数组元素赋值。
初始化分两种:
- 静态: 直接指定数组元素的初始值
int aaa[] = { 1, 2, 3 };
- 动态: 只指定数组长度
int[] bbb = new int[3];
二维数组
int[][] arr = new int[3][2];
由于不一定每个数组的长度都相同,可以用动态方法逐一定义
int[][] arr = new int[3][];
arr[0] = new int[2];
arr[1] = new int[3];
arr[2] = new int[4];
最简单明了的就是直接定义
int[][] arr = {{1,2,3},{4,6},{6}};
内存分配
区域划分
| 区域 | 说明 | 特点 |
| ————– | ——————- | —————————— |
| 栈 | 存储局部变量 | 出了作用域就会自动释放 |
| 堆 | 存储new
出来的东西 | 存放所有的对象实例以及数组 |
| 方法区 | (面向对象部分讲) | / |
| 本地方法区 | (和系统相关) | / |
| 寄存器 | (给CPU使用) | / |
对于对象(如数组), 实例在堆中生成, 使用的其实是引用, 引用在栈中生成
面向对象
类与对象的关系:类是对象的模板,对象是类的实例
- 类:是一组相关的属性和行为的集合 (模板)
- 对象:是该类事物的具体体现
类 学生
对象 班长就是一个对象
封装
- 好处:
- 提高安全性
- 提高复用性
- 提隐藏细节
- 原则:
- 将不需要对外提供的内容隐藏起来
- 仅对外提供公共访问方式
private
private
修饰的属性或方法,只能在本类中访问
一般私有变量都会提供get
和set
方法, 避免直接访问
this
this
代表当前对象的引用
方法被哪个对象调用,this就代表那个对象
构造方法
- 构造方法是一种特殊的方法,用来初始化对象
- 方法名与类名相同
- 无返回值, 无需注明类型, 无需
void
类初始化
Student s = new Student();
运行后, 内存中的变化如下:
- 加载
Student.class
文件进内存 - 在栈内存为
s
开辟空间 - 在堆内存为学生对象开辟空间
- 对学生对象的成员变量进行默认初始化
- 对学生对象的成员变量进行显式初始化
- 通过构造方法对学生对象的成员变量赋值
- 学生对象初始化完毕,把对象地址赋值给
s
变量
static
static
修饰的成员变量叫做静态变量
特点:
- 随着类的加载而加载
- 优先于对象存在
- 被类的所有对象共享
- 这也是我们判断是否使用静态关键字的条件
- 可以通过类名调用
注意:
- 在静态方法中是没有
this
关键字的 - 静态方法只能访问静态的成员变量和静态的成员方法
静态变量 和 成员变量 的区别:
- 所属不同
- 静态变量属于类,所以也称为为类变量
- 成员变量属于对象,所以也称为实例变量(对象变量)
- 内存中位置不同
- 静态变量存储于方法区的静态区
- 成员变量存储于堆内存
- 内存出现时间不同
- 静态变量随着类的加载而加载,随着类的消失而消失
- 成员变量随着对象的创建而存在,随着对象的消失而消失
- 调用不同
- 静态变量可以通过类名调用,也可以通过对象调用
- 成员变量只能通过对象名调用
继承
class 子类名 extends 父类名 {}
单独的这个类称为父类,基类或者超类;
这多个类可以称为子类或者派生类。
一个类只能有一个父类,不可以有多个父类。
但支持多层继承(继承体系)
只能继承父类所有非私有的成员(成员方法和成员变量)
super
super
关键字和this
关键字类似:
- this代表本类对应的引用。
- super代表父类存储空间的标识(可以理解为父类引用)
重写
方法重载(Overloading):在同一个类中,方法名相同但参数列表(参数类型、参数数量、参数顺序)不同的方法,被称为方法重载。方法重载允许改变方法的返回类型。
方法重写(Overriding):在子类中,有一个与父类中声明相同的方法(包括相同的方法名、相同的参数列表、相同的返回类型),被称为方法重写。方法重写不允许改变方法的返回类型。
final
final
关键字是最终的意思(不再变化)
- 修饰类,类不能被继承
- 修饰变量,变量就变成了常量,只能被赋值一次
- 修饰方法,方法不能被重写
多态
同一对象在不同情况下体现出来的不同形态
日常中看到猫, 叫”猫猫”
但是泛泛来说, 叫”动物”
前提:
- 有继承关系
- 有方法重写
- 有父类引用指向子类对象
成员访问特点:
- 成员变量:编译看左边,运行看左边
- 成员方法:编译看左边,运行看右边
- 静态方法:编译看左边,运行看左边
根据引用和实际对象的关系,有:
- 向上转型:
父 t = new 子();
- 向下转型:
子 s = (子)t;
向上转型是自动且安全的
向下转型需要强制, 而且要确保实际对象是子类对象
abstract
- 抽象类和抽象方法必须用
abstract
关键字修饰 abstract class 类名 {};
- 抽象类不一定有抽象方法,有抽象方法的类一定是抽象类
- 抽象类不能实例化
- 按照多态的方式,由具体的子类实例化。其实这也是多态的一种,抽象类多态。
- 抽象类的子类
- 要么是抽象类
- 要么重写抽象类中的所有抽象方法
抽象类的意义:
每个子类都有自己的特点, 作为父类的抽象类, 只需要声明抽象方法, 不需要实现, 由子类实现
简单来说, 抽象类就是为了继承而存在的, 就是希望你去重写它的方法abstract 关键字不能与以下关键字共存:
final
:final 关键字表示一个类不能被继承,而 abstract 关键字表示一个类是为了被继承而设计的。因此,abstract 和 final 是互斥的,不能同时用于一个类。private
:abstract 方法是为了被子类重写的,而 private 方法只能在类内部访问,子类无法访问到。因此,abstract 和 private 不能同时用于一个方法。static
:static 方法是属于类的,而不是属于类的实例的。abstract 方法需要被子类的实例重写,因此 abstract 和 static 不能同时用于一个方法。
接口 interface
接口是一种特殊的抽象类,用来描述类具备的功能,而不提供具体实现。
“类A实现接口B”,就意味着类A具备了接口B设计的方法
特点:
- 接口中的方法都只能是抽象方法(
public abstract
类型) - 接口中的成员变量只能是常量(
public static final
类型) - 不存在构造方法
和抽象类的区别:
- 一个类可以实现多个接口,但只能继承一个抽象类
- 接口之间可以多继承,而类只能单继承
interface 接口名 {
// 常量
public static final 数据类型 常量名 = 数据值;
// 抽象方法
public abstract 返回值类型 方法名(参数列表);
}
implements
implements
关键字用于实现接口
class 类名 implements 接口名 {
// 重写接口中的抽象方法
}
多继承的实现:
interface C extends A, B {
void showC();
}
内部类
定义在类或方法中的类,称为内部类
要调用必须先创建外部类对象,再创建内部类对象
class Outer {
public int num = 10;
class Inner {
public int num = 20;
public void show() {
int num = 30;
System.out.println(num);
System.out.println(this.num);
System.out.println(Outer.this.num);
}
}
}
class test {
public static void main(String[] args) {
Outer.Inner oi = new Outer().new Inner();
oi.show();
}
}
这里的
Outer.this.num
表示外部类的num
Outer.this
表示的是外部类Outer
的一个实例,而不是Outer
类本身最后的定义部分也能写成:
java
Outer o = new Outer();
Outer.Inner oi = o.new Inner();
oi.show();
局部内部类
定义在方法中的类,称为局部内部类
只能在当前方法中使用
注意:
局部变量用完就消失, 但局部对象还在, 所以局部内部类访问局部变量必须用final
修饰
局部内部类访问局部变量必须用final
修饰
匿名内部类
没有类名的内部类,称为匿名内部类(内部类的简化写法)
前提是得有个接口或者父类
new 类名或接口名() {
// 重写方法
}
本质是一个继承了该类或实现了该接口的子类对象
包
包就是文件夹,用于对类文件进行分类管理
定义
package 包名;
多级包定义:
package 包名1.包名2.包名3;
注意:
- package语句必须是程序的第一条可执行的代码
- package语句在一个java文件中只能有一个
- 如果没有package,默认表示无包名
导包
用import
关键字导入包, 不用每次都写全类名
package
和import
和class
的顺序是固定的:
必须是package
->import
->class
权限修饰符
| | public | protected | default | private |
| ———— | —— | ——— | ——- | ——- |
| 同一个类 | √ | √ | √ | √ |
| 同一个包 | √ | √ | √ | × |
| 不同包子类 | √ | √ | × | × |
| 不同包非子类 | √ | × | × | × |
常用类
Scanner
用于获取用户输入
import java.util.Scanner;
Scanner sc = new Scanner(System.in);
int a = sc.nextInt();
sc.close();
默认以空格为分隔符,可以使用
sc.useDelimiter("\n");
改为回车
String
String
是一个类,不是基本数据类型
字符串可以被看做是一个字符数组, 实质还是对象
FQA:
-
String s = new String(“hello”)
和String s = “hello”
的区别?前者创建了新的对象, 后者直接引用常量池中的对象
-
s1 == s2
结果怎么判断?==
比较的是引用,所以要看是否指向同一个对象 -
内容要怎么比较?
s1.equals(s2)
比较的是内容 -
字符串直接的加法发生了什么?
由于字符串常量是只读的, 所以加法的结果是创建一个新的对象(不取常量池)
常用的方法:
int length()
: 返回字符串的长度char charAt(int index)
: 返回指定索引处的字符int indexOf(int ch)
: 返回指定字符在此字符串中第一次出现处的索引String substring(int start, int end)
: 返回一个新的字符串,它是此字符串的一个子字符串boolean equals(Object obj)
: 将此字符串与指定对象进行比较boolean isEmpty()
: 当且仅当 length() 为 0 时返回 truechar[] toCharArray()
: 将此字符串转换为一个新的字符数组static String valueOf(int i)
: 返回 int 参数的字符串表示形式String concat(String str)
: 将指定字符串连接到此字符串的结尾String trim()
: 返回字符串的副本,忽略前导空白和尾部空白
StringBuffer
StringBuffer
弥补了String
的不可变性
StringBuffer
是线程安全的可变的字符序列,可以对字符串进行修改
构造方法:
StringBuffer()
: 构造一个其中不带字符的字符串缓冲区,其初始容量为 16 个字符StringBuffer(int capacity)
: 构造一个不带字符,但具有指定初始容量的字符串缓冲区StringBuffer(String str)
: 构造一个字符串缓冲区,并将其内容初始化为指定的字符串内容
常用的方法:
StringBuffer append(数据类型 b)
: 将任意类型数据添加到字符串缓冲区StringBuffer insert(int offset, 数据类型 b)
: 在指定位置插入数据StringBuffer delete(int start, int end)
: 删除指定位置的字符StringBuffer replace(int start, int end, String str)
: 替换指定位置的字符串StringBuffer reverse()
: 反转字符串String substring(int start, int end)
: 返回一个新的字符串,它是此字符串的一个子字符串
StringBuilder
StringBuilder
和StringBuffer
类似,但是StringBuilder
是非线程安全的
StringBuilder
的方法和StringBuffer
一样
如果要操作的字符串是多线程的,建议使用
StringBuffer
如果是单线程的,建议使用StringBuilder
Arrays
Arrays
类是java.util
包下的一个工具类,提供了一系列静态方法来操作数组
import java.util.Arrays;
常用的方法:
static String toString(数组)
: 返回指定数组的内容的字符串表示形式static void sort(数组)
: 对指定的数组按数字升序进行排序static int binarySearch(数组, 数据)
: 使用二分搜索算法在给定数组中搜索指定值的索引
int[] arr = { 1, 4, 2, 8, 5, 7 };
Arrays.sort(arr);
System.out.println(Arrays.toString(arr)); // [1, 2, 4, 5, 7, 8]
System.out.println(Arrays.binarySearch(arr, 4)); // 3
其他基本数据类型
Integer
Integer i5 = 127;
Integer i6 = 127;
System.out.println(i5 == i6); // true
System.out.println(i5.equals(i6)); // true
Integer i7 = 128;
Integer i8 = 128;
System.out.println(i7 == i8); // false
System.out.println(i7.equals(i8)); // true
和
String
类似,Integer
也有常量池, 但是范围是-128
到127
超过范围就会创建新的对象
Date & DateFormat
Date
类表示特定的瞬间,精确到毫秒
import java.util.Date;
Date date = new Date();
System.out.println(date); // Thu May 24 15:36:10 CST 2024
System.out.println(date.getTime()); // 1690244970000
DateFormat
类用于格式化与解析日期
import java.util.Date;
import java.text.DateFormat;
Date date1 = new Date();
DateFormat df = DateFormat.getDateInstance();
System.out.println(df.format(date1)); // 2024-5-24
Date date2 = df.parse("2024年6月5日");
System.out.println(df.format(date2)); // 2024-5-24
calendar
Calendar
类是一个抽象类,提供了很多操作日期的方法
import java.util.Calendar;
Calendar c = Calendar.getInstance();
System.out.println(c.get(Calendar.YEAR)); // 2024
System.out.println(c.get(Calendar.MONTH)); // 4
System.out.println(c.get(Calendar.DATE)); // 24
异常
- Throwable
- Error
- Exception
- RuntimeException
- IOException
- ClassNotFoundException
- SQLException
分类
两大类
- 编译时异常
- 编译时异常是在编译阶段会出现的异常,也就是说在编译时,就会检查出这类异常
- 如
FileNotFoundException
、IOException
等 - 运行时异常
- 所有
RuntimeException
类及其子类的实例被称为运行时异常 - 如
NullPointerException
、ArrayIndexOutOfBoundsException
等
线程
生命周期
- 新建状态
- 就绪状态
- 运行状态
- 阻塞状态
- 死亡状态
多线程的实现
class MyThread extends Thread {
public void run() {
for (int i = 0; i < 100; i++) {
System.out.println(Thread.currentThread().getName() + " " + i);
}
}
}
public class test {
public static void main(String[] args) {
MyThread mt1 = new MyThread();
MyThread mt2 = new MyThread();
mt1.start();
mt2.start();
// 打印优先级
System.out.println(mt1.getPriority());
System.out.println(mt2.getPriority());
}
}
优先级为1~10, 默认为5, 10最高