一、概念
1. 说一下Java特点
-
平台无关性:Java编译器将源代码编译成字节码,该字节码可以在任何安装了Java虚拟机(JVM)的系统上运行
-
面向对象:Java是一门严格的面向对象编程语言,几乎一切都是对象。面向对象编程这一特性使得代码更容易维护和重用,包括类、对象、继承、多态、抽象和封装
-
内存管理:Java有自己的垃圾回收机制,自动管理内存和回收不再使用的对象。这样开发者不需要手动管理内存,从而减少内存泄漏和其他内存相关的问题
2. Java的优势和劣势
优势:
-
Java的特点也是他的优势
-
强大的生态系统,比如Spring框架、各种库和工具
-
社区支持大,企业应用广泛
-
多线程支持,方便并发编程
-
安全性方面,Java有安全模型,比如沙箱机制,适合网络环境
-
稳定性强,企业级应用长期使用
-
版本更新也比较注重向后兼容
劣势:
-
性能比较差,相比于C这种原生编程语言性能较差
-
内存消耗大,JVM本身占内存
-
面向对象过于严格,有时候写简单程序反而麻烦
-
开发效率相比动态语言(比如Python)较低,Java需要更多代码
-
编译过程也可能拖慢开发节奏
3. Java为什么是跨平台的
-
主要依赖于JVM
-
编写的Java源码编译后生成.class文件(也就是字节码文件)
-
JVM就是负责将字节码文件翻译成特定平台下的机器码然后运行
-
也就是说,只要在不同平台上安装对应的JVM,就可以运行字节码文件从而运行编写的Java程序
4. JVM、JDK、JRE三者关系
-
JVM(Java虚拟机):是Java程序运行的环境,负责将Java字节码编译成机器码,并执行程序。JVM提供了内存管理、垃圾回收、安全性等功能,使Java程序具备跨平台性
-
JDK(Java开发工具包):是开发Java程序所需的工具集合,包含了JVM、编译器、调试器等开发工具,以及一系列的类库。JDK提供了开发、编译、调试和运行Java程序所需的全部工具和环境
-
JRE(Java运行时环境):是Java程序运行所需的最小环境,包含了JVM和一组Java类库,用于支持Java程序执行。JRE不含开发工具,只提供Java程序运行时所需的运行环境
5. 编译型语言和解释型语言的区别
-
编译型语言:在程序执行之前,整个源代码会被编译成机器码或者字节码,生成可执行文件。执行时直接运行编译后的代码,速度快,但跨平台性较差
-
解释型语言:在程序执行时,逐行解释执行源代码,不生成独立的可执行文件。通常由解释器动态解释并执行代码,跨平台性好但执行速度较慢
-
典型的编译型语言如C、C++,典型的解释型语言如Python、JavaScript
6. 值传递和引用传递的区别
-
在Java中参数传递只有一种方式就是值传递,但是根据传递的参数类型(基本类型或引用类型)会表现出不同的行为
-
对于基本类型,传递的是值的副本,在方法内修改不会影响原来的变量
-
对于引用类型,传递的是对象内存地址的副本。也就是说在方法内修改对象的属性会影响原来的对象,因为引用指向同一个对象。但在方法内让引用指向一个新对象,不会影响原来的变量
二、数据类型
1. 基本数据类型
整数类型:
-
byte:1字节
-
short:2字节
-
int:4字节
-
long:8字节
浮点类型:
-
float:4字节
-
double:8字节
字符类型:
- char:2字节
位数等于字节数×8
2. 数据类型转换方式
自动类型转换(隐式转换):
当目标类型范围大于源类型时,Java会自动将源类型转换为目标类型,不需要显式的类型转换。比如int → long,float → double。
强制类型转换(显式转换):
当目标类型范围小于源类型范围时,需要使用强制类型转换将源类型转换为目标类型,可能导致数据丢失或溢出。比如long → int,double → int。
字符串转换:
将字符串转换为整型或浮点型,比如Integer.parseInt()、Double.parseDouble()。
数值之间的转换:
通过类型的包装类可以实现转换,比如整型转换为字符型,字符型转换为整型等。
3. 类型互转会出现什么问题?
-
大范围类型转换为小范围类型时会出现数据溢出或者精度损失
-
数据溢出:目标类型无法容纳原数据就会数据溢出
-
精度损失:浮点数类型转换会出现精度损失
-
父类转换为子类(向下转型)时会出现问题,解决方式是用instanceof检查
4. 为什么用BigDecimal不用double?
double会出现精度损失的问题,double执行的是二进制浮点运算,二进制有些情况下不能准确地表示一个小数,而BigDecimal是精确计算。
5. 装箱和拆箱是什么?
自动装箱是程序需要一个包装类对象时,如果传入的是一个基本类型的值,编译器会自动将这个基本类型值转换为对应的包装类对象。
自动拆箱是程序需要一个基本数据类型的值时,如果传入的是一个包装类对象,编译器会自动将这个包装类对象转换为对应的基本数据类型值。
弊端:
-
包装类对象为null时拆箱会报错
-
循环时拆箱或者装箱会影响程序性能
6. Java中为什么会有包装类?
包装类是对应基本数据类型的引用类型。
泛型只能用引用类型,因此要在泛型中用到int就必须使用Integer包装类。转换时,把int转换为字符串需要先把它转换为Integer再转换为字符串类型。集合也只能存储对象,不能存储基本数据类型。
但是基本类型的读写效率和存储效率要比包装类高效。
7. Integer缓存(128陷阱)
Java的Integer类内部实现了一个静态缓存池,用于存储特定范围内的整数值对应的Integer对象,这个范围是-128到127。数据在这个范围时不会每次都生成新的对象实例,而是直接复用缓存的现有对象,直接从内存中取出,不需要新建一个对象。因此在-128到127范围内的Integer对象比较是相等的,超出就是不相等的。
三、面向对象
1. 怎么理解面向对象?简单说说封装、继承、多态
面向对象是一种编程范式,它是将现实世界中的事务抽象为对象,对象具有属性和方法。面向对象编程的设计思想是以对象为中心,通过对象之间的交互来完成程序的功能,具有灵活性和拓展性。
封装:是指将对象的属性和方法结合在一起,对外隐藏对象的内部细节,仅通过对象提供的接口与外界交互。封装的目的是增强安全性和简化编程,使得对象更独立。
继承:继承是一种可以使得子类共享父类数据结构和方法的机制,是代码复用的重要手段。通过继承可以建立类与类之间的层次关系,使得结构更加清晰。
多态:是指允许不同类的对象对同一消息作出响应,即同一个接口使用不同的实例而执行不同操作。可以分为编译时多态(重载)和运行时多态(重写),它使得程序具有良好的灵活性和拓展性。
2. 多态体现在哪几个方面?
-
重载
-
重写
-
接口:类实现接口需要实现接口中的方法,多个类可以实现同一个接口
-
抽象类:抽象类的子类需要实现父类中的抽象方法
-
向上转型和向下转型
3. 面向对象的设计原则你知道有哪些吗?
面向对象编程的六大原则:
-
单一职责原则
-
开放封闭原则
-
里氏替换原则
-
接口隔离原则
-
依赖倒置原则
-
最少知识原则
4. 抽象类和普通类区别?
-
实例化:普通类可以实例化对象,抽象类不能被实例化,只能被继承
-
方法实现:普通类中的方法可以有具体实现,抽象类方法可以有实现可以没有实现
-
继承:一个类可以继承一个普通类,继承多个接口,而一个类只能继承一个抽象类
-
实现限制:普通类可以被其他类继承和使用,而抽象类一般用于作为基类,被其他类继承和扩展使用
5. 抽象类和接口的区别?
实现方式 :实现接口关键字为implements,继承抽象类关键字为extends,一个类可以实现多个接口但只能继承一个抽象类。
方法方式 :接口只有定义,没有方法的实现,Java 1.8可以定义default方法体,抽象类可以有定义与实现。
访问修饰符:
-
接口成员变量默认为
public static final,必须赋初值,不能被修改 -
接口中的抽象方法默认是
public abstract -
从Java 8开始接口可以定义
default和static方法,并且可以实现 -
Java 9还可以定义
private方法 -
抽象类中成员变量默认为
default访问权限,可在子类中被重新定义,也可被重新赋值 -
抽象方法被
abstract修饰
变量:抽象类可以包含实例变量和静态变量,接口只能包含常量。
6. 接口里面可以定义哪些方法?
-
抽象方法 :默认是
public abstract修饰,可以省略 -
默认方法 :
default修饰,在Java 8引入,允许修饰的方法提供具体实现 -
静态方法 :
static修饰,Java 8引入,通过接口名调用,不需要重写 -
私有方法:Java 9引入,不能被实现类访问,只能在接口内部使用
7. 解释Java中的静态变量和静态方法
静态变量
-
静态变量属于类本身而不是某个实例
-
共享性:所有该类的实例共享同一个静态变量,如果一个实例改变了静态变量的值,其他实例也会看到这个更改
-
初始化:静态变量在类被加载时初始化,只会对其进行一次分配内存
-
访问方式:静态变量可以通过类名访问也可以通过实例访问
静态方法
-
静态方法属于类本身而不是某个实例
-
无实例依赖:静态方法可以在没有创建类实例的情况下调用,对于静态方法来说,不能直接访问非静态成员变量或方法
-
访问静态成员:静态方法可以直接调用其他静态变量或静态方法
-
多态性:静态方法不支持重写
四.关键字
1. final关键字
修饰类:该类不能被继承
修饰方法:该方法不能被重写
修饰变量:
-
修饰基本数据类型变量,则该变量被赋值后不能更改
-
修饰引用类型变量,则该变量不能再指向其他对象,但是该对象属性的值是可以修改的
2. static关键字
修饰变量:静态变量
修饰方法:静态方法
修饰代码块:静态代码块,在类加载时执行,且只执行一次,用于初始化静态变量或执行类级别的预处理操作
修饰内部类:静态内部类不依赖于外部类的实例,可以独立存在,不能直接访问外部类的非静态成员
五、深拷贝和浅拷贝
1. 深拷贝和浅拷贝的区别?
浅拷贝:
-
创建一个新的对象
-
将原对象的字段值复制到新对象中
-
但如果原对象内部有引用类型的字段,只是将引用复制到新对象中
-
两个对象指向的是同一个引用对象
深拷贝:
-
会递归复制对象内部所有引用类型的字段
-
生成一个全新的对象以及其内部的所有对象
2. 实现深拷贝的三种方式是什么?
-
实现
Cloneable接口并重写clone()方法 -
使用序列化和反序列化
-
手动递归复制