java基础学习总结

基础篇

1 Java 语言有哪些特点
1 、简单易学、有丰富的类库
2 、面向对象( Java 最重要的特性,让程序耦合度更低,内聚性更高)
2 、面向对象和面向过程的区别
面向过程 :是分析解决问题的步骤,然后用函数把这些步骤一步一步地实现,然后在使用的时候一
一调用则可。性能较高,所以单片机、嵌入式开发等一般采用面向过程开发
面向对象 :是把构成问题的事务分解成各个对象,而建立对象的目的也不是为了完成一个个步骤,
而是为了描述某个事物在解决整个问题的过程中所发生的行为。面向对象有 封装、继承、多态 的特
性,所以易维护、易复用、易扩展。可以设计出低耦合的系统。 但是性能上来说,比面向过程要
低。
标识符的命名规则。
标识符的含义: 是指在程序中,我们自己定义的内容,譬如,类的名字,方法名称以及变量名称等 等,都是标识符。
命名规则:(硬性要求) 标识符可以包含英文字母, 0-9 的数字, $ 以及 _ 标识符不能以数字开头 标 识符不是关键字
命名规范:(非硬性要求) 类名规范:首字符大写,后面每个单词首字母大写(大驼峰式)。 变量名规范:首字母小写,后面每个单词首字母大写(小驼峰式)。 方法名规范:同变量名。
重载和重写的区别
重写 (Override)
从字面上看,重写就是 重新写一遍的意思。其实就是在子类中把父类本身有的方法重新写一遍。子
类继承了父类原有的方法,但有时子类并不想原封不动的继承父类中的某个方法,所以在方法名,
参数列表,返回类型 ( 除过子类中方法的返回值是父类中方法返回值的子类时 ) 都相同的情况下, 对
方法体进行修改或重写,这就是重写。但要注意子类函数的访问修饰权限不能少于父类的。
public class Father {
public static void main ( String [] args ) {
// TODO Auto-generated method stub
Son s = new Son ();
s . sayHello ();
}
public void sayHello () {
System . out . println ( "Hello" );
}
}
class Son extends Father {
@Override
public void sayHello () {
// TODO Auto-generated method stub
System . out . println ( "hello by " );
}
}
重写 总结: 1. 发生在父类与子类之间 2. 方法名,参数列表,返回类型(除过子类中方法的返回类型
是父类中返回类型的子类)必须相同 3. 访问修饰符的限制一定要大于被重写方法的访问修饰符
public>protected>default>private) 4. 重写方法一定不能抛出新的检查异常或者比被重写方法申
明更加宽泛的检查型异常
重载( Overload
在一个类中,同名的方法如果有不同的参数列表( 参数类型不同、参数个数不同甚至是参数顺序不
)则视为重载。同时,重载对返回类型没有要求,可以相同也可以不同,但 不能通过返回类型是
否相同来判断重载
public class Father {
public static void main ( String [] args ) {
// TODO Auto-generated method stub
Father s = new Father ();
s . sayHello ();
s . sayHello ( "wintershii" );
}
public void sayHello () {
System . out . println ( "Hello" );
}
public void sayHello ( String name ) {
System . out . println ( "Hello" + " " + name );
}
}
重载 总结: 1. 重载 Overload 是一个类中多态性的一种表现 2. 重载要求同名方法的参数列表不同 (
数类型,参数个数甚至是参数顺序 ) 3. 重载的时候,返回值类型可以相同也可以不相同。无法以返回
型别作为重载函数的区分标准
 
equals == 的区别
==
== 比较的是变量 ( ) 内存中存放的对象的 ( ) 内存地址,用来判断两个对象的地址是否相同,即是
否是指相同一个对象。比较的是真正意义上的指针操作。
1 、比较的是操作符两端的操作数是否是同一个对象。 2 、两边的操作数必须是同一类型的(可以是父子类之间)才能编译通过。 3 、比较的是地址,如果是具体的阿拉伯数字的比较,值相等则为
true ,如: int a=10 long b=10L double c=10.0 都是相同的(为 true ),因为他们都指向地
址为 10 的堆。
equals
equals 用来比较的是两个对象的内容是否相等,由于所有的类都是继承自 java.lang.Object 类的,所
以适用于所有对象,如果没有对该方法进行覆盖的话,调用的仍然是 Object 类中的方法,而 Object
中的 equals 方法返回的却是 == 的判断。
总结:
所有比较是否相等时,都是用 equals 并且在对常量相比较时,把常量写在前面,因为使用 object
equals object 可能为 null 则空指针
在阿里的代码规范中只使用 equals ,阿里插件默认会识别,并可以快速修改,推荐安装阿里插件来 排查老代码使用“==” ,替换成 equals
Hashcode 的作用
java 的集合有两类,一类是 List ,还有一类是 Set 。前者有序可重复,后者无序不重复。当我们在 set 中插入的时候怎么判断是否已经存在该元素呢,可以通过equals 方法。但是如果元素太多,用这样的方法就会比较满。
于是有人发明了哈希算法来提高集合中查找元素的效率。 这种方式将集合分成若干个存储区域,每个对象可以计算出一个哈希码,可以将哈希码分组,每组分别对应某个存储区域,根据一个对象的哈希码就可以确定该对象应该存储的那个区域。
hashCode 方法可以这样理解:它返回的就是根据对象的内存地址换算出的一个值。这样一来,当
集合要添加新的元素时,先调用这个元素的 hashCode 方法,就一下子能定位到它应该放置的物理
位置上。如果这个位置上没有元素,它就可以直接存储在这个位置上,不用再进行任何比较了;如
果这个位置上已经有元素了,就调用它的 equals 方法与新元素进行比较,相同的话就不存了,不相
同就散列其它的地址。这样一来实际调用 equals 方法的次数就大大降低了,几乎只需要一两次。
 
String String StringBuffffer StringBuilder 的区别是什 ?
String 是只读字符串,它并不是基本数据类型,而是一个对象。从底层源码来看是一个 fifinal 类型的
字符数组,所引用的字符串不能被改变,一经定义,无法再增删改。每次对 String 的操作都会生成
新的 String 对象。
private final char value [];
每次 + 操作 : 隐式在堆上 new 了一个跟原字符串相同的 StringBuilder 对象,再调用 append 方法 拼
+ 后面的字符。
StringBuffffer StringBuilder 他们两都继承了 AbstractStringBuilder 抽象类,从
AbstractStringBuilder 抽象类中我们可以看到
char [] value ;
他们的底层都是可变的字符数组,所以在进行频繁的字符串操作时,建议使用 StringBuffffer
StringBuilder 来进行操作。 另外 StringBuffffer 对方法加了同步锁或者对调用的方法加了同步锁,所
以是线程安全的。 StringBuilder 并没有对方法进行加同步锁,所以是非线程安全的。
ArrayList linkedList 的区别
Array (数组)是基于索引 (index) 的数据结构,它使用索引在数组中搜索和读取数据是很快的。
Array 获取数据的时间复杂度是 O(1), 但是要删除数据却是开销很大,因为这需要重排数组中的所有
数据 , ( 因为删除数据以后 , 需要把后面所有的数据前移 )
缺点 : 数组初始化必须指定初始化的长度 , 否则报错
例如 :
int [] a = new int [ 4 ]; // 推介使用 int[] 这种方式初始化
int c [] = { 23 , 43 , 56 , 78 }; // 长度: 4 ,索引范围: [0,3]
List— 是一个有序的集合,可以包含重复的元素,提供了按索引访问的方式,它继承 Collection
List 有两个重要的实现类: ArrayList LinkedList
ArrayList: 可以看作是能够自动增长容量的数组
ArrayList toArray 方法返回一个数组
ArrayList asList 方法返回一个列表
ArrayList 底层的实现是 Array, 数组扩容实现
LinkList 是一个双链表 , 在添加和删除元素时具有比 ArrayList 更好的性能 . 但在 get set 方面弱于
ArrayList. 当然 , 这些对比都是指数据量很大或者操作很频繁。
12 HashMap HashTable 的区别
1 、两者父类不同
HashMap 是继承自 AbstractMap 类,而 Hashtable 是继承自 Dictionary 类。不过它们都实现了同时
实现了 map Cloneable (可复制)、 Serializable (可序列化)这三个接口。
2 、对外提供的接口不同
Hashtable HashMap 多提供了 elments() contains() 两个方法。 elments() 方法继承自
Hashtable 的父类 Dictionnary elements() 方法用于返回此 Hashtable 中的 value 的枚举。
contains() 方法判断该 Hashtable 是否包含传入的 value 。它的作用与 containsValue() 一致。事实
上, contansValue() 就只是调用了一下 contains() 方法。
3 、对 null 的支持不同
Hashtable key value 都不能为 null
HashMap key 可以为 null ,但是这样的 key 只能有一个,因为必须保证 key 的唯一性;可以有多个
key 值对应的 value null
4 、安全性不同
HashMap 是线程不安全的,在多线程并发的环境下,可能会产生死锁等问题,因此需要开发人员自己处理多线程的安全问题。
Hashtable 是线程安全的,它的每个方法上都有 synchronized 关键字,因此可直接用于多线程中。
虽然 HashMap 是线程不安全的,但是它的效率远远高于 Hashtable ,这样设计是合理的,因为大部
分的使用场景都是单线程。当需要多线程操作的时候可以使用线程安全的 ConcurrentHashMap
ConcurrentHashMap 虽然也是线程安全的,但是它的效率比 Hashtable 要高好多倍。因为
ConcurrentHashMap 使用了分段锁,并不对整个数据进行锁定。
5 、初始容量大小和每次扩充容量大小不同
6 、计算 hash 值的方法不同
 
13 Collection 包结构,与 Collections 的区别
Collection 是集合类的上级接口,子接口有 Set List LinkedList ArrayList Vector Stack
Set
Collections 是集合类的一个帮助类, 它包含有各种有关集合操作的静态多态方法,用于实现对各种集合的搜索、排序、线程安全化等操作。此类不能实例化,就像一个工具类,服务于Java
Collection 框架。

Java 的四种引用,强弱软虚
强引用
强引用是平常中使用最多的引用,强引用在程序内存不足( OOM )的时候也不会被回收,使用
方式:
String str = new String ( "str" );
System . out . println ( str );
软引用
软引用在程序内存不足时,会被回收,使用方式:
// 注意: wrf 这个引用也是强引用,它是指向 SoftReference 这个对象的,
// 这里的软引用指的是指向 new String("str") 的引用,也就是 SoftReference 类中 T
SoftReference < String > wrf = new SoftReference < String > ( new String ( "str" ));
可用场景: 创建缓存的时候,创建的对象放进缓存中,当内存不足时, JVM 就会回收早先创建
的对象。
弱引用
弱引用就是只要 JVM 垃圾回收器发现了它,就会将之回收,使用方式:
WeakReference < String > wrf = new WeakReference < String > ( str );
可用场景: Java 源码中的 java.util.WeakHashMap 中的 key 就是使用弱引用,我的理解就是,
一旦我不需要某个引用, JVM 会自动帮我处理它,这样我就不需要做其它操作。
虚引用
虚引用的回收机制跟弱引用差不多,但是它被回收之前,会被放入 ReferenceQueue 中。注意
哦,其它引用是被 JVM 回收后才被传入 ReferenceQueue 中的。由于这个机制,所以虚引用大多
被用于引用销毁前的处理工作。还有就是,虚引用创建的时候,必须带有 ReferenceQueue
使用例子:
PhantomReference < String > prf = new PhantomReference < String > ( new String ( "str" ),
new ReferenceQueue <> ());
可用场景: 对象销毁前的一些操作,比如说资源释放等。 Object.finalize() 虽然也可以做这
类动作,但是这个方式即不安全又低效
上诉所说的几类引用,都是指对象本身的引用,而不是指 Reference 的四个子类的引用
(SoftReference )
泛型常用特点
泛型是 Java SE 1.5 之后的特性, 《 Java 核心技术》中对泛型的定义是:
泛型 意味着编写的代码可以被不同类型的对象所重用。
泛型 ,顾名思义, 泛指的类型 。我们提供了泛指的概念,但具体执行的时候却可以有具体的规则来约束,比如我们用的非常多的ArrayList 就是个泛型类, ArrayList 作为集合可以存放各种元素,如
Integer, String ,自定义的各种类型等,但在我们使用的时候通过具体的规则来约束,如我们可以约 束集合中只存放Integer 类型的元素,如
List < Integer > iniData = new ArrayList <> ()
使用泛型的好处?
以集合来举例,使用泛型的好处是我们不必因为添加元素类型的不同而定义不同类型的集合,如整
型集合类,浮点型集合类,字符串集合类,我们可以定义一个集合来存放整型、浮点型,字符串型
数据,而这并不是最重要的,因为我们只要把底层存储设置了 Object 即可,添加的数据全部都可向
上转型为 Object 。 更重要的是我们可以通过规则按照自己的想法控制存储的数据类型
 
Java 创建对象有几种方式?
java 中提供了以下四种创建对象的方式 :
new 创建新对象
通过反射机制
采用 clone 机制
通过序列化机制
17 、有没有可能两个不相等的对象有相同的 hashcode
有可能 . 在产生 hash 冲突时 , 两个不相等的对象就会有相同的 hashcode . hash 冲突产生时 , 一般
有以下几种方式来处理 :
拉链法 : 每个哈希表节点都有一个 next 指针 , 多个哈希表节点可以用 next 指针构成一个单向链
表,被分配到同一个索引上的多个节点可以用这个单向链表进行存储 .
开放定址法 : 一旦发生了冲突 , 就去寻找下一个空的散列地址 , 只要散列表足够大 , 空的散列地址总
能找到 , 并将记录存入
再哈希 : 又叫双哈希法 , 有多个不同的 Hash 函数 . 当发生冲突时 , 使用第二个 , 第三个 …. 等哈希函数
计算地址 , 直到无冲突 .
18 、深拷贝和浅拷贝的区别是什么 ?
浅拷贝 : 被复制对象的所有变量都含有与原来的对象相同的值 , 而所有的对其他对象的引用仍然指
向原来的对象 . 换言之 , 浅拷贝仅仅复制所考虑的对象 , 而不复制它所引用的对象 .
深拷贝 : 被复制对象的所有变量都含有与原来的对象相同的值 . 而那些引用其他对象的变量将指向
被复制过的新对象 . 而不再是原有的那些被引用的对象 . 换言之 . 深拷贝把要复制的对象所引用的
对象都复制了一遍 .
fifinal 有哪些用法 ?
fifinal 也是很多面试喜欢问的地方 , 但我觉得这个问题很无聊 , 通常能回答下以下 5 点就不错了 :
fifinal 修饰的类不可以被继承
fifinal 修饰的方法不可以被重写
fifinal 修饰的变量不可以被改变 . 如果修饰引用 , 那么表示引用不可变 , 引用指向的内容可变 .
fifinal 修饰的方法 ,JVM 会尝试将其内联 , 以提高运行效率
fifinal 修饰的常量 , 在编译阶段会存入常量池中 .
除此之外 , 编译器对 fifinal 域要遵守的两个重排序规则更好 :
在构造函数内对一个 fifinal 域的写入 , 与随后把这个被构造对象的引用赋值给一个引用变量 , 这两个操作之间不能重排序 初次读一个包含fifinal 域的对象的引用 , 与随后初次读这个 fifinal , 这两个操作之间不能重排序
OOM 你遇到过哪些情况, SOF 你遇到过哪些情况
OOM
1 OutOfMemoryError 异常
除了程序计数器外,虚拟机内存的其他几个运行时区域都有发生 OutOfMemoryError(OOM) 异常的
可能。
Java Heap 溢出:
一般的异常信息: java.lang.OutOfMemoryError:Java heap spacess
java 堆用于存储对象实例,我们只要不断的创建对象,并且保证 GC Roots 到对象之间有可达路径来避免垃圾回收机制清除这些对象,就会在对象数量达到最大堆容量限制后产生内存溢出异常。 仅供 出现这种异常,一般手段是先通过内存映像分析工具( Eclipse Memory Analyzer) dump 出来的堆转存快照进行分析,重点是确认内存中的对象是否是必要的,先分清是因为内存泄漏(Memory
Leak) 还是内存溢出 (Memory Overflflow)
如果是内存泄漏,可进一步通过工具查看泄漏对象到 GCRoots 的引用链。于是就能找到泄漏对象是
通过怎样的路径与 GC Roots 相关联并导致垃圾收集器无法自动回收。
如果不存在泄漏,那就应该检查虚拟机的参数 (-Xmx -Xms) 的设置是否适当。
2 ,虚拟机栈和本地方法栈溢出
如果线程请求的栈深度大于虚拟机所允许的最大深度,将抛出 StackOverflflowError 异常。
如果虚拟机在扩展栈时无法申请到足够的内存空间,则抛出 OutOfMemoryError 异常
这里需要注意当栈的大小越大可分配的线程数就越少。
3 ,运行时常量池溢出
异常信息: java.lang.OutOfMemoryError:PermGenspace
如果要向运行时常量池中添加内容,最简单的做法就是使用 String.intern() 这个 Native 方法。该方法
的作用是:如果池中已经包含一个等于此 String 的字符串,则返回代表池中这个字符串的 String
象;否则,将此 String 对象包含的字符串添加到常量池中,并且返回此 String 对象的引用。由于常量池分配在方法区内,我们可以通过-XX:PermSize -XX:MaxPermSize 限制方法区的大小,从而间接限制其中常量池的容量。
4 ,方法区溢出
方法区用于存放 Class 的相关信息,如类名、访问修饰符、常量池、字段描述、方法描述等。也有可能是方法区中保存的class 对象没有被及时回收掉或者 class 信息占用的内存超过了我们配置。
异常信息: java.lang.OutOfMemoryError:PermGenspace
方法区溢出也是一种常见的内存溢出异常,一个类如果要被垃圾收集器回收,判定条件是很苛刻
的。在经常动态生成大量 Class 的应用中,要特别注意这点。
SOF (堆栈溢出 StackOverflflow ):
StackOverflflowError 的定义:当应用程序递归太深而发生堆栈溢出时,抛出该错误。
因为栈一般默认为 1-2m ,一旦出现死循环或者是大量的递归调用,在不断的压栈过程中,造成栈容量超过1m 而导致溢出。
栈溢出的原因:递归调用,大量循环或死循环,全局变量是否过多,数组、 List map 数据过大。
29 Java IO NIO 的区别(补充)
NIO New IO ,这个库是在 JDK1.4 中才引入的。 NIO IO 有相同的作用和目的,但实现方式不同,
NIO 主要用到的是块,所以 NIO 的效率要比 IO 高很多。在 Java API 中提供了两套 NIO ,一套是针对标
准输入输出 NIO ,另一套就是网络编程 NIO
30 java 反射的作用于原理
1 、定义:
反射机制是在运行时,对于任意一个类,都能够知道这个类的所有属性和方法;对于任意个对象,
都能够调用它的任意一个方法。在 java 中,只要给定类的名字,就可以通过反射机制来获得类的所
有信息。
这种动态获取的信息以及动态调用对象的方法的功能称为 Java 语言的反射机制。
2 、哪里会用到反射机制?
jdbc 就是典型的反射
Class . forName ( 'com.mysql.jdbc.Driver.class' ); // 加载 MySQL 的驱动类
这就是反射。如hibernate struts 等框架使用反射实现的。
3 、反射的实现方式:
第一步:获取 Class 对象,有 4 中方法: 1 Class.forName(“ 类的路径 ”) 2 )类名 .class 3 )对象
.getClass() 4 )基本类型的包装类,可以调用包装类的 Type 属性来获得该包装类的 Class 对象
4 、实现 Java 反射的类:
1 Class :表示正在运行的 Java 应用程序中的类和接口 注意: 所有获取对象的信息都需要 Class
来实现。 2 Field :提供有关类和接口的属性信息,以及对它的动态访问权限。 3 Constructor
提供关于类的单个构造方法的信息以及它的访问权限 4 Method :提供类或接口中某个方法的信息
5 、反射机制的优缺点:
优点: 1 )能够运行时动态获取类的实例,提高灵活性; 2 )与动态编译结合 缺点: 1 )使用反射
性能较低,需要解析字节码,将内存中的对象进行解析。 解决方案: 1 、通过 setAccessible(true)
关闭 JDK 的安全检查来提升反射速度; 2 、多次创建一个类的实例时,有缓存会快很多 3
ReflflectASM 工具类,通过字节码生成的方式加快反射速度 2 )相对不安全,破坏了封装性(因为通过反射可以获得私有方法和属性)
 
说说 List,Set,Map 三者的区别?
List( 对付顺序的好帮手 ) List 接口存储一组不唯一(可以有多个元素引用相同的对象),有序
的对象
Set( 注重独一无二的性质 ): 不允许重复的集合。不会有多个元素引用相同的对象。
Map( Key 来搜索的专家 ): 使用键值对存储。 Map 会维护与 Key 有关联的值。两个 Key 可以引
用相同的对象,但 Key 不能重复,典型的 Key String 类型,但也可以是任何对象。
 
36 、用过 ArrayList 吗?说一下它有什么特点?
只要是搞 Java 的肯定都会回答 用过 。所以,回答题目的后半部分 ——ArrayList 的特点。可以从这
几个方面去回答:
Java 集合框架中的一种存放相同类型的元素数据,是一种变长的集合类,基于定长数组实现,当加
入数据达到一定程度后,会实行自动扩容,即扩大数组大小。
底层是使用数组实现,添加元素。
如果 add(o) ,添加到的是数组的尾部,如果要增加的数据量很大,应该使用 ensureCapacity()
方法,该方法的作用是预先设置 ArrayList 的大小,这样可以大大提高初始化速度。
如果使用 add(int,o) ,添加到某个位置,那么可能会挪动大量的数组元素,并且可能会触发扩
容机制。
高并发的情况下,线程不安全。多个线程同时操作 ArrayList ,会引发不可预知的异常或错误。
ArrayList 实现了 Cloneable 接口,标识着它可以被复制。注意: ArrayList 里面的 clone() 复制其实
是浅复制。
37 、有数组了为什么还要
搞个 ArrayList 呢?
通常我们在使用的时候,如果在不明确要插入多少数据的情况下,普通数组就很尴尬了,因为你不
知道需要初始化数组大小为多少,而 ArrayList 可以使用默认的大小,当元素个数到达一定程度
后,会自动扩容。
可以这么来理解:我们常说的数组是定死的数组, ArrayList 却是动态数组。
fail-fast 机制是 Java 集合( Collection )中的一种错误机制。当多个线程对同一个集合的内容进行
操作时,就可能会产生 fail-fast 事件。
例如:当某一个线程 A 通过 iterator 去遍历某集合的过程中,若该集合的内容被其他线程所改变
了,那么线程 A 访问集合时,就会抛出 ConcurrentModifificationException 异常,产生 fail-fast
件。这里的操作主要是指 add remove clear ,对集合元素个数进行修改。
解决办法:建议使用 “java.util.concurrent 包下的类 去取代 “java.util 包下的类
可以这么理解:在遍历之前,把 modCount 记下来 expectModCount ,后面 expectModCount
modCount 进行比较,如果不相等了,证明已并发了,被修改了,于是抛出
ConcurrentModifificationException 异常。
说说 Hashtable HashMap 的区别
本来不想这么写标题的,但是无奈,面试官都喜欢这么问 HashMap
1. 出生的版本不一样, Hashtable 出生于 Java 发布的第一版本 JDK 1.0 HashMap 出生于 JDK
1.2
2. 都实现了 Map Cloneable Serializable (当前 JDK 版本 1.8 )。
3. HashMap 继承的是 AbstractMap ,并且 AbstractMap 也实现了 Map 接口。 Hashtable 继承
Dictionary
4. Hashtable 中大部分 public 修饰普通方法都是 synchronized 字段修饰的,是线程安全的,
HashMap 是非线程安全的。
5. Hashtable key 不能为 null value 也不能为 null ,这个可以从 Hashtable 源码中的 put
法看到,判断如果 value null 就直接抛出空指针异常,在 put 方法中计算 key hash 值之
前并没有判断 key null 的情况,那说明,这时候如果 key 为空,照样会抛出空指针异常。
6. HashMap key value 都可以为 null 。在计算 hash 值的时候,有判断,如果
key==null ,则其 hash=0 ;至于 value 是否为 null ,根本没有判断过。
7. Hashtable 直接使用对象的 hash 值。 hash 值是 JDK 根据对象的地址或者字符串或者数字算出
来的 int 类型的数值。然后再使用除留余数法来获得最终的位置。然而除法运算是非常耗费时
间的,效率很低。 HashMap 为了提高计算效率,将哈希表的大小固定为了 2 的幂,这样在取
模预算时,不需要做除法,只需要做位运算。位运算比除法的效率要高很多。
8. Hashtable HashMap 都使用了 Iterator 。而由于历史原因, Hashtable 还使用了
Enumeration 的方式。
9. 默认情况下,初始容量不同, Hashtable 的初始长度是 11 ,之后每次扩充容量变为之前的
2n+1 n 为上一次的长度)而 HashMap 的初始长度为 16 ,之后每次扩充变为原来的两倍。
另外在 Hashtable 源码注释中有这么一句话:
Hashtable is synchronized. If a thread-safe implementation is not needed, it is
recommended to use HashMap in place of Hashtable . If a thread-safe highly
concurrent implementation is desired, then it is recommended to use
ConcurrentHashMap in place of Hashtable.
大致意思: Hashtable 是线程安全,推荐使用 HashMap 代替 Hashtable ;如果需要线程安全高并
发的话,推荐使用 ConcurrentHashMap 代替 Hashtable
这个回答完了,面试官可能会继续问: HashMap 是线程不安全的,那么在需要线程安全的情况下
还要考虑性能,有什么解决方式?
这里最好的选择就是 ConcurrentHashMap 了,但面试官肯定会叫你继续说一下
ConcurrentHashMap 数据结构以及底层原理等。
41 HashMap 的长度为什么是 2 N 次方呢?
为了能让 HashMap 存数据和取数据的效率高,尽可能地减少 hash 值的碰撞,也就是说尽量把数
据能均匀的分配,每个链表或者红黑树长度尽量相等。
我们首先可能会想到 % 取模的操作来实现。
下面是回答的重点哟:
取余(%)操作中如果除数是 2 的幂次,则等价于与其除数减一的与(&)操作(也就是说
hash % length == hash &(length - 1) 的前提是 length 是 2 的 n 次方)。并且,采用二进
制位操作 & ,相对于 % 能够提高运算效率。
这就是为什么 HashMap 的长度需要 2 N 次方了。
怎么处理 Java 异常的
try-catch-fifinally
try 块负责监控可能出现异常的代码
catch 块负责捕获可能出现的异常,并进行处理
fifinally 块负责清理各种资源,不管是否出现异常都会执行
其中 try 块是必须的, catch fifinally 至少存在一个标准异常处理流程
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值