Java 内存、HashMap、Hashtable面试题

本文深入探讨Android内存泄漏的原因及解决方案,包括静态变量、内部类、Handler、监听器、资源对象、属性动画等问题,同时对比了HashMap和Hashtable的特性与区别。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

01

Android 内存泄漏的原因以及解决方案 

 

1、内存泄漏指对象不再使用,本该被回收,却因为有其他正在使用的对象持有该对象的引用,而无法被JVM回收

 

2、内存泄漏的影响:

  1. 应用可用内存减少,增加堆内存压力

  2. 频繁触发GC,会降低了应用的性能

  3. 到一定程序会导致内存溢出错误

 

3、Android开发中常见内存泄漏及解决办法

  1. 静态变量生命周期与应用的生命周期一样,如果静态变量持有某个Activity的上下文,则对应Activity无法释放,导致内存泄漏(单例模式) 解决办法:使用Application的上下文

  2. 匿名内部类与非静态内部类因为都会持有外部类引用,当执行异步操作易导致内存泄漏 解决办法:将非静态内部类转为静态内部类+WeakReferenct的方式

  3. Handler消息队列存在延时消息导致内存泄漏 在onDestroy方法中调用Handler相应的方法移除回调和删除消息

  4. 各种注册的监听器忘记移除导致内存泄漏 解决办法:在onDestroy方法中取消注册

  5. 资源对象未关闭导致内存泄漏,如(IO,数据库,Bitmap等) 解决办法:及时关闭资源

  6. 属性动画未取消导致内存泄漏(如无限轮播图效果) 解决办法:onDestroy方法中取消动画

  7. 其他解决办法:使用AAC框架

 

4、内存泄漏排查工具: AS Monitor,MAT,LeakCanary

 

5、扩展: Java内存管理,GC

 

 

 

02

HashMap和Hashtable的区别 

 

HashMap是map接口的子类,是将键映射到值的对象,其中键和值都是对象,并且不能包含重复键,但可以包含重复值。HashMap允许null key和null value,而hashtable不允许。

 

HashMap是Hashtable的轻量级实现(非线程安全的实现),他们都完成了Map接口,由于非线程安全,效率上可能高于Hashtable。

 

HashMap把Hashtable的contains方法去掉了,改成containsvalue和containsKey。

 

Hashtable继承自Dictionary类,而HashMap是Java1.2引进的Map interface的一个实现。

 

Hashtable的方法是Synchronize的,而HashMap不是,在多个线程访问Hashtable时,不需要自己为它的方法实现同步,而HashMap 就必须为之提供外同步。但是如果使用Java 5或以上的话,可以用ConcurrentHashMap代替Hashtable。

 

Hashtable和HashMap采用的hash/rehash算法都大概一样,所以性能不会有很大的差。

 

 

 

03

ScrollView嵌套ListView的解决方案及其原理 

 

自定义ListView 解决:重写其中的onMeasure()方法

 

原因: ScrollView默认把Childview设置为UNSPEFEIED模式,而该模式下的ListView给自己的测量的高度就是第一个item的高度.原理: 

 

int expandSpec = MeasureSpec.makeMeasureSpec(Integer.MAX_VALUE >> 2, MeasureSpec.AT_MOST);

 

这个方法的作用是根据大小和模式来生成一个int值,这个int值封装了模式和大小信息. 

 

首先MeasureSpec类是View的一个静态内部类,MeasureSpec类封装了从父布局到子布局传递的布局需求. 每个MeasureSpec对象代表了宽度和高度的要求.

 

MeasureSpec用int类型表示,前2位代表模式,后30位代表大小. 第一个参数

 

Integer.MAX_VALUE >> 2:Integer.MAX_VALUE

 

获取到int的最大值,但是表示大小的值size是int数值的底30位,所以把这个值右移两位,留出高两位表示布局模式. 此时这个值仍旧是一个30位所能表示的最大数,用该数作为控件的size,应该足够满足控件大小的需求. 第二个参数MeasureSpec.AT_MOST:表示这个控件适配父控件的最大空间.

 

(以下三种仅供参考,不推荐使用) 2.手动设置ListView高度 3.使用单个ListView取代ScrollView中所有内容 4.使用LinearLayout取代ListView

 

参考资料:

https://juejin.im/entry/5979ab4d5188253e3271c953 

https://juejin.im/post/5a322cbf6fb9a045204c3da1

 

 

04

String,StringBuilder,StringBuffer的区别 

 

可变不可变 String:字符串常量,在修改时不会改变自身;若修改,等于重新生成新的字符串对象。 StringBuffer:在修改时会改变对象自身,每次操作都是对 StringBuffer 对象本身进行修改,不是生成新的对 象;使用场景:对字符串经常改变情况下,主要方法:append(),insert()等。

 

线程是否安全 String:对象定义后不可变,线程安全。 StringBuffer:是线程安全的(对调用方法加入同步锁),执行效率较慢,适用于多线程下操作字符串缓冲区 大量数据。 StringBuilder:是线程不安全的,适用于单线程下操作字符串缓冲区大量数据。

 

共同点 StringBuilder 与 StringBuffer 有公共父类AbstractStringBuilder(抽象类)。StringBuilder、StringBuffer的方法都会调用AbstractStringBuilder 中的公共方法,如 super.append(...)。 只是 StringBuffer 会在方法上加 synchronized 关键字,进行同步。最后,如果程序不是多线程的,那么使用 StringBuilder 效率高于 StringBuffer。

 

 

 

05

谈谈你的职场规划 

 

主要看的是面试者对自己的定位,这样便于让企业去识别这个人的培养方向。问完这个问题会有第二个问题你有没有想过如何达成你的目标,这个通常看面试者的规划能力,说的越详细越好。

 

有目标并有清晰规划的人,通常这类人自驱力比较强的人。一般没有明确目标和清晰规划的人我是不会招的。

 

还有企业文化,通常我问面试者是否认同我们的企业文化,不认同技术再好也不行。

 

06

结束语 

 

 原文

### 线程安全性 HashMap 是线程不安全的,这意味着在多线程环境下,如果多个线程同时修改了 HashMap 的结构(例如添加或删除元素),则可能会导致数据不一致的问题。为了在多线程环境中使用 HashMap,需要外部同步机制来保证线程安全。相比之下,Hashtable 是线程安全的,它的方法都是 synchronized 的,因此在多线程访问时不需要额外的同步措施[^2]。 ### 键值允许为 null 的情况 HashMap 允许键和值都为 null,其中键只能有一个 null 值。而在 Hashtable 中,键和值都不允许为 null,尝试插入 null 值会导致抛出 NullPointerException 异常。 ### 迭代器差异 HashMap 使用的是 Iterator,这是一种 fail-fast 迭代器,当迭代过程中集合被修改,除了通过迭代器自身的 remove 方法外,会抛出 ConcurrentModificationException 异常。而 Hashtable 使用的是 Enumeration 迭代器,它不是 fail-fast 的,因此在迭代过程中集合被修改不会抛出异常。 ### Hash 计算方式 HashMap 在计算 hash 值时进行了额外的处理,以减少哈希冲突的概率。而 Hashtable 直接使用了 key 的 hashCode 方法来计算 hash 值。 ### 默认初始大小与扩容方式 HashMap 默认初始大小为 16,并且容量必须是 2 的整数次幂,扩容时将容量变为原来的 2 倍。而 Hashtable 默认初始大小为 11,扩容时将容量变为原来的 2 倍加 1[^2]。 ### 是否包含 contains 方法 HashMap 没有 contains 方法,而 Hashtable 包含了类似于 containsValue 的 contains 方法。 ### 继承关系 HashMap 继承自 AbstractMap 类,而 Hashtable 继承自 Dictionary 类[^2]。 ### 数据结构 HashMap 采用数组、链表和红黑树的数据结构,而非线程安全且无序,查找效率较高,初始化默认容量为 $2^4$,每次扩容为原来的 2 倍。而 Hashtable 采用数组和链表的数据结构,线程安全,键值均不允许为 null,默认初始大小为 11,每次扩充为原来的 $2n+1$[^3]。 ### 同步机制 最大的不同在于 Hashtable 的方法是 synchronized 的,而 HashMap 不是,在多个线程访问 Hashtable 时,不需要自己为它的方法实现同步,而 HashMap 就必须提供外同步 (Collections.synchronizedMap)[^4]。 ```java // 示例代码:HashMap 需要外部同步 Map<String, String> map = Collections.synchronizedMap(new HashMap<>()); ``` ### 相关问题 1. 如何在多线程环境中安全地使用 HashMap? 2. HashMapHashtable 在性能上有何差异? 3. Java 中如何实现一个线程安全的 HashMap
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值