Java
简介
Java由詹姆斯高斯林设计,Sun公司推出,现属于ORACLE
Java是跨平台语言,基于Java虚拟机(即JVM)
Java本质是解释型语言,源码编译为Java字节码(.java文件 -> .class文件),JVM对其进行解释执行,即只需要编译器进行一次编译,后续每次运行都由虚拟机解释(一次编译,处处运行)
Java灵感来自C++,但去除了难以掌握的指针等复杂特性,此外垃圾收集器(JC)使得用户不必过多高度内存溢出等问题
Java主要具有三个版本,即Java SE(标准版)、Java EE(企业版)、Java ME(移动版)
Java的组件,Java开发工具包(JDK)、Java运行环境(JRE)、Java虚拟机(JVM)
OpenJDK是开源版本的JDK,基本满足普通开发
从JDK8开始,舍弃了前缀1.,之前的称为1.7等,1.7也可称为7
语言简单
语法简单,容易上手
面向对象(OOP)
Java中一切对象都是或类的实例
可移植
基于JVM,一次编译处处运行
高性能
性能接近C++
分布式
拥有丰富的分布式框架支持
动态
基于注解和反射实现了一定程度的动态运行
多线程
安全性
健壮性
安装
卸载
删除安装目录,删除环境变量
安装
下载
Java 存档下载 — Java SE 8 | Oracle 中国
安装
双击安装(路径自选,但不要包含中文字符)后找到系统设置->环境变量->系统变量
1.新增变量 变量名为JAVA_HOME,变量值为安装的路径
2.编辑Path变量,新建%JAVA_HOME%\bin\ %JAVA_HOME%\jre\bin\ 这两个变量值
检查
在命令行中键入 java -version 返回java的版本信息,说明安装成功
Hello world
// 创建java文件 HelloWorld.java
// 内容如下
public class HelloWorld {
public static void main(String[] args) {
System.out.println("hello world!");
}
}
// 在命令行中cd到 Hello.java 文件所在目录
// 编译java源码
C:\Users\ssydx\Desktop\code> javac HelloWorld.java
C:\Users\ssydx\Desktop\code> ls
Directory: C:\Users\ssydx\Desktop\code
Mode LastWriteTime Length Name
---- ------------- ------ ----
-a---- 2025/5/21 9:25 426 HelloWorld.class
-a---- 2025/5/21 9:21 118 HelloWorld.java
// 执行文件,输出hello world!
// 注意:文件名没有后缀
C:\Users\ssydx\Desktop\dos> java HelloWorld
hello world!
IDEA
一个高效的Java集成开发环境(IDE)
下载: Download IntelliJ IDEA 选择社区版IntelliJ IDEA Community Edition
安装: 双击安装(路径自选,但不要包含中文字符)
快捷命令
// psvm
public static void main(String[] args) {
}
// sout
System.out.println();
// .var
// .for
基础
前置知识
大小写敏感
注释
public class HelloWorld {
public static void main(String[] args) {
// 这是一个单行注释
int a = 10; // 给变量a赋值为10
/*
这是
一个多行注释,
它可以跨越多行。
*/
int b = 20;
int total = add(a, b);
System.out.println(total);
}
/**
* 这是一个文档注释的例子, 文档注释可以通过javadoc命令导出为文档
* @author ssydx
* @param a 参数a 类型为int
* @param b 参数b 类型为int
* @return 返回值为int类型
*/
private static int add(int a, int b) {
return a + b;
}
}
变量名称
// 以 A到Z a到z _ $ 开头, 甚至可以是中文名(强烈不建议使用中文), 不能使用关键字
public class TestVarName {
public static void main(String[] args) {
int $num = 10;
int num = 20;
int _num = 30;
int 数字 = 40;
System.out.println($num + num + _num + 数字);
}
}
// 通常类名为大驼峰写法: MyClass
// 通常常量名为全大写: MAX_VALUE
// 通常方法名或变量名小驼峰写法: getName(), myName
字符和字符串
// 高版本(13预览, 15发布)支持三双引号的多行文本
public class TestCharAndString {
public static void main(String[] args) {
// 单引号为字符
char c = 'x';
// 双引号为字符串
String str1 = "这是单行文本";
}
}
关键字
abstract | 用于声明抽象类或抽象方法 |
assert | 用于调试目的,测试条件是否为真 |
boolean | 表示布尔类型的值(true或false) |
break | 用于立即退出循环或switch语句 |
byte | 一个8位的原始数据类型 |
case | switch语句的一部分,表示匹配表达式的每个可能值 |
catch | 用于捕获try块中抛出的异常 |
char | 表示16位Unicode字符的原始数据类型 |
class | 定义类 |
const | 保留作未来使用,目前未被实现 |
continue | 跳过当前循环的剩余部分,并继续下一个循环迭代 |
default | 用于switch语句中的默认分支或在接口中提供默认方法实现 |
do | 与while结合使用来创建do-while循环 |
double | 64位双精度浮点数原始数据类型 |
else | if语句的备用分支 |
enum | 定义枚举类型 |
extends | 表明正在继承另一个类或实现接口 |
final | 使变量、方法或类不可更改或不可覆盖 |
finally | 用于定义无论是否发生异常都会执行的代码块 |
float | 32位单精度浮点数原始数据类型 |
for | 定义for循环结构 |
goto | 保留作未来使用,目前未被实现 |
if | 条件语句 |
implements | 表明一个类实现了给定的接口 |
import | 引入其他类包到当前文件 |
instanceof | 检查对象是否是指定类型的一个实例 |
int | 32位整数原始数据类型 |
interface | 定义接口 |
long | 64位长整数原始数据类型 |
native | 指示方法是用平台相关的语言编写的 |
new | 创建新的类实例 |
null | 表示空引用 |
package | 声明当前文件所在的包 |
private | 访问控制修饰符,限制成员只能在声明它的类内部访问 |
protected | 访问控制修饰符,允许子类和同一包内的其他类访问成员 |
public | 访问控制修饰符,允许任何类访问成员 |
return | 从方法返回一个值并退出方法 |
short | 16位短整数原始数据类型 |
static | 表示属于类而不是类的实例的成员 |
strictfp | 限制浮点计算以确保可移植性 |
super | 引用父类的对象 |
switch | 基于不同的匹配情况执行不同的代码块 |
synchronized | 控制对资源的并发访问 |
this | 引用当前对象实例 |
throw | 手动抛出一个异常 |
throws | 声明方法可能抛出的异常 |
transient | 标记不需要序列化的字段 |
try | 尝试执行一段代码,并可能抛出异常 |
void | 表示方法没有返回值 |
volatile | 指示一个字段可能会被多个线程异步修改 |
while | 定义while循环结构 |
数据类型
基本类型
public class TestBaseType {
public static void main(String[] args) {
// 字符, 默认为空字符
char char1 = '1';
char char2 = 'a';
char char3 = 'A';
char char4 = '啊';
// 布尔, 默认为false
boolean b1 = true;
boolean b2 = false;
// 整数
// 字节, 默认为0, -128~127, 8个bit, 1个byte
byte byte1 = 6;
// 短整型, 默认为0, -32768~32727, 16个bit, 2个byte
short short1 = 365;
// 整型, 默认为0, -2147483648~2147483647, 32个bit, 4个byte
int int1 = 3455534;
// 长整型, 默认为0, -9223372036854775808~9223372036854775807, 64个bit, 8个byte
// 长整型末尾加L或l, 推荐加L
long long1 = 3455534455L;
// 浮点数
// 单精度浮点数, 默认为0.0, 1.4E-45~3.4028235E38, 32个bit, 4个byte
// 单精度浮点数末尾加f或F
float float1 = 3.14f;
// 双精度浮点数, 默认为0.0, 1.4E-45~3.4028235E38, 64个bit, 8个byte
double double1 = 3.1415926;
}
}
基本类型拓展知识
public class TestBaseTypeExpend {
public static void main(String[] args) {
// 字符编码
char char1 = '0';
char char2 = '9';
char char3 = 'A';
char char4 = 'Z';
char char5 = 'a';
char char6 = 'z';
char char7 = '中';
System.out.println((int)char1); // 48
System.out.println((int)char2); // 57
System.out.println((int)char3); // 65
System.out.println((int)char4); // 90
System.out.println((int)char5); // 97
System.out.println((int)char6); // 122
System.out.println((int)char7); // 20013
System.out.println(Integer.toHexString(char7)); // 4e2d
char char8 = '\u4f3d'; // 伽
System.out.println(char8);
// 每个字符都对应一个字符编码, 范围 U0000~UFFFF(十六进制)
// 转义字符
System.out.println("hello\tworld!"); // 制表符, hello world!
/*
换行符
hello
world!
*/
System.out.println("hello\nworld!");
System.out.println("hello\"world!"); // 原义双引号, hello"world!
System.out.println("hello\\world!"); // 原义转义字符, hello\world!
// 进制
// 二进制
int num1 = 0b1010; // 10
// 八进制
int num2 = 07070; // 3640
// 十六进制
int num3 = 0xF0F0; // 61680
System.out.println(num1);
System.out.println(num2);
System.out.println(num3);
// 浮点精度
float money1 = 0.1F;
float money2 = 1.0F / 10;
double money3 = 0.1;
double money4 = 1 / 10.0;
System.out.println(money1); // 0.1
System.out.println(money2); // 0.1
System.out.println(money3); // 0.1
System.out.println(money4); // 0.1
System.out.println(money1 == money2); // true
System.out.println(money3 == money4); // true
System.out.println(money1 == money3); // false
System.out.println(money1 == money4); // false
System.out.println(money2 == money3); // false
System.out.println(money2 == money4); // false
float bignum1 = 233333333333333f;
float bignum2 = bignum1 + 1;
System.out.println(bignum1 == bignum2); // true
// 以上结果出现了奇怪的结果,原因是浮点数的精度问题,实际应避免浮点数的比较
// 实际业务中使用 BigDecimal 等引用类型
}
}
类型转换
public class TestCast {
public static void main(String[] args) {
int num1 = 10;
byte num2 = 1;
short num3 = 2;
char char1 = 'a';
// 自动类型转换, 这四者之间的运算都会将自身转换为int, 且最终结果为int
System.out.println(num1 + num2); // 11
System.out.println(num1 + num3); // 12
System.out.println(num1 + char1); // 107
System.out.println(num2 + num3); // 3
System.out.println(num2 + char1); // 98
System.out.println(num3 + char1); // 99
// byte、short、char、int 同一类型之间运算也会提升
byte num5 = 100;
byte num6 = 50;
System.out.println(num5 + num6);
// 具体规则是: 在未遇到不同类型运算前都按原类型计算
// 例如 1.2+24/5 结果是5.2,因为24/5先运算,此时仍按整数运算,得到结果4再与1.2相加
// 注意: boolean 是特殊的, 它不能和其他类型进行运算
// 整数与浮点数运算会转换为浮点数
int int1 = 10;
double double1 = 10.0;
System.out.println(int1 + double1); // 20.0
// 自动转换优先级: byte,short,char —> int —> long —> float —> double
// 强制类型转换
// 表示范围较大的值被赋予表示范围较小的值时要进行强制类型转换
// 溢出, 转换前后值不相等
int cnt1 = 365;
byte cnt2 = (byte) cnt1;
System.out.println(cnt1); // 365
System.out.println(cnt2); // 109
// 未溢出, 转换前后值相等
int cnt3 = 36;
byte cnt4 = (byte) cnt3;
System.out.println(cnt3); // 36
System.out.println(cnt4); // 36
// 强制类型转换会丢失高位字节
System.out.println(Integer.toHexString(cnt1)); // 16d
System.out.println(Integer.toHexString(cnt2)); // 6d
// 由于自动类型转换,未溢出
byte cnt5 = 100;
byte cnt6 = 50;
int cnt7 = cnt5 + cnt6;
System.out.println(cnt7); // 150
// 运算溢出
// int和int之间的运算不会自动转换为long
// 在赋值给 cnt10 之前, 已经溢出
int cnt8 = 20_0000_0000;
int cnt9 = 10;
long cnt10 = cnt8 * cnt9;
System.out.println(cnt10); // -1474836480
// 避免溢出
long cnt11 = (long) cnt8 * cnt9;
System.out.println(cnt11); // 20000000000
// 验证
// 11111111111111111111111111111111 10101000000101111100100000000000
System.out.println(Long.toBinaryString(cnt10));
// 100 10101000000101111100100000000000
System.out.println(Long.toBinaryString(cnt11));
// 前者的 100 三个 bit 溢出, 最高位为 1, 即符号位为1
// java 按照符号位进行高位扩展为 long, 即前面补32个1
// 其中涉及一些计算机补码的知识, 有兴趣可自行查阅资料
}
}
包装类型
public class TestPackageType {
public static void main(String[] args) {
// 基础类型的包装, 也是引用类型, Java进行了优化
// 基本类型和对应的包装类型会自动进行装箱拆箱
Boolean bool1 = true;
Boolean bool2 = Boolean.valueOf(false);
Boolean bool3 = Boolean.valueOf("true");
System.out.println(Boolean.TYPE); // boolean
System.out.println(Boolean.TRUE); // true
System.out.println(Boolean.FALSE); // false
Character char1 = 'a';
Character char2 = Character.valueOf('a');
System.out.println(Character.TYPE); // char
System.out.println(Character.BYTES); // 2
System.out.println(Character.DIRECTIONALITY_WHITESPACE); // 12
Byte byte1 = 10;
Byte byte2 = Byte.valueOf("10");
Byte byte3 = Byte.valueOf((byte)10);
System.out.println(Byte.TYPE); // byte
System.out.println(Byte.BYTES); // 1
System.out.println(Byte.MAX_VALUE); // 127
System.out.println(Byte.MIN_VALUE); // -128
Integer int1 = 100;
Integer int2 = Integer.valueOf(100);
Integer int3 = Integer.valueOf("100");
System.out.println(Integer.TYPE); // int
System.out.println(Integer.BYTES); // 4
System.out.println(Integer.MAX_VALUE); // 2147483647
System.out.println(Integer.MIN_VALUE); // -2147483648
Double double1 = 3.14;
Double double2 = Double.valueOf("3.14");
Double double3 = Double.valueOf(3.14);
System.out.println(Double.TYPE); // double
System.out.println(Double.BYTES); // 8
System.out.println(Double.MAX_VALUE); // 1.7976931348623157E308
System.out.println(Double.MIN_VALUE); // 4.9E-324
// 未列出的同理
}
}
引用类型
public class TestRefType {
public static void main(String[] args) {
// 除了基本类型外均为引用类型
// 字符串类型
String str = "hello world";
System.out.println(str);
// 数组类型
int[] ints1 = new int[5];
int[] ints2 = new int[]{1, 2, 3, 4, 5};
for (int i = 0; i < ints2.length; i++) {
System.out.println(ints2[i]);
}
}
}
运算符
import java.util.Arrays;
public class TestOperator {
public static void main(String[] args) {
// 赋值运算符
int num1 = 10;
int num2 = 3;
// 算术运算符, 对于大整数的运算一定要注意整型溢出问题
int num3 = num1 + num2;
System.out.println(num3); // 13
int num4 = num1 - num2;
System.out.println(num4); // 7
int num5 = num1 * num2;
System.out.println(num5); // 30
int num6 = num1 / num2;
System.out.println(num6); // 3
int num7 = num1 % num2;
System.out.println(num7); // 1
int num8 = (int)Math.pow(num1, num2);
System.out.println(num8); // 1000
// 相等判断
// 对于 基本类型 的比较的是内容
System.out.println(num1 == num2); // false
System.out.println(num1 != num2); // true
// 对于 包装类型或字符串 比较的是地址
// 情况比较奇怪, 因为存在常量池机制, 会在一定程度上对常量池中存在的值进行复用, 从而造成两个对象引用同一地址
// 因此不建议使用 == 进行相等判断, 推荐使用 equals 方法
Long num9 = 100L;
Long num10 = 100L;
Long num11 = 10000000L;
Long num12 = 10000000L;
System.out.println(num9 == num10); // true
System.out.println(num11 == num12); // false
System.out.println(num11.equals(num12)); // true
String str1 = "hello";
String str2 = "hello";
String str3 = new String("hello");
String str4 = new String("hello");
System.out.println(str1 == str2); // true
System.out.println(str3 == str4); // false
System.out.println(str3.equals(str4)); // true
// 对于 其他引用类型 比较的是地址
double[] doubles1 = new double[]{1,2,3,4,5};
double[] doubles2 = new double[]{1,2,3,4,5};
System.out.println(doubles1 == doubles2); // false
// 综上, 对于基本类型推荐使用 == 运算符, 对于引用类型(包括包装类型和字符串)则应使用专门的方法
// 比较运算符
// 基本类型
System.out.println(num1 > num2); // true
System.out.println(num1 >= num2); // true
System.out.println(num1 < num2); // false
System.out.println(num1 <= num2); // false
// 包装类型同理, 会自动拆箱进行比较
// 其他如字符串等引用类型, 不支持使用比较运算符, 应使用对应的方法
// 类型判断
// instanceof 不支持基本类型, 包括基本类型的数组
System.out.println(num9 instanceof Long); // true
System.out.println(str1 instanceof String); // true
System.out.println(doubles1.getClass().isArray());
// 逻辑运算
int cnt1 = 10;
int cnt2 = 10;
int cnt3 = 5;
boolean bool1 = (cnt1 == cnt2) && (cnt1 == cnt3); // true && false
System.out.println(bool1); // false
boolean bool2 = (cnt1 == cnt3) || (cnt1 == cnt2); // false || true
System.out.println(bool2); // true
boolean bool3 = !(cnt1 == cnt2); // !true
System.out.println(bool3); // false
// 逻辑运算具有短路特性, 这点在实际场景中十分重要
// 即如果某个分表达式的 bool 结果已经决定了整个表达式的结果, 后续的分表达式将被忽略
// 例如以下两者, 虽然结果不变, 但实际运算却与之前不同
boolean bool4 = (cnt1 == cnt3) && (cnt1 == cnt2); // false [&& true]
System.out.println(bool4); // false
boolean bool5 = (cnt1 == cnt2) || (cnt1 == cnt3); // true [|| false]
System.out.println(bool5); // true
// 如果要避开短路, 需要借助位运算的 & 和 |
// 自增自减
System.out.println(++cnt1); // 11
System.out.println(cnt1++); // 11
System.out.println(cnt1); // 12
System.out.println(--cnt2); // 9
System.out.println(cnt2--); // 9
System.out.println(cnt2); // 8
// 位运算, 位运算是非常高效的, 有很多复杂技巧(位运算同样满足自动转换的提升规则和符号扩展)
int val1 = 0b1010;
int val2 = 0b0110;
int val3 = val1 & val2;
int val4 = val1 | val2;
int val5 = val1 ^ val2;
int val6 = ~val1;
System.out.println(Integer.toBinaryString(val3)); // 10(0010)
System.out.println(Integer.toBinaryString(val4)); // 1110
System.out.println(Integer.toBinaryString(val5)); // 1100
// 11111111111111111111111111110101(0101), 前面的一串1是因为之前转换时提到的符号位扩展后取反
System.out.println(Integer.toBinaryString(val6));
int int1 = 0b10000000000000000000000000010101;
int int2 = 0b10000000000000000000000000010101;
int int3 = 0b10000000000000000000000000010101;
int int4 = int1 >> 1; // 有符号右移, 即左侧补符号位
int int5 = int2 >>> 2; // 无符号右移, 即左侧补0
int int6 = int3 << 3; // 右移, 右侧补0
System.out.println(Integer.toBinaryString(int4)); // 11000000000000000000000000001010
System.out.println(Integer.toBinaryString(int5)); // 100000000000000000000000000101
System.out.println(Integer.toBinaryString(int6)); // 10101000
// 赋值扩展
cnt1 += cnt3; // 12 + 5
cnt2 -= cnt3; // 8 - 5
System.out.println(cnt1); // 17
System.out.println(cnt2); // 3
// 其他同理
// 条件运算
int a = 10;
int b = 5;
int c = a > b ? a : b;
System.out.println(c); // 10
}
}
变量和常量
// Java是强类型语言,即变量是先定义后使用,定义后类型不可改变
// Java10及之后提供了var关键字, 用于简化局部变量的声明(必须在声明定义时进行初始化以便编译器自动推断类型)
public class TestVar {
public static void main(String[] args) {
// 声明、定义、初始化三者是不同的
// 声明和定义通常是同时进行的,例外情况之一是接口和抽象类声明了方法, 实现类中进行定义
// 变量一定要初始化后再使用
// 可以先声明定义, 再初始化
String str1;
str1 = "hello";
System.out.println(str1); // hello
// 声明定义的同时进行初始化
String str2 = "world";
System.out.println(str2);
// 变量值可修改
str1 += str2;
System.out.println(str1); // hello world
// 常量, 声明定义时必须初始化, 初始化后不可更改
final String STR3 = "hello world";
System.out.println(STR3); // hello world
// 作用域
// java一切都以类为基础, 因此不具备常规意义上的全局变量
// 可在一定程度上将静态变量和实例变量视为全局变量
// 静态变量: 类和实例均可访问(不建议实例访问), 所有实例共享
// 实例变量: 只有实例可以访问, 每个实例都单独拥有, 互相隔离
// 局部变量: 方法中定义的变量可视为局部变量
}
}
基本语句
import java.util.Scanner;
public class TestStatement {
public static void main(String[] args) {
// 顺序执行, 程序按照代码顺序由上至下执行
int a = 10;
int b = 20;
int c = a + b;
System.out.println(c); // 30
// 条件语句
// if-else if-else, 判断灵活
int num1 = getIntValue();
if (num1 > 100) {
System.out.println("大");
} else if (num1 > 10) {
System.out.println("中");
} else {
System.out.println("小");
}
// switch case default break, 只适合相等判断
// 支持整型、字符、枚举值、字符串(Java7引入)
int num2 = getIntValue();
switch (num2) {
case 10:
System.out.println("十");
// 总是使用 break 终止执行之后的代码, 除非你明确自己在做什么
break;
case 20:
System.out.println("二十");
break;
// 总是使用 default 捕获未枚举到的情况
default:
System.out.println("其他");
break;
}
// 循环语句
// while continue break
int num3 = getIntValue();
while (num3 != 0) {
System.out.println("1-请输入0以终止程序");
num3 = getIntValue();
if (num3 == 10) {
continue;
}
System.out.println("1-你输入了: " + num3);
}
// do while continue break
int num4 = 1;
do {
System.out.println("2-请输入0以终止程序");
num4 = getIntValue();
if (num4 == 10) {
System.out.println("2-你输入了: " + num3);
break;
}
} while (num4 != 0);
// for continue break
for (int i = 0; i < 10; i++) {
System.out.println("第: " + i + "次");
int intValue = getIntValue();
if (intValue == 0) {
break;
}
}
// 增强型foreach
int[] ints = {5, 4, 3, 2, 1};
for (int i : ints) {
System.out.println("数组元素为: " + i);
}
// 标签, 跳出循环到指定标签出, 常用于一次跳出多重循环, 谨慎使用
out:
for (int i = 0; i < 10; i++) {
for (int j = 0; j < 10; j++) {
System.out.println("i=" + i + " j=" + j);
if (i == 5 && j == 5) {
break out;
}
}
}
}
private static int getIntValue() {
// 扫描标准输入流(即从命令行读取数据, 即接受键盘输入的数据)
Scanner scanner = new Scanner(System.in);
// 声明定义一个 int 类型的局部变量, 并进行初始化, 你总是应该保持进行初始化的好习惯
int num = 0;
System.out.println("开始接受输入:");
// 如果存在输入(输入以换行结束)
if (scanner.hasNext()) {
// 把输入的整数类型的值赋值给 num 变量
num = scanner.nextInt();
}
return num;
}
}
类和对象
普通类 | ✅ 支持 | ✅ 支持 | ✅ 支持 | ✅ 支持 | ✅ 支持 | ❌ 不支持 | ❌ 不支持 | ✅ 支持 | ✅ 支持 | ✅ 支持 | ✅ 支持 |
抽象类 | ✅ 支持 | ✅ 支持 | ✅ 支持 | ✅ 支持 | ✅ 支持 | ✅ 支持 | ❌ 不支持 | ✅ 支持 | ✅ 支持 | ✅ 支持 | ✅ 支持 |
接口 | ✅ 支持 (Java 8+) | ❌ 不支持 | ✅ 支持 (Java 8+) | ❌ 不直接支持 | ❌ 不支持 | ✅ 支持 | ✅ 支持 (Java 8+) | ❌ 不支持 | ❌ 不支持 | ❌ 不支持 | ❌ 不支持 |
静态嵌套类 | ✅ 支持 | ✅ 支持 | ✅ 支持 | ✅ 支持 | ✅ 支持 | ❌ 不支持 | ❌ 不支持 | ✅ 支持 | ✅ 支持 | ✅ 支持 | ✅ 支持 |
非静态内部类 | ✅ 支持 | ✅ 支持 | ✅ 支持 | ✅ 支持 | ✅ 支持 | ❌ 不支持 | ❌ 不支持 | ✅ 支持 | ✅ 支持 | ✅ 支持 | ✅ 支持 |
局部类(非静态) | ❌ 不支持 | ✅ 支持 | ❌ 不支持 | ✅ 支持 | ✅ 支持 | ✅ 支持 | ❌ 不支持 | ✅ 支持 | ✅ 支持 | ❌ 不支持 | ❌ 不支持 |
匿名类 | ❌ 不支持 | ✅ 支持 | ❌ 不支持 | ✅ 支持 | ❌ 不支持(通过实例化表达式) | ✅ 支持(隐式) | ❌ 不支持 | ✅ 支持 | ❌ 不支持 | ❌ 不支持 | ❌ 不支持 |
枚举类 | ✅ 支持 | ✅ 支持 | ✅ 支持 | ✅ 支持 | ✅ 支持(有限制) | ✅ 支持(有限制) | ❌ 不支持 | ✅ 支持 | ✅ 支持 | ✅ 支持 | ✅ 支持 |
注解类 | ✅ 支持 | ❌ 不支持 | ✅ 支持 | ❌ 不支持 | ❌ 不支持 | ❌ 不支持 | ❌ 不支持 | ❌ 不支持 | ❌ 不支持 | ❌ 不支持 | ❌ 不支持 |
包装类型的使用
字符串类型的使用
数组的使用
其他常见类
Math、Random
进阶
泛型
枚举
基类
元类
注解
反射
大数字
格式化
日期和时间
容器
异常和错误
输入和输出
流式编程
Lambda
简化过程
普通类(Do1) | ✅ 是 | ✅ 是 | N/A | ❌ 否 | ❌ 否 |
静态成员类(Do2) | ✅ 是 | ✅ 是 | N/A | ❌ 否 | ❌ 否 |
局部类(Do3) | ✅ 是 | ✅ 是 | ✅ 可访问 final 变量 | ❌ 否 | ✅ 是 |
匿名类(do4) | ❌ 否 | ✅ 是 | ✅ 可访问 final 变量 | ❌ 否 | ✅ 是 |
Lambda(do5) | ❌ 否 | ✅ 是(编译器自动生成) | ✅ 可访问 final 变量 | ✅ 是 | ✅ 是 |
public class Lambda {
// 成员类实现
static class Do2 implements DoSomething {
@Override
public void doSomething(String name) {
System.out.println(name + "做些事");
}
}
public static void main(String[] args) {
Do1 do1 = new Do1();
do1.doSomething("普通类");
Do2 do2 = new Do2();
do2.doSomething("成员类");
// 局部类实现
class Do3 implements DoSomething {
@Override
public void doSomething(String name) {
System.out.println(name + "做些事");
}
}
Do3 do3 = new Do3();
do3.doSomething("局部类");
// 匿名类实现
DoSomething do4 = new DoSomething() {
@Override
public void doSomething(String name) {
System.out.println(name + "做些事");
}
};
do4.doSomething("匿名类");
// Lambda实现
// DoSomething do5 = (name) -> {
// System.out.println(name + "做些事");
// };
DoSomething do5 = name -> System.out.println(name + "做些事");
do5.doSomething("Lambda");
}
}
// 函数式接口,即只有一个抽象方法的接口(可以有任意个默认方法、静态方法、静态变量),函数式接口可以使用Lambda表达式
interface DoSomething {
void doSomething(String name);
}
// 普通类实现
class Do1 implements DoSomething {
@Override
public void doSomething(String name) {
System.out.println(name + "做些事");
}
}
内置函数式接口
import java.util.Random;
import java.util.function.Consumer;
import java.util.function.Function;
import java.util.function.Predicate;
import java.util.function.Supplier;
public class BuiltinFunctionalInterface {
public static void main(String[] args) {
// 接受一个参数,返回一个boolean类型的值
Predicate<String> predicate = name -> name.equals("name");
System.out.println(predicate.test("ssydx"));
// 接受一个参数,返回一个值
Function<Integer, String> function = age -> "张三今年" + age + "岁";
System.out.println(function.apply(20));
// 接受一个参数,不返回值
Consumer<String> consumer = name -> System.out.println("当前输入的姓名是: " + name);
consumer.accept("zhangsan");
// 不接受参数,返回一个值
Supplier<Integer> supplier = () -> new Random().nextInt();
System.out.println(supplier.get());
// 除此之外
// BiFunction<T, U, R> 接受两个参数,返回一个值
// UnaryOperator<T> 等价Function<T, T>
// BinaryOperator<T> 等价Function<T, T, T>
// BiConsumer<T, U> 接受两个参数,不返回值
// BiPredicate<T, U> 接受两个参数,返回一个布尔类型的值
// LongSuplier 不接受参数,返回一个long类型的值
// ...
}
}
JDBC
GUI
代理
静态代理
// 仔细观察可以发现他就是new Thread().start();的实现原理
public class StaticProxy {
public static void main(String[] args) {
new Driver(new Myself()).drive();
}
}
interface Drive {
void drive();
}
class Myself implements Drive {
@Override
public void drive() {
System.out.println("正在开车");
}
}
class Driver implements Drive {
private Drive target;
public Driver(Drive target) {
this.target = target;
}
@Override
public void drive() {
before();
this.target.drive();
after();
}
private void before() {
System.out.println("代驾前与本人沟通");
}
private void after() {
System.out.println("代驾后向本人收款");
}
}
// 执行结果
代驾前与本人沟通
正在开车
代驾后向本人收款
动态代理
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
public class DynamicProxy {
public static void main(String[] args) {
// 创建被代理对象
Drive driver = new Myself();
// 创建 InvocationHandler 实例
DriverInvocationHandler handler = new DriverInvocationHandler(driver);
// 使用 Proxy.newProxyInstance 创建代理对象
Drive proxyDriver = (Drive) Proxy.newProxyInstance(
driver.getClass().getClassLoader(),
driver.getClass().getInterfaces(),
handler);
// 调用代理对象的方法
proxyDriver.drive();
}
}
// 创建一个 InvocationHandler 实现类
class DriverInvocationHandler implements InvocationHandler {
private Object target;
public DriverInvocationHandler(Object target) {
this.target = target;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
before(); // 前置操作
Object result = method.invoke(target, args); // 调用目标对象的方法
after(); // 后置操作
return result;
}
private void before() {
System.out.println("代驾前与本人沟通");
}
private void after() {
System.out.println("代驾后向本人收款");
}
}
#java##java日常##java学习#本专栏包含Java、Linux、MySQL、Redis、RabbitMQ、Docker、HTML、CSS、JS等等,作为个人学习记录及知识总结,将长期进行更新!