面试题
一 . Java基础
Java基础
1. JDK和JRE和JVM有什么区别
**JDK(包含JRE、JVM):**Java工具包,提供了Java的开发工具和运行环境
**JRE(包含JVM):**Java运行环境,为Java的运行提供了所需环境
**JVM:**虚拟机
JDK中包含了JRE,同时还包含了编译Java源码的编辑器javac,以及很多java程序调试和分析工具
如果只需要运行java环境,安装JRE即可,如果需要编写Java程序,则需要安装JDK
JDK1.8之后新特性:
- 速度更快
- Lambda
- Stream API
- 便于并行
- 最大减少空指针异常Optional
在JDK1.8之前,interface之中可以定义变量和方法,变量必须是public、static、final的,方法必须是public abstract的
在JDK1.8之后,支持使用static(静态方法)和default修饰,可以写方法体,不需要子类重写
2.== 和 equals的区别是什么?
- ==:对于基本数据类型和引用数据类型的作用效果是不同的
- 基本数据类型:比较的是指
- 引用数据类型:比较的是地址
- equals:本质上与"=="相同,只不过很多类重写了Object的equals方法,把它变成了值比较,例如String、Integer,所以一般情况下equals比较的是指是否相等
3.什么是引用?什么是地址?你怎么理解
例:String s = new String(“A”);
- 引用:可以说是引用变量,相当于对象或数组起的一个名称,可以在程序中使用栈中的引用变量来访问堆中的对象或数组
- 地址:在推内存中开辟一块空间,这个空间地址便是对象本身
特殊的引用类型:String
String类型不属于基本数据类型,但却可以使用基本数据类型的声明方法,而且String类型的数据在栈上的存储也有一定的机制
例:
String s = “aaa” ; 储存在常量池中的对象 (堆中的常量池)
String s = new String(“aaa”); 储存在堆中的对象
4.对象的hashCode相等,则equals也相等吗?
(hashCode()方法用于返回字符串的哈希值
对象的hashCode()相等,equals()不一定相等。因为在散列的表中,hashCode()相等即两个键值对的哈希值相等,并不一定能得出键值对相等
5.final在Java中有什么作用?
final修饰类:被final修饰的类叫做最终类,该类无法被继承
final修饰方法:被final修饰的方法无法被重写
final修饰变量:fianl修饰的变量叫常量,必须被初始化赋值,初始化之后的值无法改变
6.Java中的Math.roud(-1.5)等于多少?
-1,在数轴上取值时,中间值(0.5)像左取整,正数0.5往上取整,负数0.5直接舍弃
x = Math.round(20.49); //20
x = Math.round(20.5); //21
x = Math.round(-20.5); //-20
x = Math.round(-20.51); //-21
7.String属于基本数据类型吗?
String不属于基本数据类型,属于字符串类型,也是一个引用类型
八大基本数据类型的字节以及二进制位数是多少
byte | short | int | long | float | double | boolean | char | |
---|---|---|---|---|---|---|---|---|
字节对应 | 1 | 2 | 4 | 8 | 4 | 8 | 1 | 2 |
二进制位数 | 8位 | 16位 | 32位 | 64位 | 32位 | 64位 | 只有true和false两个取值 | 16位 |
封装类 | Byte | Short | Integer | Double | Float | Long | Boolean | Character |
基本数据类型与封装类类型使用对比
以int-Integer为例对比:
- Integer是int的包装类;int是基本数据类型
- Integer变量必须实例化才能使用;int变量不需要
- Integer实际是对象的引用,指向此new的Integer对象;int是直接储存数据值
- Integer的默认值是Null;int的默认值是0
7.Java中操作字符串都有哪些类?它们之间有什么区别?
操作字符串的类:String StringBuffer StringBuilder
String声明的是不可变的对象,每次操作都会产生新的String对象,然后指针指向新的String对象
StringBuffer和StringBuilder可以在原有的对象基础上进行操作,经常改变字符串内容的情况下最好不要使用String
StringBuffer是线程安全的,StringBuilder是非线程安全的,但StringBuffer的效率高于StringBuffer
在单线程环境下推荐使用StringBuilder,多线程环境下推荐使用StringBuffer
8.String str = "i"与String str = new String(“i”)一样吗?
不一样,内存分配方式不一样,String str = "i"的方式,Java虚拟机会将其分配到常量池中,而String str = new String(“i”)则会被分配到推内存中
9.如何将字符串反转?
将对象封装到StringBuilder或StringBuffer中,调用reverse()方法反转
10.String类的常用方法都有哪些?
indexOf():返回指定字符串的索引
charAt():返回指定索引处的字符
replace():字符串替换
trim():去除字符串两端空白
split():分割字符串,返回一个分割后的字符串数组
getBytes():返回字符串的byte类型长度
length():返回字符串长度
toLowerCase():将字符串转为小写字母
toUpperCase():将字符串转为大写字母
substring():截取字符串
equals():字符串比较
11.抽象类必须要用抽象方法吗?
不一定,抽象类中也可以有非抽象方法
12.普通类和抽象类的区别?
普通类不能包含抽象方法;抽象类可以包含抽象方法,也可以包含普通方法
抽象类不能被实例化,被继承才能实例化;普通类可以直接实例化
13.抽象类能使用final修饰吗?
不能,定义抽象类就是让其他类继承的,如果定义为 final 该类就不能被继承,这样彼此就会产生矛盾,所以 final 不能修饰抽象类
14.接口和抽象类有什么区别
实现:抽象类的子类使用extends来继承;接口必须使用implements来实现
构造函数:抽象类可以有构造函数;接口不能有
实现数量:类可以有实现很多接口,但是只能继承一个抽象类
访问修饰符:接口中的方法默认使用public修饰;抽象类中的方法可以是任意修饰符
访问修饰符:
default:在同一包内可见,不使用任何修饰符。使用对象:类、接口、变量、方法
private:在同一类内可见。使用对象:变量、方法 注意:不能修饰类(外部类)
public:对所有类可见。使用对象:类、接口、变量、方法
protected:对同一包内的类和所有的子类可见。使用对象:变量、方法 注意:不能修饰类(外部类)
修饰符 | 当前类 | 同一包内 | 子孙类(同一包) | 子孙类(不同包) | 其他包 |
---|---|---|---|---|---|
public | Y | Y | Y | Y | Y |
protected | Y | Y | Y | Y/N | N |
default | Y | Y | Y | N | N |
private | Y | N | N | N | N |
15.Java中IO流分为几种?
按功能来分:输入流(input)、输出流(output)
按类型来分:字节流、字符流
字节流和字符流的区别:字节流按8位传输以字节为单位输入输出数据,字符流按16位传输以字符为单位输入输出数据
16.BIO、NIO、AIO有什么区别?
BOI:Block IO同步阻塞式IO,就是我们平常传统使用的IO,他的特点是模式简单使用方便,并发处理能力低
NIO:New IO同步非阻塞式IO,是传统IO的升级,客户端和服务端通过Channel(通道)通讯,实现了多路复用
AIO:Asynchronous IO是NIO的升级,也叫做NIO2,实现了异步非阻塞式IO,异步IO操作基于事件和回调机制
17.Files的常用方法有哪些?
Files.exists():检测文件路径是否存在
Files.createFile():创建文件
Files.createDirectory():创建文件夹
Files.delete():删除一个文件或目录
Files.copy():复制文件
Files.move():移动文件
Files.size():查看文件个数
Files.read():读取文件
Files.write():写入文件
18.重写和重载有什么区别?
方法的重写和重载都是实现多态的方式
- 重写实现的是编译时的多态性
- 重载实现的是运行时的多态性
重载发生在一个类中
- 同名的方法有不同的参数列表,返回值类型没有特殊要求视为重载
重写发生在子类和父类之间
- 重写要求子类重写父类方法:方法名、参数列表、返回值必须相同,并且访问权限修饰符不能大于被重写的方法
19.静态变量和实例变量的区别
静态变量:也称之为类变量,归全类所有,可以通过类名直接访问
实例变量:必须依存于某一实例,只能通过对象才能访问
20.Java中有哪些引用类型
**强引用:**证明该对象还活着gc(垃圾回收机制)不会回收该引用,当内存不足时,哪怕抛出OutOfMemeryError异常也不会回收该对象,JVM判定该对象正在使用,回收会导致系统错误,将该引用赋值为Null就可以被gc回收
**软引用:**相对于强引用弱化一些,当内存不足时,回收该对象,通常用来实现内存中的缓存,如果还有空闲就保留,没有就进行回收
**弱引用:**用来构建一种没有约束的特殊关系,当JVM触发gc时回收该对象
**虚引用:**也称为幻影引用:一个对象是都有虚引用的存在都不会对生存时间都构成影响,也无法通过虚引用来获取对一个对象的真实引用。唯一的用处:能在对象被GC时收到系统通知,JAVA中用PhantomReference
来实现虚引用
21.面向对象
把相关的数据和方法阻止为一个整体来看待,相比面向过程,面向过程比较直接高效,面向对象更易于复用、扩展、维护
封装:
尽可能隐藏对象的细节,对外界形成一道边界,只保留接口和方法与外界进行交互;封装的原则是使对象以外的部分不能随意的访问和操作对象的内部属性,从而避免了外界对对象内部属性的破坏;可以通过对类的成员设置一定的访问权限,实现类中成员的隐藏
继承:
继承父类的全部属性和方法,并做出改变或扩展
多态:
同一个行为具有多个不同表现形式或者形态的能力,就是同一个接口,使用不同的实例而执行不同的操作
前提:继承或者实现关系
orm框架:
操作数据库,我们不需要关系连接如何建立,sql如何执行 ,只需要引入mybatis,调用方法即可
22.Java代理模式
**代理模式:**为其他对象提供一种代理以控制这个对象的访问,真正对象和代理对象是实现同一接口,先访问代理类再访问要访问的对象
**优点:**保护对象,降低程序耦合性,提供扩展性
静态代理:需要定义接口或者父类,被代理对象和代理对象一起实现相同的接口或者继承相同的父类
动态代理:代理对象不需要实现接口,代理对象的生成,是利用JDK的API,动态的在内存中构建代理对象
cglib代理:使用目标的子类实现代理
23:泛型
Java泛型是JDK5中引入的一个新特征,泛型提供了编译时类型安全监测机制,该机制允许程序员在编译时监测到非法的类型,泛型的本质是参数化类型,也就是说操作的数据类型被指定为一个参数,泛型类型必须是引用类型
**优点:**保护对象,降低程序的耦合性,提高扩展性
**三种使用方法:**泛型类、泛型接口、泛型方法
24.注解
注解又称标注,是JDK5.0引入的一种注释机制
Java中的类、方法、变量、参数和包等都可以被标注。Java标注可以通过反射获取标注内容。在编译器生成类文件时,标注可以被嵌入到字节码中
25.NoClassDefFoundError和ClassNotFoundException的区别
我们可以从异常中恢复程序,而不可以从错误中恢复程序
ClassNotFoundException是一个异常:ClassNotFoundException产生的原因,在Java中我们支持Class.forName方法来动态加载一个类,任意一个类名作为一个参数传递给这个方法,都可以使这个方法得到加载,如果在Java运行过程中没有找到,就会产生
NoClassDefFoundError是一个错误,产生的原因,Java是找不到这个类名的定义,常出现的地方又,打包的时候没有找到该类
26.throw和throws的区别
throw是语句抛出一个异常
语法:throw(异常对象)
throws是方法可能抛出异常的声明(用在声明方法时,表示该方法可能要抛出异常),可以单独使用
27.反射
获取Class对象的三种方式
通过全限定类名:Class.forName(“全类名”)
通过类名:类名.class
通过对象:对象.getClass()
原理:能够在运行状态中,对于任意一个实体类,都能够获取到这个类的所有属性和方法
对于任意一个对象,能够调用它的任意方法和属性,这种动态获取信息以及动态调用对象方法的功能称为Java的反射机制
容器
1.介绍一下List Set Map
首先Lits Set继承自集合库的顶级接口Collection,而Map是一个单独的集合接口
- List以及它的所有实现类保持了每个元素的插入顺序,而且它的数值可以为空
- Set底层的数据结构是Hash表,它的元素是无序排列的,是不可重复的,但是通过Set的实现类TreeSet以及LinkHashSet是可以进行排序,且Set不可为空
- Map与Set一样对元素进行无序存储,但某些实现类对元素进行了排序,如:TreeMap根据键对其中的元素进行升序排列;Map也是不可重复的,所以它的键可以含有一个空值,值允许出现很多空值
2.Collection和Collections有什么区别
Collection:是一个集合的接口(集合库的一个顶级接口),它提供了对集合对象进行基本操作的通用接口方法,其直接继承接口有List和Set
Collections:是集合的一个工具类服务于Collection,提供一系列静态方法实现对各种集合的搜索、排序、线程安全化等操作
3.ArrayList和LinkedList有什么区别
首先ArrayList和LinkedList都是List集合下的子类
ArrayList是基于数组实现的,增删效率慢,查询效率快
LinkedList是以链表的形式储存的
- 相对于ArrayList,LinkedList的插入增删操作速度更快,因为当元素被添加到集合任意位置的时候,不需要像数组那样重新计算大小或者更新索引
- 但是LinkedList比ArrayList更占内存,因为LinkedList为每一个节点储存了两个引用
4.如何实现数组和List之间的转换
List转换数组:调用ArrayList的toArray()方法
数组转换List:调用Array的asList()方法
5.Array和ArrayList有什么区别
容量大小功能
Array可以容纳基本数据类型和对象,而ArrayList只能容纳对象或者包装类,不能容纳基本数据类型
Array是指定大小的,而ArrayList初始大小是固定(默认容量为10)
Array没有提供ArrayList那么多功能,比如addAll、removeAll等
6.HashMap和HashTable有什么不同
HashMap是一个散列表,它存储的内容是键值对(key-value)映射,实现了Map接口,根据键的HashCode值存储数据,具有很快的访问速度,最多允许一天记录的键为null,不支持线程同步,HashMap是无序的,即不会记录插入的数据,HashMap继承于AbstractMap,实现了Map、Cloneable、java.io.Serializable接口
Hashtable是原始的java.util的一部分,是一个Dictionary具体的实现
HashMap去掉了Hashtable的contains的方法,但是加上了containsValue()和containsKey()方法
Hashtable是同步的,HashMap是非同步的,所以效率比Hashtable高
HashMap允许空值键,Hashtable不允许
7.HashMap的实现原理
HashMap是基于Hash算法实现的
- 当我们通过put()存储数据时
- 当传入key的值,HashMap会根据Key计算出Key的Hash值,根据Hash值把value保持在bucket中
Hash冲突时
- 当计算出相同的Hash值时,Hash冲突时,这个键会存储在链表中
问题:如果两个键的HashCode相同,如何获取值对象
- 当我们调用get(),HashMap会使用键对象的hashcode找到bucket位置,然后获取值对象
问题:如果两个值存储在一个bucket
- 遍历链表找到值对象,然后获取值对象
问题:因为没有值比较,如何确定能找到值对象?
- 找到bucket位置后调用key.equals找到链表中正确的节点,最终找到该对象
8.HashMap和ArrayList的容量
ArrayList:JDK1.2的时候初始化容量为10,经过版本不断迭代JDK1.8之后更新为 初始化容量为0,添加元素之后容量为10
HashMap:HashMap的初始化容量为16,负载因子为75%,当一个集合被填满到75%时,会重建一个原来的HashMap两倍的数组,并将原来的集合存放到新的集合中
9.HashCode()方法的作用
hashcode()方法主要配合基于散列表的集合一起使用,比如HashSet、HashMap
- 当集合需要添加新的对象时,先调用这个对象的hashcode()方法,得到对应的hashcode值
- 实际上hashmap中会有一个table保存已经存进去的对象的hashcode值
- 如果table中没有该hashcode值,则直接存入
- 如果有,就调用equals方法与新元素进行比较,相同就不存入,不同就存入
10.高并发的情况下,你怎么使用List集合
- 首先我们可以使用List集合下线程安全的Vector
- 也可以使用一些Controllers下的加锁方法,比如synchronizedList()
- 写时复制
11.HashMap的数据结构
在JDK1.7和JDK1.8不同
JDK1.7中,使用的时数组加链表
在JDK1.8中,使用的时数组加链表加红黑树,当hashmap中数组链表的长度大于8且数组长度大于64的时候它会转化为红黑树
红黑树:
红黑树是基于二叉树实现了平衡二叉树,它的优势就是提升了查询效率
e()方法主要配合基于散列表的集合一起使用,比如HashSet、HashMap
- 当集合需要添加新的对象时,先调用这个对象的hashcode()方法,得到对应的hashcode值
- 实际上hashmap中会有一个table保存已经存进去的对象的hashcode值
- 如果table中没有该hashcode值,则直接存入
- 如果有,就调用equals方法与新元素进行比较,相同就不存入,不同就存入
10.高并发的情况下,你怎么使用List集合
- 首先我们可以使用List集合下线程安全的Vector
- 也可以使用一些Controllers下的加锁方法,比如synchronizedList()
- 写时复制
11.HashMap的数据结构
在JDK1.7和JDK1.8不同
JDK1.7中,使用的时数组加链表
在JDK1.8中,使用的时数组加链表加红黑树,当hashmap中数组链表的长度大于8且数组长度大于64的时候它会转化为红黑树
红黑树:
红黑树是基于二叉树实现了平衡二叉树,它的优势就是提升了查询效率