参考:10分钟速成Java、JavaGuidePro、JAVA基础——接口等
话说真是忘了太彻底了,和新学一样
基础中的基础
长期支持的java版本:8、11、17、21
JDK - java development kit
包含:代码编译器javac、运行环境jre、其他工具
编译器负责将java源文件编译为字节码文件(.class)给jre执行
jre中的jvm将字节码转换为不同设备上的机器码并执行
.java文件由类构成,类名应与文件同名,如下固定格式设置 main 方法
1
2
3
4
5
class HelloWorld {
public static void main(String[] args) {
System.out.println("Hello,World!");
}
}
(String[] args)
:参数列表,接收一个字符串数组,用于传递命令行参数。static
:静态修饰符,表示该方法属于类本身,而非类的实例。因此,调用时无需创建对象。
在终端中:
用 javac HelloWorld.java
编译
得到字节文件 HelloWorld.class
用 java+类名 的方式运行文件:java HelloWorld
有关强制类型转换
1
System.Out.println((double)10 / 3)
变量
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
int num = 10;
double num2;
num2 = 20.2;
final int num3 = 30; //变量不可修改
byte num4 = 127;//8位
short num5 = 32767;//16位
long num6 = Long.MAX_VALUE;//64位 最大9,223,372,036,854,775,807
float num7 = 100.3F;//32位单精度浮点
char char1 = 'a';//字符型
boolean b = true;//布尔
//字符串
String string1 = "abc";
String string2 = new String("qwe");//构造函数的方式声明
//字符串可以通过 + 连接 .length()方法获取字符串长度
String str3 = "abc" + "-" + "qwe" + "-" + "666";
System.out.println(str3.indexOf("qwe"));//通过indexOf查找(子串)的位置(输出4-当然从零开始的下标)
//replace("qwe", "rty")替换子串
System.out.println(String.join("~",str3.split("-")));
//通过join()连接由split分割的str3 分割条件为- 连接之间添加~
条件判断和循环
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
31
System.out.println(b ? 1 : 2);//三目运算
if (num4 >= 100) {
System.out.println("6");
} else {
System.out.println("666");
}
switch (num) {
case 1:
System.out.println("666");
break;
default:
System.out.println("66");
}
for (int i = 0; i < 10 ; i++) {
System.out.println(i);
}
int i =0;
while (i<10){
System.out.println("6666");
i++;
}
do {
System.out.println("6666");
i++;
}while (i<10);
数组
1
2
3
4
5
int [] aa = {1, 2, 3};//完整int [] aa = new int[3] {1, 2, 3};
int [] bb = new int[3];//元素个数声明后无法更改
System.out.println(Arrays.toString(aa));//注意输出需转换
System.out.println(aa[0]);//通过索引访问
int [] cc = Arrays.copyOf(aa, 5);//复制数组,改变长度
类 — 对一类事物的抽象
具体的:实例对象
抽象的:类
面向对象的三步操作:封装 继承 多态
- 封装(Encapsulation) 是指将数据(属性)和操作数据的方法(行为)绑定在一起,并通过访问控制修饰符(如private、public)限制外部对数据的直接访问。封装的核心目标是隐藏对象的内部实现细节,仅对外提供必要的接口,从而提高代码的安全性、可维护性和复用性。
- 继承是 extends
- 多态是一个方法多个效果
创造对象
在 Java 中,类型 名称 = new 对象;
这种写法是创建和使用对象的核心方式
- 左边:声明一个引用变量(reference variable),它存储的是对象在内存中的地址(类似指针),而不是对象本身。
- 右边:在堆内存中创建一个实际的对象实例,并返回该对象的内存地址。
以下是一个综合例子
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
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
package org.example;
import java.lang.reflect.Array;
import java.util.Arrays;
public class Main {
public static void main(String[] args) {
Animal a1 = new Animal("dog",10);//new Animal()创建实例对象
a1.print();//调用
System.out.println(a1.getName());//通过getter函数获取名字
a1.setName("cat");//setter函数更新名字
System.out.println(a1.getName());//获取名字
Cat c1 = new Cat("圆头耄耋", 6 ,"黄");//new了子类对象(创建一个 Cat 类的对象实例,并调用其构造方法进行初始化)
a1.say();
c1.say();//这就是多态
a1.eat();
c1.eat("欧润橘");//这也是多态
}
}
class Animal { //class+类名创建类
private String name = "66";//默认值,private时,外部获取会报错
int age = 5;
public Animal (String name, int age) { //与类同名的构造方法,进行值的接收
this.name = name;
this.age = age;//this代表实例
}
void print () {
System.out.println(name + age);
}
public String getName () {//getter函数,方便外部获取值
return this.name;
}
public void setName (String newValue1) { //setter函数
this.name = newValue1;//更改name值
}
public void eat () {//更多功能
System.out.println("您的"+this.name+"正在吃屎!");
}
public void say () {
System.out.println("大狗叫");
}
}
class Cat extends Animal {//子类,继承。故意保留了一部分Animal的味道让你知道我使用了继承。
private String color = "";//Cat 类的私有成员变量
public Cat(String name, int age, String color) {//构造,添加了新的熟悉color
super(name, age);//super 关键字:显式调用父类 Animal 的构造方法,将参数传递给父类初始化。
this.color = color;
}
@Override//重写方法(多态方式一)多态
public void say() {
System.out.println(color+"色"+"哈基咪");
}
public void eat(String food) {//重载(多态方法二)与原方法同名但参数不同
System.out.println("您的"+ this.getName() +"正在吃"+food+"!");//使用父类方法
}
}
更进一步
接口 - interface
巴拉巴拉:
Java接口是一系列方法的声明,是一些方法特征的集合,一个接口只有方法的特征没有方法的实现,因此这些方法可以在不同的地方被不同的类实现,而这些实现可以具有不同的行为(功能)
有接口是因为Java不像C++一样支持多继承,但是接口在实际中更多的作用是制定标准.
一个类可以实现不止一个接口。
一个接口可以继承于另一个接口,或者另一些接口,接口也可以继承,并且可以多继承。
一个类如果要实现某个接口的话,那么它必须要实现这个接口中的所有方法。
接口中所有的方法都是抽象的和public的,所有的属性都是public,static,final的。
接口也可以用来实现解耦。
解耦:抽象层次上的依赖关系使得各个组件之间的耦合度降低,从而更容易地进行修改和替换。
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
public class test2 {
interface i1{
final int a = 10;
void display();
}
static class tell_666 implements i1 {//静态类
@Override
public void display() {
System.out.println("666");
}
public void display2() {
System.out.println("六百六十六");
}
}
public static void main (String[] args){
tell_666 t = new tell_666();//具体类类型引用
i1 t2 = new tell_666();//注意! 接口类型引用,只能访问 i1 接口中声明的方法,无法直接访问 tell_666 类特有的方法
t.display();
((tell_666)t2).display2();//此时需要强制类型转换才能调用YouPan类特有的方法
System.out.println(i1.a);//访问接口i1的常量a
}
}
回调函数 - Callback
在 Java 中,回调函数是一种通过接口实现的编程模式,允许将一个方法作为参数传递给另一个方法,在某个事件发生或条件满足时被调用。
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
31
32
33
34
35
36
37
38
39
40
41
42
43
package org.example;
interface Callback {// 回调接口
void onComplete(String result); // 回调方法
}
class Task {
public void execute(Callback callback) {
// 模拟耗时操作
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
// 操作完成后调用回调
String result = "任务完成";
callback.onComplete(result);
}
}
public class Main {
public static void main(String[] args) {
Task task = new Task();
// 实现回调接口(匿名内部类)
task.execute(/*
new Callback() { //这里传递的是一个匿名内部类对象,它实现了Callback接口。
@Override
public void onComplete(String result) {
System.out.println("收到结果: " + result);
}
} */
//下面是Lambda 表达式简化版,用于简化函数式接口(只有一个抽象方法的接口)的实现
result -> {
System.out.println("收到结果: " + result);
}
);//Lambda 的本质:自动创建一个实现了Callback接口的匿名类实例,并将 Lambda 体作为接口方法的实现。
System.out.println("主线程继续执行...");
}
}
Java 的回调机制看似复杂,实则是为了在类型安全和灵活性之间取得平衡。
回调允许代码在运行时动态决定执行哪个方法,而不是在编译时硬编码。
在处理耗时操作(如网络请求、文件读写)时,回调避免了线程阻塞。
回调是事件监听模式的基础,广泛用于 GUI、消息队列等场景。
一个综合例子——短信服务商
一个典型的适配器模式(Adapter Pattern) 示例,核心目的是解决 “不同接口的类无法直接兼容” 的问题。而且更灵活,修改更方便。
简单说,适配器就像 “转换插头”—— 不同国家的插座(第三方服务)接口不同,但通过转换插头(适配器),都能在同一台设备(系统)上使用。
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
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
package org.example;
// 短信服务接口
interface CommonSmsServiceInterface {
void sendLoginSMS(String phoneNumbers, String message);
}
// 阿里云短信实现-不可修改
class AliyunSMS {
void sendLoginSMS(String phoneNumbers, String message) {
System.out.println("【阿里云】登录短信发送给"+phoneNumbers+":"+message);
}
}
// 腾讯云短信实现-不可修改
class TencentSMS {
void sendLoginSMS(String message, String phoneNumbers) {
System.out.println("【腾讯云】登录短信发送给"+phoneNumbers+":"+message);
}
}//(阿里云、腾讯云)提供的接口参数顺序不一样
// 阿里云短信服务适配器
class AliyunSmsServiceInterfaceImpl implements CommonSmsServiceInterface {
private final AliyunSMS aliyunSMS;// 持有第三方服务的引用
public AliyunSmsServiceInterfaceImpl(AliyunSMS aliyunSMS) {//// 构造方法传入阿里云实例
this.aliyunSMS = aliyunSMS;
}
@Override public void sendLoginSMS(String phoneNumbers, String message) {
aliyunSMS.sendLoginSMS(phoneNumbers, message);// 实现统一接口:直接调用阿里云方法(参数顺序一致)
}
}
// 腾讯云短信服务适配器
class TencentSmsServiceInterfaceImpl implements CommonSmsServiceInterface {
private final TencentSMS tencentSMS;
public TencentSmsServiceInterfaceImpl(TencentSMS tencentSMS) {
this.tencentSMS = tencentSMS;
}
@Override public void sendLoginSMS(String phoneNumbers, String message) {
tencentSMS.sendLoginSMS(message, phoneNumbers);// 这里交换了参数
}
}//适配器的作用是 “包装” 第三方服务,让它们符合 CommonSmsServiceInterface 标准。
public class test20 {
public static void main(String[] args) {
// 使用阿里云短信服务
CommonSmsServiceInterface smsService = new AliyunSmsServiceInterfaceImpl(new AliyunSMS());
smsService.sendLoginSMS("13800138000", "您的验证码是1234");
// 切换到腾讯云(只需换适配器,调用代码不变)
TencentSMS tencentSMS = new TencentSMS();//1
smsService = new TencentSmsServiceInterfaceImpl(tencentSMS);//2,到时候只需修改这两句和适配器。
smsService.sendLoginSMS("13800138000", "您的验证码是5678");
}
}//假设有一百个地方用到这些代码,那么更换短信服务商就变得非常简单了。
适配器模式的核心价值
- 解耦:系统代码只依赖统一接口,不依赖具体服务商。
- 兼容:让接口不兼容的类可以一起工作(比如腾讯云的参数顺序问题)。
- 灵活:切换服务商时,调用代码无需修改(符合 “开闭原则”)。
持有(Holding) 是一种对象间的关系,指一个对象(持有者)内部包含对另一个对象(被持有者)的引用。这种关系通过成员变量实现,使得持有者可以直接访问被持有者的方法和属性。
持有是has-A 继承是is-A
- 避免类爆炸:如果通过继承修改接口,每个第三方服务都需要创建子类,导致类数量膨胀。
- 更灵活:持有关系允许在运行时动态更换被持有者(如切换不同的短信服务商)。
适配器类 AliyunSmsServiceInterfaceImpl 通过成员变量 private final AliyunSMS aliyunSMS 持有阿里云服务的引用
Lambda
Lambda 表达式本质上是一个匿名函数,它允许你将函数作为参数传递给方法,或者将代码作为数据进行处理。
基本语法如下:
1
2
3
(parameters) -> expression
或
(parameters) -> { statements; }
- parameters:表示 Lambda 表达式的参数列表,可以为空。
- ->:箭头符号,用于分隔参数列表和 Lambda 表达式的主体。
- expression:如果 Lambda 表达式的主体只有一条语句,可以直接使用表达式。
- { statements; }:如果 Lambda 表达式的主体包含多条语句,需要使用花括号将语句括起来。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
package org.example;
class Main {
public static void main(String[] args) {
// 传统方式创建 Runnable 实例
Runnable r1 = new Runnable() { //Runnable:Java 中内置的接口,用于表示一个可执行的任务,只有一个 run() 方法
@Override
public void run() {
System.out.println("传统方式执行任务");
}
};
// 使用 Lambda 表达式创建 Runnable 实例
Runnable r2 = () -> System.out.println("Lambda 方式执行任务");
// 启动线程
new Thread(r1).start();
new Thread(r2).start();
}
}