0%

0928-Java常见面试题

Java相关

引用拷贝、深拷贝、浅拷贝

  • 引用拷贝:不会生成新的对象,只会在原对象上增加了一个新的对象引用,两个引用指向的对象还是同一个

  • 浅拷贝:会生成新的对象,但是对象中的引用类型并不会重新生成(修改该类属性仍然会连环修改)

    • 实现方式:对象实现cloneable接口,在直接调用clone方法
  • 深拷贝:会生成新的对象,且对象中的引用类型也会重新生成对象

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    package JavaGuide;

    public class Teacher implements Cloneable{
    public int num;
    public Student s;

    @Override
    protected Object clone() throws CloneNotSupportedException {
    Teacher teacher = (Teacher) super.clone();
    teacher.s = (Student) this.s.clone();
    return teacher;
    }

    public static void main(String[] args) throws CloneNotSupportedException {
    Student stu = new Student();
    stu.num = 1111;
    Teacher t1 = new Teacher();
    t1.num = 1;
    t1.s = stu;

    // Teacher t2 = t1;
    Teacher t2 = (Teacher) t1.clone();
    t2.s.num = 2222;
    System.out.println(t1.s.num);
    }
    }

    class Student implements Cloneable{
    public int num;

    @Override
    public Object clone() throws CloneNotSupportedException {
    return super.clone();
    }
    }

JDK和JRE

  • JDK 是 Java Development Kit 缩写,它是功能齐全的 Java SDK。它拥有 JRE 所拥有的一切,还有编译器(javac)和工具(如 javadoc 和 jdb)。它能够创建和编译程序。

  • JRE 是 Java 运行时环境。它是运行已编译 Java 程序所需的所有内容的集合,包括 Java 虚拟机(JVM),Java 类库,java 命令和其他的一些基础构件。但是,它不能用于创建新程序。

  • 如果你只是为了运行一下 Java 程序的话,那么你只需要安装 JRE 就可以了。如果你需要进行一些 Java 编程方面的工作,那么你就需要安装 JDK 了。

有哪些集合是线程不安全的?怎么解决呢?

我们常用的 Arraylist ,LinkedList,Hashmap,HashSet,TreeSet,TreeMapPriorityQueue 都不是线程安全的。解决办法很简单,可以使用线程安全的集合来代替。

如果你要使用线程安全的集合的话, java.util.concurrent 包中提供了很多并发容器供你使用:

  1. ConcurrentHashMap: 可以看作是线程安全的 HashMap
  2. CopyOnWriteArrayList:可以看作是线程安全的 ArrayList,在读多写少的场合性能非常好,远远好于 Vector.
  3. ConcurrentLinkedQueue:高效的并发队列,使用链表实现。可以看做一个线程安全的 LinkedList,这是一个非阻塞队列。
  4. BlockingQueue: 这是一个接口,JDK 内部通过链表、数组等方式实现了这个接口。表示阻塞队列,非常适合用于作为数据共享的通道。
  5. ConcurrentSkipListMap :跳表的实现。这是一个Map,使用跳表的数据结构进行快速查找。

Arraylist 与 LinkedList 区别?

  1. 是否保证线程安全: ArrayListLinkedList 都是不同步的,也就是不保证线程安全;
  2. 底层数据结构: Arraylist 底层使用的是 Object 数组LinkedList 底层使用的是 双向链表 数据结构(JDK1.6 之前为循环链表,JDK1.7 取消了循环。注意双向链表和双向循环链表的区别,下面有介绍到!)
  3. 插入和删除是否受元素位置的影响:ArrayList 采用数组存储,所以插入和删除元素的时间复杂度受元素位置的影响。 比如:执行add(E e)方法的时候, ArrayList 会默认在将指定的元素追加到此列表的末尾,这种情况时间复杂度就是 O(1)。但是如果要在指定位置 i 插入和删除元素的话(add(int index, E element))时间复杂度就为 O(n-i)。因为在进行上述操作的时候集合中第 i 和第 i 个元素之后的(n-i)个元素都要执行向后位/向前移一位的操作。 ② LinkedList 采用链表存储,所以对于add(E e)方法的插入,删除元素时间复杂度不受元素位置的影响,近似 O(1),如果是要在指定位置i插入和删除元素的话((add(int index, E element)) 时间复杂度近似为o(n))因为需要先移动到指定位置再插入。
  4. 是否支持快速随机访问: LinkedList 不支持高效的随机元素访问,而 ArrayList 支持。快速随机访问就是通过元素的序号快速获取元素对象(对应于get(int index)方法)。
  5. 内存空间占用: ArrayList 的空 间浪费主要体现在在 list 列表的结尾会预留一定的容量空间,而 LinkedList 的空间花费则体现在它的每一个元素都需要消耗比 ArrayList 更多的空间(因为要存放直接后继和直接前驱以及数据)。

多线程相关

什么是线程和进程? 线程与进程的关系,区别及优缺点?

  • 进程是具有一定独立功能的程序,关于某个数据集合上的一次运行活动,进程是系统进行资源分配和调度的一个独立单位
  • 进程在执行过程中拥有独立的内存单元,而多个线程共享内存,从而极大地提高了程序的运行效率。

使用多线程可能带来什么问题?

内存泄漏、死锁、线程不安全等等

创建线程有哪几种方式?

a.继承 Thread 类;b.实现 Runnable 接口;c. 使用 Executor 框架;d.使用 FutureTask

线程的生命周期和状态?

什么是上下文切换

CPU通过时间片分配算法来循环执行任务,当前任务执行一个时间片后会切换到下一个任务。但是,在切换前会保存上一个任务的状态,以便下次切换回这个任务时,可以再次加载这个任务的状态,从任务保存到再加载的过程就是一次上下文切换

synchronized加锁方式

1、修饰一个代码块,作用的范围是大括号括起来的对象,作用的对象是调用这个代码块的对象

2、修饰一个方法,被修饰的方法称为同步方法,作用的范围是整个方法,作用的对象是调用这个 方法的对象

3、修饰一个静态的方法,其作用的范围是整个静态方法,租用的对象是这个类的所有对象

4、修饰一个类,起作用的范围是synchronized后面括号括起来的部分,作用的对象是这个类的所有对象

什么是线程死锁?如何避免死锁?

当线程A持有独占锁a,并尝试去获取独占锁b的同时,线程B持有独占锁b,并尝试获取独占锁a的情况下,就会发生AB两个线程由于互相持有对方需要的锁,而发生的阻塞现象,我们称为死锁

破坏死锁的四个必要条件:互斥条件、请求与保持条件、不剥夺条件、循环等待条件。其中前三个称为独占锁。

synchronized 关键字和 volatile 关键字的区别

volatile能够保证可见性和有序性,但无法保证原子性;synchronized则都能保证