JAVA八股文口述总结-JAVA基础

1. 重载和重写的区别

重载是在一个类里面的方法,方法名相同参数列表不同的情形

而重写是发生在父子类里面,子类重写父类方法,方法名和参数列表必须和父类方法一致,而且需要返回值和抛出异常小于等于父类方法,而修饰符大于等于父类方法

还有就是构造方法只能重载不能重写,因为构造方法要求方法名必须和类名一样,如果子类重写父类的方法的话,就会使得构造方法名和类名不一致

2. 说一下对于java集合的理解

Java的集合主要有四种,以四种接口来代表,分别为List,set,queuemap

其中list,set,queue都是继承自collection接口

其中list是列表,存放的是有序且可重复的元素

Set存放的是无序且不可重复的元素

Queue是一个先进先出的队列

Map是键值对类型的集合

这是接口,当然有其具体的实现,比如ArrayList,linkedlist,hashset,arrayqueue,hashmap等等,接口以及这些接口的实现都在java.util包下,这些实现都是非线程安全的,但是性能比较好。当然有一些线程安全的集合比如Vector、hashtable等等

当然这些非线程安全的集合在多线程环境下不建议使用,就需要把这些非线程安全的集合变成线程安全的集合,以Hashmap举例来说

第一种方法就是,使用hashtable,但是是一个老API了官方也不建议使用了

第二种方法就是,使用collection类里面的synochronized方法把非线程安全的实现包装成线程安全的

第三种方法就是使用concurrentHashMap,这个是线程安全的

3. 具体说一下为什么HashMap是非线程安全的,而concurrenthashmap是线程安全的呢

Hashmap底层是数组+链表/红黑树组成的,在多线程写操作的时候会发生数据的覆盖,并且对于hashmap的底层代码,比如执行put操作的时候,modcount变量会执行++操作,这个看似是一行代码,实际上是读取、增加、保存的操作,这并不是一个原子操作,因此是非线程安全的。

而对于concurrenthashmap来说,内部使用了lock来解决了非线程安全的问题,上锁的时候只锁对应下标的元素,不会对其他位置造成影响,既保证了安全又保证了性能

4. 那说一下Hashmap和Hashtable的区别是什么

是不是线程安全的。Hashtable是线程安全的但是是比较老的API了不建议使用了,而hashmap是非线程安全的,但是他的性能比较好,如果想要变成线程安全的,一种就是使用collection类里面的synolized方法将hashmap包装成线程安全的实现,第二种就是使用concurrenthashmap,是线程安全的,使用lock保证了线程安全,上锁的时候只锁对应元素的下标,不会对其他位置造成影响,既保证了安全,又保证了性能。

允不允许存入null值,hashtable是不允许的,不论是key还是value都不行,而hashmap可以,无论是key还是value都可以。

5. 前面提到了lock,那么能不能说一下lock和synochronized的区别

① 首先lock是个接口,而synochronized是一个关键字

② synochronized在发生异常的时候会自动释放占有的锁,因此不会发生死锁。而lock在发生异常的时候不会释放占有的锁,必须手动通过unlock来释放,可能引起死锁的发生。

③ Lock可以根据trylock来知道有没有获取锁,而synochronized不能

④ 线程1如果发生阻塞的话,线程2在等待,对于lock锁可以使用interrupt来中断等待,直接结束而对于synochronized的话会一直等待下去,直到锁释放。

6. 说一下Hashmap以及什么是哈希冲突怎么解决重要

Hashmap就是那种键值对类型的集合,底层的话在JDK1.8之前是数组+链表的形式,在JDK1.8之后是数组+红黑树的形式,能够提高一个查询速度

具体来说的话,哈希表获取到key值之后通过hashfunction计算出hashcode,然后hashcode对数组长度进行一个取余操作得到一个position,得到之后把value值插入到这个位置。

哈希冲突的话就是说key值虽然不同但是可能通过hashfunction得到的hashcode的值是一样的,这就是哈希冲突

怎么解决哈希冲突呢?主要有两种方法,分别是拉链法和线性探测法

拉链法就是将发生冲突的元素存储在链表里(因此我们要适当的选择哈希表的大小,既不会因为有空值而浪费空间,也不会因为链表长度太长而使得查询困难)

而线性探测法:要保证数组的长度大于数据的个数,来依靠哈希表中的空位来存储冲突的值

7. 说一下对ArrayList的理解?

ArrayList是基于数组实现的,内部封装了一个object数组

JDK1.8之前,是直接创建长度为10的数组

JDK1.8之后,通过默认构造器创建容器时,先初始化一个空数组,之后在第一次调用add方法的时候才会创建一个长度为10的数组

当然我们可以通过构造器来指定大小,或者使用size方法也可以。

那么随着元素的加入,达到10个元素以后就需要对ArrayList进行扩容:

  • 创建新数组,数组长度是原来的1.5倍,也就是说原来是10,现在变成15
  • 利用arrays里面的一个方法,就是copyof将原数组中的内容拷贝到新数组中
  • 再想要添加元素的时候直接将元素加到新的数组当中

当然也支持ArrayList的缩容,但是不会自动缩容

8. 说一下ArrayList和LinkedList的区别重要

相同点:都是List接口的实现,其中list存放的是有序可重复的元素,而且他们都是非线程安全的

不同点

  • 底层实现不同:ArrayList是基于数组实现的,linkedlist底层是双向链表
  • 应用不同:ArrayList由于是基于数组实现的,适用于查询多,增删少的情形(要重新计算大小以及索引等)而LinkedList适用于增删多,查询少的情况(每次查询都要依次遍历)
  • 所占内存:LinkedList由于是双向链表,因此除了要存放数据本身,还要存放指向两个位置的地址值;而对于ArrayList的自动扩容又容易造成空间的浪费

 9. == 和equals 的区别

  • == 是操作符,而equals是object类当中的方法
  • ==既能比较基本数据类型,也能比较引用数据类型,而equals只能比较引用数据类型

对于==比较基本数据类型的时候比较的是值,如果比较引用数据类型的话比较的是地址

而对于equals如果没有重写的话,默认相当于==,就是比较的是引用数据类型的地址值,重写方法之后,可以按照引用所指内存的内容进行比较

10.说一下hashcode()方法和equals()方法的区别,为什么重写equals就要重写hashcode()

        首先是hashcode()函数的作用是获取哈希值,而equals()的作用是比较两个对象,默认如果不重写相当于是==,比较的是两个对象的地址值,重写之后就能比较两个对象的内容了,这也就是为什么重写equals()方法,就是有时候我们需要比较两个对象的属性值而不是比较两个对象的地址值

        接下来两者之间的约定就是说,如果两个对象相等,他们的哈希值一定相等,但如果两个对象的哈希值相等,两个对象不一定相等,也就是说equals()比较两个对象相等了,那么用hashcode()方法一定也是相等的,但用hashcode()方法比较两个对象相等了,但用equals()方法比较的结果就不一定相等

如果重写equals的时候不重写hashcode的话,由于默认的hashcode()方法是按照对象的地址来根据哈希算法得到的,显然比较两个哈希值时候是不相等的

而按刚才的规则的话equals方法比较的时候相等的话,那么hashcode()方法比较也一定相等,不符合这条约定了,因此重写hashcode就能解决这一问题

11. String、stringbuffer、stringbuilder的区别(重点)

String是不可变类,导致每次对String的操作都会生成新的String对象,不仅效率低,而且还会浪费内存空间

StringBuffer和StringBuilder是可变类

区别在于stringbuffer是线程安全的,因为里面的方法都被synchronized修饰了,因为是线程安全的因此效率不高。但StringBuilder是非线程安全的,效率会比较高

因此说单线程建议使用StringBuilder,多线程建议使用Stringbuffer

待补充......

 

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值