5514 字
7 分钟
13 次
- 2025-09-20
又看又背了一整天才弄了这么点,看来我专注力真是不够。。。
1 概念
1.1 说一下 Java 的特点
- 平台无关性: java 编译器将源代码编译成字节码,可以在任何安装了 java 虚拟机的系统上运行。
- 面向对象: 包括类、对象、封装、继承、多态、抽象。
- 内存管理:java 有自己的垃圾回收机制,不需要手动管理内存。
Java 的主要特点有三点:
第一,平台无关性,通过 JVM 实现“一次编写,到处运行”;
第二,面向对象,支持封装、继承、多态等特性;
第三,自动内存管理,通过垃圾回收机制(GC)减少内存泄漏风险。
1.2 java 的优势和劣势
- 优势:
- 有 JVM ,可以跨平台运行 java 程序。
- 面向对象。
- 内存管理。
- 生态强大:Spring 框架、Hibenate 以及各种库和工具。
- 支持多线程,内置线程机制,方便并发编程。
- 有安全模型,例如沙箱机制。
- 有企业级长期稳定支持版本。
- 劣势:
- 性能相比 C++ 或者 Rust 开销更多,启动时间慢。
- 语法繁琐,样板代码多。
- 内存消耗多,对资源有限的环境不友好。
Java 的优势在于:跨平台能力强、生态系统成熟(如 Spring)、自动垃圾回收、内置多线程支持,适合企业级开发。 劣势是性能相对原生语言略低,启动较慢,内存占用较高,语法也较为冗长,样板代码多。
1.3 java 为什么是跨平台的
和 JVM 的关系比较大。 java 源码编译后生成字节码文件,而 JVM 就是将字节码文件翻译成特定平台的机器码来运行。 也就是说,只要不同平台安装了对应的 JVM 就可以运行字节码文件,运行 java 程序。
Java 能跨平台是因为“字节码和JVM”。源代码被编译成与平台无关的 .class 文件,再由对应平台的 JVM 将字节码翻译成本地机器码执行,从而实现“一次编写,到处运行”。
1.4 JVM、JDK、JRE 的关系
- JVM(Java Virtual Machine) 是 Java 虚拟机,是 java 程序运行的环境。 它负责将 java 字节码文件解释或者编译成机器码,并执行程序,实现一次编写,到处运行。包括:内存管理、垃圾回收、安全性、线程和同步。
- JDK(Java Development Kit) 是 Java 开发工具包,是开发 Java 程序所需的工具包,提供了开发、编译、调试和运行 Java 程序所需的全部工具和环境。包括:JVM、编译器(javac-Java Compiler)、调试器(jdb-Java Debugger)以及一系列类库。
- JRE(Java Runtime Environment) 是 Java 运行时的环境,是 Java 程序运行所需的最小环境。包含了 JVM 和一组 java 类库,用于支持程序的执行。
三者关系是包含关系:
- JVM 是 Java 虚拟机,负责将字节码文件解释或者编译成机器码,并执行程序;
- JRE 包含 JVM 和运行所需类库,用于运行 Java 程序;
- JDK 是开发工具包,包含 JRE 和编译、调试等工具,用于开发 Java 程序。
所以:JDK 包含 JRE,JRE 包含 JVM。
1.5 为什么 Java 解释和编译都有
java 使用的是解释器和编译器混合的模式,JVM 中的一个方法调用计数器,累计计数达到一定值的时候,就使用 JIT 进行编译生成机器码文件,否则就是用解释器进行解释执行。
JVM 使用“解释 + 编译”混合模式:程序启动时通过解释器逐行执行字节码,对频繁执行的“热点代码”,JIT 编译器会将其编译为本地机器码,提升执行效率,兼顾了启动速度和运行性能。
1.6 JVM 是什么
JVM 是 Java 虚拟机,主要工作是解释或者编辑字节码文件,并映射到本机的 CPU 指令集和 OS 系统调用。
JVM(Java 虚拟机)是 Java 程序运行的核心,它负责解释或编译执行字节码,并提供内存管理、垃圾回收、线程调度和安全控制等功能,实现 Java 的跨平台能力。
1.7 编译型语言和解释型语言的区别(Java 和 Python 的区别)
- 编译型语言:程序运行之前,会将源代码编译成机器码或者字节码,生成可执行文件,执行时运行编译后的代码,速度快,但跨平台性差。
- 解释型语言:程序执行时,逐行解释并执行源代码,不生成独立的可执行文件,跨平台性好,但速度较慢。
- Java 属于中间路线:编译为字节码,再由 JVM 解释或 JIT 编译。
编译型语言(如 C++)在运行前将源码直接编译为机器码,执行效率高但跨平台性差; 解释型语言(如 Python)在运行时逐行解释执行,跨平台好但速度慢; Java 是混合型:先编译为字节码,再由 JVM 解释执行或通过 JIT 编译为机器码,兼顾了性能和跨平台性。
2 数据类型
2.1 八种数据类型
- 数值型:byte、short、int、long、float、double
- 字符型:char
- 布尔型:boolean
整型:byte(1)、short(2)、int(4)、long(8);
浮点型:float(4)、double(8);
字符型:char(2);
布尔型:boolean(true/false)。
2.2 int 和 long 是多少位,多少字节的
- int 是 32 位,4 字节的。
- long 是 64 位,8 字节的。
int 是 32 位、4 字节;
long 是 64 位、8 字节,
字符型:char(2);
布尔型:boolean(true/false)。
2.3 long 和 int 可以互转吗
可以,但由于 long 类型的取值范围比 int 大,所以 int 转 long 是类型安全的,但 long 转 int 会出现数据丢失或者溢出。
可以互转。int 到 long 是自动安全转换;但 long 转 int 需要强制类型转换,如果 long 值超出 int 范围,会发生数据截断或溢出,导致结果错误。
2.4 数据类型转换方式有哪些
- 自动类型转换(隐式转换):目标类型的范围大于源类型,Java 会自动将源类型转化为目标类型,例如 int 转换位 long、float 转换为 double
- 强制类型转换(显示转换):目标类型的取值范围小于源类型,需要使用强制类型转换,语法为:
目标类型 变量名 = (目标类型) 源类型。 - 字符串转换:Java 提供字符串转其他类型的方法,例如
Integer.parseInt()方法,Double.parseDouble()。 - 数值之间转换:Java 提供了 数值类型之间转换的方法,例如正序转化为字符型,将字符型转换为整型等。
Java 类型转换主要有四种:
- 自动转换:小类型转大类型,如
int到double; - 强制转换:需加
(类型),可能丢失精度; - 字符串转数值:如
Integer.parseInt("123"); - 字符与数值互转:字符可转为 ASCII 码参与计算。
2.5 类型互转会出现什么问题
- 数据溢出、精度损失。
- 如果是对象,向下转型可能会出现对象引用转换的问题。
2.6 为什么用 bigDecimal 不用 double
double 进行的是二进制浮点运算,由于有些小数不能使用 1/(2^n) 这种形式表示,导致 Java 在浮点数运算的时候,会出现精度丢失的问题。 Decimal 进行的是精确计算,可以避免这种问题。
double 使用二进制浮点运算,像 0.1 这样的数无法精确表示,会导致精度误差
BigDecimal 提供任意精度的十进制运算,能精确表示和计算小数
2.7 装箱和拆箱是什么
- 装箱是指将基本数据类型转换为包装类的过程。
- 拆箱是指将包装类转化为基本数据类型的过程。
2.8 Java 为什么要有 Integer (包装类)
- 将数据和数据处理的方法结合在一起,封装成对象,可以方便的处理数据。
- Java 中的绝大部分方法或类都是处理对象的,例如 ArrayList,用基本数据类型就没办法处理。
Java 是面向对象语言,有些工具类,例如集合,只能存储对象,不能存基本数据类型。 此外,引入包装类,还能让基本数据类型参与泛型、反射等对象操作。
2.9 Integer 相比 int 有什么区别。
- int 是 java 中的基本数据类型,而 Integer 是 int 的包装类,是引用类型。
- int 可以直接赋值为0,而包装类必须通过实例化对象来赋值,不然会出现空指针异常。
- int 存储数据时不需要分配内存,而 Integer 是引用类型,是需要分配内存的。
- 基本数据类型的操作比相应引用类型更快。
int 是基本类型,直接存值,效率高,不能为 null。
Integer 是包装类,是对象,可为 null,可用于泛型,但有装箱拆箱开销,可能引发空指针异常。
2.10 说一下 Integer 缓存
Java 的 Integer 类内部实现了一个静态缓存池,范围是 -128 ~ 127 ,当通过 Integer.valueOf(int) 方法创建一个在范围内的对象时,会直接从缓存池中复用,不会创建新的对象实例。
Integer 类内部缓存了 -128 到 127 的实例。当使用 Integer.valueOf(100) 时,会从缓存中获取对象,避免重复创建,提升性能。
3 面向对象
3.1 怎么理解面向对象
面向对象是一种编程范式,它将现实世界中的事物抽象为对象,具有属性和行为。通过对象之间的交互完成程序的功能,具有灵活性和可拓展性。
3.2 简单说说封装、继承和多态
- 封装是指将对象的属性和行为结合在一起,对外隐藏内部细节,只提供接口与外界交互的机制。目的是简化编程、使对象更加独立安全。
- 继承是可以让子类拥有父类的属性和行为的机制。目的是代码复用,使类与类之间的结构更加清晰。
- 多态是允许不同类对同一消息做出不同的响应的机制。可以让程序具有良好的灵活性和可扩展性。
3.3 多态体现在哪几个方面
- 方法重载
- 方法重写
- 接口与实现
3.4 多态解决了什么问题
解决了“如何在不修改现有代码的前提下,让系统支持新类型”的问题,从而提升了代码的灵活性、可扩展性和可维护性。
3.5 面向对象的设计原则有哪些
- 单一职责原则
- 开放封闭原则
- 里氏替换原则
- 接口隔离原则
- 依赖倒置原则
- 最少支持原则
3.6 重载和重写有什么区别
- 重载是在同一个类中,可以有多个同名方法,它们具有不同的参数列表(类型、顺序、个数不同)。
- 重写是子类可以重新定义父类中的方法,但方法名、参数列表和返回类型必须与父类中的一致。
3.7 抽象类和普通类的区别
- 普通类可以之间实例化对象,抽象类不能被实例化,只能被继承。
- 普通类方法可以有具体实现,而抽象类方法可以有具体实现,也可以没有具体实现。
3.8 抽象类和接口的区别
- 一个类只能使用
extends继承一个抽象类,但可以使用implements实现多个接口。所以接口支持‘多实现’,并且接口还可以多重继承。 - 抽象类中可以有构造方法、成员变量、普通方法和抽象方法;而接口在 Java 8 之前只能有抽象方法,但从 Java 8 开始支持
default方法和static方法,允许有默认实现。
3.9 抽象类能加 final 修饰吗
不能,Java 中的抽象类是用来被继承的,而被 final 修饰的类是被禁止继承的,因此抽象类和 final 是互斥的,不能同时使用。
3.10 解释一下静态变量和静态方法
-
静态变量是在类中使用
static声明的变量。- 所有该类的实例共享一个静态变量。
- 静态变量在类被加载时初始化,并且只会分配一次内存。
- 静态变量可以通过实例访问,也可以之间通过类名访问。
-
静态方法是在类中使用
static声明的方法。- 静态方法可以在没有创建类实例的情况下调用。
- 静态方法可以直接调用其他静态变量和静态方法,但不能访问非静态成员。
- 静态方法不支持重写。
4 关键字
4.1 final 的作用
final 关键字主要用于修饰类、方法和变量。
- 修饰类时,表示该类不能被继承。
- 修饰方法时,表示该方法不能在子类中被重写。
- 修饰基本数据类型时,变量一旦被赋值,就不能再修改。
- 修饰应用数据类型时,表示这个引用变量不能再指向其他对象,但对象本身的内容是可以变的。
4.2 static 的作用
static 关键字主要用于修饰类的成员和内部类,作用是将修饰内容和类本身关联。
- 修饰变量的时候,表示变量属于类本身,所有对象共享一份静态变量,内存中只存在一份。
- 修饰方法时,表示方法属于类,不需要创建类实例也能调用。
- 修饰内部类的时候,表示内部类不依赖于外部类的实例,可以独立存在。
5 深拷贝和浅拷贝
5.1 深拷贝和浅拷贝的区别
浅拷贝和深拷贝的区别主要在于对对象中引用类型字段的处理方式。
浅拷贝只是复制对象本身,如果对象里还引用了其他对象,它不会去复制那个对象,而是让新对象指向原来的那个引用对象。这就意味着,修改其中一个对象的引用内容,另一个也会受影响。
而深拷贝会把对象内部的所有引用对象也递归地复制一份,生成一个完全独立的新对象,两个对象之间互不影响。
5.2 实现深拷贝的三种方法
- 实现 Cloneable 接口并重写 clone() 方法。
- 使用序列化和反序列化。
- 手动递归复制。
6. 泛型
6.1 什么是泛型
泛型(Generic)是 Java 的一种语法特性,它允许你在定义类、接口或方法时,使用“类型参数”,例如<T>,代替具体的类型,等到使用时再指定实际类型。可以提高代码的类型安全性和代码复用性。
7 对象
7.1 java 创建对象有哪些方式
- 使用 new 关键字。
- 使用 Class 类的
newInstance()方法。 - 使用 Constructor 类的
newInstance()方法。 - 使用
close()方法 - 使用反序列化
- 使用工厂模式封装 new 方法
7.2 创建对象除了 new 还有什么别的方法
- 通过反射创建对象。
- 通过反序列化创建对象。
- 通过 clone 创建对象。
7.3 new 出的对象什么时候回收
通过 new 创建的对象,当它不再被任何引用变量指向,也就是变成‘不可达’时,就会在下一次垃圾回收时被自动回收。具体时间由 JVM 的垃圾回收器决定,开发者不能控制。
7.4 如何获取私有对象
- 通过公共访问器方法(getter)。
- 通过反射机制。
8 反射
8.1 什么是反射
反射是允许程序在运行时动态地获取类的信息,比如类的属性、方法、构造器等,并可以动态地创建对象、调用方法、访问和修改成员变量的一种机制。
9 注解
9.1 注解的原理
Java 注解的原理主要分为三个阶段:定义、存储和读取。
首先,注解是用 @interface 定义的特殊接口,继承自 Annotation 这个接口,配合元注解,例如 @Retention、@Target 来控制它的行为。
其次,编译后,注解信息会写入 .class 文件。保留策略决定了它能存在多久:SOURCE(仅源码)、CLASS(字节码)、RUNTIME(运行时)。
最后,在运行时,框架通过反射(如 getAnnotation())读取这些注解,并根据标记执行相应的逻辑,比如注册 Bean、映射请求等。
9.2 注解的作用域
- 类级。
- 方法级。
- 字段级。
10 异常
10.1 介绍一下异常
异常主要基于两大类:Throwable 及其子类。Throwable 有两个重要的子类: Error 和 Exception。
- Error (错误)表示运行时环境错误,是程序无法处理的严重错误,例如系统崩溃、虚拟机错误等等。
- Exception(异常)表示程序本身可以处理的异常。异常分为两大类:
- 非运行时异常,在编译时就被捕获或者声明抛出。
- 运行时异常,运行时异常由程序错误导致的。
10.2 Java 的异常处理有哪些
- try-catch 语句块,用于捕获并处理可能抛出的异常。
- throw 语句,用于手动抛出异常。
- throws 关键字,用于在方法中声明可能抛出的异常类型。
- finally 块,无论是否发生异常都会执行的代码块。
11 object
11.1 == 与 equals 有什么区别
- == 是一个运算符,对于基本数据类型,比较的是值是否相等,语句引用类型,比较的是两个引用是否指向同一个内存地址。
- equals 是 Object 类的一个方法,默认实现和 == 一样,但很多类重写了该方法,用来比较对象内容是否相等。
11.2 String、StringBuffer、StringBuilder的区别和联系
- String 是不可变的,一旦创建,内容就不可修改,每次就改都会创建一个新的对象。而 StringBuffer 和 StringBuilder 是可变的,对字符串内容进行修改不会创建新的对象。
- String 因为不可变,天然线程安全;StringBuilder 不是线程安全的,适用于单线程环境;StringBuffer 是线程安全的,通过
synchronized实现了同步,适用于多线程。 - String 性能较低,StringBuilder 的性能最高。
- 使用环境不同。
12. Java 新特性
12.1 Lambda 表达式是什么
Lambda 表达式是一种简洁的写法, 用于创建匿名函数,简化函数式编程的写法,特别是替代匿名内部类。它适用于只有一个方法的接口,也就是函数式接口中。
12.2 介绍一下 Stream API
Stream 是 Java 8 引入的一个函数式编程工具,用于高效、简洁地处理集合数据,主要分为创建流、中间操作,终止操作几个流程。
- 中间操作主要有 filter、map、sorted等,它们返回新的 Stream,支持链式调用。
- 终止操作有 forEach、collect、count等,真正触发执行,并返回结果。
13 其他
13.1 BIO、NIO、AIO 是什么
- BIO是同步阻塞模型,每个连接需要一个线程,线程在读写时会阻塞。
- NIO是同步非阻塞模型,多个连接复用一个线程,通过“轮询”检查是否有数据。
- AIO是异步非阻塞模型,发起 I/O 操作后立即返回,系统在操作完成时通过回调通知。