面试 _java_SE
SE 基础
阐述你对 JVM、JDK 和 JRE 的理解?
答案 JVM 是 java 虚拟机,提供了不依赖底层和操作系统的接口,跨平台基础;
JRE 是 java 运行环境,支撑 Java 程序的运行,包含基本类库,面向使用 java 程序的用户;
JDK 是 java 开发程序包,支持 Java 程序的开发,包含 JRE,面向 java 开发人员;
== 和 equals 的区别是什么?
答案
- ==
如果是基本类型,判断是否相等
如果是对象,判断地址是否相等
- equals
只能判断对象内容是否相等。
对于自定义类,如果没有重写 equals 方法,则比较的是地址。
Math.round(-1.5) 等于多少?
答案 四舍五入的本质是:加 0.5 然后取整
重写和重载的区别
答案 重写:子类修改父类的方法;
重载: 同一个类里的不同参数;
为什么函数不能根据返回类型来区分重载
答案 函数的返回值只是作为函数运行之后的一个 "状态",不能作为标识。
抽象类 (abstract class) 和接口 (interface) 有什么异同
答案 构造函数:接口不能有
方法:接口必须全部是抽象类
属性(成员变量):接口中都是常量
权限修饰符:接口全是 public,抽象不限制
静态变量和实例变量的区别
答案 静态变量由 static 修饰。属于类,不属于任何一个实例。
而实例变量就是我们每次 new 后在内存中开辟的新的对象。
Java 中实现多态的机制是什么
答案 父类的引用变量可以指向子类的实例对象;
switch 是否能作用在 byte 上,是否能作用在 long 上,是否能作用在 String {#toc_h4_9}
答案 可以,
java 任何版本都不能作用在 Long 上;
jdk7 开始,可以作用在 String 上。
String 、StringBuilder 、StringBuffer 的区别
答案 String 是只读字符串
StringBuffer/StringBuilder 是可修改字符串。
StringBuilder 它的所有方法都没有被 synchronized 修饰,因此它的效率理论上也比 StringBuffer 要高
如何取得年 月日、小时分钟秒
答案
Calendar cal = Calendar.getInstance();
System.out.println(cal.get(Calendar.YEAR));
System.out.println(cal.get(Calendar.MONTH)); // 0 - 11
System.out.println(cal.get(Calendar.DATE));
System.out.println(cal.get(Calendar.HOUR_OF_DAY));
System.out.println(cal.get(Calendar.MINUTE));
System.out.println(cal.get(Calendar.SECOND));
jdk8 日期处理函数
答案 TODO
string 常量池
答案
Integer 常量池
答案
serialVersionUID 的作用
答案 serialVersionUID 指定了 class 的版本。
如果你不定义,会自动生成,每次修改类属性都会变。
反编译时,如果 UID 不一样则反序列化失败。
当我们修改 class 但仍然想反序列化之前文件,则必须要定义这个 UID
如何实现对象克隆
答案 方法一: 继承 Cloneable 接口,并重写 clone() 方法
方法二: 实现 Serializable 接口,通过序列化和反序列化,实现深度克隆。
public class MyUtil {
/** * 通过序列化实现深度克隆 * 先序列化对象到内存 * 再反序列化对象并返回 * * @param obj * @param <T> * @return * @throws Exception */
public static <T extends Serializable> T clone(T obj) throws Exception {
/** * 先序列化对象到内存 */
ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
ObjectOutputStream objectOutputStream = new ObjectOutputStream(outputStream);
objectOutputStream.writeObject(obj);
/** * 反序列对象并返回 */
ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream(outputStream.toByteArray());
ObjectInputStream objectInputStream = new ObjectInputStream(byteArrayInputStream);
return (T) objectInputStream.readObject();
}
}
异常处理
异常分类
答案 编译时异常 CheckedException:(try...catch 、throws)
运行时异常
error 和 exception 的区别
答案 Error 类一般是指与虚拟机相关的问题,如系统崩溃,虚拟机错误,内存溢出等。
Exception 类表示程序可以处理的异常,分为编译时异常和运行时异常。
java 异常处理机制
答案 详细信息
请写出你最常见的 5 个 RuntimeException
答案 运行时异常,没有使用 try catch,JVM 进行处理的异常。
未初始化然后调用函数,NullPointException
下标越界:ArrayIndexOutOfBoundsException StringIndexOutOfBoundsException
强转失败: ClassCastException NumberFormatException
除数为 0: ArithmeticException
throw 和 throws 的区别
答案 throw 方法体内,执行就一定抛出异常;
throws 方法声明后,表示可能发生异常。
final、finally、finalize 的区别
答案 final: 修饰类、属性、方法,表示不能继承、重写。
finally:try catch
finalize:object 的一个方法,永远回收对象。
Java 的集合(重点)
阐述 Collection 和 Map 的体系
答案
阐述 hashmap 和 arrayList 底层原理
答案
hashmap 底层原理 解释的时候,说出 new、put、get 和影响性能的地方。
arraylist 原理 初始化 10,数组拷贝等,重点掌握 hashmap。
阐述集合的线程安全
答案
ArrayList HashSet HashMap 线程不安全。
Vector HashTable 线程安全。
其实,Collections 提供了方法可以 jiang 将不安全转换为安全:
Collections.synchronizedCollection(c)
Collections.synchronizedList(list)
Collections.synchronizedMap(m)
Collections.synchronizedSet(s)
打开源码可以查看到,其实就是在方法上面加了同步代码块。
如何给 hashmap 排序
答案 先存到 list 集合中,排序后使用 linkedhashmap 保存
什么是并发集合
答案 * ConcurrentHashMap(原理:分段锁) * CopyOnWriteArrayList(原理:操作的时候给一个副本,读多写少的时候使用) * CopyOnWriteHashSet
Map 中的 key 和 value 可以为 null 么
答案 HashMap 都可以 HashTable key value 都不可以
多线程和并发库
在 java 程序中怎么保证多线程的运行安全?
答案
原子性:同步、锁、CAS(基础类型变量自增)其本质是利用了 CPU 级别的 CAS 指令 可见性:volatile,还有上面的 顺序性:volatile 还有上面的
如何开启多线程
答案 继承 Thread
继承 Runable
继承 Callable
线程状态
答案
什么是 ThreadLocal
答案 是为了维护当前线程变量不被其他线程影响的结构,还是存储在自己的线程,以当前线程为 key,一个 threadlocal 只能保存一个变量。
synchronized 和 volatile 关键字的作用
答案 volatile 本质是在告诉 jvm 当前变量在寄存器(工作内存)中的值是不确定的,需要从主存中读取;只能修饰变量,不保证原子性。
为什么要用线程池及线程池的启动策略???
答案 降低资源消耗(避免重复创建和销毁)
提高响应速度(需要的时候直接去拿)
提高线程的可管理性(规定线程数量等)
线程池的启动策略
ThreadPoolExecutor executor = new ThreadPoolExecutor(10,
20,
60L,
TimeUnit.SECONDS,
new SynchronousQueue<Runnable>(),
Executors.defaultThreadFactory(),
new ThreadPoolExecutor.AbortPolicy()
);
线程池创建
1、当线程数小于corePoolSize
时,创建线程执行任务。
2、当线程数大于等于corePoolSize
并且workQueue
没有满时,放入workQueue
中
3、线程数大于等于corePoolSize
并且当workQueue
满时,新任务新建线程运行,线程总数要小于maximumPoolSize
4、当线程总数等于maximumPoolSize
并且workQueue
满了的时候执行handler
的rejectedExecution
。也就是拒绝策略。
如何控制某个方法允许并发访问线程的个数
答案
import java.util.concurrent.Semaphore;
public class SemaphoreTest {
static Semaphore semaphore = new Semaphore(5, true);
public static void main(String[] args) {
for (int i = 0; i < 100; i++) {
new Thread(new Runnable() {
@Override public void run() {
ceshi();
}
}).start();
}
}
public static void ceshi() {
try {
/** * 申请一个请求 */
semaphore.acquire();
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName()+"进来了");
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName() + "出去了");
/** * 释放一个请求 */
semaphore.release();
}
}
谈谈你对死锁的理解
答案 什么是死锁: 多个线程竞争资源而造成无限等待的情况。
产生死锁的条件? 互斥:一个资源同一个时间只能为一个线程使用。 不剥夺:未使用完不能被剥夺。 请求和保持:请求资源,但是不释放自己的 资源。 会形成一个资源等待链。
如何避免? 加锁顺序 加锁时限
并发和并行的区别 答案
说一下 runnable 和 callable 有什么区别?
答案
runnable 没有返回值,不能抛出异常 callable 靠 futuretask(实现 runable)来实现。可以有返回值和异常。
JavaSE 高级
反射
答案 根据类的字节码来实例并初始化对象、执行方法。
如何获取类的字节码:
类名.class
类.getClass
Class.forName("")
动态代理
答案
JVM 内存模型
答案
JVM 内存分配
答案
堆:存放引用对象;
方法区:存放类的字节码文件、常量池、字节码对象;
栈:存储基本类型的变量、对象名和对应的堆地址、及时调用的方法开辟的空间。
垃圾回收机制
答案
GC 机制:
主要处理堆内存;
1、判断是不是垃圾:
引用计数器算法
根搜索算法 (gc root:栈中引用的对象,方法区中的静态变量和常量,本地 native 中引用的对象) 2、怎么处理垃圾:
新生代 -edon:标记清除
新生代 -survivor:复制算法
老年代:标记整理算法
jvm 如何优化
答案
先监视是程序问题还是配置问题。
1、程序问题
先看日志,是否有错误提示
是否有死循环
大量递归
数据库查询数据
集合中是否有大量不用的对象。
java 类加载器有哪些
答案
- 系统提供的:
引导类加载器(bootstrap class loader):它用来加载 Java 的核心库
扩展类加载器(extensions class loader):它用来加载 Java 的扩展库
系统类加载器(system class loader):它根据 Java 应用的类路径(CLASSPATH)来加载 Java 类 - 自定义加载器 (必须继承 ClassLoader)
类加载机制 -- 双亲委托
答案
子类加载器,先看是否加载过,没有则让父级去加载; 父级是否加载过,加载直接返回 class,没有继续往上,直到引导类加载器。
只有父类找不到的时候,才会从自己的目录寻找并加载。
类什么时候初始化,初始化顺序?
答案
什么时候初始化?
new 一个对象;
静态方法被调用;
静态域被赋值和调用;
初始化子类,父类会被初始化;
反射;
程序启动时,作为程序入口包含 main 方法的类。
初始化顺序?
如果父类没有被加载和初始化,先加载父类。
静态属性:static 开头定义的属性
静态方法块: static {} 圈起来的方法块
普通属性: 未带 static 定义的属性
普通方法块: {} 圈起来的方法块
构造函数: 类名相同的方法
方法: 普通方法
既然有 GC 机制,为什么还会有内存泄露的情况
答案 存在无用但可达的对象。
在开发中遇到过内存溢出么?原因有哪些?解决方法有哪些?
答案
有。
原因:
一次加载太多数据;
程序循环、迭代太多产生太多对象;
启动参数设置太小。
监听程序,查看内存消耗状态。
加大内存查看是内存原因还是程序原因。
如果是程序,查看错误日志或者是否有死循环等。
重点:
数据库查询是否数据量过大。
检查代码中是否有死循环或递归调用;
检查是否有大循环重复产生新对象实体
如果集合存有大量数据,使用完后要及时清除。
BIO、NIO、AIO 有什么区别?
答案
BIO (Blocking I/O):同步阻塞 I/O 模式 NIO (NoneBlock I/O):非阻塞模式 AIO ( Asynchronous I/O):异步非阻塞 I/O 模型
netty 处理 socket 的工具。 RPC, Remote Procedure Call 即远程过程调用,比如 dubbo