Java中高难度的面试题长什么样???

Java基础

Java中有强引用和弱引用虚引用他们之间有什么区别?

强引用、弱引用和虚引用在Java中用于不同的垃圾回收策略。强引用(StrongReference)是最常用的,垃圾回收器不会回收它们指向的对象,除非强引用被显式清除。弱引用(WeakReference)允许垃圾回收器在对象没有强引用时回收它们,但在对象被回收之前,它们仍然可以被访问。虚引用(PhantomReference)用于跟踪对象被垃圾回收器处理后的状态,它们不影响对象的生命周期,只能用于在对象被垃圾回收时进行一些清理操作。

Java里面所有的类都会继承Object类,里面有个wait()方法和finalize()方法,他们是干嘛的

wait() 方法是用于线程间通信,允许当前线程等待直到其他线程调用 notify() 或 notifyAll()。finalize() 方法是对象被垃圾回收前调用的方法,用于进行资源清理操作,但现代Java中建议使用 try-with-resources 结构代替它。

Java虚拟机如何判断怎么判断哪些对象是可以回收的呢?

  • 引用计数法
    原理:每个对象维护一个计数器,记录有多少引用指向该对象。当计数器为零时,对象即被认为不可达,可以被回收。
    优点:实现简单,实时性高。
    缺点:无法处理循环引用,即两个对象互相引用,计数器永远不会归零。

  • 可达性分析法
    原理:从一组称为 GC Roots 的对象出发,遍历所有可达的对象。未被遍历到的对象被认为不可达,可以回收。
    优点:能够处理循环引用问题。
    缺点:实现较复杂,可能导致暂停时间较长。

Java创建对象有的分配在堆 有的分配在栈上?为什么?

堆:用于存储对象实例和数组,堆内存是动态分配的,适合长期存储对象。在堆上分配的对象具有较长的生命周期,可以跨多个方法调用和线程使用。

栈:用于存储方法的局部变量和方法调用的状态,栈内存是线程私有的,生命周期短。局部变量包括基本数据类型和对象的引用,引用指向堆中的对象。

分配在堆上的对象便于在多个方法和线程间共享,而栈上的数据则具有较短的生命周期,适合方法调用和局部变量的快速处理。

int类型的数组存放在哪里?

int 类型的数组存放在 上。在Java中,数组,无论是基本数据类型的数组还是对象的数组,都是在堆上分配内存的。栈上只存储对数组的引用。

解决哈希冲突有哪些方法(常见的三种)

1. 链接法(Chaining)
原理:
将哈希表的每个桶(或槽)看作一个链表。当发生哈希冲突时,将所有映射到同一桶的元素添加到该桶的链表中。
每个桶实际上是一个链表的头部,哈希表的每个槽都可以包含一个链表的引用。
优点:
动态调整:能够处理动态数据集,即使有大量的冲突也能有效地扩展。
插入和删除操作较为简单。
缺点:
当链表长度增加时,查询操作可能变慢。
需要额外的存储空间来维护链表。

2. 开放寻址法(Open Addressing)
原理:
当发生冲突时,通过探测(或搜索)来寻找下一个可用的位置。常用的探测策略有:
线性探测:按线性序列(例如,当前位置 + 1, 当前位置 + 2, …)检查下一个位置。
二次探测:使用二次函数(例如,当前位置 + i^2, 当前位置 + (i + 1)^2, …)来确定下一个位置。
双重哈希:使用两个哈希函数来计算探测序列。
优点:
相比于链接法,空间利用率更高,因为不需要额外的链表存储空间。
查询速度通常较快。
缺点:
可能会出现“聚集”现象,即相邻的位置可能会发生冲突,导致探测效率下降。
删除操作可能变得复杂,需要特别的处理。

3. 再哈希法(Rehashing)
原理:
当哈希表的负载因子(即存储的元素数与桶的数量之比)超过某个阈值时,重新计算哈希表的大小,并将所有元素重新哈希到新的表中。
再哈希时,通常会选择一个更大的表,并将原表中的元素重新分配到新的哈希表中。
优点:
能够减少冲突的发生,提高哈希表的性能。
通过增加桶的数量,可以减小链表的长度(在链接法中)或减少探测长度(在开放寻址法中)。
缺点:
再哈希的过程可能很耗时,需要重新计算所有元素的位置。
实现起来比较复杂,需要处理再哈希的细节和负载因子的管理。

重写equals()和hashCode()什么时候

自定义对象比较: 当你需要在集合中使用自定义对象(如 HashSet 或 HashMap),并希望基于对象内容进行比较而不是默认的引用比较时。此时,equals() 确保对象相等的定义,hashCode() 确保对象的哈希值一致。

作为集合键值: 如果你的自定义对象被用作集合(如 HashMap)的键,必须重写这两个方法以保持一致性。equals() 确保键的等价性,hashCode() 确保键的有效性和分布。

保持一致性: 当 equals() 方法被重写时,hashCode() 也必须重写,确保相等对象的哈希值相同。违反这一原则会导致哈希表行为异常。

实现比较逻辑: 如果你的对象有特定的业务规则来定义“相等”,如通过多个字段来比较对象的等价性,你需要重写这两个方法以实现自定义的比较逻辑。

HashMap为什么不是线程安全?

1. 没有同步机制
HashMap 的内部结构(即哈希表和链表)没有内建的同步机制来防止多个线程同时访问和修改。这意味着,在多个线程并发执行写操作(如 put 或 remove)时,可能会出现数据竞争、丢失更新或其他不一致的情况。

2. 不支持并发一致性
HashMap 的方法在并发情况下不能保证一致性。例如,若一个线程在 HashMap 中插入一个新条目,而另一个线程同时读取该条目,可能会得到一个不完整或不一致的视图。这是因为 HashMap 不保证在并发环境中操作的原子性和可见性。

3. 链表操作不安全
在 HashMap 中,冲突的元素存储在链表中。多个线程对同一桶进行操作时(例如,插入或删除),可能会导致链表的结构不一致。若在一个线程中删除链表节点而另一个线程同时遍历链表,会引发异常或产生不可预测的行为。

4. 扩容操作问题
HashMap 在需要扩容时(即,桶的数量增加)会重新计算所有现有条目的位置,并重新分配到新的哈希表中。在并发环境下,这种操作可能会导致数据丢失或不一致,因为扩容涉及到多个操作,且这些操作不是原子的。
不仅仅是没有 syconnize 关键字 头插法和尾插法等

怎么判断一个类是不是线程安全?

1. 是否使用了适当的同步机制
内置同步:线程安全的类通常会在其方法内部使用同步机制,如 synchronized 关键字,确保在多线程环境下的操作是原子的。
显式锁:类可能使用显式锁(如 ReentrantLock)来管理对共享资源的访问。
原子变量:类可能使用 java.util.concurrent.atomic 包中的原子类(如 AtomicInteger, AtomicReference)来实现线程安全操作。

2. 不变性(Immutability)
不可变对象:如果一个类的实例在创建后不能被修改(即它是不可变的),那么它是线程安全的。例如,String 和 Integer 类就是不可变的,所以它们在多线程环境中是安全的。

3. 使用线程安全的数据结构
内建线程安全:类可能使用线程安全的数据结构,如 ConcurrentHashMap, CopyOnWriteArrayList 等。这些类专为并发设计,能够处理多线程环境中的操作而不需要外部同步。

4. 方法的同步策略
原子性:检查方法是否确保操作的原子性。如果多个线程可以同时调用方法而不引发数据竞争,则这个类可能是线程安全的。
可见性:确保一个线程对共享数据的修改对其他线程是可见的。如果类的字段更新被恰当地同步,确保所有线程能够看到最新的数据,则它是线程安全的。

怎么判断一个类是否支持有序性操作?

实现细节:检查类的实现,确定它是否维护了元素的顺序。例如,TreeSet 会按照自然排序或指定的比较器排序元素。

方法行为:观察类的方法行为,是否能保持操作顺序。比如,LinkedList 支持按插入顺序遍历元素。

HashMap如何变成是线程安全的?有几种区别?他们之间有什么区别

使用 Collections.synchronizedMap:
方式:使用 Collections.synchronizedMap(new HashMap<>()) 创建一个线程安全的 Map。
区别:所有对该 Map 的操作都被同步(通过内部锁),确保线程安全,但可能会导致性能下降。

使用 ConcurrentHashMap:
方式:直接使用 ConcurrentHashMap,它是设计为线程安全的。
区别:ConcurrentHashMap 在内部使用分段锁和非阻塞的操作,比 Collections.synchronizedMap 性能更好,尤其是在高并发环境下。

使用 ConcurrentSkipListMap:
方式:使用 ConcurrentSkipListMap,它是一个线程安全的、有序的 Map 实现。
区别:除了线程安全外,ConcurrentSkipListMap 还保持键的排序,适合需要有序性的场景。

MySQL

索引是什么?它的底层实现 b+树

索引 是一种数据库技术,用于提高数据检索的效率。它类似于书籍中的目录,可以快速找到书中某个章节的位置。在数据库中,索引是一个数据结构,用于加快对数据库表中数据的检索速度。

索引的作用
加速查询:通过索引,可以显著提高对表中数据的查询速度。
优化排序:索引可以帮助快速完成排序操作。
加速连接:在多表连接操作中,索引可以提高连接的速度。

B+树(B Plus Tree)作为索引的底层实现
B+树 是一种自平衡的树数据结构,广泛用于数据库和文件系统的索引实现中。它的特点包括:
平衡性:B+树是一种平衡树,所有的叶子节点都在同一层,这保证了从根节点到任何叶子节点的路径长度相同,从而保证了查询效率的一致性。
多路平衡:与二叉搜索树不同,B+树的每个节点可以有多个子节点。这种多路特性使得树的高度较低,从而减少了磁盘I/O操作次数,提高了查询效率。
排序:B+树的叶子节点是按照键值的顺序链接在一起的,这使得范围查询和排序操作非常高效。
节点分裂和合并:在插入和删除操作时,B+树会自动进行节点的分裂和合并操作,以维持树的平衡性。

事务是什么?

事务底层原理

  1. 日志机制
    事务操作前,会先记录到日志中。这样即使系统崩溃,也能通过日志恢复数据:

重做日志:记录所有的修改操作,崩溃后恢复数据。
撤销日志:记录如何撤销修改,用于事务回滚。
2. 锁机制
锁机制确保事务在并发操作中不会出现冲突:

共享锁:允许读取,但不允许修改。
排他锁:只允许一个事务访问,阻止其他事务读写。
意向锁:通知系统即将加锁的意图。
3. 隔离级别
控制事务间的相互影响:

读未提交:可以读取其他事务的未提交数据(可能脏读)。
读已提交:只读取已提交的数据,避免脏读。
可重复读:同一事务内读取的数据一致,避免脏读和不可重复读。
串行化:最严格的隔离级别,完全顺序化事务,避免所有并发问题。
4. 幻读
幻读是指在同一事务中多次读取时,结果因为其他事务的插入或删除而不同。串行化隔离级别可以避免幻读。

  1. 原子性和一致性
    原子性:事务要么完全成功,要么完全失败。
    一致性:事务执行后,数据库保持一致的状态。
  2. 持久性
    事务一旦提交,所有修改都应该永久保存,即使系统崩溃也不丢失。

并发事务
并发事务是指多个事务同时执行。为了避免数据冲突和保持一致性

ACID

  1. 原子性(Atomicity)
    原子性保证了事务中的所有操作要么全部完成,要么完全不做。事务是一个不可分割的操作单元。如果事务在执行过程中发生错误,数据库会回滚到事务开始前的状态,确保数据库的一致性不受影响。

  2. 一致性(Consistency)
    一致性确保事务的执行不会破坏数据库的完整性约束。事务开始前和结束后,数据库必须处于一致的状态。例如,转账操作应当确保在扣款账户和充值账户之间的金额总和保持不变。

  3. 隔离性(Isolation)
    隔离性确保一个事务的执行不会被其他事务的操作干扰。不同事务之间的操作是隔离的,即使多个事务并发执行,也不会对彼此造成干扰。隔离性可以通过设置不同的隔离级别来实现,常见的隔离级别有:

  4. 持久性(Durability)
    持久性保证了事务一旦提交,其所做的更改会永久保存在数据库中,即使系统崩溃也不会丢失。数据库系统通过日志记录和数据备份等技术来实现持久性。

隔离级别
读未提交(Dirty Read)
读已提交(Read Committed)
可重复读(Repeatable Read)
串行化(Serializable)

范式

  1. 第一范式(1NF)
    第一范式要求表中的每一列都是原子的,即列中不能有重复的组或多值属性。

  2. 第二范式(2NF)
    第二范式要求表满足第一范式,并且每个非主属性完全依赖于主键,消除部分依赖。

  3. 第三范式(3NF)
    第三范式要求表满足第二范式,并且所有非主属性都直接依赖于主键,而不是间接依赖于主键,消除传递依赖。

计算机网络

TCP三次握手

  1. SYN:客户端发送连接请求
    客户端向 服务器 发送一个 SYN(同步)包,表示请求建立连接。这个包包含一个初始序列号 Seq,用于同步双方的序列号。
    状态:客户端进入 SYN_SENT 状态。

  2. SYN-ACK:服务器确认请求
    服务器收到 SYN 包后,向 客户端 发送一个 SYN-ACK 包。这个包包含:
    一个确认号 Ack,值为客户端的序列号加 1,表示确认收到客户端的 SYN 包。
    服务器自己的初始序列号 Seq,用于同步双方的序列号。
    状态:服务器进入 SYN_RECEIVED 状态。

  3. ACK:客户端确认
    客户端收到服务器的 SYN-ACK 包后,向 服务器 发送一个 ACK(确认)包,确认号 Ack 为服务器的序列号加 1,表示连接建立确认。
    状态:客户端进入 ESTABLISHED 状态,表示连接已建立。

如果三次握手中间断开了会如何?

客户端发送 SYN 包后:

如果服务器未能接收到 SYN 包或无法响应,客户端会在超时时间内重试,直到达到重试次数限制。超时后,客户端会报告连接失败。
服务器收到 SYN 包但无法发送 SYN-ACK 包:

如果服务器在发送 SYN-ACK 包的过程中发生错误或网络中断,客户端可能无法收到响应。客户端在超时后会重试连接,或者最终报告连接失败。
客户端收到 SYN-ACK 包但无法发送 ACK 包:

如果客户端收到 SYN-ACK 包但无法发送 ACK 包(如网络中断或客户端故障),服务器在超时后会放弃连接请求,客户端也会最终报告连接失败。
在这种情况下,双方都不会进入 ESTABLISHED 状态,连接不会建立

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值