14.三种引用数据类型
答:类、接口、数组
15.new出的对象什么时候回收
通过关键字new创建的对象,由Java的垃圾回收器(Garbage Collector)负责回收。垃圾回收器的工作是在程序运行过程中自动进行的,它会周期性地检测不再被引用地对象,并将其回收释放内存。
具体来说Java对象地回收实际是有垃圾回收器根据一些算法来决定地,主要有以下几种情况:
1.引用计数法:某个对象的引用计数为0时,表示该对象不再被引用,可以被回收
2.可达性分析算法:从根对象(如方法区中的类静态属性、方法中的局部变量等)出发,通过对象之间的引用链进行遍历,如果存在一条引用链到达某个对象,则说明该对象是可达的,反之不可达,不可达的对象将被回收。
3.终结器(Finalizer):如果对象重写了finalize()方法,垃圾回收器会在回收该对象之前调用finalize()方法,对象可以在finalize()方法中进行一些清理操作。然而,终结器机制的使用不被推荐,因为它的执行时间是不确定的,可能会导致不可预测的的性能问题。
16.Java中的代理模式
定义:给目标对象提供一个代理对象,并且由代理对象控制对目标对象的引用
目的:①:功能增强:通过代理业务对原有业务进行增强
②:控制访问:通过代理对象的方式间接的访问目标对象,防止直接访问目标对象给系统带来不必要的复杂性
17.Socket和WebSocket的区别
首先从本质和层级上来说,Socket 其实不是一个协议,而是 TCP/IP 协议栈下的编程接口,是实现网络通信的底层基础 ------ 不管是 TCP 还是 UDP 通信,都得通过 Socket 来做,它就像个 "通信插座",只负责字节流的传输,至于连接怎么建立、数据怎么拆包粘包、怎么保活这些,都得我们开发者自己写代码处理,属于偏底层、通用的通信方式。
而 WebSocket 是基于 HTTP 的应用层协议,它本质上是在 Socket 的基础上做了高层封装,专门解决浏览器和服务器之间双向实时通信的问题。它会先通过一次 HTTP 握手把连接升级成持久化的,之后就能双向收发数据,而且帧格式、心跳保活这些底层细节都已经内置好了,不用我们再手动处理,特别适配 Web 浏览器的场景。
18.Java异常
Throwable:所有异常 / 错误的顶层父类,包含两个直接子类:
-
Error:JVM 层面问题,程序无法捕获 / 修复,只能提前规避;
-
Exception:
程序级异常,可捕获处理,又分两类:
-
受检异常(Checked Exception):编译期强制捕获(如
IOException、SQLException),不处理编译报错; -
非受检异常(Unchecked Exception):运行时异常(
RuntimeException及其子类,如NullPointerException、ArrayIndexOutOfBoundsException),编译期不强制处理,多由代码逻辑错误导致。
-
19.Object类所有的方法
Object 是 Java 所有类的根父类,定义了 11 个基础方法,核心可分为 4 类,以下是极简总结:
1. 对象描述与比较
-
toString()
:默认返回 "类名 @哈希码",重写可自定义对象的可读字符串(如User{name='张三'}`); -
equals(Object obj):默认比较对象地址(==),重写可实现 "内容相等" 判断(如 String 类); -
hashCode():返回对象哈希码,重写 equals 必须重写它,保证哈希表(HashMap)逻辑正确。
2. 对象克隆
clone():创建对象副本,默认浅拷贝(仅复制对象本身,引用属性仍指向原地址),需实现Cloneable接口,否则抛异常。
3. 线程通信
wait()/notify()/notifyAll():配合synchronized实现多线程等待 / 唤醒,需在同步代码块中调用,wait()会释放对象锁。
4. 其他核心方法
-
getClass():返回对象运行时的 Class 对象(反射入口),final 修饰不可重写; -
finalize():GC 回收前的清理方法,已废弃,推荐用try-with-resources释放资源。
20.==和equals()的区别
==对于基本数据类型而言比较的是值是否相同,对于引用数据而言,比较的是引用地址是否相同。
equals()方法不能在基本数据类型当中使用,Object类当中的equals()方法用的是==比较地址是否相同,但是String类重写了equals()方法,先是比较地址是否相同,如果不相同,则比较值是否相同。
21.重写equals()方法为什么重写hashCode()方法
Java语言规范对equals()和hashCode()有明确的契约要求
1.若两个对象通过equals()判定为相等(返回true),则它们的hashCode()必须返回相同的哈希码;
2.若两个对象的hashCode()返回相同的哈希码,它们的equals()不一定相等(允许哈希冲突,但需通过equals()进一步区分)。
只重写equals()会违反第一条契约:equals()认为相等的对象,哈希码却不同,导致哈希集合无法识别重复的元素。只有同时重写 hashCode (),让 "值相等的对象拥有相同的哈希码",才能满足契约要求,保证哈希集合的正确性。
22.String,StringBuilder,StringBuffer之间的区别和联系
首先是联系
三者都是 Java 中用于处理字符串的核心类,底层都基于字符数组(char [])实现,其中 StringBuilder 和 StringBuffer 本质上是为了解决 String 不可变带来的性能问题而设计的 ------ 可以理解为,StringBuilder 是 StringBuffer 的 "轻量版",二者的核心 API(比如 append、insert、replace 等修改字符串的方法)几乎完全一致,只是在线程安全上做了区分。
然后是核心区别,主要分三点:
-
可变性不同:这是最根本的区别。
String 被设计成不可变的(类用 final 修饰,内部存储字符的 value 数组也用 final 修饰),所以每次对 String 做拼接、替换等修改操作,都会生成新的 String 对象,原对象不会被改变;
而 StringBuilder 和 StringBuffer 是可变的,它们内部维护了可扩容的字符缓冲区,所有修改操作都是在原有数组上进行,不会创建新对象,频繁操作时性能远高于 String。
-
线程安全性不同:
String 因为不可变,天然是线程安全的(多线程操作不会修改它的内容);
StringBuffer 的所有方法都加了 synchronized 同步锁,所以是线程安全的,但加锁会带来额外的性能开销;
StringBuilder 没有加任何锁,线程不安全,但性能比 StringBuffer 更高,也是日常单线程场景(比如业务代码里拼接字符串)的首选。
-
性能表现不同:
从快到慢排序:StringBuilder > StringBuffer > String(频繁修改场景)。
只有当字符串完全不需要修改(比如常量定义)时,String 的性能才是最优的;一旦涉及频繁拼接(比如循环里拼接字符串),用 String 会产生大量临时对象,性能极差,这时候必须用 StringBuilder(单线程)或 StringBuffer(多线程)。
简单总结一下
三者都是处理字符串的类,String 不可变、线程安全但修改性能差;StringBuilder 和 StringBuffer 可变、修改性能优,其中 StringBuffer 加锁保证线程安全(性能略低),StringBuilder 无锁(性能高但线程不安全)。日常开发中,单线程用 StringBuilder,多线程共享修改字符串用 StringBuffer,字符串无需修改时用 String 即可。