当前位置: 首页 > article >正文

Java面试黄金宝典3

1. 什么是 NIO

  • 原理

  • 缓冲区(Buffer)
    1. 它是一个线性的、有限的基本数据元素序列,本质上是一块内存区域,被包装成了一个对象,以便于进行高效的数据读写操作。不同类型的基本数据都有对应的Buffer子类,如ByteBufferIntBuffer等。
    2. Buffer有三个重要属性:capacity(容量)、position(位置)和limit(界限)。capacity表示缓冲区的最大容量;position指示下一个要读写的元素的位置;limit表示缓冲区中可以读写的元素的上限。在读写操作过程中,这些属性会动态变化。
  • 通道(Channel)
    1. 通道是双向的,既可以进行读操作,也可以进行写操作,这与传统的流(Stream)不同,流通常是单向的(输入流或输出流)。
    2. 通道可以与多种数据源进行连接,如文件、网络套接字等。例如,FileChannel用于文件的读写,SocketChannel用于网络套接字的读写。
  • 选择器(Selector)
    1. 选择器可以让一个线程同时监听多个通道的事件。它通过Selector对象的select()方法来检查是否有通道发生了感兴趣的事件(如读就绪、写就绪等)。
    2. 当有事件发生时,select()方法会返回发生事件的通道的数量,然后可以通过selectedKeys()方法获取发生事件的通道的SelectionKey集合,进而处理这些通道的事件。

  • 要点

  1. 非阻塞 I/O 模型使得一个线程可以处理多个连接,大大提高了系统的并发处理能力和资源利用率。
  2. 基于缓冲区和通道的操作方式,减少了数据的复制次数,提高了数据传输效率。
  3. 适用于构建高性能的网络服务器,如 HTTP 服务器、即时通讯服务器等。

  • 应用

  1. NIO.2 引入了异步 I/O 操作,通过AsynchronousFileChannelAsynchronousSocketChannel等类,实现了真正的异步文件和网络 I/O,进一步提高了系统的性能和响应速度。
  2. 在实际应用中,Netty 框架是基于 Java NIO 构建的高性能网络编程框架,它简化了 NIO 编程的复杂性,提供了更强大的功能和更好的性能。

2. 什么是 ThreadLocal

  • 原理

  1. ThreadLocal内部维护的ThreadLocalMap是一个自定义的哈希表,它的键是ThreadLocal对象的弱引用。当ThreadLocal对象没有其他强引用时,垃圾回收器会自动回收该对象,从而避免了内存泄漏的风险。
  2. 每个Thread对象都有一个ThreadLocalMap实例,当调用ThreadLocalset()方法时,会首先获取当前线程的ThreadLocalMap,如果ThreadLocalMap为空,则会创建一个新的ThreadLocalMap,并将当前ThreadLocal对象作为键,要存储的值作为值存储到ThreadLocalMap中;当调用get()方法时,会从当前线程的ThreadLocalMap中获取对应的值。

  • 要点

  1. 为每个线程提供独立的变量副本,避免了多线程之间的变量共享问题,提高了代码的线程安全性。
  2. 常用于存储与线程相关的上下文信息,如数据库连接、用户会话信息等。

  • 应用

  1. 在使用ThreadLocal时,需要注意内存泄漏问题。除了及时调用remove()方法清除数据外,还可以使用弱引用的ThreadLocal对象,让垃圾回收器自动回收不再使用的ThreadLocal对象。
  2. 在 Java 8 中,ThreadLocal提供了withInitial()方法,用于创建一个带有初始值的ThreadLocal对象,简化了ThreadLocal的使用。

3. 什么是 finalize, finalization, finally,有什么区别

  • 原理

  1. finalizeObject类中的finalize()方法是一个受保护的方法,当垃圾回收器确定对象没有任何引用时,会在回收对象之前调用该对象的finalize()方法。finalize()方法的目的是让对象在被回收之前有机会进行一些资源清理工作,如关闭文件、释放数据库连接等。
  2. finalization:指的是对象的终结过程,包括垃圾回收器标记对象为可回收对象、调用对象的finalize()方法(如果有的话)以及回收对象占用的内存。
  3. finallyfinally是 Java 中的一个关键字,用于try-catch语句块中。无论try块中的代码是否抛出异常,finally块中的代码都会被执行。这是因为finally块的执行是由 Java 虚拟机(JVM)保证的,即使在trycatch块中使用了returnbreakcontinue语句,finally块中的代码也会在这些语句执行之前被执行。

  • 要点

  1. finalize方法的执行时间不确定,且不保证一定会被调用,因此不建议依赖它进行资源清理。
  2. finalization是对象的整个终结过程,包括多个步骤。
  3. finally用于确保某些代码一定会被执行,常用于资源的释放,如关闭文件、释放数据库连接等。

  • 应用

  1. 在 Java 7 及以后的版本中,引入了try-with-resources语句,它可以自动关闭实现了AutoCloseable接口的资源,进一步简化了资源管理的代码。
  2. 由于finalize()方法的性能开销较大,且可能导致内存泄漏,从 Java 9 开始,finalize()方法被标记为@Deprecated,建议使用其他方式进行资源清理。

4. 什么是 Object

  • 原理

  1. 在 Java 中,所有的类都直接或间接地继承自Object类。这意味着所有的类都可以使用Object类中定义的方法,如equals()hashCode()toString()clone()等。
  2. 当创建一个对象时,该对象会自动继承Object类的所有方法和属性。如果子类没有重写这些方法,则会使用Object类中默认的实现。

  • 要点

  1. Object类是 Java 类层次结构的根,为所有类提供了一些通用的方法,这些方法是 Java 面向对象编程的基础。
  2. 可以将任何类型的对象赋值给Object类型的变量,这体现了 Java 的多态性。

  • 应用

  1. 在实际开发中,经常需要重写Object类的一些方法,以满足特定的业务需求。例如,重写equals()方法可以实现对象内容的比较,重写toString()方法可以方便地输出对象的信息。
  2. Object类的clone()方法用于创建对象的副本,但默认的clone()方法是浅克隆,即只复制对象的基本数据类型和引用,而不复制引用指向的对象。如果需要深克隆,则需要在子类中重写clone()方法。

5. equals 和 == 的区别

  • 原理

  1. ==:对于基本数据类型,==比较的是两个变量的值是否相等;对于引用数据类型,==比较的是两个对象的引用是否相等,即它们是否指向同一个内存地址。
  2. equals:在Object类中,equals()方法的默认实现是比较两个对象的引用是否相等,与==的作用相同。但很多类(如StringInteger等)会重写equals()方法,以实现自定义的内容比较逻辑。例如,String类的equals()方法会比较两个字符串的内容是否相等。

  • 要点

  1. ==比较的是对象的引用或基本数据类型的值,而equals()比较的是对象的内容。
  2. 在比较对象时,应该根据具体需求选择使用==还是equals()方法。

  • 应用

  1. 在重写equals()方法时,通常需要遵循以下几个原则:自反性、对称性、传递性、一致性和非空性。
  2. 重写equals()方法时,通常也需要重写hashCode()方法,以保证相等的对象具有相同的哈希码,这在使用哈希表(如HashMapHashSet等)时非常重要。

6. 什么是 public, private, default, protected,有什么区别

  • 原理

  1. public:被public修饰的类、方法和变量可以被任何其他类访问,无论这些类是否在同一个包中。
  2. private:被private修饰的类、方法和变量只能在其所在的类内部访问,其他类无法直接访问。
  3. default:当没有使用任何访问修饰符时,默认就是default权限。被default修饰的类、方法和变量只能在其所在的包内访问,不同包的类无法访问。
  4. protected:被protected修饰的类、方法和变量可以在其所在的包内访问,也可以在不同包的子类中访问。在不同包的子类中,可以通过子类对象访问父类的protected成员。

  • 要点

  1. public的访问权限最大,private的访问权限最小。
  2. defaultprotected的区别在于,protected允许不同包的子类访问。

  • 应用

  1. 合理使用访问修饰符可以提高代码的封装性和安全性,隐藏类的实现细节,只暴露必要的接口给外部使用。
  2. 在设计类和接口时,应该根据类和成员的使用场景和安全性要求,选择合适的访问修饰符。

7. 什么是异常

  • 原理

  1. 在 Java 中,异常是指程序在运行过程中出现的错误或意外情况,它会导致程序的正常执行流程被打断。Java 中的异常是通过异常类来表示的,所有的异常类都继承自Throwable类。
  2. Throwable类有两个重要的子类:ErrorExceptionError表示系统级的错误,如内存溢出(OutOfMemoryError)、栈溢出(StackOverflowError)等,这些错误通常是不可恢复的,程序无法处理;Exception表示程序可以处理的异常,又分为检查异常(Checked Exception)和非检查异常(Unchecked Exception)。

  • 要点

  1. 异常分为检查异常和非检查异常。检查异常必须在方法的声明中使用throws关键字声明,或者在方法内部使用try-catch语句进行处理;非检查异常(如RuntimeException及其子类)不需要进行声明或处理。
  2. 异常处理可以提高程序的健壮性,避免程序因意外情况而崩溃。

  • 应用

  1. Java 中提供了try-catchtry-with-resourcesthrowsthrow等关键字来进行异常的捕获、处理和抛出。在实际开发中,应该根据具体情况选择合适的异常处理方式。
  2. 自定义异常类可以继承自ExceptionRuntimeException,用于表示特定的业务异常,提高代码的可读性和可维护性。

8. 什么是 Comparable 接口和 Comparator 接口

  • 原理

  1. Comparable 接口:该接口只有一个compareTo()方法,用于定义对象的自然排序规则。实现了Comparable接口的类的对象可以进行比较和排序。compareTo()方法返回一个整数值,如果返回值小于 0,表示当前对象小于参数对象;如果返回值等于 0,表示当前对象等于参数对象;如果返回值大于 0,表示当前对象大于参数对象。
  2. Comparator 接口:该接口有多个方法,常用的是compare()方法,用于定义对象的自定义排序规则。Comparator接口可以在不修改对象类的情况下,为对象提供不同的排序方式。compare()方法的返回值规则与compareTo()方法相同。

  • 要点

  1. Comparable接口是类内部的排序规则,而Comparator接口是类外部的排序规则。
  2. 当需要对对象进行排序时,可以根据具体情况选择使用Comparable接口或Comparator接口。

  • 应用

  1. 在使用Collections.sort()Arrays.sort()方法对对象进行排序时,如果对象类实现了Comparable接口,则可以直接进行排序;如果需要自定义排序规则,则可以传入一个Comparator对象。
  2. Comparator接口还提供了一些静态方法,如comparing()thenComparing()等,用于方便地创建和组合比较器。

9. 什么是接口和抽象类

  • 原理

  1. 接口:是一种抽象类型,它定义了一组方法的签名,但没有提供方法的实现。接口中的方法默认是public abstract的,变量默认是public static final的。一个类可以实现多个接口,通过实现接口中的方法来满足接口的规范。
  2. 抽象类:是一种不能被实例化的类,它可以包含抽象方法(只有方法签名,没有方法体)和具体方法。抽象类的主要作用是为子类提供一个通用的模板,子类必须实现抽象类中的抽象方法,同时可以继承抽象类中的具体方法。

  • 要点

  1. 接口强调的是行为的规范,而抽象类强调的是类的抽象和继承。
  2. 接口用于实现多继承的效果,而抽象类用于代码的复用和扩展。

  • 应用

  1. 在 Java 8 及以后的版本中,接口可以包含默认方法和静态方法,默认方法提供了方法的默认实现,静态方法可以通过接口名直接调用。
  2. 在设计类和接口时,应该根据具体需求选择使用接口还是抽象类。如果需要定义一组规范,让不同的类去实现,并且类之间没有太多的代码复用,可以使用接口;如果需要对一些类进行抽象和复用代码,可以使用抽象类。

10. 什么是 Socket

  • 原理

  1. 客户端(Socket):通过创建Socket对象,指定服务器的 IP 地址和端口号,与服务器建立连接。连接建立后,就可以通过Socket的输入输出流进行数据的读写操作。Socket的输入流用于接收服务器发送的数据,输出流用于向服务器发送数据。
  2. 服务器端(ServerSocket):通过创建ServerSocket对象,指定监听的端口号,等待客户端的连接请求。当有客户端连接时,ServerSocket会返回一个Socket对象,用于与客户端进行通信。服务器端可以通过该Socket对象的输入输出流与客户端进行数据的读写操作。

  • 要点

  1. Socket是基于 TCP 协议的,提供可靠的、面向连接的通信。
  2. 适用于需要确保数据准确传输的场景,如文件传输、邮件发送等。

  • 应用

  1. 除了基于 TCP 协议的Socket,Java 还提供了基于 UDP 协议的DatagramSocketDatagramPacket类,用于实现无连接的、不可靠的网络通信,适用于对实时性要求较高、对数据准确性要求较低的场景,如视频直播、实时游戏等。
  2. 在实际应用中,为了提高网络通信的性能和可扩展性,可以使用线程池来处理多个客户端的连接请求,避免创建过多的线程导致系统资源耗尽。

 友情提示:本文已经整理成文档,可以到如下链接免积分下载阅读

https://download.csdn.net/download/ylfhpy/90496058


http://www.kler.cn/a/592673.html

相关文章:

  • 【Linux】手动部署并测试内网穿透
  • 并发编程面试题三
  • 2000-2016年各省地方财政营业税数据
  • 【人工智能】【Python】在Scikit-Learn中使用网格搜索对决策树调参
  • ROS合集(三)RTAB-Map + EuRoC 数据格式概述
  • 上取整,下取整,四舍五入
  • LS-NET-001-什么是承载网,核心网和接入网
  • 面试总结之 Glide自定义的三级缓存策略
  • 小程序开发与物联网技术的结合:未来趋势
  • 网络编程(客户端间通信)
  • 【2025】基于python+django的小区物业管理系统(源码、万字文档、图文修改、调试答疑)
  • 深入解析 TouchSocket 插件系统架构与实践
  • k8s--集群内的pod调用集群外的服务
  • 穿越是时空之门(java)
  • 《深度学习》—— YOLOv1
  • 突破时空边界:Java实时流处理中窗口操作与时间语义的深度重构
  • 汇编移位指令
  • BERT系列模型
  • 解决下载npm 缓存出现的问题
  • JAVA并发-volatile底层原理