JavaSE篇

JavaSE

概念

编译型语言和解释型语言的区别?

  • 编译型语言是先编译成字节码,再直接执行,如:C、C++
  • 接事情语音是由解释器逐行解释执行源代码,如:python

Java是什么语言?

Java首先经过编译后生成字节码文件,再进入JVM中,就有两个步骤编译和解释。

对象转换的问题

向上转换是自动进行的,安全:

1
2
3
4
5
class Animal {}
class Dog extends Animal {}

Dog dog = new Dog();
Animal animal = dog; // 自动向上转型

向下转换会出现错误,抛出ClassCastException错误

1
2
Animal animal = new Animal();
Dog dog = (Dog) animal; // 运行时抛出ClassCastException

Decimal和double

Decimal更精确,没有精度丢失和错误;

double会出现,精度丢失和错误;

面向对象

面向对象的三大特性

继承、封装、多态

多态体现在哪几个方面?

  • 方法重载:方法名相同,根据传入参数类型不同,执行不同方法。如:sqrt(int a); sqrt(doble a);
  • 方法重写:子类调用父类方法时,可以重写方法效果。
  • 接口与实现
  • 向上转型和向下转型

多态有什么作用?

提高了代码的拓展性和复用性

静态变量

静态变量相当于一个被所有相同对象都能看到的实例变量,都是公用的。不支持被重写。

非静态内部类可以直接访问外部方法,编译器是怎么做到的?

相当于创建非静态内部类的同时,会将包含他的外部类也一起生成,编译器会将两个一起创建,外部方法自然能被内部类给识别到。

深拷贝和浅拷贝

深拷贝和浅拷贝的区别

浅拷贝相当于只复制对象本身和其内部的值类型字段,创建一个相同引用的对象,拷贝的对象和被拷贝的对象都是同一个引用对象

深拷贝相当于将对象内部的所有引用类型字段的内容也复制一份

实现深拷贝的三种方法是什么?

  • 实现 Cloneable 接口并重写 clone() 方法
  • 使用序列化和反序列化:通过将对象序列化为字节流,再从字节流反序列化为对象来实现深拷贝。要求对象及其所有引用类型字段都实现 Serializable 接口。
  • 手动递归复制

泛型

泛型的作用

  • 用于多种数据类型执行相同的代码
  • 泛型中的类型在使用时指定,不需要强制类型转换

对象

对象的创建方法

  • new
  • Class、constructor类的newInstance():通过反射
  • clone()
  • 反序列化:通过将对象序列化(保存到文件或网络传输)然后再反序列化(从文件或网络传输中读取对象)的方式来创建对象,对象能被序列化和反序列化的前提是类实现Serializable接口。

反射

什么是反射

Java 反射机制是在运行状态中,对于任意一个类,都能够知道这个类中的所有属性和方法,对于任意一个对象,都能够调用它的任意一个方法和属性;这种动态获取的信息以及动态调用对象的方法的功能称为 Java 语言的反射机制。

简单来说,就是知到一个类,就能知到这个类的全部。

反射的应用场景

第一是 Spring 容器自动注入和方法调用。项目中我们有一些通用接口,比如 Controller 层方法,并不在代码中显式调用,而是通过 URL 请求匹配到具体方法。框架底层会用反射 Class.forName() 加载类,用 getMethod() 定位到对应方法,再通过 invoke() 执行。这样可以在运行时动态调用不同方法,而不需要提前写死调用逻辑。

第二是 MyBatis 映射数据库字段到实体类。MyBatis 执行 SQL 查询后会得到一个 ResultSet,它在内部用反射获取实体类的字段(包括私有属性),然后调用 setAccessible(true) 修改访问权限,再把查询到的值注入到对象里。这样即使我们改动了实体类的属性名或者新增字段,也不需要手动写赋值逻辑。

在这些场景中,反射的好处是解耦通用性,让框架在运行时动态处理对象,而不是在编译期就固定死调用关系。不过我也知道反射会带来一定性能损耗,所以一般会在框架初始化时做缓存,避免频繁反射调用。

注解

什么是注解

在 Java 中,注解是一种元数据(Metadata),它用 @ 开头,可以标记在:

  • 类(Class)
  • 方法(Method)
  • 属性(Field)
  • 参数(Parameter)
    上面。

它可以被:

  • 编译器使用(检查、生成代码)
  • 运行时使用(通过反射读取注解信息,动态执行逻辑)

注解的本质

注解本质是继承了Annotation的特殊接口。

注解的分类

  • 源代码级(source):
    只在源代码中有,编译后就没了
  • 类文件级(class):
    编译后保留在 .class 文件,但运行时 JVM 不会读取。
  • 运行时级(RUNTIME):
    编译后保留,并且运行时可以通过反射读取。

注解的作用

  • 编译检查@Override 防止写错方法名)
  • 减少配置文件(Spring Boot 大量用注解代替 XML 配置)
  • 代码生成(Lombok 的 @Getter@Setter 自动生成方法)
  • 运行时动态处理(Spring AOP、事务管理等依赖反射读取注解)

注解的底层原理

注解在底层是编译器为类、方法、字段等添加的元数据,以 RuntimeVisibleAnnotations 等属性的形式保存在 .class 文件的字节码中。

编译时由 RetentionPolicy 决定是否写入 .class 文件,以及是否在运行时加载到 JVM 内存中。

如果是 RUNTIME 注解,运行时可以通过反射 API 读取注解信息,JVM 会为注解生成一个实现注解接口的代理对象,从常量池中获取注解值返回。这也是为什么注解常和反射配合使用的原因。

异常

异常的分类

img

try catch的运行情况

当前面的异常被捕获,后面的异常不会捕获。

try{return “a”} fianlly{return “b”}这条语句返回啥

finally块中的return语句会覆盖try块中的return返回,因此,该语句将返回”b”。

object

==和equals有什么不同

==比较的是内存地址的值。equals比较的是数值。

equals方法和hashcode方法

如果两个对象通过 equals() 比较是相等的,那么它们的 hashCode() 必须相等。
但反过来,hashCode() 相等的对象不一定 equals() 相等(哈希碰撞)。

String、StringBuffer、StringBuilder

  1. 可变性:String每次修改,都会创建一个新对象;StringBuffer、StringBuilder不会。
  2. 线程安全性:String和StringBuffer是安全的,String因为创建新对象所以安全,StringBuffer因为基于互斥锁sychronized,所以线程安全;StringBuilder不是线程安全的。

序列化

怎么把一个对象从一个jvm转移到另一个jvm?

  • 使用序列化和反序列化:一个JVM将对象序列化传给另一个JVM,再反序列化得到对象。
  • 利用消息队列:如Kafka,RabbitMQ这类。
  • 远程调用(RPC)
  • 使用共享数据库或缓存

JavaSE篇
http://example.com/2025/08/13/JAVASE/
作者
Luogic
发布于
2025年8月13日
许可协议