Java面试题汇总(不定期更新)

各部分运行顺序?

JVM虚拟机启动会仅加载一次所有static变量,之后仅加载一次static代码块,在之后是main函数。每当有类实例化都会运行构造代码块,再执行构造函数。

即顺序为

  1. static静态变量
  2. static静态代码块
  3. main函数
  4. 构造代码块{}
  5. 构造函数
  6. 普通方法
  7. main函数结束

继承时运行顺序?

  1. 父类静态块
  2. 子类静态块
  3. 父类构造块{}
  4. 父类构造函数
  5. 子类构造块{}
  6. 子类构造函数
  7. 子类方法

CAS?

CAS全称 Compare And Swap,是一种无锁算法。在不使用锁(没有线程被阻塞)的情况下实现多线程之间的变量同步。

  • 需要读写的内存值 V
  • 进行比较的值 A
  • 要写入的新值 B

当且仅当 V 的值等于 A 时,CAS通过原子方式用新值B来更新V的值(“比较+更新”整体是一个原子操作),否则不会执行任何操作。一般情况下,“更新”是一个不断重试的操作。

锁?

https://tech.meituan.com/2018/11/15/java-lock.html

悲观锁:认为在使用数据的时候一定有别的线程来修改数据,synchronized关键字和Lock的实现类。【适合写操作多的场景】

乐观锁:认为自己在使用数据时不会有别的线程修改数据,所以不添加锁,只在更新数据的时候去判断之前有没有别的线程更新了这个数据,如果没有被更新则成功写入,如果已经被更新,根据不同的实现方式执行不同的操作(例如报错或者自动重试),最常用CAS算法。【适合读操作多的场景】

锁的升级?

  1. 无锁
  2. 偏向锁
  3. 轻量级锁
  4. 重量级锁

线程间通信方式?

  1. 消息队列
  2. 全局变量(volatile)
  3. 使用事件

线程池的主要参数?

  1. corePoolSize(线程池基本大小)
  2. maximumPoolSize(线程池最大大小)
  3. keepAliveTime(线程存活保持时间)
  4. workQueue(任务队列)
  5. threadFactory(线程工厂)
  6. handler(线程饱和策略)

mysql事务?

一个或一组sql语句组成的一个执行单元,这个执行单元要么全部执行,要么全部不执行。

继承的作用?

  1. 提现相关类的层次结构
  2. 提供了复用,减少冗余,增加重用性
  3. 多态的前提

Java容器?

  1. Map
    1. HashMap
    2. Hashtable
    3. TreeMap
  2. Collection
    1. List
      1. ArrayList
      2. LinkedList
      3. Vector
      4. Stack
    2. Set
      1. HashSet
        1. LinkedHashSet
      2. TreeSet
    3. Queue

为什么要重写equals()和hashcode()?

我们知道 == 用于比较两个对象的内存地址,Object的equal()方法实际上也是比较两个对象的内存地址是否相等。String类的equals()方法之所以是比较了内容,是因为对equals()方法进行了重写,使其比较的是字符的序列。

equals()方法需要满足:

  1. 自反:x.equals(x)
  2. 对称:x.equals(y) y.equals(x)
  3. 一致:x.equals(y) 多次调用结果不变
  4. 传递:x.equals(y) 且 y.equals(z) => x.equals(z)
  5. null返回false:x.equals(null) 返回false

在向Hash结构中添加元素时,首先调用hashCode()方法,若没有其他元素则直接保存,若已经有元素存在,则调用equals()方法来判断两个元素是否相同,相同则不储存,不同则链到后面(链地址法)。

Java约定:

  1. 如果两个对象根据equals方法比较是相等的,那么调用这两个对象的任意一个hashcode方法都必须产生相同的结果。
  2. 两个对象的hashCode相同,它们的equals()方法不一定相同。

而如果不重写hashCode()方法,就会出现两个对象equals()返回true,但hashCode值不相同的情况。

以下为示例代码:

import java.util.*;
class Employee{
    String name;
    int age;
    Employee(){
        name = "null";
        age = 0;
    }
    Employee(String name,int age){
        this.name = name;
        this.age = age;
    }

    @Override
    public boolean equals(Object obj) {
        if(this == obj) return true;
        if(obj == null) return false;
        if(getClass() != obj.getClass()) return false;
        var other = (Employee)obj;
        return Objects.equals(name,other.name) && age == other.age;
    }

    @Override
    public int hashCode() {
        return Objects.hash(name,age);
    }
}
public class Test {
    public static void main(String[] args) {
        Employee a = new Employee("aname",5);
        Employee aCopy = a;
        Employee b= new Employee("aname",5);
        System.out.println("a == aCopy: "+(a == aCopy));
        System.out.println("a == b: "+(a == b));
        System.out.println("aCopy == b: "+(aCopy == b));
        System.out.println("===============");
        System.out.println("a equals aCopy: "+a.equals(aCopy));
        System.out.println("a equals b: "+(a.equals(b)));
        System.out.println("aCopy equals b: "+(aCopy.equals(b)));
        System.out.println("===============");
        System.out.println(a.hashCode());
        System.out.println(aCopy.hashCode());
        System.out.println(b.hashCode());
    }
}

数据库范式相关

这里直接搬《数据库系统概论》(第五版)第六章中的内容。

规范化过程

函数依赖:R(U)是属性集U上的关系模式,X,Y是U的子集。若对于R(U)的任意一个可能的关系r,r中不可能存在两个元组在X上的属性值相等,而在Y上的属性值不等,则称X函数确定YY函数依赖于X,记X→Y。

R(U)中,如果X→Y,并且对于X的任何一个真子集X‘,都有X’不能函数确定Y(或Y不函数依赖于X‘),则称Y对X完全函数依赖。如果X→Y,但Y不完全函数依赖于X,则称Y对于X部分函数依赖

决定因素:若X→Y,则X称为这个函数依赖的决定属性组,也成为决定因素

U={Sno, Sdept, Mname, Cno, Grade}中

F={Sno→Sdept, Sdept→Mname, (Sno,Cno)→Grade}

例如(Sno,Cno)→Grade是完全函数依赖,(Sno,Cno)→Sdept是部分函数依赖(因为Sno即可函数确定Sdept)。

1NF:每一个分量必须是不可分的数据项。

2NF:在1NF的前提上,每一个非主属性完全函数依赖于任何一个候选码。(可以成为主码,即U完全函数依赖于候选码)

3NF:每一个非主属性不传递依赖于码,也不部分依赖于码。(2NF条件基础上限制传递依赖)

备注:3NF的不彻底表现在可能存在主属性对码的部分依赖和传递依赖。

BCNF:关系模式R<U,F>∈1NF,若X→Y且Y⊈X时X必含有码。(在3NF基础上每一个决定因素都包含码)。详细来讲:

  • 所有非主属性对每一个码都是完全函数依赖(2NF条件)
  • 所有主属性对每一个不包含它的码也是完全函数依赖
  • 没有任何属性完全函数依赖于非码的任何一组属性

例子:关系模式STJ(S,T,J),S表示学生,T表示老师,J表示课程。老师只教一门课,每门课有若干老师,某一学生选定某门课固定一个老师。则:

(S,J)→T,(S,T)→J,T→J

(S,J)和(S,T)是候选码,因此S,J,T都是主属性。满足3NF,但是主属性内出现了部分依赖。不满足BCNF,BCNF在3NF的基础上要求每一个决定因素都包含码,这里T并不包含码。

多值依赖:设R(U)是属性集U上的一个关系模式。X,Y,Z是U的子集,且Z=U-X-Y。关系模式R(U)中多值依赖X→→Y成立,当且仅当对R(U)的任一关系r,给定的一对(x,z)值,有一组Y的值,这组值仅仅决定于x值而与z值无关。

若X→→Y,而Z=Ø,则称X→→Y为平凡的多值依赖

4NF:限制关系模式属性之间不允许有非平凡且非函数依赖的多值依赖。根据定义,对于每一个非平凡的多值依赖X→→Y,X都含有候选码,于是就有X→Y,所以4NF所允许的非平凡的多值依赖实际上是函数依赖。

volatile关键字的作用(华为技术面)

volatile关键字解析

  1. 受限原子性(不保证)
  2. 可见性
  3. 有序性(没答出来)

有序性关系到指令重排序的问题。重排序过程不会影响到单线程程序的执行,却会影响到多线程并发执行的正确性。