一、JAVA中的几种基本数据类型是什么?,各自占用多少字节?
数据类型 | 字节 |
int | 32bit |
long | 64bit |
short | 16bit |
byte | 8bit |
char | 16bit |
float | 32bit |
double | 64bit |
boolean | 1bit |
二、 String类能被继承吗,为什么?
源码如下图:
上图中可知 String 被 final 修饰了,所有不能被继承
三、final 的作用是什么?
1)、final修饰的对象不能被修改
2)、final修饰的类不能被继承
3)、final修饰的方法不能被重写
四、String、Stringbuffer、StringBuilder的区别?
4.1 可变性
String 是不可变的,String 使用 final 修饰的字符数组保存字符串,因此不可变,如下图:
Stringbuffer 和 StringBuilder 是可变的,Stringbuffer 和 StringBuilder 都继承了 AbstractStringBuilder 了,AbstractStringBuilder 类中使用字符数组保存字符串的,如下图:
4.2 线程安全性
String对象是不可变的,即为常量,肯定是线程安全的
StringBuilder 是线程不安全的
StringBuffer 是线程安全的
StringBuilder 和 StringBuffer 都继承 AbstractStringBuilder,为什么出现两者不同的呢?
Stringbuffer 和 StringBuilder 都继承了 AbstractStringBuilder,AbstractStringBuilder 定义了一些字符串的基本操作,如expandCapacity、append、insert、indexOf等没有加锁的公共方法
1)、StringBuilder 直接调用的 AbstractStringBuilder 的那些方法,因此线程不安全
2)、StringBuffer 对方法加了 synchronized 同步锁或者对调用的方法加了 synchronized 同步锁,因此是线程安全的,源码如下:
总结:单线程情况下,使用 StringBuilder 比 StringBuffer 效率高,因为 StringBuffer 的方法加了 synchronized 同步锁,会造成线程阻塞
五、成员变量、局部变量和静态变量的区别?
三者之间的区别总结为表格,如下:
成员变量 | 局部变量 | 静态变量 | |
定义位置 | 类中 && 方法外 | 方法中或者方法形式参数 | 类中,方法外 |
初始化值 | 有默认初始值 | 无初始值,先定义再赋值 | 有默认初始值 |
调用方式 | 对象调用 | --- | 对象调用或者类调用 |
JVM存储位置 | 堆中 | 栈中 | 方法区 |
生命周期 | 与对象共存亡 | 与对象方法共存亡 | 与类共存亡 |
别名 | 实例变量 | --- | 类变量 |
六、类的实例化顺序是什么?例如父类静态数据,构造函数,字段,子类静态数据,构造函数,字段,当new的时候,他们的执行顺序?
总体思想:先静态再父子
实例化顺序:父类静态数据 -> 子类静态数据 -> 父类字段和代码块 -> 父类构造方法 -> 子类字段和代码块 -> 子类构造方法
具体的实例化顺序如下:
1)、父类【静态成员】和【静态代码块】,按在代码中出现的顺序依次执行
2)、子类【静态成员】和【静态代码块】,按在代码中出现的顺序依次执行
3)、父类的【普通成员变量被普通成员方法赋值】和【普通代码块】,按在代码中出现的顺序依次执行
4)、执行父类的构造方法
5)、子类的【普通成员变量被普通成员方法赋值】和【普通代码块】,按在代码中出现的顺序依次执行
6)、执行子类的构造方法
七、ArrayList和LinkedList有什么区别?
7.1 实现方式
ArrayList使用数组实现,源码如下图:
LinkedList使用循环双向链表数据结构,源码如下图:
7.2 使用场景
ArrayList 适用于查询频率高的场景,即可以随机访问
ArrayList 使用的数组实现,具有下标特性,查询起来效率很高,但是ArrayList的中间插入或删除一个元素就需要移动所有的元素位置,性能较差
LinkedList 适用于插入和删除频率高的场景
LinkedList 使用的双向链表实现,插入和删除元素后,只需要修改前后指针的位置即可,效率很高,但是查询元素需要遍历整个链表,效率低
如果是在列表末尾进行插入和删除元素的场景,则 ArrayList 和 LinkedList 性能一样,使用两者都行
7.3 空间浪费
ArrayList的空间浪费主要体现在在list列表的结尾要预留一定的容量空间,而LinkedList的空间花费则体现在它的每一个元素都需要消耗相当的空间,即指针空间
八、常用的 map 有哪些?它们之间有什么区别?内部原理分别是什么?
常用的Map实现类有: HashMap、 ConcurrentHashMap(jdk1.8)、 LinkedHashMap、 TreeMap、 HashTable
最常用的 map: HashMap 和 ConcurrentHashMap
非线程安全 map:HashMap、 LinkedHashMap、 TreeMap
线程安全 map:ConcurrentHashMap 和 HashTable
有顺序的 map:LinkedHashMap 和 TreeMap
LinkedHashMap 和 TreeMap 实现顺序方式:
1)、TreeMap 是基于元素的比较器 (由 Comparator 或者 Comparable 确定) 实现
2)、LinkedHashMap 是基于元素进入集合的顺序或者被访问的先后顺序排序实现
ConcurrentHashMap 和 HashTable 是线程安全的,并发下可以使用二者,二者的主要区别如下:
1)、hash计算方式
ConcurrentHashMap的hash计算公式:(key.hascode() ^ (key.hascode()>>> 16)) & 0x7FFFFFFF
HashTable的hash计算公式:key.hascode() & 0x7FFFFFFF
2)、存储结构
ConcurrentHashMap 是数组+链表+红黑树结构
HashTable 是链表+数组结构,数组里面放的是当前hash的第一个数据,链表里面放的是hash冲突的数据
3)、容量、负载因子、扩容
ConcurrentHashMap 默认容量16,负载因子是0.75,扩容为原来的2倍,当hashmap填充了75%的busket是就会扩容,最小的可能性是(16*0.75)
HashTable 默认容量11,负载因子是0.75,扩容为原来的2倍
4)、线程安全保证
ConcurrentHashMap 使用 CAS(compare and swap)来保证线程安全的
HashTable 是在每个操作方法上面加了 synchronized 来达到线程安全
九、JDK8的 ConcurrentHashMap 为什么放弃了分段锁,有什么问题吗?如果你来设计,你如何设计?
jdk8 放弃了分段锁而是采用了Node锁,减低锁的粒度,提高性能,并使用CAS操作来确保Node的一些操作的原子性,取代了锁
但是ConcurrentHashMap的一些操作使用了synchronized锁,而不是ReentrantLock,虽然说jdk8的synchronized的性能进行了优化,但是我觉得还是使用ReentrantLock锁能更多的提高性能
十、 抽象类和接口的区?类可以继承多个类么? 接口可以继承多个接口么?类可以实现多个接口么?
抽象类和接口的区别:
1)、抽象类可以有自己的实现方法,接口在jdk8以后也可以有自己的实现方法(default)
2)、抽象类的抽象方法是由非抽象类的子类实现,接口的抽象方法由接口的实现类实现
3)、接口不能有私有的方法和对象,抽象类可以有自己的私有的方法和对象
类不可以继承多个类,接口可以继承多个接口,类可以实现多个接口
十一、反射的原理?反射创建类实例的三种方式是什么?
反射的原理:知道一个类的名称或者它的一个实例对象, 就能把这个类的所有方法和变量的信息(方法名,变量名,方法,修饰符,类型,方法参数等等所有信息)找出来
反射创建类实例的三种方式:
1)、Class.forName("com.A");
2)、new A().getClass();
3)、A.class;
十二、在反射中,Class.forName 和 ClassLoader区别?
class.forName:除了将类的.class文件加载到jvm中之外,还会对类进行解释,执行类中的static块
classLoader:只是将.class文件加载到jvm中,不会执行static中的内容,只有在 newInstance 才会去执行static块
十三、动态代理有几种实现方式?各自的特点是什么?
动态代理 : JDK动态代理 和 CGLIB动态代理
JDK动态代理:前提是目标类必须实现一个接口,代理对象和目标类实现一个接口,从而避过虚拟机的校验
CGLIB动态代理:继承并重写目标类,因此目标类和方法不能被声明成final,由于接口可以被继承,因此也可以使用CGLIB动态代理实现
代理总结图如下:
十四、深拷贝和浅拷贝区别?
浅拷贝只拷贝指针,更新对象的值后,浅拷贝的对象也会同步修改
深拷贝就是拷贝他的值,重新生成新的对像,更新对的值不会影响深拷贝的对象
十五、常见的java异常以及结构?error 和 exception的区别?CheckedException 和 RuntimeException的区别?
java异常结构图如下:
error 和 exception 都继承了 Throwable
Error(错误):表示系统级的错误和程序不必处理的异常,是java运行环境中的内部错误或者硬件问题。比如:内存资源不足等。对于这种错误,程序基本无能为力,除了退出运行外别无选择,它是由Java虚拟机抛出的
Exception(异常):表示需要捕捉或者需要程序进行处理的异常,它处理的是因为程序设计的瑕疵而引起的问题或者在外的输入等引起的一般性问题,是程序必须处理的
Exception分为 运行时异常 和 受检查异常 两种类型
RuntimeException(运行时异常):这种异常我们不需要处理,完全由 JVM 接管。比如我们常见的NullPointerException,我们在写程序时不会进行catch或throw
CheckedException(受检查异常):这种异常是强制我们catch或throw的异常。你遇到这种异常必须进行catch或throw,如果不处理,编译器会报错。比如:IOException
十六、在自己的代码中,如果创建一个java.lang.String对象,这个对象是否可以被类加载器加载?为什么?
不可以,双亲委派模式会保证父类加载器先加载类,就是BootStrap(启动类)加载器加载jdk里面的java.lang.String类,而自定义的java.lang.String类永远不会被加载到
十七、泛型的存在是用来解决什么问题?
泛型的好处是在编译的时候检查类型安全,并且所有的强制转换都是自动和隐式的,提高代码的重用率
十八、OO设计理念是什么?谈谈访问修饰符public、private、protected、default在应用设计中的作用?
OO设计理念:封装、继承、多态
对于访问修饰符的总结入下表格:
关键字 | 类内部 | 本包 | 子类 | 外部包 |
public | √ | √ | √ | √ |
protected | √ | √ | √ | × |
default | √ | √ | × | × |
private | √ | × | × | × |
十九、TCP协议与UDP协议有什么区别?
TCP : 传输控制协议是基于连接的协议,在正式收发数据前,必须和对方建立可靠的连接。速度慢,合适传输大量数据
UDP : 用户数据报协议是与TCP相对应的协议。面向非连接的协议,不与对方建立连接,而是直接就把数据包发送过去,速度快,适合传输少量数据,一般聊天工具使用的就是 UDP
参考: