Java八股0

137 阅读7分钟

概念与内存

面向对象三大特性

image.png

image.png

重载和重写的区别

image.png

构造器不能被重写,但可以被重载

初始化

image.png

抽象类和接口的区别

image.png

基本类型与包装类

什么是基本类型,int、double这些是;Integer、Double这些是包装类。

image.png

==和equals的区别

image.png

image.png

成员变量和类变量

image.png

final关键字用法

image.png

深拷贝和浅拷贝

image.png

String

image.png

image.png

image.png

image.png

Error和Exception的区别

image.png

image.png

Object中的方法

clone():返回对象的浅拷贝??

getClass():获取Class类对象。

equals():比较值和对象。

hashcode():

wait()/notify()/notifyAll():

泛型要详细了解

Java泛型的实现采取了“伪泛型”的策略,即Java在语法上支持泛型,但是在编译阶段会进行所谓的“类型擦除”(Type Erasure),将所有的泛型表示(尖括号中的内容)都替换为具体的类型(其对应的原生态类型),就像完全没有泛型一样。

泛型的本质是为了参数化类型(在不创建新的类型的情况下,通过泛型指定的不同类型来控制形参具体限制的类型)。也就是说在泛型使用过程中,操作的数据类型被指定为一个参数,这种参数类型可以用在类、接口和方法中,分别被称为泛型类、泛型接口、泛型方法。

引入泛型的意义在于:适用于多种数据类型执行相同的代码(代码复用);泛型中的类型在使用时指定,不需要强制类型转换(类型安全,编译器会检查类型

泛型使用:泛型类、泛型接口、泛型方法

泛型上下限:<? extends A>表示该类型参数可以是A(上边界)或者A的子类类型。

pdai.tech/md/java/bas…

类型擦除是一个什么样的机制,怎么做的,为什么

反射要详细了解

pdai.tech/md/java/bas…

在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法;对于任意一个对象,都能够调用它的任意一个方法和属性;这种动态获取的信息以及动态调用对象的方法的功能称为java语言的反射机制。

反射基础:Class类和类加载

反射的使用:

class类对象获取

  • 根据类名:类名.class
  • 根据对象:对象.getClass()
  • 根据全限定类名:Class.forName(全限定类名)

Constructor类、Field类、Method类常用方法,getMethod()这样的

数据结构

Java中数据结构在util.Collection和util.Map包下,包括三大类型:List、Set和Map。

Hashmap的插入和扩容

HashMap精选面试题(2021版) - 知乎 (zhihu.com)

hashmap底层首先使用了一个hash数组,数组中的每个节点可以看做一个桶。一个桶中可以放入多个Node<K,V>键值对。

(一)插入的过程中有以下几个点,其中有几个是重点:

  1. 判断当前容量大小是否为空,如果为空(未设置容量初始值),则把容量扩充为16。
  2. 获取key的hashCode,使用hash函数,对hashCode进行扰动处理,计算出元素的下标。

这一步就比较重要了,在java8中的计算:一次位运算一次异或。

首先根据key的值得到hashcode

将hashcode高16位和低16位进行异或操作,增加低16位随机性。(扰乱函数?)

最后根据hashcode&(len-1)得到数组下标

一般用Integer、String 这种不可变类当 HashMap 当 key,而且 String 最为常用。

  • 因为字符串是不可变的,所以在它创建的时候 hashcode 就被缓存了,不需要重新计算。这就是 HashMap 中的键往往都使用字符串的原因。
  • 因为获取对象的时候要用到 equals() 和 hashCode() 方法,那么键对象正确的重写这两个方法是非常重要的,这些类已经很规范的重写了 hashCode() 以及 equals() 方法。
  1. 根据下标判断有无hash碰撞,如果没有,则直接放入桶中。
  2. 如果发生碰撞,比较两个key是否相同,相同则覆盖,不同则则以链表的方式插入到尾部(尾插法)。
  3. 如果插入后链表的长度超过了阈值(TREEIFY_THRESHOLD = 8),首先要看数组长度是否超过64,如果没有超过64则不转为红黑树而是扩容,否则把链表转为红黑树。
  4. 插入成功后,如果元素个数到达了阈值(size = 容量 * 阈值 ),则执行扩容操作判断(容量最大值为1<<31)

这里扩容的过程也是一个重点

下面的方法是java7中的代码,java8做了一定的改进

一个改进是: resize 之后,元素的位置在原来的位置,或者原来的位置 +oldCap (原来哈希表的长度)。不需要像 JDK1.7 的实现那样重新计算hash ,只需要看看原来的 hash 值新增的那个bit是1还是0就好了,是0的话索引没变,是1的话索引变成“原索引 + oldCap ”。这个设计非常的巧妙,省去了重新计算 hash 值的时间。

void transfer(Entry[] newTable) {
        Entry[] src = table;                   //src引用了旧的Entry数组
        int newCapacity = newTable.length;
        for (int j = 0; j < src.length; j++) { //遍历旧的Entry数组
            Entry<K,V> e = src[j];             //取得旧Entry数组的每个元素
            if (e != null) {
                src[j] = null;//释放旧Entry数组的对象引用(for循环后,旧的Entry数组不再引用任何对象)
                do {
                    Entry<K,V> next = e.next;
                    int i = indexFor(e.hash, newCapacity); //!!重新计算每个元素在数组中的位置
                    e.next = newTable[i]; //标记[1]
                    newTable[i] = e;      //将元素放在数组上
                    e = next;             //访问下一个Entry链上的元素
                } while (e != null);
            }
        }
    }

  1. 扩容成功后,对元素的下标进行重新计算。

(二)1.7和1.8HashMap的变化

(1)首先区别体现在hashmap插入元素put的过程中。 区别在两处:

解决哈希冲突时,JDK1.7 只使用链表,JDK1.8 使用链表+红黑树,当满足一定条件,链表会转换为红黑树。

这里有一个问题就是,为什么选用红黑树而不是其他结构??

image.png

image.png

链表插入元素时,JDK1.7 使用头插法插入元素,在多线程的环境下有可能导致环形链表的出现,扩容的时候会导致死循环。因此,JDK1.8使用尾插法插入元素,在扩容时会保持链表元素原本的顺序,就不会出现链表成环的问题了,但JDK1.8 的 HashMap 仍然是线程不安全的,具体原因会在另一篇文章分析。

这里也是很重要的是为什么会造成线程不安全、链表成环??

cloud.tencent.com/developer/a…

(2)其次就是上面提到的扩容过程的优化

(三)了解哪些hash算法

Hash函数是指把一个大范围映射到一个小范围,目的往往是为了节省空间,使得数据容易保存。 比较出名的有MurmurHash、MD4、MD5等等。

MD5加密把一个很长的字符串变为32位的。

HashMap

首先要介绍hashmap底层数据结构

默认初始容量是16,负载因子是0.75。HashMap 的容量必须是2的N次方,HashMap 会根据我们传入的容量计算一个大于等于该容量的最小的2的N次方,例如传 9,容量为16。

image.png

提升在 hash 冲突严重时(链表过长)的查找性能,使用链表的查找性能是 O(n),而使用红黑树是 O(logn)。

其次要说清楚hashmap插入过程

image.png

然后要说明白hashmap的扩容过程

image.png

红黑树的特点也经常被问道 cloud.tencent.com/developer/n…

最后说下hashmap和其他几个兄弟的区别

image.png

List & Queue

ArrayList和LinkedList的区别

image.png

image.png

I/O

NIO之IO多路复用

Reactor模式讲挺好,但不是关于epoll的,pdai.tech/md/java/io/…

NIO概念

image.png

Netty-NIO+AIO框架

Linux I/O 模型

pdai.tech/md/java/io/…

image.png

前四种 I/O 模型的主要区别在于第一个阶段,而第二个阶段是一样的: 将数据从内核复制到应用进程过程中,应用进程会被阻塞。

第三种当然是关注度最高的:

image.png

BIO:Blocking IO,阻塞式IO,最初传统常见的,问题是:

image.png

字节流和字符流

image.png

使用过字节流来处理图片,填写入职资料中的上传附件,不知道用的是什么,不是的是不是字符流?

Java I/O设计中的装饰着模式 pdai.tech/md/java/io/…

设计模式

单例模式

工厂模式

策略模式

模板方法模式