Java基础-知识点复习

1. 为什么重载了equals方法之后要重载hashCode方法
Hash的时候需要保证equals的对象映射到同一个位置
发散一下:

    public boolean equals(Object otherObject){
        //a quick test to see if the objects are identical
        if(this == otherObject){
            return true;
        }
        //must return false if the explicit parameter is null
        if(otherObject == null){
            return false;
        }
        //if the classes don't match, they can't be equal
        if(getClass()!= otherObject.getClass()){
            return false;
        }
        //now we know otherObject is a non-null Employee
        Employee other = (Employee) otherObject;

        //test whether the fields have identical values
        /* return name.equals(other.name)
                && salary.equals(other.salary);*/
        
        //为防止name为null,需要调用Objects.equals()方法
        //   public static boolean equals(Object a, Object b) {
        //        return (a == b) || (a != null && a.equals(b));
        //    }
        return Objects.equals(name,other.name)
                && salary.equals(other.salary);
    }

相等测试与继承
equals 要满足:

  1. 自反性

  2. 对称性

  3. 传递性

  4. 一致性

  5. 对于任意非空引用x,x.equals(null)应该返回 false

    就对称性来说,当参数不属于同一个类时还要仔细思考一下。

  6. 如果子类能拥有自己的相等概念,则对称性需求将强制采用getClass进行检测、

  7. 如果由超类决定相等概念,那么可以使用instanceof进行检测,这样可以在不同子类的对象之间进行相等的比较
    在这里插入图片描述
    下面给出编写一个完美的equals的建议:

  • 显式参数命名为otherObject,稍后需要将它转换成另一个叫other的变量
  • 检测this和otherObject是否引用同一个对象:
if(this == otherObject) return true;
  • 检测otherObject是否为null,如果为null,则返回false
  • 比较this与otherObject是否同属一个类。
    如果equals语义在每个子类中有所改变,就要用
if(getClass()!= otherObject.getClass()) return false;

如果所有字累都有统一的语义,就要用instanceof检测

if(!(otherObject instanceof ClassName)) return false;
  • 将otherObject转换为相应的类类型变量
 ClassName other = (ClassNme) otherObject
  • 现在开始对所有需要比较的域(field)进行比较
    使用 == 比较基本类型
    使用equals比较对象域。
   return Objects.equals(field1,other.field1)
                && Objects.equals(field2,other.field2)
                && ...;

2. 重载与覆盖(重写)的区别

3. static 关键字到用法
静态方法和静态代码块
static和非static的区别,一般什么情况下会使用,怎么去用;
什么时候执行;
加分 —— 实例变量,静态变量,构造函数、父类相对变量的执行过程。

4. final / finalize / finally 关键字的用法

5. String / StringBuffer / StringBuilder 的区别
StringBuffer和StringBuilder是线程安全问题,String和StringBuilder是效率以及内存分配问题。

加分1: String和StringBuilder在编译优化之后结果基本一致;

加分2: String在循环中操作,回导致声明很多的StringBuilder,因此禁止这种操作;

6. HashMap的实现原理
基本:底层数据结构,冲突解决(Hash值映射到同一个位置——List,再次Hash)

加分:链表解决冲突的情况下如何优化速度?List长度超过一个值,B Tree。

加分:ConcurrentHashMap的实现——Segment。

加分:ConcurrentModificationException异常发生的原因

7. wait和sleep的区别
前者要求必须先获得锁才能调用,后者不需要。前者调用后会释放锁(进入等待池),后者不存在释放问题。
8. synchronized关键字修饰静态方法和实例方法的区别
加锁对象不一样。

加分:和volatile关键字的区别?:volatile只管可见性,synchronized同时保证互斥性

9. 死锁的四个条件
(1) 互斥条件:一个资源每次只能被一个进程使用。
(2) 请求与保持条件:一个进程因请求资源而阻塞时,对已获得的资源保持不放。
(3) 不剥夺条件:进程已获得的资源,在末使用完之前,不能强行剥夺。
(4) 循环等待条件:若干进程之间形成一种头尾相接的循环等待资源关系。

10. notify和notifyAll的区别
除唤醒线程外,前者调用后其余线程还在等待池,后者其余线程进入锁池(可以主动竞争锁)

11. Java的范型的实现原理
基本:概念用法,T ? extends

加分:泛型擦除,如下:编译报错还是运行报错

public void test(List li){ }

public void test(List ls){ }

12. 浅克隆和深克隆?深克隆的方法?
对象的深复制与浅复制

13. Integer缓存?Integer比较大小的注意问题。==和equals的区别考察
Integer是有缓冲池的,java.lang.Integer.valueOf(int)方法默认情况下如果参数在-128到127之间,则返回缓存中的对象,否则返回new Integer(int)。java使用该机制是为了达到最小化数据输入和输出的目的,这是一种优化措施,提高效率

其他的包装器:
Boolean: (全部缓存) Byte: (全部缓存) Character ( <=127 缓存)

Short
Long
Float
Doulbe (没有缓存)

(-128~127 缓存) (-128~127 缓存)

(没有缓存)

可以设置系统属性 java.lang.Integer.IntegerCache.high 修改缓冲区上限,默认为127。参数内容应为大于127的十进制数形式的字符串,否则将被忽略。取值范围为127-Long.MAX_VALUE,但是用时将 强转为int。当系统中大量使用Integer时,增大缓存上限可以节省小量内存。

区别== 和equals(): "=="比较两个对象是不是引用自同一个对象。 “equals()”是比较两个对象的内容。

14. 装箱和解箱的机制
自动装箱和拆箱

15. Java的类加载器体系结构和双亲委托机制
jvm的

16. 简述Java异常体系,什么是受检异常?什么是运行时异常?封装一个API的时候什么情况下抛出异常?

17. String常量池的考核
String s1 = new String(“hello”);

String s2 = “hello”;
区别

18. Hash冲突,有哪几种常见解决方法,Java中的HashMap用的是哪一种

  • 开放地址法
  • 拉链法 详情 Java中用的是拉链法

19. Java HashMap在高并发情况下不当使用,可能会导致什么极端情况

在并发的多线程使用场景中,在resize扩容的时候,使得HashMap形成环链,造成死循环,CPU飙升至100%。可以举例子说明。

20. HashMap / ConcurrentHashMap的数据结构实现,扩容机制
答案参考前面。 补充:扩容机制考察扩容时机,扩容容量变化机制,扩容具体实现步骤-源码resize() 函数

21. ArrayList和LinkedList的区别,数据结构实现,扩容机制
(1) ArrayList是实现了基于动态数组的数据结构,LinkedList基于双向循环链表的数据结构。
(2) 对于随机访问get和set,ArrayList觉得优于LinkedList,因为LinkedList要移动指针。
(3) 对于新增和删除操作add和remove,LinedList比较占优势,因为ArrayList要移动数据。
(4) 查找操作indexOf, lastIndexOf, contains等,两者差不多。

(5) 随机查找指定节点的操作get,ArrayList速度要快于LinkedList. 当操作是在一列数据的后面添加数据而不是在前面或中间,并且需要随机地访问其中的元素时,使用ArrayList会提供比较好的性能;当你的操作是在 一列数据的前面或中间添加或删除数据,并且按照顺序访问其中的元素时,就应该使用LinkedList了。
扩容: 针对ArrayList,在新增的时候,容量不够就需要扩容,2倍。

22. Hash函数的构造方法常见的有那几种
(1)直接寻址法:取关键字或关键字的某个线性函数值为散列地址。即H(key)=key或H(key) = a·key + b为散列函数。若其中H(key)中已经有值了,就往下一个找,直到H(key)中没有值了,就放进去。
(2) 数字分析法:就是找出数字的规律,尽可能利用这些数据来构造冲突几率较低的散列地址。
(3)平方取中法:取关键字平方后的中间几位作为散列地址。
(4) 折叠法:将关键字分割成位数相同的几部分,最后一部分位数可以不同,然后取这几部分的叠加和(去除进位)作为散列地址。
(5)随机数法:选择一随机函数,取关键字的随机值作为散列地址,通常用于关键字长度不同的场合。
(6)除留余数法:取关键字被某个不大于散列表表长m的数p除后所得的余数为散列地址。即 H(key) = key MOD p,p<=m。不仅可以对关键字直接取模,也可在折叠、平方取中等运算之后取模。对p的选择很重要,一般取素数或m,若p选的不好,容易产生同 义词。

23. HashMap的实现原理(内部数据结构,null key, rehash);为什么说HashMap不是线程安全的

(1)内部数据结构实现:数组+链表 (最好画个图能解释清楚)
(2)key值不能重复,只能put一个key为null的键值对。可以更深层次考察对put(null,value)以及get(null)的 理解。
(3)HashMap在put时,经过了两次hash,一个是JDK自带的对对象key的hash,然后再对结果使用HashMap内部函数hash(int h);hash(int h)方法根据key的hashCode重新计算一次散列。
可以更深入考察对hash(int h)以及indexFor(int h, int length)两个函数的理解。
(4)在put时如果空间不够就需要扩容resize(),考察扩容过程–重新计算复制。
(5)在并发的多线程使用场景中,使用HashMap形成环链,造成死循环,CPU飙升至100%。

24. List有哪些实现,实现原理,如何选择实现;是否比较过性能差异?contains方法是怎样比较对象的?
(1)List的直接实现是两个抽象类,AbstactList和AbstractSequentialList.
其中,AbstractList为随即访问(如数组)实现方案提供尽可能的封装 ,AbstractSequentialList为连续访问(如链表)实现方案提供了尽可能的封装。
ArrayList,直接父类是AbstractList,数据结构是大小可变的数组, 它不是同步的。
LinkedList,直接父类是AbstractSquentialList,数据结构是双向链表,它不是同步的,它同时实现了Deque(双向队列)和Queue(队 列)接口。
同时它还提供了push和pop这两个堆栈操作的接口。Vector,直接父类是AbstractList,特性和ArrayList一样,只是它是线程同步的。Stack ,直接父类是Vector,实现堆栈这种数据结构。

(2)通过对象的equals方法。
25. 如何拷贝数组,怎样效率最高?为什么
(1)使用循环结构 这种方法最灵活。唯一不足的地方可能就是代码较多

(2)使用Object类的clone()方法,
这种方法最简单,得到原数组的一个副本。灵活形也最差。效率最差,尤其是在数组元素很大或者复制对象数组时。
这种方法最简单,得到原数组的一个副本。灵活形也最差。效率最差,尤其是在数组元素很大或者复制对象数组时。

(3) 使用Systems的arraycopy这种方法被告之速度最快,并且灵活性也较好,可以指定原数组名称、以及元素的开始位置、复 制的元素的个数,目标数组名称、目标数组的位置。

浅拷贝和深拷贝得理解:定义一个数组int[] a={3,1,4,2,5}; int[] b=a; 数组b只是对数组a的又一个引用,即浅拷贝。
如果改变数组b中元素的值,其实是改变了数组a的元素的值,要实现深度复制,可以用clone或者System.arrayCopy clone和System.arrayCopy都是对一维数组的深度复制;因为java中没有二维数组的概念,只有数组的数组。所以二维数组a中存储的实际上是两 个一维数组的引用。当调用clone函数时,是对这两个引用进行了复制。

26. Java HashMap,已知整个生命周期内不会放入超过100个元素,那么占用内存大小最优且设置完初始值后无需自动扩容,该初始值应该设置为多少?

如果默认使用H ashMap内置的负载因子loadFactor为0.75。鉴于HashMap初始化设置大小为2的n次方,则100/0.75=133. 大于133的最小2的n次方为256个。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值