Java基础
基础概念与常识
Java 语言有哪些特点?
- 简单易学
- 面向对象(封装,继承,多态)
- 平台无关性( Java 虚拟机实现平台无关性)
- 支持多线程( C++ 语言没有内置的多线程机制,因此必须调用操作系统的多线程功能来进行多线程程序设计,而 Java 语言却提供了多线程支持);
- 可靠性(具备异常处理和自动内存管理机制);
Java SE vs Java EE
Java SE 是 Java 的基础版本,Java EE 是 Java 的高级版本
Java SE 更适合开发桌面应用程序或简单的服务器应用程序,Java EE 更适合开发复杂的企业级应用程序或 Web 应用程序。
JVM vs JDK vs JRE
JVM
Java 虚拟机(Java Virtual Machine, JVM)是运行 Java 字节码的虚拟机。
JDK 和 JRE
JDK(Java Development Kit)是一个功能齐全的 Java 开发工具包,供开发者使用,用于创建和编译 Java 程序。它包含了 JRE(Java Runtime Environment),以及编译器 javac 和其他工具,如 javadoc(文档生成器)、jdb(调试器)、jconsole(监控工具)、javap(反编译工具)等。
什么是字节码?采用字节码的好处是什么?
在java中,JVM可以理解的代码就叫做字节码(即扩展名为.class的文件),只面向虚拟机。
解决了传统解释型语言执行效率低的问题,同时又保留了解释型语言可移植的特点。
由于字节码并不针对一种特定的机器,因此,java程序无须重新编译便可在多种不同操作系统的计算机上运行
为什么说 Java 语言“编译与解释并存”?
这是因为java语言既具有编译型语言的特征,也具有解释型语言的特征。因为java程序要经过先编译,后解释两个步骤,由java编写的程序需要先经过编译步骤,生成字节码(.class文件),这种字节码必须由java解释器来解释执行
基本语法
注释有哪几种形式?
- 单行注释
- 多行注释
- 文档注释
标识符和关键字的区别是什么?
标识符就是一个名字,我们需要给程序、类、接口等取名字。
关键字就是被赋予特殊含义的标识符。
Java 语言关键字有哪些?
访问控制 类、方法和变量修饰符 程序控制 错误处理 包相关 基本类型 变量引用 保留字
自增自减运算符
符号在前就先加/减,符号在后就后加/减。
移位运算符
高效
continue、break 和 return 的区别是什么?
- continue 跳出当前的这一次循环,继续下一次循环
- break 跳出真个循环体,继续执行循环下面的语句
- return 用于跳出所在方法,结束该方法的运行
基本数据类型
Java 中的几种基本数据类型了解么?
java中有8个基本数据类型
- 6种数字类型:
- 4种整数型:byte short int long
- 2种浮点型:float、double
- 1种字符类型:char
- 1种布尔型:boolean
这八种基本类型都有对应的包装类分别为:Byte、Short、Integer、Long、Float、Double、Character、Boolean 。
基本类型和包装类型的区别?
- 用途:包装类可用于泛型,而基本类型不可以
- 存储方式:基本类型的局部变量存放在java虚拟机栈种的局部变量表中,基本数据类型的成员变量存放在java虚拟机的堆中。包装类属于对象类型,几乎所有的对象实例都存在堆。
- 占用空间:相比于包装类(对象类型),基本数据类型占用的空间往往非常小
- 默认值:成员变量包装类不赋值就是null,而基本类型由默认值且不是null
- 比较方式:对于基本数据类型来说,==比较的是值。对于包装数据来说,==比较的是对象的内存地址。
包装类型的缓存机制了解么?
Java基本数据类型的包装类型的大部分都用到了缓存机制来提升性能。
Byte,Short,Integer,Long这4包装类默认创建了数值[-128,127]的相应类型的缓存数据 Character创建了数值在[0,127]范围的缓存数据,Boolean直接返回True Or False
所有整型包装类对象之间值的比较,全部使用 equals 方法比较。
自动装箱与拆箱了解吗?原理是什么?
什么是自动拆装箱?
- 装箱:将基本类型用它们对应的引用类型包装起来
- 拆箱:将包装类型转换为基本数据类型
为什么浮点数运算的时候会有精度丢失的风险?
这个和计算机保存浮点数的机制有很大关系。
我们知道计算机是二进制的,而计算机在表示一个数字时,宽度是有限的,无限循环的小数存储在计算机时,只能被截断,所以就会导致小数精度发生损失的情况。
这也就是解释了为什么浮点数没有办法用二进制精确表示
如何解决浮点数运算的精度丢失问题?
BigDecimal 可以实现对浮点数的运算,不会造成精度丢失。通常情况下,大部分需要浮点数精确运算结果的业务场景(比如涉及到钱的场景)都是通过 BigDecimal 来做的。
超过 long 整型的数据应该如何表示?
基本数值类型都有一个表达范围,如果超过这个范围就会有数值溢出的风险。
在 Java 中,64 位 long 整型是最大的整数类型。
BigInteger 内部使用 int[] 数组来存储任意大小的整形数据。
变量
成员变量与局部变量的区别?
- 语法形式:成员变量属于类 局部变量是在代码块中或方法定义的变量或者参数;成员变量可以被public,private,static等修饰符所修饰,而局部变量不能被访问控制修饰符以及static所修饰;但是成员变量和局部变量都能被final修饰。
- 存储方式:而对象存在于堆内存,局部变量则存在于栈内存。
- 生存时间:成员变量是对象的一部分,它随着对象的创建而存在 局部变量随着方法的调用而自动生成,随着方法的调用结束而消亡
- 默认值:成员变量如果没有被赋初始值,则会自动以类型的默认值而赋值
静态变量有什么作用?
静态变量也就是被 static 关键字修饰的变量。
它可以被类的所有实例共享,无论一个类创建了多少个对象,它们都共享同一份静态变量。
也就是说,静态变量只会被分配一次内存,即使创建多个对象,这样可以节省内存。
字符型常量和字符串常量的区别?
- 形式:'' ""。
- 含义:字符常量相当于一个整数值(ASCII值);字符串常量代表一个地址值。
- 占内存大小:字符常量只占用2个字节;字符串常量占若干个字节。
方法
什么是方法的返回值?方法有哪几种类型?
方法的返回值就是获取某个方法体中的代码执行后产生的结果
- 无参数无返回值
- 有参数无返回值
- 有返回值无参数
- 有返回值有参数
静态方法为什么不能调用非静态成员?
静态方法是属于类的,在类的加载的时候就会分配内存,可以通过类名直接访问。而非静态成员变量属于实例对象,只有在对象实例化之后才存在,需要通过类的实例对象去访问。
静态方法和实例方法有何不同?
- 调用方式:调用静态方法可以无需创建对象。类名.方法名
- 访问类成员是否存在限制:静态方法在访问本类的成员时,只允许访问静态成员,不允许访问实例成员。
重载和重写有什么区别?
重载
发生在同一个类中,方法名必须相同,参数类型不同、个数不同、顺序不同,方法返回值和访问修饰符可以不同
重写
重写发生在运行时期,是子类对父类的允许访问的方法的实现过程进行重新编写
总结
方法重写要遵循"两同两小一大"
什么是可变长参数?
允许在调用方法时传入不定长度的参数。就可以接受0个或者多个参数
遇到方法重载的情况怎么办呢?会优先匹配固定参数
面向对象基础
面向对象和面向过程的区别
面向过程编程是 POP :将解决问题的过程拆成一个个方法,通过一个个方法的执行解决问题
面向对象编程是 OOP :先抽象出对象,然后用对象执行方法的方式解决问题
创建一个对象用什么运算符?对象实体与对象引用有何不同?
new,创建对象实例存放在堆内存中,对象引用指向对象实例,对象引用存放在栈内存中
- 一个对象引用可以指向0个或1个对象
- 一个对象可以有n个引用指向它
对象的相等和引用相等的区别
对象相等指的是内存中存放的内容是否相同
引用相同指的是他们指向的内存地址是否相同
如果一个类没有声明构造方法,该程序能正确执行吗?
可以
默认会有不带参数的构造方法
构造方法有哪些特点?是否可被 override?
- 名称与类型相同
- 没有返回值
- 自动执行
构造方法不能被重写,但可以被重载。
可以有多个构造方法,根据参数列表的不同。
面向对象三大特征
封装
把一个对象的信息隐藏在对象内部,不允许外部对象直接访问对象的内部信息,但是可以提供一些可以被外界访问的方法来操作属性。
继承
- 子类拥有父类所有的方法和属性,但是父类中的私有属性和方法子类是无法访问,只是拥有
- 子类可以拥有自己的属性和方法,即子类可以对父类进行扩展
- 子类可以用自己的方法实现父类的方法
多态
表示一个对象具有多种的状态,具体表现为父类的引用指向子类的实例。
接口和抽象类有什么共同点和区别?
共同点:
- 实例化
- 抽象方法 不同点:
- 继承和实现
- 设计目的
- 成员变量
- 方法
深拷贝和浅拷贝区别了解吗?什么是引用拷贝?
浅拷贝:在堆上创建一个新的对象,如果原对象的属性是引用地址的话,浅拷贝就会复制内部对象的引用地址,也就是说拷贝对象和原对象共用一个内部对象
深拷贝:会完全复制整个对象,包含这个对象所包含的内部对象
引用拷贝:共同引用堆上的
Object
Object 类的常见方法有哪些?
getClass
hashCode
equals
clone
toString
notify
notifyAll
wait
finalize
== 和 equals() 的区别
- 如果是基本数据类型,==比较是值
- 如果是引用类型,==比较的是对象的内存地址
equals() 方法存在两种使用情况:
- 类没有重写 equals()方法:通过equals()比较该类的两个对象时,等价于通过“==”比较这两个对象,使用的默认是 Object类equals()方法。
- 类重写了 equals()方法:一般我们都重写 equals()方法来比较两个对象中的属性是否相等;若它们的属性相等,则返回 true(即,认为这两个对象相等)。
hashCode() 有什么用?
用来获得哈希码(int整数),作用就是确定该对象在哈希表中的索引位置
为什么要有 hashCode?
我们以“HashSet 如何检查重复”为例子来说明为什么要有 hashCode?
为什么重写 equals() 时必须重写 hashCode() 方法?
- equals 方法判断两个对象是相等的,那这两个对象的 hashCode 值也要相等。
- 两个对象有相同的 hashCode 值,他们也不一定是相等的(哈希碰撞)。
String
String、StringBuffer、StringBuilder 的区别?
- 可变性:String不可变
- 线程安全性:String、StringBuffer线程安全
- 性能:
总结:
- 操作少量数据,String
- 单线程操作字符串缓冲区下操作大量数据,StringBuilder
- 多线程操作字符串缓冲区下操作大量数据,StringBuffer
String 为什么是不可变的?
- String类被final修饰导致其不能被继承,进而避免子类破坏String不可变
- 保存字符串数组被final修饰且为私有的,并且String类并没有提供/暴露修改这个字符串的方法
字符串拼接用“+” 还是 StringBuilder?
- 是通过StringBuilder调用append方法来实现的,拼接完成之后调用toString得到一个String对象。缺陷就是在循环体中,编译器不会创建单个 StringBuilder 以复用,会导致创建过多的 StringBuilder 对象。
如果直接使用 StringBuilder 对象进行字符串拼接的话,就不会存在这个问题了。
String#equals() 和 Object#equals() 有何区别?
String 中的 equals 方法是被重写过的,比较的是 String 字符串的值是否相等。
Object 的 equals 方法是比较的对象的内存地址。
字符串常量池的作用了解吗?
是jvm为了提升性能和减少内存和减少内存消耗针对字符串专门开辟的一块区域,主要目的是为了避免字符串的重复创建
String s1 = new String("abc");这句话创建了几个字符串对象?
如果字符串常量池里面有这个字符串,那么就只会创建一个字符串对象。如果没有在这个字符串,那么就会在字符串常量池里面创建一个,在堆上也创建一个,创建了两个字符串对象。
String#intern 方法有什么作用?
用来处理字符串常量池中的字符串对象引用
- 字符串已有相同内容的字符串对象:直接返回该对象的引用
- 常量池中没有相同内容的字符串对象:这个方法就会将当前字符串对象的引用添加到字符串常量池中,并返回该引用。
String 类型的变量和常量做“+”运算时发生了什么?
无法理解
异常
Exception 和 Error 有什么区别?
Exception 程序本身可以处理的异常
Error 程序无法处理的错误
Checked Exception 和 Unchecked Exception 有什么区别?
Checked Exception 即 受检查异常 ,Java 代码在编译过程中,如果受检查异常没有被 catch或者throws 关键字处理的话,就没办法通过编译。
Unchecked Exception 即 不受检查异常 ,Java 代码在编译过程中 ,我们即使不处理不受检查异常也可以正常通过编译。
Throwable 类常用方法有哪些?
toString
getMessage
getLocalizedMessage
printStackTrace
try-catch-finally 如何使用?
try 用于捕获异常
catch 用于处理try捕获到的异常
finally 在return之前执行这段代码
finally 中的代码一定会执行吗?
不一定,在finally之前虚拟机被终止运行的话,finally中的代码就不会别执行
如何使用 try-with-resources 代替try-catch-finally?
try (BufferedInputStream bin = new BufferedInputStream(new FileInputStream(new File("test.txt")));
BufferedOutputStream bout = new BufferedOutputStream(new FileOutputStream(new File("out.txt")))) {
int b;
while ((b = bin.read()) != -1) {
bout.write(b);
}
}
catch (IOException e) {
e.printStackTrace();
}
异常使用有哪些需要注意的地方?
- 抛出的异常信息一定要有意义。
泛型
什么是泛型?有什么作用?
Java 泛型(Generics) 是 JDK 5 中引入的一个新特性。使用泛型参数,可以增强代码的可读性以及稳定性。
举个例子 ArrayList Person,这段代码指明了只能传入Person对象,如果传入其他对象就会发生错误
泛型的使用方式有哪几种?
- 泛型类
- 泛型接口
- 泛型方法
项目中哪里用到了泛型?
- 自定义接口通用返回结果Result可根据具体的返回类型动态指定结果的数据类型
- 定义Excel处理类用于动态指定Excel导出的数据类型
- 构建集合工具类
反射
何谓反射?
在运行时分析类以及执行类中方法的能力。
通过反射你可以获取任意一个类的所有属性和方法,你还可以调用这些方法和属性。
反射的优缺点?
反射可以让我们的代码更加灵活、为各种框架提供开箱即用的功能提供了便利。
反射的应用场景?
这些框架中也大量使用了动态代理,而动态代理的实现也依赖反射。
注解
何谓注解?
主要用于修饰类、方法或者变量,提供某些信息供程序在编译或者运行时使用。
注解的解析方法有哪几种?
- 编译期直接扫描:@Override
- 运行期通过反射处理:比如说Spring框架自带的注解@Value、@Component都是通过反射来进行处理的
SPI
何谓 SPI?
SPI service provider interface 服务提供者的接口
将服务接口和具体的服务实现分离开来,将服务调用方和服务实现者解耦,能够提升程序的扩展性、可维护性。
很多框架都使用了Java的SPI机制,比如:Spring框架、数据库加载驱动、日志接口、以及Dubbo的扩展
SPI 和 API 有什么区别?
当实现方提供了接口和实现,我们可以通过调用实现方的接口从而拥有实现方给我们提供的能力,这就是API
当接口存在与调用方这边时,这就是SPI
SPI 的优缺点?
提高接口的设计的灵活性
- 并发问题
- 不能按需加载,需要全部遍历
序列化和反序列化
什么是序列化?什么是反序列化?
序列化:将数据结构或对象转换成可以存储或传输的形式,通常是二进制字节流,也就是JSON,XML等文本格式
反序列化:将在序列化过程中所生成的数据转换为原始数据结构或者对象的过程
如果有些字段不想进行序列化怎么办?
对于不想进行序列化的变量,使用 transient 关键字修饰。
常见序列化协议有哪些?
Hessian、Kryo、Protobuf、ProtoStuff,这些都是基于二进制的序列化协议。
为什么不推荐使用 JDK 自带的序列化?
- 不支持跨语言调用
- 性能差
- 存在安全问题
I/O
Java IO 流了解吗?
java io即输入和输出。
数据输入到计算机内存的过程即输入,反之输出到外部存储的过程即输出。
数据传输过程类似于水流,因此称为io流。
I/O 流为什么要分为字节流和字符流呢?
- 字符流是由java虚拟机将字节转换得到的,这个过程还算是比较耗时
- 如果我们不知道编码类型的话,使用字节流的过程很容易出现乱码问题
Java IO 中的设计模式有哪些?
装饰器
适配器
工厂
观察者模式
BIO、NIO 和 AIO 的区别?
BIO 阻塞直到处理完成
NIO Selector监听多个Channel非阻塞
AIO 通知回调
语法糖
什么是语法糖?
实现相同的功能,基于语法糖写出来的代码往往更简单简洁且更易阅读。
Java 中有哪些常见的语法糖?
Java 中最常用的语法糖主要有泛型、自动拆装箱、变长参数、枚举、内部类、增强 for 循环、try-with-resources 语法、lambda 表达式等。