Java面试-2022遇到的面试题

目录

阐述java 3大特性,

重写和继承和重载,

异常体系,

mysql的脏读幻读,

怎么解决脏读幻读,

常用的集合类,

使用线程池的优点,

java多线程的创建方法. 

spring的事务机制(这个完全不会),

linux常用命令,

jvm的内存区域.


阐述java 3大特性,


封装:

        封装是把一个对象的状态信息(也就是属性)隐藏在对象内部,不允许外部对象直接访问对象的内部信息。但是可以提供一些可以被外部访问的方法来操作属性。

继承:

        继承是使用已存在的类的定义作为基础建立新类的技术,新类的定义可以增加新的数据或新的功能,也可以用父类的功能,但不能选择性地继承父类。通过使用继承,可以快速地创建新的类,可以提高代码的重用,程序的可维护性,节省大量创建新类的时间 ,提高我们的开发效率。

关于继承如下 3 点请记住:

  1. 子类拥有父类对象所有的属性和方法(包括私有属性和私有方法),但是父类中的私有属性和方法子类是无法访问,只是拥有
  2. 子类可以拥有自己属性和方法,即子类可以对父类进行扩展。
  3. 子类可以用自己的方式实现父类的方法。

多态:

        表示一个对象具有多种的状态,具体表现为父类的引用指向子类的实例。

多态的特点:


  • 对象类型和引用类型之间具有继承(类)/实现(接口)的关系;
  • 引用类型变量发出的方法调用的到底是哪个类中的方法,必须在程序运行期间才能确定;
  • 多态不能调用“只在子类存在但在父类不存在”的方法;
  • 如果子类重写了父类的方法,真正执行的是子类覆盖的方法,如果子类没有覆盖父类的方法,执行的是父类的方法。

重写和继承和重载,


重写【重点】【Override】:

        重写目的:子类可以继承父类的非私有化的方法,但是有的 时候父类的需求满足不了子类的需求时,这个时候需要在子类中重写父类非私有的方法。

        ​重写要求:

                1.必须有继承关系
                2.父类的方法必须是非私有化的
                3.在子类中重写父类的方法,这个方法除了方法体不一样其他都一样的。
                4.必须再子类中去重写

重载 【 Overload 】:

        1.方法的重载必须在一个类中

        2.方法的重载必须是方法的名字一样

        3.方法的参数类型必须不一样

        4.方法的返回值可以不一样

        5.有参构造和无参构造也是一种重载(构造器重载)

异常体系,


Java面试-2022遇到的面试题_第1张图片

 Exception 和 Error 有什么区别?

在 Java 中,所有的异常都有一个共同的祖先 java.lang 包中的 Throwable 类。Throwable 类有两个重要的子类:

  • Exception :程序本身可以处理的异常,可以通过 catch 来进行捕获。Exception 又可以分为 Checked Exception (受检查异常,必须处理) 和 Unchecked Exception (不受检查异常,可以不处理)。
  • ErrorError 属于程序无法处理的错误 ,不建议通过catch捕获 。例如 Java 虚拟机运行错误(Virtual MachineError)、虚拟机内存不够错误(OutOfMemoryError)、类定义错误(NoClassDefFoundError)等 。这些异常发生时,Java 虚拟机(JVM)一般会选择线程终止。

Checked Exception 和 Unchecked Exception 有什么区别?

        Checked Exception 即 受检查异常 ,Java 代码在编译过程中,如果受检查异常没有被 catch或者throws 关键字处理的话,就没办法通过编译。

Unchecked Exception不受检查异常 ,Java 代码在编译过程中 ,我们即使不处理不受检查异常也可以正常通过编译。

RuntimeException 及其子类都统称为非受检查异常,常见的有(建议记下来,日常开发中会经常用到):

  • NullPointerException(空指针错误)
  • IllegalArgumentException(参数错误比如方法入参类型错误)
  • NumberFormatException(字符串转换为数字格式错误,IllegalArgumentException的子类)
  • ArrayIndexOutOfBoundsException(数组越界错误)
  • ClassCastException(类型转换错误)
  • ArithmeticException(算术错误)
  • SecurityException (安全错误比如权限不够)
  • UnsupportedOperationExcep
  • 。。。

mysql的脏读幻读,


脏读(Dirty read): 当一个事务正在访问数据并且对数据进行了修改,而这种修改还没有提交到数据库中,这时另外一个事务也访问了这个数据,然后使用了这个数据。因为这个数据是还没有提交的数据,那么另外一个事务读到的这个数据是“脏数据”,依据“脏数据”所做的操作可能是不正确的。

幻读(Phantom read): 幻读与不可重复读类似。它发生在一个事务(T1)读取了几行数据,接着另一个并发事务(T2)插入了一些数据时。在随后的查询中,第一个事务(T1)就会发现多了一些原本不存在的记录,就好像发生了幻觉一样,所以称为幻读。幻读其实可以看作是不可重复读的一种特殊情况,单独把区分幻读的原因主要是解决幻读和不可重复读的方案不一样。

怎么解决脏读幻读,


解决脏读:

方法1:修改事务隔离级别为:read committed(读取已提交)

方法2:读取时加排它锁(select…for update),事务提交才会释放锁,修改时加共享锁(update …lock in share mode)。加排它锁后,不能对该条数据再加锁,能查询但不能更改数据。mysql InnoDB引擎默认的修改数据语句,update,delete,insert都会自动给涉及到的数据加上排他锁,select语句默认不会加任何锁类型,如果加排他锁可以使用select …for update语句,如果事务T对数据A加上共享锁后,则其他事务只能对A再加共享锁,不能加排他锁,共享锁下其它用户可以并发读取,查询数据。但不能修改,增加,删除数据。资源共享。

解决幻读:

方法1:事务隔离级别设置为:serializable(可串行化) ,那么数据库就变成了单线程访问的数据库,导致性能降低很多。

方法二:RR级别下防止幻读

RR级别下只要对 SELECT 操作也手动加行(X)锁即可类似 SERIALIZABLE 级别(它会对 SELECT 隐式加锁)。幻读只存与插入,且是当前读,在Mysql的Innodb引擎中默认开起了间隙锁,幻读是通过间隙锁+行锁方式解决的

常用的集合类,(List,Set,Map)


List

List(列表),相当于数组。长度可变,元素存放有一定的顺序,下标从0开始。

ArrayList

ArrayList性质
是否允许空元素(即null)
是否允许重复数据
是否有序
是否线程安全

LinkedList

LinkedList性质
是否允许空元素(即null)
是否允许重复数据
是否有序
是否线程安全

ArrayList 与 LinkedList 区别?

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

Set

不包含重复元素的集合。更确切地说,是不同时包含使得e1.equals(e2)成立的e1和e2(因为e1与e2的equals()逻辑可以由使用者自己定义)。并且最多包含一个空元素。这个接口是数学集合的一个抽象建模。
注意:如果可变的(mutable)对象用作集合元素,则必须非常小心。当一个对象是集合中的元素时,以影响equals()比较结果的方式更改对象的值,则无法预测集合的行为。有一个特殊情况是,不允许一个集合作为一个元素来包含它自己。所以还是尽量使用immutable的对象作为Set的元素。

HashSet

先回答四个问题:

是否允许空元素(即null)
是否允许重复数据
是否有序
是否线程安全

HashSet 的底层数据结构是哈希表(基于 HashMap 实现);HashSet 用于不需要保证元素插入和取出顺序的场景。

TreeSet

先回答四个问题:

TreeSet 底层数据结构是红黑树,元素是有序的,排序的方式有自然排序和定制排序。TreeSet 用于支持对元素自定义排序规则的场景。

Map

将key映射到value的对象。Map不能包含重复的key;每个key最多可以映射到一个value

HashMap

HashMap 的原理
HashMap 的内部可以看做数组+链表的复合结构。数组被分为一个个的桶(bucket)。哈希值决定了键值对在数组中的寻址。具有相同哈希值的键值对会组成链表。需要注意的是当链表长度超过阈值(默认是8)的时候会触发树化,链表会变成树形结构。
把握HashMap的原理需要关注4个方法:hash、put、get、resize。

  • hash方法
    将 key 的 hashCode 值的高位数据移位到低位进行异或运算。这么做的原因是有些 key 的 hashCode 值的差异集中在高位,而哈希寻址是忽略容量以上高位的,这种做法可以有效避免哈希冲突。

  • put 方法
    put 方法主要有以下几个步骤:
    通过 hash 方法获取 hash 值,根据 hash 值寻址。
    如果未发生碰撞,直接放到桶中。
    如果发生碰撞,则以链表形式放在桶后。
    当链表长度大于阈值后会触发树化,将链表转换为红黑树。
    如果数组长度达到阈值,会调用 resize 方法扩展容量。

  • get方法
    get 方法主要有以下几个步骤:
    通过 hash 方法获取 hash 值,根据 hash 值寻址。
    如果与寻址到桶的 key 相等,直接返回对应的 value。
    如果发生冲突,分两种情况。如果是树,则调用 getTreeNode 获取 value;如果是链表则通过循环遍历查找对应的 value。

  • resize 方法
    resize 做了两件事:
    将原数组扩展为原来的 2 倍
    重新计算 index 索引值,将原节点重新放到新的数组中。这一步可以将原先冲突的节点分散到新的桶中。

TreeMap

实现 NavigableMap 接口让 TreeMap 有了对集合内元素的搜索的能力。

实现SortedMap接口让 TreeMap 有了对集合中的元素根据键排序的能力。默认是按 key 的升序排序,不过我们也可以指定排序的比较器。

HashMap 和 TreeMap 区别

TreeMapHashMap 都继承自AbstractMap ,但是需要注意的是TreeMap它还实现了NavigableMap接口和SortedMap 接口。

Java面试-2022遇到的面试题_第2张图片

实现 NavigableMap 接口让 TreeMap 有了对集合内元素的搜索的能力。实现SortedMap接口让 TreeMap 有了对集合中的元素根据键排序的能力。默认是按 key 的升序排序,不过我们也可以指定排序的比较器。

 综上,相比于HashMap来说 TreeMap 主要多了对集合中的元素根据键排序的能力以及对集合内元素的搜索的能力。

使用线程池的优点,


(1)降低资源消耗。通过重复利用已创建的线程降低线程创建和销毁造成的消耗。

(2)提高响应速度。当任务到达时,任务可以不需要等到线程创建就能立即执行。

(3)提高线程的可管理性。线程是稀缺资源,如果无限制的创建,不仅会消耗系统资源,还会降低系统的稳定性,使用线程池可以进行统一的分配,调优和监控。

java多线程的创建方法. 


一.利用一个继承于Thread类的子类来实现

        1.创建一个继承于Thread类的子类

        2.重写Thread类中的run()方法,run方法中是此线程将要执行的操作

        3.在main方法中创建Thread类的子类对象

        4.通过此对象调用start()方法,(start方法就是启动当前线程,调用当前线程的run方法)

二.利用Runnable接口的方式去实现

        1创建一个实现Runnable接口的类

        2.实现类中的run()方法

        3.创建类的对象

        4.将此对象作为参数传递到Thread类的构造器中,创建Thread类的对象

        5.通过Thread类的对象调用start方法

三.实现callable方法

        1.创建callable的实现类

        2.实现call方法,将此线程需要执行的操作放入call方法中

        3.创建callable接口实现类的对象

        4.将此callable接口实现类的对象作为参数传递到futaretask构造器中,创建futaretask对象

        5.将futaretask对象作为参数传递到Thread类的构造器中,创建Thread对象,并调用start方法

四.使用线程池

        1.Executorservice   a=Executor.newFixedThreadpad(),创建a为Executorservice类型的对     象,

        2.通过调用execute()方法,括号中放的是Runnable的实现类

        3.调用shutdown方法

spring的事务机制,


Spring事务的本质其实就是数据库对事务的支持,没有数据库的事务支持,spring是无法提供事务功能的。Spring只提供统一事务管理接口,具体实现都是由各数据库自己实现,数据库事务的提交和回滚是通过 redo log 和 undo log实现的。Spring会在事务开始时,根据当前环境中设置的隔离级别,调整数据库隔离级别,由此保持一致。

spring事务的传播机制说的是,当多个事务同时存在的时候,spring如何处理这些事务的行为。事务传播机制实际上是使用简单的ThreadLocal实现的,所以,如果调用的方法是在新线程调用的,事务传播实际上是会失效的。

① PROPAGATION_REQUIRED:(默认传播行为)如果当前没有事务,就创建一个新事务;如果当前存在事务,就加入该事务。

PROPAGATION_REQUIRES_NEW:无论当前存不存在事务,都创建新事务进行执行。

③ PROPAGATION_SUPPORTS:如果当前存在事务,就加入该事务;如果当前不存在事务,就以非事务执行。‘

④ PROPAGATION_NOT_SUPPORTED:以非事务方式执行操作,如果当前存在事务,就把当前事务挂起。

⑤ PROPAGATION_NESTED:如果当前存在事务,则在嵌套事务内执行;如果当前没有事务,则按REQUIRED属性执行。

⑥ PROPAGATION_MANDATORY:如果当前存在事务,就加入该事务;如果当前不存在事务,就抛出异常。

⑦ PROPAGATION_NEVER:以非事务方式执行,如果当前存在事务,则抛出异常

linux常用命令,


1、help命令

2、pwd命令

3、ls命令

4、du命令

5、mkdir命令

7、cp命令

8、rm命令

9、mv命令

10、which

11、find命令

        11.1第一部分:查找名称查找文件的基本查找命令

        11.2第二部分:根据日期和时间查找文件和目录

        11.3第三部分:根据大小查找文件

12、type命令

13、cat命令

 14、wc命令

15、grep命令

16、tar命令

17、cat命令

 18、chmod命令

 19、ps命令

 20、kill命令

jvm的内存区域.


JDK 1.8 之前

Java面试-2022遇到的面试题_第3张图片

JDK 1.8 之后

Java面试-2022遇到的面试题_第4张图片

线程私有的:

  • 程序计数器
  • 虚拟机栈
  • 本地方法栈

线程共享的:

  • 方法区
  • 直接内存 (非运行时数据区的一部分)

Java 虚拟机规范对于运行时数据区域的规定是相当宽松的。以堆为例:堆可以是连续空间,也可以不连续。堆的大小可以固定,也可以在运行时按需扩展 。虚拟机实现者可以使用任何垃圾回收算法管理堆,甚至完全不进行垃圾收集也是可以的。

你可能感兴趣的:(Java面试,java,面试,jvm)