没有合适的资源?快使用搜索试试~ 我知道了~
资源详情
资源评论
资源推荐

Java 基础
面向对象
封装:封装的意义,在于明确标识出允许外部使用的所有成员函数和数据项,内部
细节对外部调用透明,外部调用无需修改或者关心内部实现
继承:继承基类的方法,并做出自己的改变和或扩展,子类共性的方法或者属性
直接使用父类的,而不需要自己再定义,只需扩展自己个性化的
多态:基于对象所属类的不同,外部对同一个方法的调用,实际执行的逻辑不同
JDK、JRE、JVM 之间的区别
:开发工具
: 运行时环境
:虚拟机
==和 equals 方法之前的区别
:对比的是栈中的值,基本数据类型是变量值,引用类型是堆中内存对象的地
址
: 中默认也是采用比较,通常会重写
!"与 !"之间的关系
# 介绍: !"的作用是获取哈希码,也称为散列码;它实际上
是返回一个 整数。这个哈希码的作用是确定该对象在哈希表中的索引位置。
!"定义在 的 $% 中, 中的任何类都包含有
!"函数。
散列表存储的是键值对!&'(",它的特点是:能根据“键”快速的检索出对应
的“值”。这其中就利用到了散列码!(可以快速找到所需要的对象)

如果两个对象相等,则 一定也是相同的
两个对象相等)对两个对象分别调用 方法都返回
两个对象有相同的 值,它们也不一定是相等的
因此, 方法被覆盖过,则 方法也必须被覆盖
!"的默认行为是对堆上的对象产生独特值。如果没有重写
!",则该 的两个对象无论如何都不会相等(即使这两个对象指向
相同的数据)
nal 关键字的作用是什么?
修饰类:表示类不可被继承
修饰方法:表示方法不可被子类覆盖,但是可以重载
修饰变量:表示变量一旦被赋值就不可以更改它的值。
修饰成员变量:
如果 * 修饰的是类变量,只能在静态初始化块中指定初始值或者声明该类变量
时指定初始值。
如果 * 修饰的是成员变量,可以在非静态初始化块、声明该变量或者构造器中
执行初始值。
修饰局部变量:系统不会为局部变量进行初始化,局部变量必须由程序员显示初始
化。因此使用 * 修饰局部变量时,即可以在定义时指定默认值(后面的代码不
能对变量再赋值),也可以不指定默认值,而在后面的代码中对 * 变量赋初值
(仅一次)
修饰基本类型数据和引用类型数据:
如果是基本数据类型的变量,则其数值一旦在初始化之后便不能更改;
如果是引用类型的变量,则在对其初始化之后便不能再让其指向另一个对象。但是
引用的值是可变的。
String、StringBuer、StringBuilder 的区别
+, 是不可变的,如果尝试去修改,会新生成一个字符串对象,+,-.
和 +,- 是可变的
+,-. 是线程安全的,+,- 是线程不安全的,所以在单线程环境
下 +,- 效率会更高

重载和重写的区别
重载:发生在同一个类中,方法名必须相同,参数类型不同、个数不同、顺序不同,
方法返回值和访问修饰符可以不同,发生在编译时。
重写:发生在父子类中,方法名、参数列表必须相同,返回值范围小于等于父类,
抛出的异常范围小于等于父类,访问修饰符范围大于等于父类;如果父类方法访问
修饰符为 则子类就不能重写该方法。
接口和抽象类的区别
抽象类可以存在普通成员函数,而接口中只能存在 方法。
抽象类中的成员变量可以是各种类型的,而接口中的成员变量只能是
* 类型的。
抽象类只能继承一个,接口可以实现多个。
List 和 Set 的区别
/:有序,按对象进入的顺序保存对象,可重复,允许多个 0 元素对象,可以
使用 1 取出所有元素,在逐一遍历,还可以使用 ,! 2"获取指定
下标的元素
+:无序,不可重复,最多允许有一个 0 元素对象,取元素时只能用 1
接口取得所有元素,在逐一遍历各个元素
ArrayList 和 LinkedList 区别
首先,他们的底层数据结构不同,3'/ 底层是基于数组实现的,/& /
底层是基于链表实现的
由于底层数据结构不同,他们所适用的场景也不同,3'/ 更适合随机查找,
/& / 更适合删除和添加,查询、添加、删除的时间复杂度不同
另外 3'/ 和 /& / 都实现了 / 接口,但是 /& / 还额外实现了
接口,所以 /& / 还可以当做队列来使用

HashMap 和 HashTable 有什么区别?其底层实现是什
么?
区别 :
# 方法没有 '4 修饰,线程非安全,#5 线程安全;
# 允许 &' 和 为 ,而 #5 不允许
底层实现
计算 &' 的 值,二次 然后对数组长度取模,对应到数组下标
如果没有产生 冲突!下标位置没有元素",则直接创建 0 存入数组
如果产生 冲突,先进行 比较,相同则取代该元素,不同,则判断链表
高度插入链表,链表高度达到 6,并且数组长度到 78 则转变为红黑树,长度低于
7 则将红黑树转回链表
&' 为 ,存在下标 9 的位置
谈谈 ConcurrentHashMap 的扩容机制
:%; 版本
:%:%; 版本的 # 是基于 +, 分段实现的
<%每个 +, 相对于一个小型的 #
=%每个 +, 内部会进行扩容,和 # 的扩容逻辑类似
8%先生成新的数组,然后转移元素到新数组中
>%扩容的判断也是每个 +, 内部单独判断的,判断是否超过阈值
:%6 版本
:%:%6 版本的 # 不再基于 +, 实现
<%当某个线程进行 时,如果发现 # 正在进行扩容那么该
线程一起进行扩容
=%如果某个线程 时,发现没有正在进行扩容,则将 &'( 添加到
# 中,然后判断是否超过阈值,超过了则进行扩容
8%# 是支持多个线程同时扩容的
>%扩容之前也先生成一个新的数组
7%在转移元素时,先将原数组分组,将每组分给不同的线程来进行元素的转移,
每个线程负责一组或多组的元素转移工作

&:%; 到 &:%6#发生了什么变化!底层"?
:%:%; 中底层是数组@链表,:%6 中底层是数组@链表@红黑树,加红黑树的目的
是提高 # 插入和查询整体效率
<%:%; 中链表插入使用的是头插法,:%6 中链表插入使用的是尾插法,因为 :%6 中
插入 &' 和 时需要判断链表元素个数,所以需要遍历链表统计链表元素个
数,所以正好就直接使用尾插法
=%:%; 中哈希算法比较复杂,存在各种右移与异或运算,:%6 中进行了简化,因为
复杂的哈希算法的目的就是提高散列性,来提供 # 的整体效率,而 :%6 中
新增了红黑树,所以可以适当的简化哈希算法,节省 AB 资源
说一下 HashMap 的 Put 方法
:%根据 ' 通过哈希算法与与运算得出数组下标
<%如果数组下标位置元素为空,则将 &' 和 封装为 ' 对象(:%;
中是 ' 对象,:%6 中是 0 对象)并放入该位置
=%如果数组下标位置元素不为空,则要分情况讨论
:%如果是 :%;,则先判断是否需要扩容,如果要扩容就进行扩容,如果不用扩
容就生成 ' 对象,并使用头插法添加到当前位置的链表中
<%如果是 :%6,则会先判断当前位置上的 0 的类型,看是红黑树 0 ,
还是链表 0
:%如果是红黑树 0 ,则将 &' 和 封装为一个红黑树节点并添加到红黑
树中去,在这个过程中会判断红黑树中是否存在当前 &',如果存在则更新
<%如果此位置上的 0 对象是链表节点,则将 &' 和 封装为一个链表
0 并通过尾插法插入到链表的最后位置去,因为是尾插法,所以需要遍历链表,
在遍历链表的过程中会判断是否存在当前 &',如果存在则更新 ,当遍历完
链表后,将新链表 0 插入到链表中,插入到链表后,会看当前链表的节点个数,
如果大于等于 6,那么则会将该链表转成红黑树
=%将 &' 和 封装为 0 插入到链表或红黑树中后,再判断是否需要进行
扩容,如果需要就扩容,如果不需要就结束 AB5 方法
剩余63页未读,继续阅读

















AlanChencc
- 粉丝: 2
- 资源: 1
上传资源 快速赚钱
我的内容管理 展开
我的资源 快来上传第一个资源
我的收益
登录查看自己的收益我的积分 登录查看自己的积分
我的C币 登录后查看C币余额
我的收藏
我的下载
下载帮助


安全验证
文档复制为VIP权益,开通VIP直接复制

评论0