基础知识面试题

Java基础知识面试题

1、说下你对==和equals的认识,它们有什么差别?(高频)

对于==号:

1、比较基本类型,比如int等,==比较的是值是否相同;

2、引用类型,比如自定义对象:比较地址是否相同;

2、String 类的常用方法都有那些?(高频)

indexOf():返回指定字符的索引。

length():返回字符串长度。

equals():字符串比较。

replace():字符串替换。

trim():去除字符串两端空白。

split():分割字符串,返回一个分割后的字符串数组。

3 String、StringBuilder、StringBuffer的区别?

String是不可变字符串,使用+号进行字符串拼接的时候会产生很多的临时碎片。

StringBuffer和StringBuilder是可变的字符串

StringBuilder是线程不安全的,效率高

StringBuffer是线程安全的,效率较低

4、一般的类和抽象类有哪些区别?

一般的类不能包含没有方法体的抽象方法,而抽象类可以包含抽象方法。抽象类不能直接用new来实例化,普通类可以直接实例化。

5、接口和抽象类有什么区别?(高频)

抽象类的子类要用 extends 来继承;而实现接口要用 implements 。

抽象类可以定义构造函数,而接口不能。

抽象类里可以定义 main 方法,但接口不能有 main 方法。

实现数量:类可以实现很多个接口;但是只能继承一个抽象类。

访问修饰符:接口中的方法默认使用 public 修饰;抽象类中的方法可以是任意访问修饰符。

5 Java的集合容器都有哪些?(高频)

在这里插入图片描述

6 List、Set、Map 之间的区别是什么?(高频)

List集合

1、属于单列集合,存储的都是一个一个元素

2、List和存在重复元素

3、每一个元素都有对应的索引,可以通过索引获取元素

4、元素的存取顺序一致

Set集合

1、属于单列集合,存储的都是一个一个元素

2、元素唯一

3、元素没有索引,不能通过索引获取元素

4、不能保证元素的存取顺序一致

Map集合:

1、属于双列集合,存储的是一对一对的元素

7、HashMap和Hashtable有什么区别?(高频)

相同点:

1、HashMap和Hashtable都实现了Map接口

2、都可以存储key-value数据

不同点:

1、HashMap可以把null作为key或value,Hashtable不可以

2、HashMap线程不安全,效率高。Hashtable线程安全,效率低。

8、ArrayList和LinkedList的区别?

ArrayList底层的数据结构是数组,查询快增删慢

LinkedList底层的数据结构是双向链表,查询慢增删快

9 jdk1.7到jdk1.8HashMap发生了什么变化(底层)?(高频)

1.8 之后 hashMap 的数据结构发生了变化,从之前的单纯的数组+链表结构变成数组 + 链表 + 红黑树。也就是说在 JVM 存储 hashMap 的 K-V 时仅仅

通过 key 来决定每一个 entry 的存储槽位(Node[]中的 index)。并且 Value 以链表的形式挂在到对应槽位上(1.8 以后如果 value长度大于 8 则转为红

黑树)。

在这里插入图片描述

10 HashMap的扩容原理?(高频)

初始化容量为16,达到阈值进行扩容。阈值 = 最大容量 * 负载因子(0.75),扩容每次2倍,总是2的n次方。

扩容机制:使用一个容量更大的数组替代已有的容量小的数组,transfer()方法将原有的Entry数组的元素拷贝到新的Entry数组里。

11 线程的创建方式?(高频)

继承Thread类

实现runnable接口

实现Callable接口

线程池创建线程

12 sleep() 和 wait() 有什么区别?(高频)

sleep是Thread类中的方法,不会释放同步锁

wait是Object类中的方法,会释放同步锁

13 线程的 run()和 start()有什么区别?(高频)

start(): 用来启动线程,通过该线程调用run方法执行run方法中所定义的逻辑代码。start方法只能被调用一次。

run(): 封装了要被线程执行的代码,可以被调用多次。

14 有三个线程 T1 , T2 , T3 ,如何保证顺序执行?(高频)

在多线程中有多种方法让线程按特定顺序执行,你可以用线程类的join()方法在一个线程中启动另一个线程,另外一个线程完成该线程继续执行。

public class JoinTest {

    public static void main(String[] args) {

        // 创建线程对象
        Thread t1 = new Thread(() -> {
            System.out.println("t1");
        }) ;

        Thread t2 = new Thread(() -> {
            try {
                t1.join();                          // 加入线程t1,只有t1线程执行完毕以后,再次执行该线程
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println("t2");
        }) ;


        Thread t3 = new Thread(() -> {
            try {
                t2.join();                              // 加入线程t2,只有t2线程执行完毕以后,再次执行该线程
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println("t3");
        }) ;

        // 启动线程
        t1.start();
        t2.start();
        t3.start();

    }

}

15 线程有哪些状态?

Java中的线程状态被定义在了java.lang.Thread.State枚举类中,State枚举类的源码如下:

public class Thread {
    
    public enum State {
    
        /* 新建 */
        NEW , 

        /* 可运行状态 */
        RUNNABLE , 

        /* 阻塞状态 */
        BLOCKED , 

        /* 无限等待状态 */
        WAITING , 

        /* 计时等待 */
        TIMED_WAITING , 

        /* 终止 */
        TERMINATED;
    
	}
    
    // 获取当前线程的状态
    public State getState() {
        return jdk.internal.misc.VM.toThreadState(threadStatus);
    }
    
}

16 讲一下synchronized关键字的底层原理?(高频)

① synchronized同步代码块的情况

synchronized 同步语句块的实现使用的是 monitorentermonitorexit 指令,其中monitorenter 指令指向同步代码块的开始

位置,monitorexit 指令则指明同步代码块的结束位置。当执行 monitorenter 指令时,线程试图获取锁也就是获取 monitor(monitor对象存在于每个

Java对象的对象头中,synchronized 锁便是通过这种方式获取锁的,也是为什么Java中任意对象可以作为锁的原因) 的持有权。当计数器为0则可以成功

获取,获取后将锁计数器设为1也就是加1。相应的在执行monitorexit 指令后,将锁计数器设为0,表明锁被释放。如果获取对象锁失败,那当前线程就要

阻塞等待,直到锁被另外一个线程释放为止。

② synchronized修饰方法的的情况

synchronized 修饰的方法并没有 monitorenter 指令和 monitorexit 指令,取得代之的确实是ACC_SYNCHRONIZED 标识,该标识指明了该方法是一

个同步方法,JVM 通过该 ACC_SYNCHRONIZED访问标志来辨别一个方法是否声明为同步方法,从而执行相应的同步调用。

17 Java中synchronized 和 ReentrantLock有什么不同?(高频)

相比Synchronized,ReentrantLock类提供了一些高级功能,主要有以下2项:

​ ① 等待可中断,持有锁的线程长期不释放的时候,正在等待的线程可以选择放弃等待,这相当于Synchronized来说可以避免出现死锁的情况。

​ ② Synchronized锁非公平锁,ReentrantLock默认的构造函数是创建的非公平锁,可以通过参数true设为公平锁,但公平锁表现的性能不是很好。

(公平锁,多个线程等待同一个锁时,必须按照申请锁的时间顺序获得锁。)

​ ③ synchronized是通过jvm的指令实现同步,ReentrantLock是通过java api的实现同步的

18 ThreadLocal 是什么?有哪些使用场景?(高频)

ThreadLocal是一个线程工具类,可以在一个线程内共享数据,在我们的项目中使用ThreadLocal存储的是解析token以后的用户数据。

底层实现是同一个Map进行数据的存储,Map的键是当前线程对象,值就是要共享的数据。

19 如果你提交任务时,核心线程池已经满了,这时会发生什么?(高频)

① 无界队列

​ 如果使用的是无界队列LinkedBlockingQueue,也就是无界队列的话,没关系,继续添加任务到阻塞队列中等待执行,因为LinkedBlockingQueue可以近乎认为是一个无穷大的队列,可以无限存放任务

② 有界队列

​ 如果使用的是有界队列比如ArrayBlockingQueue,任务首先会被添加到ArrayBlockingQueue中,ArrayBlockingQueue满了,会根

maximumPoolSize的值增加线程数量,如果增加了线程数量还是处理不过来,ArrayBlockingQueue继续满,那么则会使用拒绝策略RejectedExecutionHandler处理满了的任务,默认是AbortPolicy

20 创建线程池有哪几种方式?(高频)

① 通过Executor框架的工具类Executors来实现我们可以创建三种类型的:

  • FixedThreadPool: 该方法返回一个固定线程数量的线程池。该线程池中的线程数量始终不变。当有一个新的任务提交时,线程池中若有空闲线程,则立即执行。若没有,则新的任务会被暂存在一个任务队列中,待有线程空闲时,便处理在任务队列中的任务。

  • SingleThreadExecutor: 方法返回一个只有一个线程的线程池。若多余一个任务被提交到该线程池,任务会被保存在一个任务队列中,待线程空闲,按先入先出的顺序执行队列中的任务。

  • CachedThreadPool: 该方法返回一个可根据实际情况调整线程数量的线程池。线程池的线程数量不确定,但若有空闲线

    程可以复用,则会优先使用可复用的线程。若所有线程均在工作,又有新的任务提交,则会创建新的线程处理任务。所有线程在当前任务执行完毕后,将返回线程池进行复用。

② 《阿里巴巴Java开发手册》中强制线程池不允许使用 Executors 去创建,而是通过ThreadPoolExecutor 的方式:ThreadPoolExecutor最完整的构造方法:

public ThreadPoolExecutor(int corePoolSize,
                              int maximumPoolSize,
                              long keepAliveTime,
                              TimeUnit unit,
                              BlockingQueue<Runnable> workQueue,
                              ThreadFactory threadFactory,
                              RejectedExecutionHandler handler)

参数说明

corePoolSize:   核心线程的最大值,不能小于0
maximumPoolSize:最大线程数,不能小于等于0,maximumPoolSize >= corePoolSize
keepAliveTime:  空闲线程最大存活时间,不能小于0
unit:           时间单位
workQueue:      任务队列,不能为null
threadFactory:  创建线程工厂,不能为null      
handler:        任务的拒绝策略,不能为null    

任务的拒绝策略种类:

ThreadPoolExecutor.AbortPolicy: 		    丢弃任务并抛出RejectedExecutionException异常。是默认的策略。
ThreadPoolExecutor.DiscardPolicy: 		   丢弃任务,但是不抛出异常 这是不推荐的做法。
ThreadPoolExecutor.DiscardOldestPolicy:    抛弃队列中等待最久的任务 然后把当前任务加入队列中。
ThreadPoolExecutor.CallerRunsPolicy:        调用任务的run()方法绕过线程池直接执行。

21 什么是Java内存模型?

JMM(Java Memory Model)Java内存模型,是java虚拟机规范中所定义的一种内存模型。

Java内存模型(Java Memory Model)描述了Java程序中各种变量(线程共享变量)的访问规则,以及在JVM中将变量存储到内存和从内存中读取变量这样的底层细节。

特点:

  1. 所有的共享变量都存储于主内存(计算机的RAM)这里所说的变量指的是实例变量和类变量。不包含局部变量,因为局部变量是线程私有的,因此不存在竞争问题。

  2. 每一个线程还存在自己的工作内存,线程的工作内存,保留了被线程使用的变量的工作副本。

  3. 线程对变量的所有的操作(读,写)都必须在工作内存中完成,而不能直接读写主内存中的变量,不同线程之间也不能直接访问对方工作内存中的变量,线程间变量的值的传递需要通过主内存完成。
    在这里插入图片描述

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值