面试 _java_SE

本贴最后更新于 1861 天前,其中的信息可能已经天翻地覆

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

答案 可以,

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 满了的时候执行 handlerrejectedExecution。也就是拒绝策略。

如何控制某个方法允许并发访问线程的个数

答案
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

  • 面试

    面试造航母,上班拧螺丝。多面试,少加班。

    324 引用 • 1395 回帖 • 1 关注

相关帖子

欢迎来到这里!

我们正在构建一个小众社区,大家在这里相互信任,以平等 • 自由 • 奔放的价值观进行分享交流。最终,希望大家能够找到与自己志同道合的伙伴,共同成长。

注册 关于
请输入回帖内容 ...