Java基础 面试速查表
覆盖 Java 平台无关性、JVM/JRE/JDK、对象模型、内存管理、克隆与常见基础知识的面试速查记录。
概念
Java的特点
- 面向对象
- 平台无关性
- 内存管理
Java的优势和劣势是什么?
- 优势: 跨平台、面向对象、优秀的社区生态、自动垃圾回收机制、安全性。
- 劣势: 速度比原生语言慢、JVM对资源有限的环境不友好、面向对象过于严格。
Java为什么可以跨平台
因为由Java运行依托的JVM有不同平台的版本,Java编译生成的字节码文件可以直接在JVM上运行。
JVM、JRE、JDK区别和关系
- JVM:Java虚拟机,负责将Java字节码翻译成机器码并运行程序。提供内存管理、垃圾回收等机制,使得Java可以跨平台。
- JRE:Java运行时环境,包括一组类库和JVM。
- JDK:包含了Java运行、编译的所有环境。包括类库,JVM、Java编译器(javac)和Java调试器(jbd)等等。
Java为什么解释和编译都有?
Java经过编译后生成字节码文件,再由JVM解释字节码文件运行。
数据类型
八种基本数据类型
- 数值型:整数:byte(8)、short(16)、int(32)、long(64) 浮点型:float(32)、double(64)
- 字符型:char(2)
- 布尔型:boolean(无明确上限) 引用数据类型:class、interface和数组
数据类型的转换方式
- 隐式类型转换:当目标类型大于原类型时,会自动转换,如int转换为long
- 显式类型转换:int = (long) long
- 字符串转换:可以将字符串转换为其他数据类型。可以使用包装类下的方法,如
Integer.parseInt() - 数值之间的转换:可以使用包装类中的方法将字符型转换为整型。
类型转换会出现什么问题
- 数据丢失
- 数据溢出
- 精度丢失
- 类型不匹配
为什么用BigDecimal不用double
double会出现精度丢失的问题,在牵扯金钱计算的时候,都使用BigDecimal BigDecimal使用字符串创建,不能使用double创建。
装箱和拆箱是什么
基本数据类型和对应的包装类之间进行转化的过程。
- 自动装箱发生的时间:赋值、方法调用
- 自动装箱的弊端:在循环中进行自动装箱会创建多余的对象,影响程序的性能
为什么Java要有Integer
- 能够将数据和处理这些数据的方法结合在一起。例如Integer可以用parseint来处理字符串转换。
- Java中的绝大部分方法都只能处理类型,例如不能给List传入int参数。
- Java中基本类型和引用类型不能直接转换,必须使用包装类包装才能转换。
- 集合中只能储存包装类。
Integer缓存
在Integer类内部有一个缓存池,用来存储-128到127的数据。当用到这些数据时,会直接从内存中取出,不需要新建对象。
面向对象
怎么理解面向对象
面向对象是将现实生活中的事物抽象为对象。对象拥有属性(字段)和行为(方法) Java面向对象的三大特性:封装、继承、多态
- 封装:只能通过对象提供的方法与外界交互。
- 继承:继承可以使子类复用父类方法。是代码重用的重要手段。
- 多态:可以使不同类的对象对同一操作做出反应,包括重载和重写。
多态体现在哪里
- 方法重写
- 方法重载
- 接口与实现
- 向上转型和向下转型
面向对象的六大设计原则
- 单一职责原则
- 开放封闭原则
- 里氏替换原则
- 接口隔离原则
- 依赖倒置原则
- 最少知识原则
重载和重写的区别
- 重载:在一个类中,可以有多个同名的方法,它们的参数列表不同。
- 重写:在子类中可以重写父类的方法。但是方法名、参数列表和返回类型必须和父类一致。
抽象类和普通类的区别
- 抽象类不能被实例化。
- 普通类必须有方法实现,抽象类可以没有。
抽象类和接口的区别
- 抽象类可以有成员变量,构造方法和具体方法。
- 接口只能有常量和抽象方法。 区别:
- 一个类只能继承一个抽象类,但是可以继承多个接口
- 接口只能有方法定义,不能有实现。抽象类可以有默认方法。
- 接口成员变量默认为public static final,必须有初值,不能被修改。成员方法为public、abstarct的。 抽象类中的成员变量可以被重新定义。
接口中可以定义哪些方法
抽象(abstract)、默认、静态(static)、私有(private)方法。、 私有方法只能在接口内部访问,不能被实现类访问。
Java中的静态变量和静态方法
静态意味着它是和类本身关联的,而不是和类的对象关联的。它们在内存中只存在一份, 可以通过类本身调用,被类的所有实例共享。 静态方法不能访问非静态的成员变量和方法。但可以直接调用其他静态变量和静态方法。静态方法不能被重写,但可以被隐藏。
关键字
Java中final关键字的作用是什么
- 修饰类时:这个类不能被继承
- 修饰变量时:常量,不能修改
- 修饰方法:不能被子类重写
深拷贝与浅拷贝
深拷贝和浅拷贝的区别
- 浅拷贝只赋值对象中的值类型字段,对于引用字段,不会创建一个新的对象。
- 深拷贝既赋值值类型字段,也会重新创建一个新的对象。
深拷贝的三种实现方法
- 实现Cloneable()接口并重写clone()方法
public class ClassB implements Cloneable{ private int b; private ClassA cla;
@Override
protected Object clone() throws CloneNotSupportedException {
ClassB clonedClass = (ClassB) super.clone();
clonedClass.cla = (ClassA) cla.clone();
return clonedClass;
}
}
public class ClassA implements Cloneable{ private int a;
@Override
protected Object clone() throws CloneNotSupportedException {
return super.clone();
}
} ```
- 使用序列化和反序列化
- 手动递归复制
对象
Java创建对象有几种方式
- 通过new创建
- 通过反射机制创建 可以通过反射获取类名,然后调用newInstance()获取
- 通过clone()方法获取
- 通过反序列化获取
New出的对象什么时候回收
Java垃圾回收器会周期性地检测不再被引用的对象。
- 使用计数器检测对象是否被引用。
- 使用可达性分析算法,分析一个对象是否可达。
如何获得私有对象
- 如果类遵循了良好的代码规范的话,可以使用getter方法获取对象。
- 可以通过反射方法绕过private获取对象。
反射
反射机制是指在运行过程中,可以获得并调用一个类的所有字段和方法,同时可以获得他的类名、包名、父类等等。
- 运行时类信息访问:可以在运行时获得类的类名、包名、父类等等
- 动态对象创建:即使不知道具体类名,也可以通过Class的newInstance创建对象
- 动态方法调用:可以调用对象的私有方法。
- 访问和修改字段值:可以访问并修改字段值,即使是私有的。
异常
Java异常的分类
Java异常主要有两部分:Error和Exception
- 错误Error:这是指运行环境的错误,程序不应该捕获这类错误。错误是无法处理的严重错误。
- 异常Exception:表示程序本身可以处理的错误。
- 非运行时异常:在编译期就应该捕获并抛出的异常,比如类不存在
- 运行时异常:在运行期捕获的异常,如数组越界
Java的异常处理
- 使用try-catch块处理异常。
try {
//可能抛出异常的代码
} catch(ExceptionType1 e) {
//异常类型1的处理
} catch(ExceptionType2 e) {
//异常类型2的处理
} catch(ExceptionType3 e) {
//异常类型3的处理
} finally {
//可选的finally块,用于定义无论是否发生异常都会执行的代码
}
- 使用throw语句手动抛出异常。
throw new Exception();
- 使用throws关键字:如果不想在方法内部处理异常,可以使用throws关键字将异常传递给调用者处理。
public void method() throws Exception {
}
- finally块:无论是否发生异常都会执行的代码块。
Object
==和equal有什么区别
- 对于字符串对象,==对比的是两个变量在内存中的首地址,属于数值比较。对于非字符串对象,两者效果是相同的。
- equals比较的内容,比较两个字符串的内容是否相等。
hashCode和equal方法有什么关系
- 一致性:如果
a.equal(b),则两个对象的hashcode一定相等。 - 非一致性:如果两个对象的hashcode相等,
a.equal(b)不一定为true。
String、StringBuffer、StringBuilder
- String线程安全,因为每次修改都会创建一个新的对象。但是开销最大。
- StringBuilder非线程安全。可以直接修改,不会创建新对象,适合单线程使用。性能开销最小。
- StringBuffer线程安全,可以直接修改。性能开销比StringBuilder大,因为增加了线程安全机制。
Java8新特性
Lambda表达式
Lambda用于创建匿名函数,有两种表示方法。
(parameters) -> expression表达式的值作为返回值(parameters) → { statements; }需要在statments中手动return Lambda可以使代码更加清晰明了,但是过多使用lambda会增加调试困难。
Stream API
流API提供了一种高效处理集合对象的方式,包括过滤、映射、排序等。
Stream流的并行API是什么
是ParallelStream。并行流将元数据拆分成数个小任务多线程进行流操作,操作结束之后将结果合并。底层是使用通用的fork/join池来进行的。