整理21道 Java挑战面试题
1. 为什么HashMap中String、Integer这样的包装类适合作为Key
1、String和Integer等这些类都被final修饰,具有不变性;也保证了key的不变性,并且内部重写了equals和hashCode方法,不容易出现hash计算错误
2、String和Integer保证了hash值得不可变性和准确性,有效减少了hash碰撞
3、String和Integer一定重写了equals和hashCode方法
2. ConcurrentHashMap和Hashtable的区别?
HashTable是阻塞模式的,总是能获取最新的更新,好处是当线程A大量更新数据,期间线程B调用get,线程B就会被阻塞,直到线程A更新完毕,坏处是所有调用都要排除,效率比较低
ConcurrentHashMap是非阻塞模式,在更新时会局部锁住某部分数据,但不会把整个表都锁住,同步读取操作则是完全非阻塞的,好处是在保证合理的同步前提下,效率高,坏处就是读取时不能保证反映最近的更新,线程A更新了Map中的数据,期间线程B只能读取到线程A已经更新完成的数据
3. Array 和 ArrayList 有什么区别?什么时候该用 Array 而不是 ArrayList 呢?
Array可以容纳基本类型和对象,而ArrayList只能容纳对象
Array指定大小后不可变,而ArrayList大小是可变的
Array没有提供ArrayList那么多功能,比如addAll,removeAll和iterator等
4. HashSet是如何保证数据不可重复的?
1、底层由HashMap实现
2、值存放于HashMap的key上
3、HashMap的value统一为PRESENT(存在的,可以为null)
5. ArrayList集合加入1万条数据集合内部会如何处理,应该怎么提高效率?
因为ArrayList的底层是数组实现的,并且数据的默认值是10,如如果插入1万条数据,要不断的扩容,浪费时间,所以我们调用ArrayList的指定容量的构造器方法ArrayList(int size)就可以实现不扩容,提高了性能。
6. 什么情况下需要序列化?
所谓的对象流就是将对象内容进行流化,可以对流化后的对象进行读写操作,也可以将流化后的对象传输于网络之间,一般程序在运行时产生对象,这些对象随着程序的停止运行而消失,但如果我们想把某些对象保存下来,在程序终止运行后,这些对象仍然存在,可以在程序再次运行时读取到这些值,这种情况下就要用到对象的序列化
7. Thread 类中的start() 和 run() 方法有什么区别?
start()方法来启动线程,真正实现了多线程运行,这时无需等待run方法体代码执行完毕而直接继续执行下面的代码
run()方法当作普通方法的方式调用,程序还是要顺序执行,还是要等待run方法体执行完毕后才可继续执行下面的代码
8. HashMap的put方法的具体流程?
HashMap在put方法中,它使用hashCode()和equals()方法,当我们通过传递key-value对调用put方法时,HashMap计算Key的 HashCode和哈希算法来找出存储key-value对的索引。如果索引为空,则直接插入到对应的数组中,否则判断是否为红黑树,如果是则红黑树插入,否则遍历链表,若长度超过8,则将链表转为红黑树,转成功之后,再插入键值。
9. 自定义异常类时,可以继承的类是?
自定义异常可以自己控制在何处报异常,可继承的有编译时异常Exception和运行时异常runtimeException
编译时异常:必须立即处理的异常,如果不处理,程序就不能通过编译
运行时异常:java编译器不会检查它,当程序中可能出现这类异常,即使没有用try-catch语句捕获它,也没有用Throws抛出它,也会编译通过,但运行时会报错
10. 请将ATM提款机终端系统用面向对象的思想设计出来。
成员属性:操作按钮容器,余额,用户名,卡号,输入密码,单次取钱上线,插卡状态,用户是否有效
操作
- 欢迎页面
- 选择菜单
- 是否插卡
- 输入密码
- 存钱方法
- 余额加存款
- 取钱方法
- 取钱是否高于上线
- 余额减存款
- 查看余额方法
- 退出
- 生成订单号
- 操作日志信息持久化存储
- 是否打印发票方法
11. Person p = new Person()在内存中做了哪些事情?
1、加载Person.class文件到方法区,同时加载Person类中的static属性
2、在main方法所在的栈区分配引用 p
3、在java堆中开辟空间存放Person类,但是不进行初始化操作
4、默认初始化数据
5、将引用p指向java新开辟的Person类地址
12. 以下代码的执行效果是,为什么?
public class Test {
public static void main(String[] args) {
Integer f1 = 100, f2 = 100, f3 = 150, f4 = 150;
System.out.println(f1 == f2); //
System.out.println(f3 == f4); //
}
}
Integer封装类中 -128-127范围 是缓存池(常量池),数值在这范围内的hash值是固定的,而超过这个范围,Integer赋值则需要重新指向新的内存地址,== 在比较基本数据类型时比较的是数值,而比较引用类型时比较的是地址值
13. 列出几种常见的遍历输出方式
for循环
foreach循环
Iterator迭代遍历 while(hasNext){}
14. 手写一个冒泡排序
public static void main(String[] args) {
int a[] = {0,3,2,4,5,6,7,9,10,1,8};
for (int i = 0; i < a.length; i++) {
for (int j = i+1; j < a.length; j++) {
if(a[i]>a[j]) {
int temp = a[i];
a[i] = a[j];
a[j] = temp;
}
}
}
for (int i : a) {
System.out.print(i);
}
}
15. 说一些你知道的算法及使用场景
快速算法 实际项目中有很多地方是有给序列号的,有时需要对这些序列号进行排序。
哈希算法 用于计算hashCode值,HashMap底层就是用到了哈希算法
16. 说一些你知道的设计模式及使用场景。
Spring ioc就是用到了工厂模式和单例模式
17. JVM内存结构了解吗?
流程:生成.class可执行>>>类装载子系统>>>运行时数据区(内存模型)>>>字节码执行引擎
内存模型:
-
栈:存放局部变量
-
堆:开辟内存空间,创建对象
-
方法区:常量 + 静态变量 + 类信息
-
本地方法栈:native修饰,底层C语言实现的。本地方法栈运行的区域(例如:加减操作)
-
程序计数器:多线程挂起,一个线程转为另外一个线程,判断从何处开始
18. 一个加锁的方法去调用另一个加锁的方法会怎样?
加了锁的非静态方法没有受到任何影响,因为它所竞争的锁并非是class对象锁,而是实例化对象锁,受到影响的有synchronized修饰的静态方法,还有便是加了Class对象锁的方法,本质上便是它们都在竞争当前类的Class对象锁。
19. 你遇到过 OutOfMemoryError 错误嘛?你是怎么搞定的?
内存溢出异常,扩大新生代和老年代的内存分配,在允许的情况下
20. 如果我想要让自己的Object作为Key应该怎么办呢?
重写hashCode()和equals()方法
1、重写hashCode()是因为需要计算存储的存储位置
2、重写equals, 目的是为了保证key在哈希表中的唯一性
21.Spring框架你是如何使用的?
-
在项目中引入Spring 框架可以带来以下好处:
- 降低组件之间的耦合度,实现软件各层之间的解耦,可以使用容器提供众多服务,如事务管理服务,服务消费等等,当我们使用容器管理事务时,就不用再手动控制事务,也不需处理复杂的事务传播,容器提供单例模式支持,不用再自己编写实现代码,容器AOP技术,利用它很容易实现,权限拦截、运行期监控等功能
关注博客爵士,更多精彩等你来战!!(大数据,python,java,操作系统)
http://www.yazz.top/