Android 200道面试题及答案

编程入门 行业动态 更新时间:2024-10-13 12:22:08

Android 200道<a href=https://www.elefans.com/category/jswz/34/1769418.html style=面试题及答案"/>

Android 200道面试题及答案

目录

Java 基础部分

1.抽象类与接口的区别?⭐⭐⭐⭐⭐

2.分别讲讲 final、static 和 synchronized 可以修饰什么,以及修饰后的作用?⭐⭐⭐⭐⭐

3.请简述一下 String、StringBuffer 和 StringBuilder 三者的区别?⭐⭐⭐⭐⭐

4.“equals” 与 “==”、“hashCode” 的区别和使用场景?⭐⭐⭐⭐⭐

5.Java 中深拷贝与浅拷贝的区别?⭐⭐⭐⭐⭐

6.谈谈 Error 和 Exception 的区别?⭐⭐⭐⭐⭐

7.什么是反射机制?反射机制的应用场景有哪些?⭐⭐⭐⭐⭐

8.谈谈如何重写 equals() 方法?为什么还要重写 hashCode()?⭐⭐⭐⭐⭐

9.Java 中 IO 流分为几种?它们之间有什么区别?⭐⭐⭐⭐⭐

10.谈谈你对 Java 泛型中类型擦除的理解,并说说其局限性?⭐⭐⭐⭐⭐

11.String 为什么要设计成不可变的?⭐⭐⭐⭐⭐

12.说说你对 Java 注解的理解?⭐⭐⭐⭐⭐

13.谈一谈 Java 成员变量、局部变量和静态变量的创建和回收时机?⭐⭐⭐⭐⭐

14.谈谈 Java 中 List、Set 以及 Map 的区别?⭐⭐⭐⭐⭐

15.谈谈 ArrayList 和 LinkedList 的区别?⭐⭐⭐⭐⭐

16.请说一下 HashMap 与 HashTable 的区别?⭐⭐⭐⭐⭐

17.说一说 ArrayList 的扩容机制?⭐⭐⭐⭐⭐

18.请简述 LinkedHashMap 的工作原理和使用场景?⭐⭐⭐⭐⭐

19.谈谈对于 ConcurrentHashMap 的理解?⭐⭐⭐⭐⭐

20.Java 中使用多线程的方式有哪些?⭐⭐⭐⭐⭐

21.说一下线程的几种状态?⭐⭐⭐⭐⭐

22.如何实现多线程中的同步?⭐⭐⭐⭐⭐

23.谈谈线程死锁,如何有效的避免线程死锁?⭐⭐⭐⭐⭐

24.谈谈线程阻塞的原因?⭐⭐⭐⭐⭐

25.请谈谈 Thread 中 run() 与 start() 方法的区别?⭐⭐⭐⭐⭐

26.说一下 synchronized 和 volatile 关键字的区别?⭐⭐⭐⭐⭐

27.如何保证线程安全?⭐⭐⭐⭐⭐

28.谈谈 ThreadLocal 用法和原理?⭐⭐⭐⭐⭐

29.谈谈 Java 线程中 notify 和 notifyAll 方法有什么区别?⭐⭐⭐⭐⭐

30.什么是线程池?如何创建一个线程池?⭐⭐⭐⭐⭐

31.谈一谈线程 sleep() 和 wait() 方法的区别?⭐⭐⭐⭐⭐

32.什么是悲观锁和乐观锁?⭐⭐⭐⭐⭐

33.什么是 BlockingQueue?请分析一下其内部原理并谈谈它的使用场景?⭐⭐⭐⭐⭐

34.谈一谈 Java 线程安全的集合有哪些?各有什么特点?⭐⭐⭐⭐⭐

35.Java 中为什么会出现 Atomic 类?试分析它的原理和缺点?⭐⭐⭐⭐⭐

36.说说 ThreadLocal 的使用场景?与 Synchronized 相比有什么特性?⭐⭐⭐⭐⭐

37.请简要谈一谈 Java 中的垃圾回收机制?⭐⭐⭐⭐⭐

38.回答一下什么是强、软、弱、虚引用以及它们之间的区别?⭐⭐⭐⭐⭐

39.简述 JVM 中类的加载机制与加载过程?⭐⭐⭐⭐⭐

40.请谈谈 Java 的内存回收机制?⭐⭐⭐⭐⭐

41.什么是 JMM?它存在哪些问题?该如何解决?⭐⭐⭐⭐⭐

42.谈谈 Android 中几种 LaunchMode 的特点和应用场景?⭐⭐⭐⭐⭐

43.BroadcastReceiver 与 LocalBroadcastReceiver 有什么区别?⭐⭐⭐⭐⭐

44.对于 Context,你了解多少?⭐⭐⭐⭐⭐

45.IntentFilter 是什么?有哪些使用场景?匹配机制是怎样的?⭐⭐⭐⭐⭐

46.谈一谈 startService 和 bindService 方法的区别,生命周期以及使用场景?⭐⭐⭐⭐⭐

47.Service 如何进行保活?⭐⭐⭐⭐⭐

48.简单介绍下 ContentProvider 是如何实现数据共享的?⭐⭐⭐⭐⭐

49.说下切换横竖屏时 Activity 的生命周期变化?⭐⭐⭐⭐⭐

50.Activity 中 onNewIntent 方法的调用时机和使用场景?⭐⭐⭐⭐⭐

51.Intent 传输数据的大小有限制吗?如何解决?⭐⭐⭐⭐⭐

52.说说 ContentProvider、ContentResolver、ContentObserver 之间的关系?⭐⭐⭐⭐⭐

53.说说 Activity 加载的流程?⭐⭐⭐⭐⭐

54.HandlerThread 的使用场景和实现原理?⭐⭐⭐⭐⭐

55.IntentService 的应用场景和内部实现原理?⭐⭐⭐⭐⭐

56.AsyncTask 的优点和缺点?内部实现原理是怎样的?⭐⭐⭐⭐⭐

57.谈谈你对 Activity.runOnUiThread 的理解?⭐⭐⭐⭐⭐

58.Android 的子线程能否做到更新 UI?⭐⭐⭐⭐⭐

59.谈谈 Android 中消息机制和原理?⭐⭐⭐⭐⭐

60.为什么在子线程中创建 Handler 会抛异常?⭐⭐⭐⭐⭐

61.试从源码角度分析 Handler 的 post 和 sendMessage 方法的区别和应用场景?⭐⭐⭐⭐⭐

62.Handler 中有 Loop 死循环,为什么没有阻塞主线程,原理是什么?⭐⭐⭐⭐⭐

63.Android 补间动画和属性动画的区别?⭐⭐⭐⭐⭐

64.Window 和 DecorView 是什么?DecorView 又是如何和 Window 建立联系的?⭐⭐⭐⭐⭐

65.简述一下 Android 中 UI 的刷新机制?⭐⭐⭐⭐⭐

66.你认为 LinearLayout、FrameLayout 和 RelativeLayout 哪个效率高, 为什么?⭐⭐⭐⭐⭐

67.说一下 Android 中的事件分发机制?⭐⭐⭐⭐⭐

68.谈谈自定义 View 的流程?⭐⭐⭐⭐⭐

69.有针对 RecyclerView 做过哪些优化?⭐⭐⭐⭐⭐

70.谈谈你是如何优化 ListView 的?⭐⭐⭐⭐⭐

71.谈一谈自定义 RecyclerView.LayoutManager 的流程?⭐⭐⭐⭐⭐

72.什么是 RemoteViews?使用场景有哪些?⭐⭐⭐⭐⭐

73.谈一谈获取View宽高的几种方法?⭐⭐⭐⭐⭐

74.谈一谈属性动画的插值器和估值器?⭐⭐⭐⭐⭐

75.请谈谈源码中 StaticLayout 的用法和应用场景?⭐⭐⭐⭐⭐

76.有用过ConstraintLayout吗?它有哪些特点?⭐⭐⭐⭐⭐

77.关于LayoutInflater,它是如何通过 inflate 方法获取到具体View的?⭐⭐⭐⭐⭐

78.谈一谈如何实现 Fragment 懒加载?⭐⭐⭐⭐⭐

79.谈谈 RecyclerView的缓存机制?⭐⭐⭐⭐⭐

80.请说说 View.inflate 和 LayoutInflater.inflate 的区别?⭐⭐⭐⭐⭐

81.请谈谈 invalidate() 和 postInvalidate() 方法的区别和应用场景?⭐⭐⭐⭐⭐

82.谈一谈自定义View和ViewGroup的流程以及区别?⭐⭐⭐⭐⭐

83.谈一谈 SurfaceView 与 TextureView 的使用场景和用法?⭐⭐⭐⭐⭐

84.谈一谈 RecyclerView.Adapter 的几种数据刷新方式有何不同?⭐⭐⭐⭐⭐

85.说说你对 Window 和 WindowManager 的理解?⭐⭐⭐⭐⭐

86.谈一谈 Activity、View 和 Window 三者的关系?⭐⭐⭐⭐⭐

87.为什么 ViewPager 嵌套 ViewPager,内部的 ViewPager 滚动没有被拦截?⭐⭐⭐⭐⭐

88.请谈谈 Fragment 的生命周期?⭐⭐⭐⭐⭐

89.请谈谈什么是同步屏障?⭐⭐⭐⭐⭐

90.有了解过 ViewDragHelper 的工作原理吗?⭐⭐⭐⭐⭐

91.谈一谈Android的屏幕刷新机制?⭐⭐⭐⭐⭐

92.谈谈你对Android性能优化方面的了解?⭐⭐⭐⭐⭐

93.自定义 Handler 时如何有效地避免内存泄漏问题?⭐⭐⭐⭐⭐

94.ANR 出现的场景以及解决方案?⭐⭐⭐⭐⭐

95.谈谈 Android 中内存优化的方式?⭐⭐⭐⭐⭐

96.谈谈布局优化的技巧?⭐⭐⭐⭐⭐

97.对于 Android 中图片资源的优化方案你知道哪些?⭐⭐⭐⭐⭐

98.Android Native Crash 问题如何分析定位?⭐⭐⭐⭐⭐

99.该如何给 Apk 瘦身?⭐⭐⭐⭐⭐

100.说一下你是如何优化 App 启动过程的?⭐⭐⭐⭐⭐

101.谈谈代码混淆的步骤?⭐⭐⭐⭐⭐

102.说说 App 的电量优化?⭐⭐⭐⭐⭐

103.谈谈如何对 WebView 进行优化?⭐⭐⭐⭐⭐

104.如何处理大图的加载?⭐⭐⭐⭐⭐

105.谈谈如何对网络请求进行优化?⭐⭐⭐⭐⭐

106.请谈谈如何加载Bitmap并防止内存溢出?⭐⭐⭐⭐⭐

107.请回答一下 Android 中进程间通信有哪些方式?⭐⭐⭐⭐⭐

108.请谈谈你对 Binder 机制的理解?⭐⭐⭐⭐⭐

109.什么是 AIDL?它的使用场景是什么?⭐⭐⭐⭐⭐

110.请简要谈谈 Android 系统的架构组成?⭐⭐⭐⭐⭐

111.SharedPreferences 是线程安全的吗?它的 commit 和 apply 方法有什么区别?⭐⭐⭐⭐⭐

112.Serializable 和 Parcelable 有哪些区别?⭐⭐⭐⭐⭐

113.请说一下 Android 7.0 的新特性?⭐⭐⭐⭐⭐

114.谈谈 ArrayMap 和 HashMap 的区别?⭐⭐⭐⭐⭐

115.简要说说 LruCache 的原理?⭐⭐⭐⭐⭐

116.Android 中为什么推荐用 SparseArray 代替 HashMap?⭐⭐⭐⭐⭐

117.PathClassLoader 和 DexClassLoader 有何区别?⭐⭐⭐⭐⭐

118.什么是Lifecycle?请分析其内部原理和使用场景?⭐⭐⭐⭐⭐

119.谈一谈 Android 的签名机制?不同版本下的签名有什么不同?⭐⭐⭐⭐⭐

120.谈谈安卓 Apk 构建的流程?⭐⭐⭐⭐⭐

121.简述一下 Android 8.0、9.0 分别增加了哪些新特性?⭐⭐⭐⭐⭐

122.谈谈 Android 10 更新了哪些内容?如何进行适配?⭐⭐⭐⭐⭐

123.请简述 Apk 的安装过程?⭐⭐⭐⭐⭐

124.什么是 JNI?具体说说如何实现 Java 与 C++ 的互调?⭐⭐⭐⭐⭐

125.请谈谈 App 的启动流程?⭐⭐⭐⭐⭐

126.谈一谈 LeakCanray 的工作原理?⭐⭐⭐⭐⭐

127.说说 EventBus 的实现原理?⭐⭐⭐⭐⭐

128.谈谈网络请求中的拦截器 - Interceptor 的实现原理和使用场景?⭐⭐⭐⭐⭐

129.谈一谈 Glide 中的缓存机制?⭐⭐⭐⭐⭐

130.ViewModel 的出现是为了解决什么问题?并简要说说它的内部原理?⭐⭐⭐⭐⭐

131.请说说依赖注入框架 ButterKnife 的实现原理?⭐⭐⭐⭐⭐

132.谈一谈 RxJava 背压原理?⭐⭐⭐⭐⭐

133.请谈谈你对 MVC 和 MVP 的理解?⭐⭐⭐⭐⭐

134.分别介绍下你所知道的 Android 中几种存储方式?⭐⭐⭐⭐⭐

135.简述下热修复的原理?⭐⭐⭐⭐⭐

136.请谈谈你是如何进行多渠道打包的?⭐⭐⭐⭐⭐

137.MVP 中你是如何处理 Presenter 层以防止内存泄漏的?⭐⭐⭐⭐⭐

138.如何计算一张图片所占的内存空间大小?⭐⭐⭐⭐⭐

139.如何获取 Android 设备唯一 ID?⭐⭐⭐⭐⭐

140.谈一谈 Android P 禁用 HTTP 协议对我们开发有什么影响?⭐⭐⭐⭐⭐

150.什么是 AOP?在 Android 中它有哪些应用场景?⭐⭐⭐⭐⭐

151.什么是 MVVM?你是如何将其应用于具体项目中的?⭐⭐⭐⭐⭐

152.请谈谈你会如何实现数据埋点?⭐⭐⭐⭐⭐

153.webp 和 svg 格式的图片各自有什么特点?应该如何在 Android 中使用?⭐⭐⭐⭐⭐

154.如何绕过 Android 9.0 针对反射的限制?⭐⭐⭐⭐⭐

155.对于 GIF 格式的图片加载有什么思路和建议?⭐⭐⭐⭐⭐

156.为什么要将项目迁移到 AndroidX?如何进行迁移?⭐⭐⭐⭐⭐

157.你了解过哪些Android屏幕适配方面的技巧?⭐⭐⭐⭐⭐

158.请简要谈一谈单例模式?⭐⭐⭐⭐⭐

159.对于面向对象的六大基本原则了解多少?⭐⭐⭐⭐⭐

160.请列出几种常见的工厂模式并说明它们的用法?⭐⭐⭐⭐⭐

161.说说项目中用到的设计模式和使用场景?⭐⭐⭐⭐⭐

162.什么是代理模式?如何使用?Android源码中的代理模式?⭐⭐⭐⭐⭐

163.谈一谈单例模式,建造者模式,工厂模式的使用场景?如何合理选择?⭐⭐⭐⭐⭐

164.谈谈你对原型模式的理解?⭐⭐⭐⭐⭐

165.请谈谈策略模式原理及其应用场景?⭐⭐⭐⭐⭐

166.静态代理和动态代理的区别,什么场景使用?⭐⭐⭐⭐⭐

167.谈一谈责任链模式的使用场景?⭐⭐⭐⭐⭐

168.请简述 Http 与 Https 的区别?⭐⭐⭐⭐⭐

169.说一说 HTTPS、UDP、Socket 之间的区别?⭐⭐⭐⭐⭐

170.请简述一次 HTTP 网络请求的过程?⭐⭐⭐⭐⭐

171.谈一谈 TCP/IP 三次握手、四次挥手过程?⭐⭐⭐⭐⭐

172.为什么说Http是可靠的数据传输协议?⭐⭐⭐⭐⭐

173.TCP/IP 协议分为哪几层?TCP 和 HTTP 分别属于哪一层?⭐⭐⭐⭐⭐

174.Post 中请求参数放在了哪个位置?⭐⭐⭐⭐⭐

175.请简述一下什么是 Kotlin?它有哪些特性?⭐⭐⭐⭐⭐

176.Kotlin 中注解 @JvmOverloads 的作用?⭐⭐⭐⭐⭐

177.Kotlin 中实现单例的几种常见方式?⭐⭐⭐⭐⭐

178.谈谈你对 Kotlin 中的 data 关键字的理解?相比于普通类有哪些特点?⭐⭐⭐⭐⭐

179.什么是委托属性?请简要说说其使用场景和原理?⭐⭐⭐⭐⭐

180.请举例说明 Kotlin 中 with 与 apply 函数的应用场景和区别?⭐⭐⭐⭐⭐

181.Kotlin中 Unit 类型的作用以及与Java中 Void 的区别?⭐⭐⭐⭐⭐

182.Kotlin 中 infix 关键字的原理和使用场景?⭐⭐⭐⭐⭐

183.Kotlin中的可见性修饰符有哪些?相比于 Java 有什么区别?⭐⭐⭐⭐⭐

184.你觉得 Kotlin 与 Java 混合开发时需要注意哪些问题?⭐⭐⭐⭐⭐

185.在 Kotlin 中,何为解构?该如何使用?⭐⭐⭐⭐⭐

186.在 Kotlin 中,什么是内联函数?有什么作用?⭐⭐⭐⭐⭐

186.谈谈Kotlin中的构造方法?有哪些注意事项?⭐⭐⭐⭐⭐

187.谈谈 Kotlin 中的 Sequence,为什么它处理集合操作更加高效?⭐⭐⭐⭐⭐

188.请谈谈 Kotlin 中的 Coroutines,它与线程有什么区别?有哪些优点?⭐⭐⭐⭐⭐

189.Kotlin中该如何安全地处理可空类型?⭐⭐⭐⭐⭐

190.说说 Kotlin中 的 Any 与Java中的 Object 有何异同?⭐⭐⭐⭐⭐

191.Kotlin中的数据类型有隐式转换吗?为什么?⭐⭐⭐⭐⭐

192.Kotlin 中集合遍历有哪几种方式?⭐⭐⭐⭐⭐

193.为什么协程比线程要轻量?⭐⭐⭐⭐⭐

Android 面试题及答案

个人整理一些面试题及答案,有些答案不太完整,如想更仔细的解析可自己百度谷歌

Java 基础部分

1.抽象类与接口的区别?⭐⭐⭐⭐⭐

大体区别如下:

抽象类可以提供成员方法的实现细节,而接口中只能存在 public 抽象方法;

抽象类中的成员变量可以是各种类型的,而接口中的成员变量只能是 public static final 类型的;

接口中不能含有构造器、静态代码块以及静态方法,而抽象类可以有构造器、静态代码块和静态方法;

一个类只能继承一个抽象类,而一个类却可以实现多个接口;

抽象类访问速度比接口速度要快,因为接口需要时间去寻找在类中具体实现的方法;

如果你往抽象类中添加新的方法,你可以给它提供默认的实现。因此你不需要改变你现在的代码。如果你往接口中添加方法,那么你必须改变实现该接口的类。

接口更多的为了约束类的行为,可用于解耦,而抽象类更加侧重于代码复用。

2.分别讲讲 final、static 和 synchronized 可以修饰什么,以及修饰后的作用?⭐⭐⭐⭐⭐

static

static 方法

static 方法一般称作静态方法,由于静态方法不依赖于任何对象就可以进行访问,因此对于静态方法来说,是没有 this 的,因为它不依附于任何对象,既然都没有对象,就谈不上 this 了。

public class StaticTest {

public static void a(){

}

public static void main(String[]args){

StaticTest.a();

}

}

static 变量

static 变量也称作静态变量,静态变量和非静态变量的区别是:静态变量被所有的对象所共享,在内存中只有一个副本,它当且仅当在类初次加载时会被初始化。而非静态变量是对象所拥有的,在创建对象的时候被初始化,存在多个副本,各个对象拥有的副本互不影响。

static 代码块

static 关键字还有一个比较关键的作用就是 用来形成静态代码块以优化程序性能。static 块可以置于类中的任何地方,类中可以有多个 static 块。在类初次被加载的时候,会按照 static 块的顺序来执行每个 static 块,并且只会执行一次。

public class StaticTest {

private static int a ;

private static int b;

static {

a = 1;

b = 2;

}

final

final 变量

凡是对成员变量或者本地变量(在方法中的或者代码块中的变量称为本地变量)声明为 final 的都叫作 final 变量。final 变量经常和 static 关键字一起使用,作为常量。

private final int aa = 1;

static {

a = 1;

b = 2;

}

private void init(){

aa = 2;//报错编译器会提示 不能赋值。。

}

final 方法

final 也可以声明方法。方法前面加上 final 关键字,代表这个方法不可以被子类的方法重写。如果你认为一个方法的功能已经足够完整了,子类中不需要改变的话,你可以声明此方法为 final。final 方法比非 final 方法要快,因为在编译的时候已经静态绑定了,不需要在运行时再动态绑定。

public static void main(String[]args){

StaticTest.a();

}

class StaticTest2 extends StaticTest{

public final void a(){ //这边就会编译器提示不能重写

}

}

**final 类 **

其实更上面同个道理,使用 final 来修饰的类叫作 final 类。final 类通常功能是完整的,它们不能被继承。Java 中有许多类是 final 的,譬如 String,Interger 以及其他包装类。

synchronized

synchronized 是 Java 中解决并发问题的一种最常用的方法,也是最简单的一种方法。synchronized 的作用主要有三个:

确保线程互斥的访问同步代码

保证共享变量的修改能够及时可见

有效解决重排序问题。

synchronized 方法

有效避免了类成员变量的访问冲突:

private synchronized void init(){

aa = 2;

}

synchronized 代码块

这时锁就是对象,谁拿到这个锁谁就可以运行它所控制的那段代码。当有一个明确的对象作为锁时,就可以这样写程序,但当没有明确的对象作为锁,只是想让一段代码同步时,可以创建一个特殊的 instance 变量(它得是一个对象)来充当锁。

public final void a(){

synchronized (lock){

//代码

}

}

@Override

public void run() {

}

3.请简述一下 String、StringBuffer 和 StringBuilder 三者的区别?⭐⭐⭐⭐⭐

String 为字符串常量,一旦创建不可以被修改,是线程安全的;String 类使用 final 修饰符,不可以被继承;String 的长度是不变的。适用于少量操作的字符串。

StringBuffer 为字符串变量,长度是可变的,线程安全。适用于多线程下在字符缓冲区进行大量字符串操作

StringBuilder 为字符串变量,长度是可变的,线程不安全。适用于单线程下在字符缓冲区进行大量字符串操作。

字符串操作在执行速度:StringBuilder > StringBuffer > String

4.“equals” 与 “==”、“hashCode” 的区别和使用场景?⭐⭐⭐⭐⭐

== 用于比较变量所对应的内存中所存储的数值是否相同,要比较两个基本类型的数据(注意是基本类型)或两个 引用变量是否相等,只能用==操作符。

假如一个变量指向的数据是对象类型的,例如Objet obj 1= new Object()  那么,这时候涉及了两块内存;变量 obj1 是一个内存,new Object() 是另一个内存(堆内存),此时,变量 obj1 所对应的内存中存储的数值就是对象占用的那块内存(堆内存)的首地址。对于指向对象类型的变量,如果要比较两个变量是否指向同一个对象,即要看这两个变量所对应的内存中的数值是否相等,这时候就需要用==操作符进行比较;

equals 方法是用于比较两个独立对象的内容是否相同:

String a=new String("a");

String b=new String("a");

两条new语句创建了两个对象,然后用a/b这两个变量分别指向了其中一个对象,这是两个不同的对象,它们的首地址是不同的,即a和b中存储的数值(对应对象的首地址)是不相同的,所以,表达式a==b将返回false,而这两个对象中的内容是相同的,所以,表达式a.equals(b)将返回true。我们看看equal 源码:

* Note that it is generally necessary to override the {@code hashCode}

* method whenever this method is overridden, so as to maintain the

* general contract for the {@code hashCode} method, which states

* that equal objects must have equal hash codes.

*

* @param obj the reference object with which to compare.

* @return {@code true} if this object is the same as the obj

* argument; {@code false} otherwise.

* @see #hashCode()

* @see java.util.HashMap

*/

public boolean equals(Object obj) {

return (this == obj);

}

如果一个类没有重写equals 方法 那么就是调用 object 的 equals 其实就是 ==。

hashCode:

因为重写的 equals() 里一般比较的比较全面比较复杂,这样效率就比较低,而利用hashCode()进行对比,则只要生成一个 hash 值进行比较就可以了,效率很高,那么 hashCode() 既然效率这么高为什么还要 equals() 呢?

使用场景:

因为 hashCode() 并不是完全可靠,有时候不同的对象他们生成的 hashcode 也会一样(hash冲突),所以 hashCode()只能说是大部分时候可靠,并不是绝对可靠,所以可以得出:

equals() 相等的两个对象他们的 hashCode() 肯定相等,也就是用 equals() 对比是绝对可靠的。

hashCode() 相等的两个对象他们的 equals() 不一定相等,也就是 hashCode() 不是绝对可靠的。

所有对于需要大量并且快速的对比的话如果都用 equals() 去做显然效率太低,所以解决方式是,每当需要对比的时候,首先用 hashCode() 去对比,如果 hashCode() 不一样,则表示这两个对象肯定不相等(也就是不必再用 equals() 去再对比了),如果 hashCode() 相同,此时再对比他们的 equals(),如果 equals() 也相同,则表示这两个对象是真的相同了

5.Java 中深拷贝与浅拷贝的区别?⭐⭐⭐⭐⭐

首先需要明白,浅拷贝和深拷贝都是针对一个已有对象的操作。那先来看看浅拷贝和深拷贝的概念。在 Java 中,除了基本数据类型(元类型)之外,还存在 类的实例对象 这个引用数据类型。而一般使用 『 = 』号做赋值操作的时候。对于基本数据类型,实际上是拷贝的它的值,但是对于对象而言,其实赋值的只是这个对象的引用,将原对象的引用传递过去,他们实际上还是指向的同一个对象。而浅拷贝和深拷贝就是在这个基础之上做的区分,如果在拷贝这个对象的时候,只对基本数据类型进行了拷贝,而对引用数据类型只是进行了引用的传递,而没有真实的创建一个新的对象,则认为是浅拷贝。反之,在对引用数据类型进行拷贝的时候,创建了一个新的对象,并且复制其内的成员变量,则认为是深拷贝。所以到现在,就应该了解了,所谓的浅拷贝和深拷贝,只是在拷贝对象的时候,对 类的实例对象 这种引用数据类型的不同操作而已。总结来说:1、浅拷贝:对基本数据类型进行值传递,对引用数据类型进行引用传递般的拷贝,此为浅拷贝。2、深拷贝:对基本数据类型进行值传递,对引用数据类型,创建一个新的对象,并复制其内容,此为深拷贝。

6.谈谈 Error 和 Exception 的区别?⭐⭐⭐⭐⭐

Error 是系统中的错误,不可预料的,这种异常发生后,会导致程序立即崩溃。只能通过修改代码,使错误不在出现,这种错误 无法被捕获。

Exception 则是可以预料的。在程序中如果过感觉某段代码会出现 异常,则可以使用 try catch 进行捕获 ,或者直接抛出异常。Exception 可分为 编译时异常(CheckedException) 和 运行时异常(RuntimeException)。运行时异常可以 忽略捕获操作(RuntimeException),编译时异常必须使用 try catch 进行捕获。

常见的几种RuntimeException如下:

NullPointerException - 空指针引用异常

ClassCastException - 类型强制转换异常。

IllegalArgumentException - 传递非法参数异常。

ArithmeticException - 算术运算异常

ArrayStoreException - 向数组中存放与声明类型不兼容对象异常

IndexOutOfBoundsException - 下标越界异常

NegativeArraySizeException - 创建一个大小为负数的数组错误异常

NumberFormatException - 数字格式异常

SecurityException - 安全异常

UnsupportedOperationException - 不支持的操作异常

算术异常类:ArithmeticExecption

空指针异常类:NullPointerException

类型强制转换异常:ClassCastException

数组负下标异常:NegativeArrayException

数组下标越界异常:ArrayIndexOutOfBoundsException

违背安全原则异常:SecturityException

文件已结束异常:EOFException

文件未找到异常:FileNotFoundException

字符串转换为数字异常:NumberFormatException

操作数据库异常:SQLException

输入输出异常:IOException

方法未找到异常:NoSuchMethodException

java.lang.AbstractMethodError

抽象方法错误。当应用试图调用抽象方法时抛出。

java.lang.AssertionError

断言错。用来指示一个断言失败的情况。

java.lang.ClassCircularityError

类循环依赖错误。在初始化一个类时,若检测到类之间循环依赖则抛出该异常。

java.lang.ClassFormatError

类格式错误。当Java虚拟机试图从一个文件中读取Java类,而检测到该文件的内容不符合类的有效格式时抛出。

java.lang.Error

错误。是所有错误的基类,用于标识严重的程序运行问题。这些问题通常描述一些不应被应用程序捕获的反常情况。

java.lang.ExceptionInInitializerError

初始化程序错误。当执行一个类的静态初始化程序的过程中,发生了异常时抛出。静态初始化程序是指直接包含于类中的static语句段。

java.lang.IllegalAccessError

违法访问错误。当一个应用试图访问、修改某个类的域(Field)或者调用其方法,但是又违反域或方法的可见性声明,则抛出该异常。

java.lang.IncompatibleClassChangeError

不兼容的类变化错误。当正在执行的方法所依赖的类定义发生了不兼容的改变时,抛出该异常。一般在修改了应用中的某些类的声明定义而没有对整个应用重新编译而直接运行的情况下,容易引发该错误。

java.lang.InstantiationError

实例化错误。当一个应用试图通过Java的new操作符构造一个抽象类或者接口时抛出该异常.

java.lang.InternalError

内部错误。用于指示Java虚拟机发生了内部错误。

java.lang.LinkageError

链接错误。该错误及其所有子类指示某个类依赖于另外一些类,在该类编译之后,被依赖的类改变了其类定义而没有重新编译所有的类,进而引发错误的情况。

java.lang.NoClassDefFoundError

未找到类定义错误。当Java虚拟机或者类装载器试图实例化某个类,而找不到该类的定义时抛出该错误。

java.lang.NoSuchFieldError

域不存在错误。当应用试图访问或者修改某类的某个域,而该类的定义中没有该域的定义时抛出该错误。

java.lang.NoSuchMethodError

方法不存在错误。当应用试图调用某类的某个方法,而该类的定义中没有该方法的定义时抛出该错误。

java.lang.OutOfMemoryError

内存不足错误。当可用内存不足以让Java虚拟机分配给一个对象时抛出该错误。

java.lang.StackOverflowError

堆栈溢出错误。当一个应用递归调用的层次太深而导致堆栈溢出时抛出该错误。

java.lang.ThreadDeath

线程结束。当调用Thread类的stop方法时抛出该错误,用于指示线程结束。

java.lang.UnknownError

未知错误。用于指示Java虚拟机发生了未知严重错误的情况。

java.lang.UnsatisfiedLinkError

未满足的链接错误。当Java虚拟机未找到某个类的声明为native方法的本机语言定义时抛出。

java.lang.UnsupportedClassVersionError

不支持的类版本错误。当Java虚拟机试图从读取某个类文件,但是发现该文件的主、次版本号不被当前Java虚拟机支持的时候,抛出该错误。

java.lang.VerifyError

验证错误。当验证器检测到某个类文件中存在内部不兼容或者安全问题时抛出该错误。

java.lang.VirtualMachineError

虚拟机错误。用于指示虚拟机被破坏或者继续执行操作所需的资源不足的情况。

java.lang.ArithmeticException

算术条件异常。譬如:整数除零等。

java.lang.ArrayIndexOutOfBoundsException

数组索引越界异常。当对数组的索引值为负数或大于等于数组大小时抛出。

java.lang.ArrayStoreException

数组存储异常。当向数组中存放非数组声明类型对象时抛出。

java.lang.ClassCastException

类造型异常。假设有类A和B(A不是B的父类或子类),O是A的实例,那么当强制将O构造为类B的实例时抛出该异常。该异常经常被称为强制类型转换异常。

java.lang.ClassNotFoundException

找不到类异常。当应用试图根据字符串形式的类名构造类,而在遍历CLASSPAH之后找不到对应名称的class文件时,抛出该异常。

java.lang.CloneNotSupportedException

不支持克隆异常。当没有实现Cloneable接口或者不支持克隆方法时,调用其clone()方法则抛出该异常。

java.lang.EnumConstantNotPresentException

枚举常量不存在异常。当应用试图通过名称和枚举类型访问一个枚举对象,但该枚举对象并不包含常量时,抛出该异常。

java.lang.Exception

根异常。用以描述应用程序希望捕获的情况。

java.lang.IllegalAccessException

违法的访问异常。当应用试图通过反射方式创建某个类的实例、访问该类属性、调用该类方法,而当时又无法访问类的、属性的、方法的或构造方法的定义时抛出该异常。

java.lang.IllegalMonitorStateException

违法的监控状态异常。当某个线程试图等待一个自己并不拥有的对象(O)的监控器或者通知其他线程等待该对象(O)的监控器时,抛出该异常。

java.lang.IllegalStateException

违法的状态异常。当在Java环境和应用尚未处于某个方法的合法调用状态,而调用了该方法时,抛出该异常。

java.lang.IllegalThreadStateException

违法的线程状态异常。当县城尚未处于某个方法的合法调用状态,而调用了该方法时,抛出异常。

java.lang.IndexOutOfBoundsException

索引越界异常。当访问某个序列的索引值小于0或大于等于序列大小时,抛出该异常。

java.lang.InstantiationException

实例化异常。当试图通过newInstance()方法创建某个类的实例,而该类是一个抽象类或接口时,抛出该异常。

java.lang.InterruptedException

被中止异常。当某个线程处于长时间的等待、休眠或其他暂停状态,而此时其他的线程通过Thread的interrupt方法终止该线程时抛出该异常。

java.lang.NegativeArraySizeException

数组大小为负值异常。当使用负数大小值创建数组时抛出该异常。

java.lang.NoSuchFieldException

属性不存在异常。当访问某个类的不存在的属性时抛出该异常。

java.lang.NoSuchMethodException

方法不存在异常。当访问某个类的不存在的方法时抛出该异常。

java.lang.NullPointerException

空指针异常。当应用试图在要求使用对象的地方使用了null时,抛出该异常。譬如:调用null对象的实例方法、访问null对象的属性、计算null对象的长度、使用throw语句抛出null等等。

java.lang.NumberFormatException

数字格式异常。当试图将一个String转换为指定的数字类型,而该字符串确不满足数字类型要求的格式时,抛出该异常。

java.lang.RuntimeException

运行时异常。是所有Java虚拟机正常操作期间可以被抛出的异常的父类。

java.lang.SecurityException

安全异常。由安全管理器抛出,用于指示违反安全情况的异常。

java.lang.StringIndexOutOfBoundsException

字符串索引越界异常。当使用索引值访问某个字符串中的字符,而该索引值小于0或大于等于序列大小时,抛出该异常。

java.lang.TypeNotPresentException

类型不存在异常。当应用试图以某个类型名称的字符串表达方式访问该类型,但是根据给定的名称又找不到该类型是抛出该异常。该异常与ClassNotFoundException的区别在于该异常是unchecked(不被检查)异常,而ClassNotFoundException是checked(被检查)异常。

java.lang.UnsupportedOperationException

不支持的方法异常。指明请求的方法不被支持情况的异常。

7.什么是反射机制?反射机制的应用场景有哪些?⭐⭐⭐⭐⭐

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

应用场景:

逆向代码,例如反编译

与注解相结合的框架,如 Retrofit

单纯的反射机制应用框架,例如 EventBus(事件总线)

动态生成类框架 例如Gson

需要使用的类

java.lang.Class - 类,某个具体的类或接口

java.lang.reflect.Constructor - 反射构造方法

java.lang.reflect.Field - 反射属性

java.lang.reflect.Method - 反射方法

java.lang.reflect.Modifier - 访问修饰符的信息

获取 Class 对象的三种方法

Class.forName 方式,会让ClassLoader装载类,并进行类的初始化

.class 方式,ClassLoader 装载入内存,不对类进行类的初始化操作

3、getClass 方式,返回类对象运行时真正所指的对象,所属类型的Class对象

获取构造函数

getConstructor(Class[] params) 根据构造函数的参数,返回一个具体的具有public属性的构造函数

getConstructors() 返回所有具有public属性的构造函数数组

getDeclaredConstructor(Class[] params) 根据构造函数的参数,返回一个具体的构造函数(不分public和非public属性)

getDeclaredConstructors() 返回该类中所有的构造函数数组(不分public和非public属性)

获取反射对象

注:

newInstance() 方法返回的是一个泛型T,我们要强转成相应的反射类。

反射创建对象,可以使用Class.newInstance() 和 Constructor.newInstance() 两种方式,而前者必须要求反射类中存在一个无参的构造方法,并且有访问权限;后者适应各种类型的构造方法,无论是否有参数都可以调用,这是需要 setAccessible() 控制访问验证即可。一般建议是使用后者。

获取反射类的方法(四个方法)

反射类方法

public void testPublicVoidMethod() { }

public String testPublicStringMethod() {

return "";

}

private void testPrivateVoidMethod() { }

getMethod(String name, Class[] params) 根据方法名和参数,返回一个具体的具有public属性的方法

getMethods() 返回所有具有public属性的方法数组

getDeclaredMethod(String name, Class[] params) 根据方法名和参数,返回一个具体的方法(不分public和非public属性)

getDeclaredMethods() 返回该类中的所有的方法数组(不分public和非public属性)

获取反射类的属性(四个方法)

反射类属性

public String mPublicStr;

public int mPublicInt;

private String mPrivateStr;

protected String mProtectedStr;

getField(String name) 根据变量名,返回一个具体的具有public属性的成员变量

getFields() 返回具有public属性的成员变量的数组

getDeclaredField(String name) 根据变量名,返回一个成员变量(不分public和非public属性)

getDelcaredField() 返回所有成员变量组成的数组(不分public和非public属性)

获取类、属性、方法的修饰符

通过 int getModifiers() 方法获得修饰符,方法返回是是一个 int 型数值,每个修饰符都对应一个int型。

8.谈谈如何重写 equals() 方法?为什么还要重写 hashCode()?⭐⭐⭐⭐⭐

equals:比较两个对象的地址是否相等

hashCode :一般用在集合里面,比如在hashMap 里面,存入元素的时候 会首先算出 哈希值,然后根据哈希值来确定元素的位置,对于在任何一个对象上调用hashCode 时,返回的 哈希值一定相等的。

为什么 需要重写 hashCode

给集合中存元素时,首先会获取 hashCode 的值,如果没有重写 hashCode ,他会直接将元素的地址转换成一个整数返回。如果我们创建了两个对象,两个对象的所有属性值都一样,在存入HashSet 时,第一个元素会直接存进去,第二个获取的 哈希值 和 第一个不同,所以第二个元素也会存进去,因为 jdk 默认不同的 hashCode 值,equals 一定返回false。所以 这两个值都会被存进去。但是这两个对象的属性值都是一样的,所以这样会造成数据的不唯一性。所以一般重写了 equals 后必须要重写 hashCode。

内存泄露的问题

想象一下,一个类 创建了两个对象,属性值不同,同时重写了 equals 和 hashCode 。然后将他们都存进了 HashSet 中。然后修改第二个 元素的值。最后将第二个元素充 set 集合中删除。 删除之后 则迭代进行打印,会发现第二个元素没有被删除掉,为什么呢? 因为在删除 某个元素时,会获取 hashCode 值,但是由于修改了属性值,导致获取的 哈希值和 存入时获取的不同,所以查找为空,jdk 认为该对象不在集合中,所以不会进行删除操作,但是用户任务 对象已经被删除,导致该对象长时间不能被释放,造成内存泄露。解决的办法是不要在执行的期间 修改与 HashCode 值相关的对象信息,如果非要修改,则必须先从集合中删除,更新数据后在添加到集合。

总结:

1.hashCode是为了提高在散列结构存储中查找的效率,在线性表中没有作用

2.equals和hashCode需要同时覆盖。

3.若两个对象equals返回true,则hashCode一定返回相同的int数。

4.若两个对象equals返回false,则hashCode不一定返回不同的int数,但为不相等的对象生成不同hashCode值可以提高 哈希表的性能

5.若两个对象hashCode返回相同int数,则equals不一定返回true。

6.若两个对象hashCode返回不同int数,则equals一定返回false。

7.同一对象在执行期间若已经存储在集合中,则不能修改影响hashCode值的相关信息,否则会导致内存泄露问题。

9.Java 中 IO 流分为几种?它们之间有什么区别?⭐⭐⭐⭐⭐

Java中的流分为两种,一种是字节流,另一种是字符流,分别由四个抽象类来表示(每种流包括输入和输出两种所以一共四个):InputStream,OutputStream,Reader,Writer。Java中其他多种多样变化的流均是由它们派生出来的.

字符流和字节流是根据处理数据的不同来区分的。字节流按照8位传输,字节流是最基本的,所有文件的储存是都是字节(byte)的储存,在磁盘上保留的并不是文件的字符而是先把字符编码成字节,再储存这些字节到磁盘。

1.字节流可用于任何类型的对象,包括二进制对象,而字符流只能处理字符或者字符串;

2.节流提供了处理任何类型的IO操作的功能,但它不能直接处理Unicode字符,而字符流就可以。

读文本的时候用字符流,例如txt文件。读非文本文件的时候用字节流,例如mp3。理论上任何文件都能够用字节流读取,但当读取的是文本数据时,为了能还原成文本你必须再经过一个转换的工序,相对来说字符流就省了这个麻烦,可以有方法直接读取。

字符流处理的单元为2个字节的Unicode字符,分别操作字符、字符数组或字符串,而字节流处理单元为1个字节, 操作字节和字节数组。所以字符流是由Java虚拟机将字节转化为2个字节的Unicode字符为单位的字符而成的,所以它对多国语言支持性比较好!

BIO、NIO、AIO 有什么区别

BIO:Block IO 同步阻塞式 IO,就是我们平常使用的传统 IO,它的特点是模式简单使用方便,并发处理能力低。

NIO:Non IO 同步非阻塞 IO,是传统 IO 的升级,客户端和服务器端通过 Channel(通道)通讯,实现了多路复用。

AIO:Asynchronous IO 是 NIO 的升级,也叫 NIO2,实现了异步非堵塞 IO ,异步 IO 的操作基于事件和回调机制。

BIO是一个连接一个线程。

NIO是一个请求一个线程。

AIO是一个有效请求一个线程。

BIO:同步并阻塞,服务器实现模式为一个连接一个线程,即客户端有连接请求时服务器端就需要启动一个线程进行处理,如果这个连接不做任何事情会造成不必要的线程开销,当然可以通过线程池机制改善。

NIO:同步非阻塞,服务器实现模式为一个请求一个线程,即客户端发送的连接请求都会注册到多路复用器上,多路复用器轮询到连接有I/O请求时才启动一个线程进行处理。

AIO:异步非阻塞,服务器实现模式为一个有效请求一个线程,客户端的I/O请求都是由OS先完成了再通知服务器应用去启动线程进行处理。

适用场景分析

BIO方式适用于连接数目比较小且固定的架构,这种方式对服务器资源要求比较高,并发局限于应用中,JDK1.4以前的唯一选择,但程序直观简单易理解。

NIO方式适用于连接数目多且连接比较短(轻操作)的架构,比如聊天服务器,并发局限于应用中,编程比较复杂,JDK1.4开始支持。

AIO方式使用于连接数目多且连接比较长(重操作)的架构,比如相册服务器,充分调用OS参与并发操作,编程比较复杂,JDK7开始支持。

10.谈谈你对 Java 泛型中类型擦除的理解,并说说其局限性?⭐⭐⭐⭐⭐

1,类型擦除,发生在编译过程。指的是,所有的泛型信息都会被擦除(默认继承Object)

2,已解决的局限:

1)ArrayList(String> 不能够添加Integer类型的数据;通过 编译器先检查代码中的泛型的类型 解决

2)编辑器从ArrayList(String>中泛型中获取值,都有Object 强转 String

3) 父类定义泛型,子类实现;实现的 重载,实际上,编译器会变成重写。通过 编译器的桥方法解决

3,未解决的局限:

1)泛型类型变量,不能是,基本数据类型

2)运行时,无法检测类型;例如:object instanceof ArrayList(String> 这个逻辑无法实现

3)泛型类型,无法在静态方法和静态变量中使用;如下:

public class TestClass {

public static T getSome() {

return null;

}

}

这一段逻辑,添加 static字段,编译器报错

11.String 为什么要设计成不可变的?⭐⭐⭐⭐⭐

1,字符串常量池的需要

当创建一个 String 对象时,如果此字符串已经存在于常量池中,则不会创建一个新的对象,而是引用已经存在的对象

如果允许改变,那么将导致各种逻辑错误,比如改变一个对象将会影响另一个独立对象,严格来说,这种常量池的思想是一种优化手段

2,允许String对象缓存 HashCode

java 中 String 对象的哈希码会被频繁的使用,比如在 hashMap中。字符串的不变形保证了hash码的唯一性,因此可以放放心的进行缓存。这也是一种优化手段,意味着不必没说都计算新的哈希码。在 String 类中有 private int hash 来缓存hashcode

3,安全性

String 被许多的类来当做参数,如 网络url,文件路径path 等等,如果String 不是固定的,将会引起各种安全隐患

12.说说你对 Java 注解的理解?⭐⭐⭐⭐⭐

三种注解

source

class

runtime

分别在源码,编译时,运行时存活

自定义的source注解 可以用来对 一些方法 或者参数进行约束,比如说指定线程 指定参数类型

class 注解 是配合apt 编写注解处理器, 对注解的类或者变量进行解析 生成.class文件 辅助工作 比方说 arouter,在注解处理器中生成代码 帮你做 路径和 activity的路由表,butterknife的注解帮你做findviewbyid的工作

runtime注解 则是在runtime时还能存在的 通常配合 反射机制,把注解标注的对象 拿到进行操作,比方说 retrofit,通过 反射机制 拿到注解的 接口和接口中的方法,在通过动态代理 生成接口的实现类

13.谈一谈 Java 成员变量、局部变量和静态变量的创建和回收时机?⭐⭐⭐⭐⭐

成员变量:生命周期伴随类对象,类对象回收时回收 存在堆里

静态变量:不回收 在方法区 随着类的加载而加载,随着类的消失而消失,由于类需要非常长时间的不使用,不利用,不关联,才有可能会被回收机制回收,

所以静态成员变量的生命周期特别长,除非是共享数据,否则不建议使用静态;

局部变量:方法调用时创建 方法结束时被标记为可回收 存在栈里

14.谈谈 Java 中 List、Set 以及 Map 的区别?⭐⭐⭐⭐⭐

List中存储的数据是有顺序的,并且值允许重复;Map中存储的数据是无序的,它的键是不允许重复的,但是值是允许重复的;Set中存储的数据是无顺序的,并且不允许重复,但元素在集合中的位置是由元素的hashcode决定,即位置是固定的(Set集合是根据hashcode来进行数据存储的,所以位置是固定的,但是这个位置不是用户可以控制的,所以对于用户来说set中的元素还是无序的)

15.谈谈 ArrayList 和 LinkedList 的区别?⭐⭐⭐⭐⭐

1.ArrayList是基于数组的数据结构,分配的是一段连续的内存空间。

新增数据的时候效率低,因为新增一个元素的时候都要考虑数组的容量,即扩容判断,而后进行新增元素;

修改数据同样根据index索引查找修改;

删除数据的时候效率低,因为是连续的内存空间,除删除最后一个元素外,删除任一元素都会使数组中的元素进行移动;

查找数据可根据index索引快速查找;

2.LinkedList是基于链表的数据结构

对比以上:

优点: 不需要考虑扩容的问题和连续的内存空间问题,在新增和删除的效率更好

缺点: 缺少了索引,降低了查找元素的效率,对应也降低了修改元素的效率

16.请说一下 HashMap 与 HashTable 的区别?⭐⭐⭐⭐⭐

HashMap和Hashtable都实现了Map接口,但决定用哪一个之前先要弄清楚它们之间的分别。主要的区别有:线程安全性,同步(synchronization),以及速度。

继承的父类不同

HashMap和Hashtable不仅作者不同,而且连父类也是不一样的。HashMap是继承自AbstractMap类,而HashTable是继承自Dictionary类。不过它们都实现了同时实现了map、Cloneable(可复制)、Serializable(可序列化)这三个接口

特点及优缺点比较:

HashMap几乎可以等价于Hashtable,除了HashMap是非synchronized的,并可以接受null(HashMap可以接受为null的键值(key)和值(value),而Hashtable则不行)。

HashMap是非synchronized,而Hashtable是synchronized,这意味着Hashtable是线程安全的,多个线程可以共享一个Hashtable;而如果没有正确的同步的话,多个线程是不能共享HashMap的。Java 5提供了ConcurrentHashMap,它是HashTable的替代,比HashTable的扩展性更好。

另一个区别是HashMap的迭代器(Iterator)是fail-fast迭代器,而Hashtable的enumerator迭代器不是fail-fast的。所以当有其它线程改变了HashMap的结构(增加或者移除元素),将会抛出ConcurrentModificationException,但迭代器本身的remove()方法移除元素则不会抛出ConcurrentModificationException异常。但这并不是一个一定发生的行为,要看JVM。这条同样也是Enumeration和Iterator的区别。

由于Hashtable是线程安全的也是synchronized,所以在单线程环境下它比HashMap要慢。如果你不需要同步,只需要单一线程,那么使用HashMap性能要好过Hashtable。

HashMap不能保证随着时间的推移Map中的元素次序是不变的。

内部实现与操作问题

HashTable

底层数组+链表实现,无论key还是value都不能为null,线程安全,实现线程安全的方式是在修改数据时锁住整个HashTable,效率低,ConcurrentHashMap做了相关优化

初始size为11,扩容:newsize = olesize*2+1

计算index的方法:index = (hash & 0x7FFFFFFF) % tab.length

HashMap

底层数组+链表实现,可以存储null键和null值,线程不安全

初始size为16,扩容:newsize = oldsize*2,size一定为2的n次幂

扩容针对整个Map,每次扩容时,原来数组中的元素依次重新计算存放位置,并重新插入

插入元素后才判断该不该扩容,有可能无效扩容(插入后如果扩容,如果没有再次插入,就会产生无效扩容)

当Map中元素总数超过Entry数组的75%,触发扩容操作,为了减少链表长度,元素分配更均匀

计算index方法:index = hash & (tab.length – 1)

HashMap的初始值还要考虑加载因子:

哈希冲突:若干Key的哈希值按数组大小取模后,如果落在同一个数组下标上,将组成一条Entry链,对Key的查找需要遍历Entry链上的每个元素执行equals()比较。

加载因子:为了降低哈希冲突的概率,默认当HashMap中的键值对达到数组大小的75%时,即会触发扩容。因此,如果预估容量是100,即需要设定100/0.75=134的数组大小。

空间换时间:如果希望加快Key查找的时间,还可以进一步降低加载因子,加大初始大小,以降低哈希冲突的概率。

HashMap和HashTable都是用hash算法来决定其元素的存储,因此HashMap和Hashtable的hash表包含如下属性:

容量(capacity):hash表中桶的数量

初始化容量(initial capacity࿰

更多推荐

Android 200道面试题及答案

本文发布于:2024-03-12 04:04:03,感谢您对本站的认可!
本文链接:https://www.elefans.com/category/jswz/34/1730653.html
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,我们将在24小时内删除。
本文标签:面试题   答案   Android

发布评论

评论列表 (有 0 条评论)
草根站长

>www.elefans.com

编程频道|电子爱好者 - 技术资讯及电子产品介绍!