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;
    }

}

类和对象

类型 静态变量 (static) 实例变量 静态方法 (static) 实例方法 构造器 抽象方法(abstact) 默认方法 (default) 私有方法 (private) 受保护的方法 (protected) 静态初始化块 实例初始化块
普通类 ✅ 支持 ✅ 支持 ✅ 支持 ✅ 支持 ✅ 支持 ❌ 不支持 ❌ 不支持 ✅ 支持 ✅ 支持 ✅ 支持 ✅ 支持
抽象类 ✅ 支持 ✅ 支持 ✅ 支持 ✅ 支持 ✅ 支持 ✅ 支持 ❌ 不支持 ✅ 支持 ✅ 支持 ✅ 支持 ✅ 支持
接口 ✅ 支持 (Java 8+) ❌ 不支持 ✅ 支持 (Java 8+) ❌ 不直接支持 ❌ 不支持 ✅ 支持 ✅ 支持 (Java 8+) ❌ 不支持 ❌ 不支持 ❌ 不支持 ❌ 不支持
静态嵌套类 ✅ 支持 ✅ 支持 ✅ 支持 ✅ 支持 ✅ 支持 ❌ 不支持 ❌ 不支持 ✅ 支持 ✅ 支持 ✅ 支持 ✅ 支持
非静态内部类 ✅ 支持 ✅ 支持 ✅ 支持 ✅ 支持 ✅ 支持 ❌ 不支持 ❌ 不支持 ✅ 支持 ✅ 支持 ✅ 支持 ✅ 支持
局部类(非静态) ❌ 不支持 ✅ 支持 ❌ 不支持 ✅ 支持 ✅ 支持 ✅ 支持 ❌ 不支持 ✅ 支持 ✅ 支持 ❌ 不支持 ❌ 不支持
匿名类 ❌ 不支持 ✅ 支持 ❌ 不支持 ✅ 支持 ❌ 不支持(通过实例化表达式) ✅ 支持(隐式) ❌ 不支持 ✅ 支持 ❌ 不支持 ❌ 不支持 ❌ 不支持
枚举类 ✅ 支持 ✅ 支持 ✅ 支持 ✅ 支持 ✅ 支持(有限制) ✅ 支持(有限制) ❌ 不支持 ✅ 支持 ✅ 支持 ✅ 支持 ✅ 支持
注解类 ✅ 支持 ❌ 不支持 ✅ 支持 ❌ 不支持 ❌ 不支持 ❌ 不支持 ❌ 不支持 ❌ 不支持 ❌ 不支持 ❌ 不支持 ❌ 不支持

包装类型的使用

字符串类型的使用

数组的使用

其他常见类

Math、Random

进阶

泛型

枚举

基类

元类

注解

反射

大数字

格式化

日期和时间

容器

异常和错误

输入和输出

流式编程

Lambda

简化过程

实现方式 是否命名类 是否生成 .class 文件 可否访问局部变量 是否支持 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等等,作为个人学习记录及知识总结,将长期进行更新!

全部评论

相关推荐

昨天 15:55
门头沟学院 C++
ResourceUtilization:应该配文,扫描二维码加速offer发放速度
点赞 评论 收藏
分享
评论
点赞
收藏
分享

创作者周榜

更多
牛客网
牛客企业服务