Java基础面试总结(八股)
Java基础面试总结
Java概述
1. 什么是Java?
- 面向对象编程语言,由Sun公司詹姆斯·高斯林团队于1995年推出。
- 吸收C++优点,摒弃指针、手动内存管理等易出错部分。
- 平台无关性,实现“一次编译,处处运行”,需在对应平台安装JDK。
2.Java语言有哪些特点?
- 面向对象:封装、继承、多态。
- 平台无关性:可移植性强,依赖JVM实现跨平台。
- 支持多线程:内置多线程机制,无需调用操作系统API。
- 编译与解释并存:先编译为字节码,再由JVM解释执行,支持JIT即时编译提升效率。
3.JVM、JDK和JRE有什么区别?
- JVM(Java虚拟机):实现跨平台的核心,将字节码转为特定平台机器码并执行,不同操作系统有不同实现。
- JRE(Java运行环境):包含运行Java程序必需的库和JVM。
- JDK(Java开发工具包):完整SDK,包含JRE及编译器(javac)、文档生成工具(javadoc)等开发工具。
- 关系:JDK包含JRE,JRE包含JVM。
4.什么是跨平台?原理是什么?
- 跨平台指Java程序一次编译后可在多个操作系统运行。
- 原理:通过JVM中间件,JVM负责将字节码转换为特定平台机器码并执行。
5. 什么是字节码?采用字节码的好处是什么?
- 字节码是Java程序编译后生成的.class文件。
- 好处:实现平台无关性,JVM可跨平台解释执行字节码,兼顾编译型语言的高效和解释型语言的灵活。
- 运行步骤:
- 编译:将源代码文件 .java 编译成 JVM 可以识别的字节码文件 .class
- 解释:JVM 执行字节码文件,将字节码翻译成操作系统能识别的机器码
- 执行:操作系统执行二进制的机器码
6.为什么说Java是“编译与解释并存”的语言?
- 编译型语言:编译器将源码一次性转为特定平台机器码。
- 解释型语言:解释器逐行解释源码为机器码并执行。
- Java先将源码编译为字节码,再由JVM解释执行字节码,故兼具两者特点。
基础语法
7.Java有哪些数据类型?
-
基本数据类型:
- 数值型:整数(byte、short、int、long)、浮点(float、double)。
- 字符型:char。
- 布尔型:boolean。
- 引用数据类型:类、接口、数组。
8. 自动类型转换、强制类型转换了解吗?
- 自动类型转换:小范围类型值赋给大范围类型变量,如int→long。
- 强制类型转换:大范围类型值赋给小范围类型变量,需显式转换,可能丢失精度,如(double)→float。
- 示例:
float f = 3.4F
(正确),float f = 3.4
(错误,需强制转换)。
9.什么是自动拆箱/装箱?
- 装箱:基本数据类型转为包装类型,如int→Integer。
- 拆箱:包装类型转为基本数据类型,如Integer→int。
- 示例:
Integer i = 10
(装箱),int n = i
(拆箱)。
10.&和&&有什么区别?
- &:逻辑与,两边表达式均执行,都为true时结果为true。
- &&:短路与,左边为false时右边不执行,结果为false。
- 类似:|(逻辑或)与||(短路或)的区别同上。
11.switch语句能否用在byte/long/String类型上?
- Java 5前:仅支持byte、short、char、int。
- Java 5:新增枚举类型。
- Java 7:新增String类型。
- long类型在所有版本均不支持。
12.break, continue, return的区别及作用?
- break:跳出整个循环**浑身以什
- continue:跳出本次循环,继续下次循环。
- return:结束当前方法,返回结果。
13.用效率最高的方法计算2乘以8?
2 << 3
,位运算左移3位相当于乘以2的3次方。
14.说说自增自减运算?
- ++/–可位于变量前(前缀)或后(后缀)。
- 前缀:先自增/减,再赋值,如
b = ++a
。 - 后缀:先赋值,再自增/减,如
b = a++
。 - 示例:
int i = 1; i = i++
,结果为1(JVM用临时变量存储原始值)。
15.float是怎么表示小数的?
- 遵循IEEE 754标准,单精度浮点数(32位),格式为:符号位(1位)+指数部分(10位)+尾数部分(21位)。
- 表达式:V = (-1)^S × M × 2^E,可能存在精度损失。
16.讲一下数据准确性高是怎么保证的?
- 避免使用float、double,改用BigDecimal类或转换为整数(如分)计算。
- 示例:
BigDecimal num1 = new BigDecimal("0.1"); BigDecimal sum = num1.add(new BigDecimal("0.2"))
(结果为0.3)。
面向对象
17.面向对象和面向过程的区别?
- 面向过程:以过程为核心,函数+步骤的顺序流程。
- 面向对象:以对象为核心,类和对象的模块化结构,通过继承、组合、多态复用代码。
- 类比:面向过程如编年体,面向对象如纪传体。
18.面向对象编程有哪些特性?
- 封装:数据和操作数据的方法捆绑,隐藏实现细节,提供访问接口。
- 继承:子类继承父类属性和方法,提高复用性,支持扩展和重写。
- 多态:同一接口/方法在不同类有不同实现,父类引用指向子类对象,运行时动态绑定。
- 设计原则:多组合少继承,避免强耦合,遵循开闭原则。
19.多态解决了什么问题?
- 解决代码灵活性和可扩展性问题,允许程序运行时确定调用子类或父类方法。
- 原理:通过动态绑定和虚方法表实现,方法调用延迟到运行时决定。
20.重载和重写的区别?
- 重载(Overload):同一类中,方法名相同,参数不同(类型、个数、顺序),与返回值无关。
- 重写(Override):子类与父类,方法名、参数、返回值相同,子类方法访问权限不低于父类,遵循里氏代换原则。
21.访问修饰符public、private、protected、以及默认时的区别?
修饰符 | 同一类 | 同一包 | 子类 | 全局范围 |
---|---|---|---|---|
private | 可见 | 不可见 | 不可见 | 不可见 |
default | 可见 | 可见 | 不可见 | 不可见 |
protected | 可见 | 可见 | 可见 | 不可见 |
public | 可见 | 可见 | 可见 | 可见 |
- default (即默认,什么也不写): 在同一包内可见,不使用任何修饰符。可以修饰在类、接口、变量、方法。
- private :在同一类内可见。可以修饰变量、方法。注意:不能修饰类(外部类)
- public : 对所有类可见。可以修饰类、接口、变量、方法
- protected : 对同一包内的类和所有子类可见。可以修饰变量、方法。注意:不能修饰类(外部类)。
22.this关键字有什么作用?
- 引用当前对象。
- 区分成员变量和形参,如
this.name = name
。 - 调用本类构造方法,如
this(参数)
。
23.抽象类和接口有什么区别?
- 继承:一个类只能继承一个抽象类,可实现多个接口。
- 构造方法:抽象类有构造方法,接口无。
- 方法:抽象类可含抽象和非抽象方法,接口(Java 8前)仅抽象方法,Java 8后可含默认方法和静态方法。
- 关系:抽象类体现“is-a”,接口体现“has-a”。
Java支持多继承吗?
Java 不支持多继承,一个类只能继承一个类,多继承会引发菱形继承问题。
接口可以多继承吗?
接口可以多继承,一个接口可以继承多个接口,使用逗号分隔。
继承和抽象的区别?
继承是一种允许子类继承父类属性和方法的机制。通过继承,子类可以重用父类的代码。
抽象是一种隐藏复杂性和只显示必要部分的技术。在面向对象编程中,抽象可以通过抽象类和接口实现。
抽象类和普通类的区别?
抽象类使用 abstract 关键字定义,不能被实例化,只能作为其他类的父类。普通类没有 abstract 关键字,可以直接实例化。
抽象类可以包含抽象方法和非抽象方法。抽象方法没有方法体,必须由子类实现。普通类只能包含非抽象方法。
24.成员变量与局部变量的区别有哪些?
- 定义位置:成员变量属于类,局部变量在方法中或为方法参数。
- 修饰符:成员变量可被public、private等修饰,局部变量不可。
- 存储位置:成员变量(静态→类,非静态→对象)在堆,局部变量(基本类型→栈,引用类型→堆引用)。
- 生命周期:成员变量随对象创建/类加载存在,局部变量随方法调用消失。
- 初始化:成员变量有默认值(final需显式赋值),局部变量无默认值。
从语法形式上看:成员变量是属于类的,⽽局部变量是在⽅法中定义的变量或是⽅法的参数;成员变量可以被 public , private , static 等修饰符所修饰,⽽局部变量不能被访问控制修饰符及 static 所修饰;但是,成员变量和局部变量都能被 final 所修饰。
从变量在内存中的存储⽅式来看:如果成员变量是使⽤ static 修饰的,那么这个成员变量是属于类的,如果没有使⽤ static 修饰,这个成员变量是属于实例的。对象存于堆内存,如果局部变量类型为基本数据类型,那么存储在栈内存,如果为引⽤数据类型,那存放的是指向堆内存对象的引⽤或者是指向常量池中的地址。
从变量在内存中的⽣存时间上看:成员变量是对象的⼀部分,它随着对象的创建⽽存在,⽽局部变量随着⽅法的调⽤⽽⾃动消失。
成员变量如果没有被赋初值:则会⾃动以类型的默认值⽽赋值(⼀种情况例外:被 final 修饰的成员变量也必须显式地赋值),⽽局部变量则不会⾃动赋值。
25.static关键字了解吗?
- 修饰变量:静态变量,类级别,所有实例共享。
- 修饰方法:静态方法,类级别,不可访问非静态成员。
- 修饰代码块:类加载时执行,仅一次。
- 修饰内部类:独立于外部类实例。
26.final关键字有什么作用?
- 修饰类:类不可继承,如String。
- 修饰方法:方法不可重写。
- 修饰变量:基本类型值不可改,引用类型引用不可改(对象内容可改)。
27.final、finally、finalize的区别?
- final:修饰符,修饰类、方法、变量(见上文)。
- finally:异常处理块,无论try块是否异常,均执行,用于释放资源。
- finalize:Object类方法,垃圾回收前调用,做清理工作,不推荐使用。
28.==和equals的区别?
- ==:比较基本类型值或引用类型地址。
- equals:默认比较地址,可重写比较内容(如String类)。
29.为什么重写equals时必须重写hashCode方法?
- 基于哈希的集合(如HashMap)需通过hashCode定位,equals判断相等。
- 若仅重写equals,相等对象可能有不同hashCode,导致集合处理异常(如重复元素)。
30.Java是值传递,还是引用传递?
- 值传递,对象作为参数传递时,传递的是引用地址的值。
31.说说深拷贝和浅拷贝的区别?
- 浅拷贝:新对象属性与原对象相同,引用类型共享引用地址。
- 深拷贝:新对象与原对象完全独立,引用类型递归复制。
- 实现:浅拷贝→实现Cloneable并重写clone();深拷贝→手动复制或序列化。
32. Java创建对象有哪几种方式?
- new关键字:调用构造方法。
- 反射:Class.forName(“类名”).newInstance()。
- clone:实现Cloneable接口。
- 序列化:反序列化字节流。
String
33.String是Java基本数据类型吗?可以被继承吗?
- 不是,String是一个类,是引用数据类型。
- 被final修饰,不可继承。
String常用方法
length()
- 返回字符串的长度。charAt(int index)
- 返回指定位置的字符。substring(int beginIndex, int endIndex)
- 返回字符串的一个子串,从beginIndex
到endIndex-1
。contains(CharSequence s)
- 检查字符串是否包含指定的字符序列。equals(Object anotherObject)
- 比较两个字符串的内容是否相等。indexOf(int ch)
和indexOf(String str)
- 返回指定字符或字符串首次出现的位置。replace(char oldChar, char newChar)
和replace(CharSequence target, CharSequence replacement)
- 替换字符串中的字符或字符序列。trim()
- 去除字符串两端的空白字符。split(String regex)
- 根据给定正则表达式的匹配拆分此字符串。
34.String和StringBuilder、StringBuffer的区别?
- String:不可变,修改生成新对象,适合内容不变场景。
- StringBuilder:可变,非线程安全,单线程频繁修改场景效率高。
- StringBuffer:可变,线程安全(方法加synchronized),多线程场景用。
35. String str1 = new String(“abc”) 和 String str2 = “abc” 的区别?
- str2:检查常量池,存在则引用,否则创建后引用。
- str1:先检查常量池,再在堆中创建新对象(常量池对象的副本)。
36.String是不可变类吗?字符串拼接是如何实现的?
- 不可变:字符数组private final,无修改方法,类被final修饰。
- 拼接:“+”操作编译期转为StringBuilder的append(),最终调用toString()生成新String。
37. intern方法有什么作用?
- 若常量池有相同内容字符串,返回池中的;否则将当前对象加入池并返回引用。
Integer
38.Integer a= 127,Integer b = 127;Integer c= 128,Integer d = 128;相等吗?
- a和b相等:自动装箱用Integer.valueOf(),-128~127范围用缓存。
- c和d不相等:超出缓存范围,创建新对象。
39.String怎么转成Integer的?原理?
- 方法:Integer.parseInt(String s)、Integer.valueOf(String s)。
- 原理:均调用parseInt(String s, int radix),遍历字符串计算数值(负累减方式)。
Object
40.Object类的常见方法?
- hashCode():返回哈希码。
- equals(Object obj):比较对象地址,可重写。
- clone():拷贝对象,需实现Cloneable。
- toString():返回类名@哈希码,可重写。
- wait()、notify()、notifyAll():多线程等待/通知。
- getClass():获取类信息。
- finalize():垃圾回收前清理,已弃用。
异常处理
41.Java中异常处理体系?
- 根类:Throwable。
- 子类:Error(严重错误,如OutOfMemoryError)、Exception(可处理异常)。
- Exception分为:编译时异常(Checked,如IOException)、运行时异常(RuntimeException,如NullPointerException)。
42.异常的处理方式?
- 抛出:throw抛出异常,throws声明可能抛出的异常。
- 捕获:try-catch捕获处理,finally释放资源。
43.三道经典异常处理代码题
- 题1:try块return 1,finally块打印3,结果输出31。
- 题2:try块return 2,finally块return 3,结果返回3。
- 题3:try块i=2并return i,finally块i=3,结果返回2(JVM暂存原始值)。
I/O
44.Java中IO流分为几种?
- 按方向:输入流、输出流。
- 按单位:字节流(如FileInputStream)、字符流(如FileReader)。
- 按功能:节点流(直接连接数据源)、处理流(包装节点流,如缓冲流)。
45.既然有了字节流,为什么还要有字符流?
- 字符流简化字符处理,避免手动编码转换,减少乱码问题,适合文本处理;字节流适合二进制数据(如音频、图片)。
46. BIO、NIO、AIO之间的区别?
- BIO:同步阻塞,线程处理I/O时阻塞,适用于连接少场景。
- NIO:同步非阻塞,线程可处理其他任务,通过Selector监控多Channel,适用于连接多且短的场景。
- AIO:异步非阻塞,I/O完成后回调通知,适用于连接多且长的场景。
序列化
47. 什么是序列化?什么是反序列化?
- 序列化:对象转为字节流,用于存储或传输。
- 反序列化:字节流转回对象。
- 需实现Serializable接口,serialVersionUID标识类版本,transient修饰变量不序列化。
48.说说有几种序列化方式?
- Java对象流序列化:ObjectOutputStream/ObjectInputStream。
- JSON序列化:如Jackson的ObjectMapper。
- ProtoBuff序列化:高效压缩,适合网络传输。
网络编程
49.了解过Socket网络套接字吗?
- 网络通信端点,用于TCP/UDP连接,实现进程间通信。
- TCP示例:ServerSocket监听,Socket连接,通过流传输数据。
- RPC框架基于Socket,如gRPC、Dubbo。
泛型
50. Java泛型了解么?
- 提高类型安全,编译时检查,避免类型转换错误。
- 形式:泛型类、泛型接口、泛型方法。
- 通配符:T、E、K、V、?。
- 类型擦除:编译时移除泛型信息,保持向下兼容。
注解
51.说一下你对注解的理解?
- 本质是标记,用于修饰类、方法等,可在编译、运行时被解析,实现配置、检查等功能。
反射
52. 什么是反射?应用?原理?
- 反射是指程序在运行时可以获取类的信息(如属性、方法、构造器等),并能动态操作类或对象的机制。
- 应用:框架(如Spring)的依赖注入、ORM框架(如MyBatis)的映射、动态代理等。
- 原理:通过Class类获取类的元数据,进而调用相应的方法(如getMethod()、newInstance()等)操作类或对象。
JDK1.8新特性
53.JDK 1.8都有哪些新特性?
- Lambda表达式:简化函数式接口的实现。
- 函数式接口:仅含一个抽象方法的接口,可被Lambda表达式实现。
- Stream流:简化集合的操作(如过滤、映射、聚合等)。
- Optional:处理空指针异常,避免NullPointerException。
- 接口默认方法和静态方法:接口可含默认实现的方法和静态方法。
- 新的日期时间API:如LocalDateTime、ZoneId等,线程安全。
54. Lambda表达式了解多少?
- 是一个匿名函数,格式为
(参数) -> 表达式
或(参数) -> { 代码块 }
。 - 需结合函数式接口使用,可简化代码,提高可读性。
- 示例:
(a, b) -> a + b
(实现两数相加的函数式接口)。
55.Optional了解吗?
- 用于包装可能为null的对象,提供方法(如isPresent()、orElse()、ifPresent()等)处理空值。
- 避免直接使用null,减少空指针异常。
- 示例:
Optional<String> opt = Optional.ofNullable(str); opt.orElse("default")
。
56.Stream流用过吗?
- 用于对集合进行高效操作,支持链式调用,分为中间操作(如filter、map)和终端操作(如collect、count)。
- 可实现并行处理,提高大数据量下的处理效率。
- 示例:
list.stream().filter(s -> s.startsWith("a")).collect(Collectors.toList())
(过滤出以“a”开头的元素)。