2026-02-04
java 的基本数据类型有哪些?
可以分为:
整数:int(4) byte(1) short(2) long(8)
浮点数:float(4) double(8)
布尔:boolean(1)
字符:char(2)
int 和 long 有什么区别吗?
本质的区别就是存储单元大小不同
int 为4字节,也就是32bit,long 为 8字节,也就是64bit
所以long 能存储的数据范围更大
特别是在进行转换的时候,把 int 类型强转成long的时候一般是安全的,不会出现溢出,但是如果是把long强转成int,就要注意一下,可能会溢出
数据类型转化的方式你知道哪些?会有什么风险吗?为什么向下转型不会报错?
隐射转换:比如把低精度的数赋值给高精度变量,直接复制就行,例如:long a = 1; 或是 Map<Obj, Obj> map = new HashMap();
显示转换:一般指的是强转,例如:int a = (int) 10L; 或是把转递过来的 Object 对象直接强转成具体的类型【比如Integer】(前提是,新类型就是对象本身的类型才可以)
字符串与数字之间转换:这个也是比较场景的,例如:传递进来一串数字字符串,我们可以调用API进行解析成具体的类型【比如:Integer.parseInt("123")】 或是 将数字转化成字符串【比如 数字+"" 或者 String.valueOf(数字)】
风险就是:
- 如果把高精度转换成低精度,容易造成精度丢失或是溢出,比如 把 double 数值赋值给float,或是long 数值赋值给int
- 在把字符串转换成数值的时候,需要确保字符串就是由合法数值组成 ,否则报错,例如:Integer.parseInt("1a23");
因为Java运行时其实会记录每一个数值的真实类型,所以向下转型不会报错
bigDecimal 和 double 有什么区别?为什么推荐使用bigDecimal 不用double?
bigDecimal 是精确运算,存储的是数组形式,能有效的存储每一位;而double因为是二进制,但是二进制并不能很好的表示,只能用1/(2^n)进行组合表示,所以double表示的数是不精准的
而在很多的金融场景,往往是不允许数值计算出错的
BigDecimal 使用的时候也要注意一些细节:
java
import java.math.BigDecimal;
public class BigDecimalExample {
public static void main(String[] args) {
BigDecimal num1 = new BigDecimal("0.1");
BigDecimal num2 = new BigDecimal("0.2");
BigDecimal sum = num1.add(num2);
BigDecimal product = num1.multiply(num2);
System.out.println("Sum: " + sum);
System.out.println("Product: " + product);
}
}
//输出
Sum: 0.3
Product: 0.02
然后要注意的就是,使用BigDecimal的时候传入的参数最好是字符串类型,而不是直接传入浮点类型,避免造成不准确(Java的原生浮点数就是double类型,所以不精确)
什么是拆箱和装箱?为什么有了基本类型还需要包装类?
装箱:把基本类型转化成包装类
拆箱:把包装类型转化成基本类
Integer i = 10; //装箱
int n = i; //拆箱
包装类其实就是基本类型的封装,主要的优点就是
- 首先就是让类更加的强大,功能更多,比如封装了一些对数值的处理方法在里面,让用户无需再造轮子
- 其次就是语义更丰富,当一个数据不存在的时候,如果是基本类型会直接表示为0,但是包装类型可以使用null代替,这一点在数据库查询结果封装的时候用的比较多
- 最后就是为了适配Java的语法糖,Java的泛型只支持对象类型,不支持基本类型,如果没有包装类的情况下,用户想要往集合里面塞入数值类型还得去封装,但是现在可以直接使用对应包装类就行
Integer 和 int 比有什么优点?聊聊 Integer 的缓存池?
优点:
- Integer 相比 int 包含了大量对数据进行处理的方法
- Integer 语义更加的丰富,能通过null表示数据不存在的场景
- Integer 能适应泛型,能存入到集合中
虽然说 Integer 非常的优秀,但是并不是说int就没用了,因为这份优秀带来的代价就是内存开销和性能开销,对于一些就只是存储基本数据的场景,用int反而是更合适的
Integet 的缓存池:
Integer 会在类内存创建一个缓存池 cache,默认情况下会缓存范围为-128至127的对象,当调用Integer.valueOf(int)的时候如果刚好数据是在这个范围中的,会直接复用对象,而不是创建新的对象

@IntrinsicCandidate
public static Integer valueOf(int i) {
if (i >= IntegerCache.low && i <= IntegerCache.high)
return IntegerCache.cache[i + (-IntegerCache.low)];
return new Integer(i);
}
讲讲什么是面向对象?
面向对象其实就是一种编程范式,或者说是一种规范,把世间万物抽象隐射到对象上,对象具有行为和属性
面向对象的特点:封装、继承、多态
封装就是把一些处理逻辑和属性封装到内部,对外只暴露出接口进行访问(安全性和方便性)
继承就是让子类能继承父类的一些属性和方法,我的理解就是提高代码的可复用性(可复用性)
多态就是同一接口,不同实例有不同实现,我认为比较典型的就是子类重写父类方法和面向接口编程(可拓展性)
讲讲重载和重写的区别?
重写是指子类和父类间的,方法名和参数以及返回值类型都需要相同,但是子类可以在自己内部做一些自己的操作,而不必和父类一摸一样,子类重写的方法的可访问性不可低于父类定义的可访问性
XyCurrencyAccountDTO getByUserId(Long userId);
@Override
public XyCurrencyAccountDTO getByUserId(Long userId) {
return ConvertBeanUtils.convert(xyCurrencyAccountMapper.selectById(userId), XyCurrencyAccountDTO.class);
}
重载是对同一个类来说的,允许多个同名同返回类型的方法,要求区别就是,参数不能一摸一样,可以是个数,类型,顺序等某一个不相同即可
public void t(String a, int b) {}
public void t(int b, int a) {}
public void t(int b, String a) {}
讲讲面向对象场景的设计原则?
了解的不多,常见的就是:
单一设计原则:一个类只负责单一的功能就行,不要过多的去参与其他类的行为,比如用户类就处理好用户的增删改查和登录登出就行
里氏替换原则:就是凡是用到父类的地方都可以直接用子类进行替换,子类和父类兼容
开闭原则原则:对增加保持开放态度,对修改保持关闭态度
依赖倒置原则:模块之间不要直接依赖,而是抽象出一套接口进行交互
接口隔离原则:每一个接口功能都尽量的高内聚
讲讲抽象类和普通类的区别?
- 抽象类没办法直接 通过 new 进行实例化,只能先用别的类去继承,然后再实例化它的子类
- 抽象类中的方法可以有具体实现,也可以直接定义为抽象方法,让继承者去实现
- 抽象类中只要是加了 abstract 就不能再加上final,比如类上加了abstract,那么这个类就不能再加final,方法也是一样,因为final定义为继承者不可修改,而abstract定义为必需继承者进行修改
接口和抽象类有什么区别吗?为什么需要保留接口和抽象类?
从功能上两者具有极大的相似性,方法都能抽象或默认实现
抽象类是半抽象,里面通常是定义一些方法,让子类可以直接复用
接口是全抽象,通常只复杂定义,需要实现类去实现具体功能
此外就是抽象类毕竟还是类,所以如果子类继承它的话就相当于把唯一的继承位给它了,而接口可以多实现,所以不会导致无法实现其他接口的情况,更加灵活
之所以保留的原则是互补,例如ArrayList就实现了AbstractList,从而复用了它里面的get() size()等方法
同时它还继承了List等接口
public class ArrayList<E> extends AbstractList<E>
implements List<E>, RandomAccess, Cloneable, java.io.Serializable
接口中能定义什么方法?
抽象方法
默认实现方法
静态方法
私有方法
接口有构造函数吗?
没有,接口并不需要自己进行实例化,没有new操作
聊聊静态方法和静态变量?
首先要明确一个点就是静态变量和静态方法是和类直接挂钩,而不是和实例挂钩
静态变量/方法的特点就是内存中只有一份,但是能被其他的类公用
静态变量:
**共享性:**就是一个变量大家都能看到和修改,其他一个修改,大家看到的都是修改后的结果

**初始化:**静态成员是在类初始化的时候被加载,只会分配一次内存
**访问方式:**不用通过实例去调用,可以直接通过类名进行调用
静态方法:
**无实例依赖:**就是可以直接通过类名访问,不用通过实例
**只能访问静态变量:**静态方法只能访问 静态 变量,非静态方法可以访问 静态/非静态 变量
**多态性:**静态方法不支持重写,因为重写是在运行阶段,静态加载是在类阶段;其次就是静态方法执行的时候只看声明类型,不看具体类型

使用场景:静态方法一般是需要共享的数据,才会用到,静态方法一般就是一些工具类什么的
对内部类有了解吗?能介绍一下静态内部类和非静态内部类的区别吗?
静态内部类应该是有四种,按照所处位置来看,如果是在局部的话,比如方法内部,包含局部内部类和匿名内部类,区别就是是否有名字
如果是在成员变量的位置,可以根据是否加了static分成静态内部类和非静态内部类
- 实例依赖:静态内部类可独立实例化 ,非静态内部类需先实例化外部类;

- 成员访问:静态内部类仅访问外部类静态成员 (私有静态成员可直接访问),非静态内部类可访问外部类所有成员; 【这个其实说的就是静态类只能访问静态成员,哪怕是私有的也可以,但是非静态类可以访问无论是否静态的一切成员】
非静态内部类可以直接访问外部方法,编译器是怎么做到的?
public class TT {
private String outerField = "外部类成员";
private void outerMethod() {
System.out.println("外部类方法");
}
// 非静态内部类
class Inner {
// 内部类访问外部类成员(看似"直接访问")
public void innerMethod() {
System.out.println(outerField); // 访问外部类变量
outerMethod(); // 访问外部类方法
}
}
}
其实就是编译器在加载阶段 帮我们维护了一个外部类的引用 ,并传给非静态内部类,使得非静态内部类可以直接访问,其次就是访问的时候会帮我们自动的做一下拼装,最终其实还是通过外部类引用去调用的外部成员