答案均为本人看技术书的个人理解或者网上查资料所得,题目来自一些技术交流群的分享
1. JAVA 中的几种基本数据类型是什么,各自占用多少字节。
类型 | 占用字节 | 占用位数 |
---|---|---|
byte | 1 | 8 |
short | 2 | 16 |
int | 4 | 32 |
long | 8 | 64 |
float | 4 | 32 |
double | 8 | 64 |
char | 2 | 16 |
boolean | 1 | 8 |
2. String 类能被继承吗,为什么。
public final class String
implements java.io.Serializable, Comparable<String>, CharSequence {
/** The value is used for character storage. */
private final char value[];
查看JDK源码,String类定义成final,在Java中,只要是被定义为final的类,也可以说是被final修饰的类,就是不能被继承的。
3. String,Stringbuffer,StringBuilder 的区别。
String是不可变对象,如果每次赋值覆盖原来的变量,就会产生新的String对象,从题2中看到String底层实现是通过一个private final 修饰的char数组,私有不可变并且没有提供对外部的set方法来改变数组中的值。
StringBuffer是线程安全的可变字符序列,在任意时间点上它都包含某种特定的字符序列,但通过某些方法调用可以改变该序列的长度和内容。可将字符串缓冲区安全地用于多个线程。
StringBuilder是非线程安全的可变字符序列,在单线程程序中,可以尽量使用StringBuilder
4. ArrayList 和LinkedList 有什么区别。
ArrayList内部使用数组的形式实现存储,所有对于随机访问其中的元素速度较快,插入和删除元素时效率较低;
LinkedList内容使用双向链表的形式实现存储,内部类Node有三个属性,用来存放元素本身以及前后2个单元的引用,即双向链表的结构,于是插入和删除元素的时候效率较高,随机访问元素较慢。
5. 讲讲类的实例化顺序,比如父类静态数据,构造函数,字段,子类静态数据,构造函数,
字段,当new 的时候,他们的执行顺序。
顺序为:父类静态数据->子类静态数据->父类字段-父类构造函数->子类字段->子类构造函数
且静态数据只实例化一次
6. 用过哪些Map 类,都有什么区别,HashMap 是线程安全的吗,并发下使用的Map 是什么,
他们内部原理分别是什么,比如存储方式,hashcode,扩容,默认容量等。
HashMap原理 http://blog.csdn.net/g1258194015/article/details/81612480
ConcurrentHashMap原理 https://blog.csdn.net/g1258194015/article/details/81612452
7. JAVA8 的ConcurrentHashMap 为什么放弃了分段锁,有什么问题吗,如果你来设计,
你如何设计。
它摒弃了Segment(锁段)的概念,而是启用了一种全新的方式实现,利用CAS算法,段锁性能也不是很高,而CAS操作是CPU支持的操作,是一种原子操作。
8. 有没有有顺序的Map 实现类,如果有,他们是怎么保证有序的。
LinkedHashMap,HashMap和双向链表合二为一即是LinkedHashMap,保留插入的顺序。
TreeMap,默认排序规则:按照key的字典顺序来排序(升序),也可以自定义排序规则:要实现Comparator接口。
9. 抽象类和接口的区别,类可以继承多个类么,接口可以继承多个接口么,类可以实现多个接
口么。
抽象类和接口的区别(搬运):https://www.jianshu.com/p/038f0b356e9a
接口可以继承多个接口,interface C extends A, B {}是可以的.
10. 继承和聚合的区别在哪。
is a 的意思是如果A是B,那么B就是A的基类。
比如:等边三角形是三角形,所以三角形就是等边三角形的基类。
has a 是如果A中有B,那么,B就是A的组成部分
如果你确定两件对象之间是is-a的关系,那么此时你应该使用继承;比如菱形、圆形和方形都是形状的一种,那么他们都应该从形状类继承而不是聚合。
如果你确定两件对象之间是has-a的关系,那么此时你应该使用聚合;比如电脑是由显示器、CPU、硬盘等组成的,那么你应该把显示器、CPU、硬盘这些类聚合成电脑类,而不是从电脑类继承。
11. IO 模型有哪些,讲讲你理解的nio,他和bio,aio 的区别是啥,谈谈reactor 模型。
阻塞IO、非阻塞IO、多路复用IO、信号驱动IO、异步IO
BIO (Blocking I/O):同步阻塞I/O模式,数据的读取写入必须阻塞在一个线程内等待其完成。这里使用那个经典的烧开水例子,这里假设一个烧开水的场景,有一排水壶在烧开水,BIO的工作模式就是, 叫一个线程停留在一个水壶那,直到这个水壶烧开,才去处理下一个水壶。但是实际上线程在等待水壶烧开的时间段什么都没有做。
NIO (New I/O):同时支持阻塞与非阻塞模式,但这里我们以其同步非阻塞I/O模式来说明,那么什么叫做同步非阻塞?如果还拿烧开水来说,NIO的做法是叫一个线程不断的轮询每个水壶的状态,看看是否有水壶的状态发生了改变,从而进行下一步的操作。
AIO ( Asynchronous I/O):异步非阻塞I/O模型。异步非阻塞与同步非阻塞的区别在哪里?异步非阻塞无需一个线程去轮询所有IO操作的状态改变,在相应的状态改变后,系统会通知对应的线程来处理。对应到烧开水中就是,为每个水壶上面装了一个开关,水烧开之后,水壶会自动通知我水烧开了。
12. 反射的原理,反射创建类实例的三种方式是什么。
对象.getClass()
方式 类名.Class
方式 Class.forName( 类的包名 )
方式
13. 反射中,Class.forName 和ClassLoader 区别。
Class.forName(className)方法,其实调用的方法是Class.forName(className,true,classloader);注意看第2个boolean参数,它表示的意思,在loadClass后必须初始化。比较下我们前面准备jvm加载类的知识,我们可以清晰的看到在执行过此方法后,目标对象的 static块代码已经被执行,static参数也已经被初始化。
再看ClassLoader.loadClass(className)方法,其实他调用的方法是ClassLoader.loadClass(className,false);还是注意看第2个 boolean参数,该参数表示目标对象被装载后不进行链接,这就意味这不会去执行该类静态块(包括静态变量等)中间的内容。因此2者的区别就显而易见了。
14. 描述动态代理的几种实现方式,分别说出相应的优缺点。
有JDK动态代理和Cglib代理,JDK动态代理只能代理实现某一个接口的类,Cglib支持目标类的代理,Cglib代理方式目标类和方法不能声明为final类型。从执行效率上看,在调用次数较少的情况下,JDK代理效率高于CGLIB代理效率,只有当进行大量调用的时候,jdk6和jdk7比CGLIB代理效率低一点,但是到jdk8的时候,jdk代理效率高于CGLIB代理
15. 动态代理与cglib 实现的区别。
JDK动态代理只能对实现了接口的类生成代理,而不能针对类 。
CGLIB是针对类实现代理,主要是对指定的类生成一个子类,覆盖其中的方法 。
因为是继承,所以该类或方法最好不要声明成final ,final可以阻止继承和多态。
16. 为什么CGlib 方式可以对接口实现代理。
17. final 的用途。
final 所修饰的数据具有“终态”的特征,表示“最终的”意思:
final 修饰的类不能被继承。
final 修饰的方法不能被子类重写。
final 修饰的变量(成员变量或局部变量)即成为常量,只能赋值一次。
final 修饰的成员变量必须在声明的同时赋值,如果在声明的时候没有赋值,那么只有 一次赋值的机会,而且只能在构造方法中显式赋值,然后才能使用。
final 修饰的局部变量可以只声明不赋值,然后再进行一次性的赋值。
18. 写出三种单例模式实现。
(静态内部类):
1 public class Singleton {
2 private static class SingletonHolder {
3 private static final Singleton INSTANCE = new Singleton();
4 }
5 private Singleton (){}
6 public static final Singleton getInstance() {
7 return SingletonHolder.INSTANCE;
8 }
9 }
10
(枚举):
1 public enum Singleton {
2 INSTANCE;
3 public void whateverMethod() {
4 }
5 }
6
(双重校验锁):
1 public class Singleton {
2 private volatile static Singleton singleton;
3 private Singleton (){}
4 public static Singleton getSingleton() {
5 if (singleton == null) {
6 synchronized (Singleton.class) {
7 if (singleton == null) {
8 singleton = new Singleton();
9 }
10 }
11 }
12 return singleton;
13 }
14 }
15
19. 如何在父类中为子类自动完成所有的hashcode 和equals 实现?这么做有何优劣。
父类中重写Object的hashcode 和equals 方法即可,优点所有的子类都不需要自己重写,缺点子类没有自己个性化的hashcode 和equals 的实现
20. 请结合OO 设计理念,谈谈访问修饰符public、private、protected、default 在应
用设计中的作用。
访问修饰符的一个优点就是安全性,对于希望暴露给外部使用的域使用可以被外部访问的修饰符修饰,对于不想暴露给外部使用的域可以使用private仅自己使用或者使用protected仅供子类使用,起到一个权限控制的作用,开发人员开发的时候也能保证规范性等等。
21. 深拷贝和浅拷贝区别。
浅拷贝是只拷贝当前对象,深拷贝是如果当前类中还定义了其他类作为其中一个属性,那么拷贝的时候会将这个属性一起拷贝
22. 数组和链表数据结构描述,各自的时间复杂度。
数组链表的优缺点:
数组占用空间小,链表元素还要包涵上一元素和下一个元素的的信息
数组的访问速度快,因为内存是连续的
数组内部元素可以随机访问,而链表依赖于上一个元素的信息
链表的插入删除操作由于数组,因为内存不连续,只需要更改元素的前后节点信息就行了,并不需要更改元素内存地址,而数组的连续内存想要插入和删除的话就要移动所有的内存地址
链表的内存利用率高于数组,链表内存是分散的一个元素占用一块空间,数组元素少于内存空间的话,会有部分的内存浪费;
链表的扩展性强,数组的创建完成内存大小就确定了,满了就没法扩展只能再次创建新的数组,而链表可以随意的增加扩展
效率:数组查询效率高,链表增,删效率高
23. error 和exception 的区别,CheckedException,RuntimeException 的区别。
Error类一般是指与虚拟机相关的问题,如系统崩溃,虚拟机错误,内存空间不足,方法调用栈溢出等。如java.lang.StackOverFlowError和Java.lang.OutOfMemoryError。对于这类错误,Java编译器不去检查他们。对于这类错误的导致的应用程序中断,仅靠程序本身无法恢复和预防,遇到这样的错误,建议让程序终止。
Exception类表示程序可以处理的异常,可以捕获且可能恢复。遇到这类异常,应该尽可能处理异常,使程序恢复运行,而不应该随意终止异常。
RuntimeException:其特点是Java编译器不去检查它,也就是说,当程序中可能出现这类异常时,即使没有用try……catch捕获,也没有用throws抛出,还是会编译通过,如除数为零的ArithmeticException、错误的类型转换、数组越界访问和试图访问空指针等。处理RuntimeException的原则是:如果出现RuntimeException,那么一定是程序员的错误。
受检查的异常(IOException等):这类异常如果没有try……catch也没有throws抛出,编译是通不过的。这类异常一般是外部错误,例如文件找不到、试图从文件尾后读取数据等,这并不是程序本身的错误,而是在应用环境中出现的外部错误。
24. 请列出5 个运行时异常。
ArithmeticException NullPointerException IndexOutOfBoundsException ClassCastException NumberFormatException
25. 在自己的代码中,如果创建一个java.lang.String 类,这个类是否可以被类加载器加
载?为什么。
可以编译,但不会加载;自定义加载器去加载则会抛出异常:Prohibited package name: java
在双亲委派模型中,由父加载类加载的类,下层加载器是不能加载的
26. 说一说你对java.lang.Object 对象中hashCode 和equals 方法的理解。在什么场景
下需要重新实现这两个方法。
在集合框架中,例如往HashMap中添加元素时,如果只重写了equals 并且两个对象equals返回为true 把这两个对象作为key添加到HashMap中时,后一个对象不一定会覆盖前一个,因为没有重写hashcode方法,于是默认调用Object类的hashcode方法返回值不同,而HashMap是用key的hashcode值找到该元素的存储位置,这样就会存储两位置不一样但是key一样的元素。
27. 在jdk1.5 中,引入了泛型,泛型的存在是用来解决什么问题。
解决强制转换带来的内存消耗
28. 这样的a.hashcode() 有什么用,与a.equals(b)有什么关系。
算出hashcode,比较值相等,则hashCode相等
29. 有没有可能2 个不相等的对象有相同的hashcode。
存在
30. Java 中的HashSet 内部是如何工作的。
HashSet 内部使用 HashMap 。它将元素存储为键和值。(译者注:HashSet 把存储的值作为 key)
31. 什么是序列化,怎么序列化,为什么序列化,反序列化会遇到什么问题,如何解决。
序列化: 将数据结构或对象转换成二进制串的过程。
反序列化:将在序列化过程中所生成的二进制串转换成数据结构或者对象的过程。
有些特定对象无法反序列化
32. java8 的新特性。