JavaSE篇
JavaSE
概念
编译型语言和解释型语言的区别?
- 编译型语言是先编译成字节码,再直接执行,如:C、C++
- 接事情语音是由解释器逐行解释执行源代码,如:python
Java是什么语言?
Java首先经过编译后生成字节码文件,再进入JVM中,就有两个步骤编译和解释。
对象转换的问题
向上转换是自动进行的,安全:
1 |
|
向下转换会出现错误,抛出ClassCastException
错误
1 |
|
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 会为注解生成一个实现注解接口的代理对象,从常量池中获取注解值返回。这也是为什么注解常和反射配合使用的原因。
异常
异常的分类
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
- 可变性:String每次修改,都会创建一个新对象;StringBuffer、StringBuilder不会。
- 线程安全性:String和StringBuffer是安全的,String因为创建新对象所以安全,StringBuffer因为基于互斥锁sychronized,所以线程安全;StringBuilder不是线程安全的。
序列化
怎么把一个对象从一个jvm转移到另一个jvm?
- 使用序列化和反序列化:一个JVM将对象序列化传给另一个JVM,再反序列化得到对象。
- 利用消息队列:如Kafka,RabbitMQ这类。
- 远程调用(RPC)
- 使用共享数据库或缓存