<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom"><channel><title>Java on Tequila's 学习笔记</title><link>https://latnx.github.io/docs/notes/d-205f3859abe469be/d-abfc9c2201b07353/</link><description>Recent content in Java on Tequila's 学习笔记</description><generator>Hugo -- gohugo.io</generator><language>zh-cn</language><copyright>© 2026 Tequila</copyright><atom:link href="https://latnx.github.io/docs/notes/d-205f3859abe469be/d-abfc9c2201b07353/index.xml" rel="self" type="application/rss+xml"/><item><title>IO</title><link>https://latnx.github.io/docs/notes/d-205f3859abe469be/d-abfc9c2201b07353/n-89f1ecd5b831df5f/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://latnx.github.io/docs/notes/d-205f3859abe469be/d-abfc9c2201b07353/n-89f1ecd5b831df5f/</guid><description> BIO、NIO、AIO区别是什么？ # BIO（blocking IO）：就是传统的 java.io 包，它是基于流模型实现的，交互的方式是同步、阻塞方式，也就是说在读入输入流或者输出流时，在读写动作完成之前，线程会一直阻塞在那里，它们之间的调用是可靠的线性顺序。优点是代码比较简单、直观；缺点是 IO 的效率和扩展性很低，容易成为应用性能瓶颈。 NIO（non-blocking IO） ：Java 1.4 引入的 java.nio 包，提供了 Channel、Selector、Buffer 等新的抽象，可以构建多路复用的、同步非阻塞 IO 程序，同时提供了更接近操作系统底层高性能的数据操作方式。 AIO（Asynchronous IO） ：也称 NIO.2，是 Java 1.7 引入的，对 NIO 的扩展，提供了异步非阻塞的 IO 操作方式，所以人们叫它 AIO（Asynchronous IO）。异步 IO 是基于事件和回调机制实现的，也就是应用操作之后会直接返回，不会阻塞在那里，当后台处理完成，操作系统会通知相应的线程进行后续的操作。</description></item><item><title>变量</title><link>https://latnx.github.io/docs/notes/d-205f3859abe469be/d-abfc9c2201b07353/n-c67f8711c1ba54c9/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://latnx.github.io/docs/notes/d-205f3859abe469be/d-abfc9c2201b07353/n-c67f8711c1ba54c9/</guid><description>局部变量（Local Variables）：局部变量是在方法、构造函数或块内部声明的变量，它们在声明的方法、构造函数或块执行结束后被销毁，局部变量在声明时需要初始化，否则会导致编译错误。
public void exampleMethod() { int localVar = 10; // 局部变量 // ... } 实例变量（Instance Variables）：实例变量是在类中声明，但在方法、构造函数或块之外，它们属于类的实例，每个类的实例都有自己的副本，如果不明确初始化，实例变量会被赋予默认值（数值类型为0，boolean类型为false，对象引用类型为null）。
public class ExampleClass { int instanceVar; // 实例变量 } 静态变量或类变量（Class Variables）：类变量是在类中用 static 关键字声明的变量，它们属于类而不是实例，所有该类的实例共享同一个类变量的值，类变量在类加载时被初始化，而且只初始化一次。
public class ExampleClass { static int classVar; // 类变量 } 参数变量（Parameters）：参数是方法或构造函数声明中的变量，用于接收调用该方法或构造函数时传递的值，参数变量的作用域只限于方法内部。
public void exampleMethod(int parameterVar) { // 参数变量 // ... }</description></item><item><title>常用类</title><link>https://latnx.github.io/docs/notes/d-205f3859abe469be/d-abfc9c2201b07353/n-3e7b86087cbd03b5/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://latnx.github.io/docs/notes/d-205f3859abe469be/d-abfc9c2201b07353/n-3e7b86087cbd03b5/</guid><description>Object # equals方法 # 对基本类型，比如 int、long，进行判等，只能使用 ==，比较的是直接值。因为基本类型的值就是其数值。
对引用类型，比如 Integer、Long 和 String，进行判等，需要使用 equals 进行内容判等。因为引用类型的直接值是指针，使用 == 的话，比较的是指针，也就是两个对象在内存中的地址，即比较它们是不是同一个对象，而不是比较对象的内容。
hashCode方法： # 散列表需要使用 hashCode 来定位元素放到哪个桶。如果自定义对象没有实现自定义的 hashCode 方法，就会使用 Object 超类的默认实现，得到的两个 hashCode 是不同的，导致无法满足需求。
如果在重写 equals 方法时，也重写了 hashCode 方法，那么在执行判断时会去执行重写的 hashCode 方法，此时对比的是两个对象的所有属性的 hashCode 是否相同，于是调用 hashCode 返回的结果就是 true，再去调用 equals 方法，发现两个对象确实是相等的，于是就返回 true 了，因此 Set 集合就不会存储两个一模一样的数据了，于是整个程序的执行就正常了。
clone 方法： # 浅拷贝是按位拷贝对象，它会创建一个新对象，这个对象有着原始对象属性值的一份精确拷贝。
如果属性是基本类型，拷贝的就是基本类型的值；如果属性是内存地址（引用类型），拷贝的就是内存地址 ，因此如果其中一个对象改变了这个地址，就会影响到另一个对象。 深拷贝会拷贝所有的属性,并拷贝属性指向的动态分配的内存。当对象和它所引用的对象一起拷贝时即发生深拷贝。深拷贝相比于浅拷贝速度较慢并且花销较大。
深拷贝的实现方式
重写 clone() 方法 序列化 JSON 序列化 string 类 # String 类被 final 关键字修饰，表示不可继承 String 类。
String 类的数据存储于 char[] 数组，这个数组被 final 关键字修饰，表示 String 对象不可被更改。</description></item><item><title>反射</title><link>https://latnx.github.io/docs/notes/d-205f3859abe469be/d-abfc9c2201b07353/n-576a9c53c158f1d7/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://latnx.github.io/docs/notes/d-205f3859abe469be/d-abfc9c2201b07353/n-576a9c53c158f1d7/</guid><description>反射机制是 Java 语言提供的一种基础功能，赋予程序在运行时自省（introspect，官方用语）的能力。通过反射我们可以直接操作类或者对象，比如获取某个对象的类定义，获取类声明的属性和方法，调用方法或者构造对象，甚至可以运行时修改类定义。
动态代理是一种方便运行时动态构建代理、动态处理代理方法调用的机制，很多场景都是利用类似机制做到的，比如用来包装 RPC 调用、面向切面的编程（AOP）。
实现动态代理的方式很多，比如 JDK 自身提供的动态代理，就是主要利用了上面提到的反射机制。还有其他的实现方式，比如利用传说中更高性能的字节码操作机制，类似 ASM、cglib（基于 ASM）、Javassist 等。</description></item><item><title>泛型</title><link>https://latnx.github.io/docs/notes/d-205f3859abe469be/d-abfc9c2201b07353/n-bc027c9a3b209e3c/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://latnx.github.io/docs/notes/d-205f3859abe469be/d-abfc9c2201b07353/n-bc027c9a3b209e3c/</guid><description>泛型（Generics）就是“类型参数化”。
通俗讲，就是把类型当作参数来传递。平时我们定义方法时，传的是“值”参数（比如 int a）；而泛型允许我们在定义类/方法时，传的是“类型”参数（比如 &amp;lt;T&amp;gt;）。
类型安全（编译期检查） 消除强制转换（代码更优雅） 复用代码（通用性） 通过使用泛型，程序员可以实现通用算法，这些算法可以处理不同类型的集合，可以自定义，并且类型安全且易于阅读。
类型擦除 # Java 的泛型是“伪泛型”，是通过“类型擦除（Type Erasure）”实现的。
泛型信息只在编译阶段存在。编译成 .class 字节码后，泛型类型会被替换为原始的裸类型（Raw Type）。
如果没有指定边界（如 &amp;lt;T&amp;gt;），擦除后变成 Object。 如果指定了边界（如 &amp;lt;T extends Number&amp;gt;），擦除后变成 Number。 2. 擦除带来的两个经典面试陷阱 # 陷阱一：List&amp;lt;String&amp;gt; 和 List&amp;lt;Integer&amp;gt; 是同一个类吗？ 是的。在 JVM 眼里，它们都是 ArrayList.class，getClass() 返回的结果完全相同。 陷阱二：能通过反射往 List&amp;lt;Integer&amp;gt; 里加字符串吗？ 能！ 因为运行时没有泛型约束。利用反射绕过编译期检查，完全可以存入 String，但取出来时因为编译器插入了强转 (Integer)，会抛出 ClassCastException</description></item><item><title>枚举</title><link>https://latnx.github.io/docs/notes/d-205f3859abe469be/d-abfc9c2201b07353/n-5aadcc58390009c3/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://latnx.github.io/docs/notes/d-205f3859abe469be/d-abfc9c2201b07353/n-5aadcc58390009c3/</guid><description>values(), ordinal() 和 valueOf() 方法位于 java.lang.Enum 类中：
values() 返回枚举类中所有的值。 ordinal()方法可以找到每个枚举常量的索引，就像数组索引一样。 valueOf()方法返回指定字符串值的枚举常量。 enum Color { RED, GREEN, BLUE; } public class Test { public static void main(String[] args) { // 调用 values() Color[] arr = Color.values(); // 迭代枚举 for (Color col : arr) { // 查看索引 System.out.println(col + &amp;#34; at index &amp;#34; + col.ordinal()); } // 使用 valueOf() 返回枚举常量，不存在的会报错 IllegalArgumentException System.out.println(Color.valueOf(&amp;#34;RED&amp;#34;)); // System.out.println(Color.valueOf(&amp;#34;WHITE&amp;#34;)); } }</description></item><item><title>面向对象</title><link>https://latnx.github.io/docs/notes/d-205f3859abe469be/d-abfc9c2201b07353/n-906a79c35d4b0cfb/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://latnx.github.io/docs/notes/d-205f3859abe469be/d-abfc9c2201b07353/n-906a79c35d4b0cfb/</guid><description>封装 # 修改属性的可见性来限制对属性的访问 对每个值属性提供对外的公共方法访问，也就是创建一对赋取值方法，用于对私有属性的访问 继承 # extends 和 implements # extends implements 关键字可以变相的使java具有多继承的特性，使用范围为类继承接口的情况，可以同时继承多个接口
super 与 this 关键字 # final 关键字 # final 可以用来修饰变量（包括类属性、对象属性、局部变量和形参）、方法（包括类方法和对象方法）和类。
使用 final 关键字声明类，就是把类定义定义为最终类，不能被继承，或者用于修饰方法，该方法不能被子类重写：
构造器 # 子类是不继承父类的构造器（构造方法或者构造函数）的，它只是调用（隐式或显式）。如果父类的构造器带有参数，则必须在子类的构造器中显式地通过 super 关键字调用父类的构造器并配以适当的参数列表。
如果父类构造器没有参数，则在子类的构造器中不需要使用 super 关键字调用父类构造器，系统会自动调用父类的无参构造器。
多态 # 子类继承父类 子类重写父类的方法 父类引用指向子类的对象 向上转型，也叫做自动类型转换，子类型赋值给父类型（父类型的引用指向子类型），构成多态 向下转型 向下转型，也叫做强制类型转换，父类型赋值给子类型。当使用多态时，并且访问子类独有的属性或方法时，则必须进行向下转型
1. 重写 # 重写(Override) # 重写（Override）是指子类定义了一个与其父类中具有相同名称、参数列表和返回类型的方法，并且子类方法的实现覆盖了父类方法的实现。
重写的好处在于子类可以根据需要，定义特定于自己的行为。也就是说子类能够根据需要实现父类的方法。这样，在使用子类对象调用该方法时，将执行子类中的方法而不是父类中的方法。
虚拟方法调用指的是：在运行时（而不是编译时）根据对象的实际类型（而非引用类型）来决定调用哪个版本的方法，这种在运行时被动态调用的方法即为虚拟方法。
重载(Overload) # 重载(overloading) 是在一个类里面，方法名字相同，而参数不同。返回类型可以相同也可以不同。
每个重载的方法（或者构造函数）都必须有一个独一无二的参数类型列表。
最常用的地方就是构造器的重载。
2. 接口 # 抽象类中的方法可以有方法体，就是能实现方法的具体功能，但是接口中的方法不行。 抽象类中的成员变量可以是各种类型的，而接口中的成员变量只能是 public static final 类型的。 接口中不能含有静态代码块以及静态方法(用 static 修饰的方法)，而抽象类是可以有静态代码块和静态方法。 一个类只能继承一个抽象类，而一个类却可以实现多个接口。 3.</description></item><item><title>数据类型包装类</title><link>https://latnx.github.io/docs/notes/d-205f3859abe469be/d-abfc9c2201b07353/n-abbe231bdc6a5287/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://latnx.github.io/docs/notes/d-205f3859abe469be/d-abfc9c2201b07353/n-abbe231bdc6a5287/</guid><description>所有的包装类 Integer、Long、Byte、Double、Float、Short 都是抽象类 Number 的子类。
类名 对应基本类型 描述 Byte byte 字节型包装类 Short short 短整型包装类 Integer int 整型包装类 Long long 长整型包装类 Float float 单精度浮点型包装类 Double double 双精度浮点型包装类 BigInteger - 不可变任意精度整数 BigDecimal - 不可变任意精度有符号十进制数 String StringBuffer StringBuilder String # String 创建的字符串存储在公共池中，而 new 创建的字符串对象在堆上：
String s1 = &amp;#34;Runoob&amp;#34;; // String 直接创建 String s2 = &amp;#34;Runoob&amp;#34;; // String 直接创建 String s3 = s1; // 相同引用 String s4 = new String(&amp;#34;Runoob&amp;#34;); // String 对象创建 String s5 = new String(&amp;#34;Runoob&amp;#34;); // String 对象创建 StringBuilder和StringBuffer # StringBuilder 类在 Java 5 中被提出，它和 StringBuffer 之间的最大不同在于 StringBuilder 的方法不是线程安全的（不能同步访问）。</description></item><item><title>问答</title><link>https://latnx.github.io/docs/notes/d-205f3859abe469be/d-abfc9c2201b07353/n-08135360f4ea17bd/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://latnx.github.io/docs/notes/d-205f3859abe469be/d-abfc9c2201b07353/n-08135360f4ea17bd/</guid><description>接口和抽象类的区别 # 接口是对行为的抽象，它是抽象方法的集合 目的：利用接口可以达到API定义和实现分离
接口，不能实例化； 不能包含任何非常量成员，任何field都是隐含着public static final的意义； 同时，没有非静态方法实现，也就是说要么是抽象方法，要么是静态方法。
抽象类是不能实例化的类，用abstract关键字修饰class， 抽象类大多用于抽取相关Java类的共用方法实现或者是共同成员变量，然后通过继承的方式达到代码复用的目的。 除了不能实例化，形式上和一般的Java类并没有太大区别，可以有一个或者多个抽象方法，也可以没有抽象方法。
final、finally、 finalize有什么不同？ # final 可以用来修饰类、方法、变量，分别有不同的意义，final 修饰的 class 代表不可以继承扩展，final 的变量是不可以修改的，而 final 的方法也是不可以重写的（override）。
finally 则是 Java 保证重点代码一定要被执行的一种机制。我们可以使用 try-finally 或者 try-catch-finally 来进行类似关闭 JDBC 连接、保证 unlock 锁等动作。
static关键字 # 修饰方法的时候，其实跟类一样，可以直接通过类名来进行调用
被static修饰的成员变量叫做静态变量，也叫做类变量，说明这个变量是属于这个类的，而不是属于是对象，没有被static修饰的成员变量叫做实例变量，说明这个变量是属于某个具体的对象的。
int和Integer有什么区别？ # int 是我们常说的整形数字，是 Java 的 8 个原始数据类型（Primitive Types，boolean、byte 、short、char、int、float、double、long）之一。Java 语言虽然号称一切都是对象，但原始数据类型是例外。
Integer 是 int 对应的包装类，它有一个 int 类型的字段存储数据，并且提供了基本操作，比如数学运算、int 和字符串之间转换等。在 Java 5 中，引入了自动装箱和自动拆箱功能（boxing/unboxing），Java 可以根据上下文，自动进行转换，极大地简化了相关编程。</description></item><item><title>修饰符</title><link>https://latnx.github.io/docs/notes/d-205f3859abe469be/d-abfc9c2201b07353/n-d2c95b4e28471452/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://latnx.github.io/docs/notes/d-205f3859abe469be/d-abfc9c2201b07353/n-d2c95b4e28471452/</guid><description>访问控制修饰符 # 修饰符 当前类 同一包内 子孙类(同一包) 子孙类(不同包) 其他包 public Y Y Y Y Y protected Y Y Y Y/N（说明） N default Y Y Y N N private Y N N N N 非访问修饰符 # static 修饰符 # 静态变量：
static 关键字用来声明独立于对象的静态变量，无论一个类实例化多少对象，它的静态变量只有一份拷贝。 静态变量也被称为类变量。局部变量不能被声明为 static 变量。
静态方法：
static 关键字用来声明独立于对象的静态方法。静态方法不能使用类的非静态变量。静态方法从参数列表得到数据，然后计算这些数据。
static 修饰符，用来修饰类方法和类变量。
final 修饰符，用来修饰类、方法和变量，final 修饰的类不能够被继承，修饰的方法不能被继承类重新定义，修饰的变量为常量，是不可修改的。
abstract 修饰符，用来创建抽象类和抽象方法。
synchronized 和 volatile 修饰符，主要用于线程的编程。</description></item><item><title>序列化</title><link>https://latnx.github.io/docs/notes/d-205f3859abe469be/d-abfc9c2201b07353/n-fcf5ed6ca338c484/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://latnx.github.io/docs/notes/d-205f3859abe469be/d-abfc9c2201b07353/n-fcf5ed6ca338c484/</guid><description>由于，网络传输的数据必须是二进制数据，但调用方请求的出入参数都是对象。对象是不能直接在网络中传输的，所以需要提前把它转成可传输的二进制，并且要求转换算法是可逆的。
序列化（serialize）：序列化是将对象转换为二进制数据。 反序列化（deserialize）：反序列化是将二进制数据转换为对象。 JDK序列化 # Serializable 接口 # 你的类必须实现 java.io.Serializable 接口。这是一个标记接口（没有任何方法），只告诉 JVM：“这个对象允许被序列化”。
ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream(&amp;#34;user.obj&amp;#34;)) oos.writeObject(user) 1. 序列化到底保存了什么？ # 它保存的是对象的“状态”（即成员变量的值），而不保存“方法”（代码逻辑）。
具体流程：
序列化时： 通过反射获取对象的所有非静态、非瞬态（transient）字段，将字段名 + 字段值按特定格式写入字节流，同时会写入类的元信息（如类名、serialVersionUID）。 反序列化时： JVM 根据字节流中的类名，去加载对应的 .class 文件，然后直接通过内存分配创建对象（不调用构造器！），再把字节流中的字段值赋给这个新对象的对应字段。 2. 核心：serialVersionUID（版本号） # JVM 在序列化时会根据类的结构（字段、方法、访问修饰符等）计算出一个哈希值作为 serialVersionUID，并写入字节流。 反序列化时，JVM 会对比字节流中的 UID 和当前加载的类的 UID。如果一致，则允许反序列化；如果不一致，抛出 InvalidClassException。 总结： # JDK 序列化是 Java 内置的对象持久化和传输机制，通过实现 Serializable 标记接口，利用 ObjectOutputStream 和 ObjectInputStream 完成。
它的底层原理是通过反射获取对象的非静态、非瞬态字段，以特定格式写入字节流，并附带类名和 serialVersionUID。反序列化时不走构造器，直接分配内存重建对象。
这里有几个关键点需要注意：static 和 transient 字段不参与序列化；必须显式声明 serialVersionUID 避免版本冲突；如果涉及循环引用，JVM 内部有特殊处理机制。如果对默认方式不满意，还可以通过重写 writeObject 和 readObject 自定义行为。</description></item><item><title>异常处理</title><link>https://latnx.github.io/docs/notes/d-205f3859abe469be/d-abfc9c2201b07353/n-0976918b5fd3dbd6/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://latnx.github.io/docs/notes/d-205f3859abe469be/d-abfc9c2201b07353/n-0976918b5fd3dbd6/</guid><description>分类 # Throwable 包含两个子类：Error（错误）和 Exception（异常）
Error（错误） # Error 类及其子类：程序中无法处理的错误，表示运行应用程序中出现了严重的错误。 这些错误是不受检异常，非代码性错误。
Exception（异常） # 程序本身可以捕获并且可以处理的异常。Exception 这种异常又分为两类：运行时异常和编译时异常。
都是RuntimeException类及其子类异常，如NullPointerException(空指针异常)、IndexOutOfBoundsException(下标越界异常)等，这些异常是不检查异常，程序中可以选择捕获处理，也可以不处理。这些异常一般是由程序逻辑错误引起的，程序应该从逻辑角度尽可能避免这类异常的发生。
是RuntimeException以外的异常，类型上都属于Exception类及其子类。从程序语法角度讲是必须进行处理的异常，如果不处理，程序就不能编译通过。如IOException、SQLException等以及用户自定义的Exception异常，一般情况下不自定义检查异常。
异常基础 # try：用于包裹可能会抛出异常的代码块。
catch：用于捕获异常并处理异常的代码块。
finally：用于包含无论是否发生异常都需要执行的代码块。
throw：用于手动抛出异常。
throws：用于在方法声明中指定方法可能抛出的异常。</description></item><item><title>注解</title><link>https://latnx.github.io/docs/notes/d-205f3859abe469be/d-abfc9c2201b07353/n-96a17f69c82a3aa7/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://latnx.github.io/docs/notes/d-205f3859abe469be/d-abfc9c2201b07353/n-96a17f69c82a3aa7/</guid><description>注解是一种标签，其实质上可以视为一种特殊的注释，如果没有解析它的代码，它并不比普通注释强。
编译器信息 - 编译器可以使用注解来检测错误或抑制警告。 编译时和部署时的处理 - 程序可以处理注解信息以生成代码，XML 文件等。 运行时处理 - 可以在运行时检查某些注解并处理。</description></item></channel></rss>