<b>1、==和 equals 的区别?</b>
1、<b style=""><font style="font-size: 16px;" color="#e74f4c">==</font></b> : 它的作⽤是判断两个对象的<b>地址是不是相等</b>。即,判断两个对象是不是同⼀个对象(基本数据类型==比较的是值,引⽤数据类型==比较的是内存地址)。
2、<b><font style="font-size:16px;" color="#e74f4c">equals()</font><font style="font-size:16px;" color="#ec7270"> </font></b>: 它的作⽤也是判断两个<b>对象是否相等</b>。但是这个相等一般也分两种情况:
3、拓展
1.默认情况:类没有覆盖 equals() ⽅法。则通过 equals() 比较该类的两个对象时,等价于通过==比较这两个对象,还是相当于比较内存地址。
2.自定义情况:类覆盖了 equals() ⽅法。我们平时覆盖的 equals()方法一般是比较两个对象的内容是否相同,自定义了一个相等的标准,也就是两个对象的值是否相等。
2、为什么重写 equals 时<font color="#e74f4c">必须重写 hashCode</font>?
1、因为 <b>Java 的约定要求</b>:两个对象如果 equals 相等,它们的 hashCode<b> 必须相等</b>。如果不重写 hashCode,默认实现(基于内存地址)可能使得两个逻辑相等的对象返回不同的哈希码,导致在使用哈希集合(如 HashMap、HashSet)时出现以下问题:
2、<b>对象存入集合后无法正确检索</b>(可能被放入不同桶中);<br> 集合可能允许重复元素(违反 Set 不重复的语义)。<br>
因此,为了保证基于哈希的集合能正常工作,重写 equals 时必须同时重写 hashCode,确保逻辑相等时哈希码一致。
3、Java是<font color="#e74f4c">值传递</font>,还是引用传递?
1、Java语言是<font color="#e74f4c">值传递</font>。Java 语言的<font color="#e74f4c">方法调用只支持参数的值传递</font>。
2、当一个对象实例作为一个参数被传递到方法中时,<font color="#e74f4c">参数的值</font>就是对该<font color="#e74f4c">对象的引用</font>。对象的属性可以在被调用过程中被改变,但对对象引用的改变是不会影响到调用者的。
4、Java<font color="#e74f4c">创建对象</font>有哪几种<font color="#e74f4c">方式</font>?
2. 使用反射
Class.newInstance()
Constructor.newInstance()
3.使用 clone() 方法
需实现 Cloneable 接口,并重写 clone() 方法(默认为浅拷贝)。
4.使用反序列化
从字节流中恢复对象,需实现 Serializable 接口。
5. 使用 Unsafe.allocateInstance()
通过 sun.misc.Unsafe 分配内存,不调用构造方法(通常不推荐在业务代码中使用)。
5、String怎么转成Integer的?原理?
1、String转成Integer,主要有两个方法:
Integer.parseInt(String s)
Integer.valueOf(String s)
2、不管哪一种,最终还是会调用Integer类内中的
parseInt(String s, int radix)
6、<font color="#e74f4c">Object </font>类的<font color="#e74f4c">常见方法</font>?
3、相关面试题
1. 为什么 wait()、notify() 和 notifyAll() 被定义在 Object 类中,而不是 Thread 类中?
<b>关键点:</b>锁机制与对象关联。
解析:
1.在Java中,每个对象都有一个内置的监视器锁(monitor)。wait() 和 notify() 操作的是当前线程对某个对象锁的等待/通知,它们必须与对象锁绑定。
2.如果定义在 Thread 类中,线程需要知道它正在等待哪个对象的锁,这会使设计更复杂(例如需要传入对象参数)。而定义在 Object 中,线程可以直接调用对象的方法,语义上更自然:线程等待该对象的锁。
3.同时,Java的锁机制是基于对象而非线程的,将相关方法放在 Object 中符合“每个对象都可以作为锁”的设计哲学。
2. 如果只重写 equals() 而不重写 hashCode(),使用 HashMap 会有什么后果?
<b>关键点:</b>哈希表的工作机制。
解析:
1.假设一个类只重写 equals()(基于内容比较),但未重写 hashCode()(仍基于内存地址)。当将该对象作为 HashMap 的键时,两次存储内容相同的对象会得到不同的哈希码,导致它们被放到不同的桶中。
2.结果:即使两个对象逻辑相等,map.get(object1) 可能无法找到 object2 存储的值,因为哈希码不同,无法定位到同一个桶;即使偶发哈希碰撞进入同一桶,equals() 比较也会通过,但存在无法检索的风险。这严重违反了 HashMap 的约定,可能导致内存泄漏和数据混乱。
7、Java 中<font color="#e74f4c">异常处理体系</font>?
1、<font color="#e74f4c">Throwable </font>是 Java 语言中所有错误或异常的<font color="#e74f4c">基类</font>。
2、<font color="#e74f4c">Throwable </font>又分为<font color="#e74f4c">Error</font>和<font color="#e74f4c">Exception</font>
2.1 其中<b>Error是系统内部错误</b>,比如虚拟机异常,是程序无法处理的。
2.2 <b>Exception是程序问题导致的异常</b>,又分为两种:
<b><font color="#e74f4c">CheckedException</font>受检异常</b>:编译器会强制检查并要求处理的异常。
<b><font color="#e74f4c">RuntimeException</font>运行时异常</b>:程序运行中出现异常,比如我们熟悉的空指针、数组下标越界等等
8、Java 中<font color="#e74f4c"> IO流</font>分为几种?
1、流按照不同的特点,有很多种划分方式。
1.按照流的<font color="#e74f4c">流向</font>划分,可以分为<font color="#e74f4c">输入流</font>和<font color="#e74f4c">输出流</font>;
2.按照<font color="#e74f4c">操作单元</font>划分,可以划分为<font color="#e74f4c">字节流</font>和<font color="#e74f4c">字符流</font>;
3.按照流的<font color="#e74f4c">角色</font>划分,可以为<font color="#e74f4c">节点流</font>和<font color="#e74f4c">处理流</font>
2、<b>Java Io流</b>共涉及<b>40多个类</b>,看上去杂乱,其实都存在一定的关联, Java I0流的40多个类都是从如下<b>4个抽象类基类中派生出来的</b>。
<b>1.InputStream/Reader:</b> 所有的<b>输入流的基类</b>,前者是<b>字节</b>输入流,后者是<b>字符</b>输入流。
<b>2.OutputStream/Writer: </b>所有<b>输出流的基类</b>,前者是<b>字节</b>输出流,后者是<b>字符</b>输出流。
9、<font color="#e74f4c">BIO</font>、<font color="#e74f4c">NIO</font>、<font color="#e74f4c">AIO</font>?
1、BIO(blocking I/O) :
就是传统的IO,<b>同步阻塞</b>,服务器实现模式为<b>一个连接一个线程</b>,即客户端有连接请求时服务器端就需要启动一个线程进行处理,如果这个连接不做任何事情会造成不必要的线程开销,可以通过连接池机制改善(实现多个客户连接服务器)。
2、NIO ( java non-blocking IO)
是指 JDK 提供的新 API。从JDK1.4开始,Java 提供了一系列改进的输入/输出的新特性,被统称为NIO(即New IO)。
NIO是<b>同步非阻塞</b>的,服务器端用<b>一个线程处理多个连接</b>,客户端发送的连接请求会注册到多路复用器上,多路复用器轮询到连接有IO请求就进行处理(NIO的数据是面向缓冲区Buffer的,必须从Buffer中读取或写入)
3、AIO:
<b>JDK 7 </b>引入了 Asynchronous I/O,是<b>异步非阻塞</b>的 IO。在进行 I/O 编程中,常用到两种模式:Reactor 和 Proactor。
Java 的 NIO 就是 <font color="#e74f4c">Reactor</font>,当有事件触发时,服务器端得到通知,进行相应的处理,完成后才通知服务端程序启动线程去处理,<b>一般适用于连接数较多且连接时间较长的应用</b>。
10、Java <font color="#e74f4c">泛型</font>了解么?什么是类型擦除?介绍一下常用的通配符?
1、什么是泛型?
1.概述
Java 泛型(generics)是 <b>JDK 5 </b>中引入的一个新特性, 泛型提供了编译时类型安全检测机制,该机制允许程序员在编译时检测到非法的类型。泛型的本质是参数化类型,也就是说所操作的数据类型被指定为一个参数。
2.泛型使用方式:
泛型一般有三种使用方式:<b>泛型类</b>、<b>泛型接口</b>、<b>泛型方法</b>。
3.泛型常用的通配符有哪些?
常用的通配符为: <font color="#e74f4c">T</font>,<font color="#e74f4c">E</font>,<font color="#e74f4c">K</font>,<font color="#e74f4c">V</font>,<font color="#e74f4c">?</font>
2、什么是泛型擦除?
1.概述
所谓的泛型擦除,官方名叫类型擦除。所谓的泛型擦除,官方名叫类型擦除。
Java 的泛型是伪泛型,这是因为 Java 在编译期间,所有的类型信息都会被擦掉。
也就是说,<b>在运行的时候是没有泛型的。</b>
2.为什么要类型擦除呢?
主要是为了<b>向下兼容</b>,因为JDK5之前是没有泛型的,为了让JVM保持向下兼容,就出了类型擦除这个策略。
11、说一下你对<font color="#e74f4c">注解</font>的理解?
1、概述
<b>注解</b>(Annotation)是Java提供的一种<b>元数据机制</b>,用于为代码(类、方法、字段等)添加描述性信息。它<b>本质上是一种特殊的接口</b>,本身不直接改变程序行为,但可以通过编译器或运行时框架读取并做出相应处理。
2、详解
1.基本作用
<b>1.编译检查:</b>如@Override让编译器验证方法是否正确重写。
<b>2.代码分析:</b>通过注解生成文档、代码模板等。
<b>3.框架配置:</b>取代繁琐的XML配置,如Spring的@Autowired、@Controller。
<b>4.运行时处理:</b>通过反射读取注解,实现动态逻辑,如JUnit的@Test。
2.内置注解
Java标准库提供了常用注解,例如@Override、@Deprecated、@SuppressWarnings等,它们定义在java.lang包中。
3.元注解
用于注解其他注解,说明注解的保留策略、作用目标等。包括@Retention(指定注解保留到源码、字节码还是运行时)、@Target(限定注解可用于哪些程序元素)、@Documented、@Inherited等。
4.自定义注解
开发者可以根据业务需求创建自己的注解。例如:
5.注解的读取
<b>编译时处理:</b>通过注解处理器(APT)在编译阶段生成代码。
<b>运行时处理:</b>通过反射获取注解信息,执行相应逻辑。
12、什么是<font color="#e74f4c">反射</font>?应用?原理?
1、什么是反射
1.我们通常都是利用new方式来创建对象实例,这可以说就是一种正射,这种方式在编译时候就确定了类型信息。而如果,我们想<b>在运行的时候动态地获取类信息、创建类实例、调用类方法</b>,这时候就要用到<b>反射</b>。
2.通过反射你可以获取任意一个类的所有属性和方法,你还可以调用这些方法和属性。
3、反射的原理
反射就是<b>利用JVM运行时为每个类维护的Class对象</b>,<b>从中提取成员元数据,并基于这些元数据在运行时动态解析和调用成员</b>,从而让程序在运行时获得内省和操作能力。
4、反射的应用
1.框架与中间件开发(最核心)
<b>Spring/MyBatis等</b>:通过读取XML或注解配置的类名,利用Class.forName()动态创建和管理Bean,实现依赖注入。无需硬编码,框架代码与业务代码解耦。
<b>Tomcat等容器</b>:动态加载和实例化Servlet,管理其生命周期。
2.开发通用工具与库
<b>JSON转换库(如Jackson、Gson)</b>:通过反射读取对象字段名和值,自动拼装成JSON字符串,或将JSON数据填充回任意类型对象。
<b>对象关系映射(ORM)</b>:将数据库查询结果集通过反射自动映射到实体类的属性上,避免手动写getter/setter赋值。
3.集成开发环境(IDE)与调试工具
<b>代码提示与自动补全:</b>IDE通过反射分析当前作用域内对象所属的类,实时获取其可用方法、字段列表供开发者选择。
<b>通用调试器:</b>无论对象是什么类型,调试工具都能通过反射遍历其内部状态并展示。
4.动态配置与热加载
通过配置文件指定具体实现类,程序启动时用反射实例化。修改配置后,可重新用反射创建新类实例,实现功能的热插拔,无需重启应用。
5.注解处理
<b>JUnit测试框架:</b>查找被@Test注解标记的方法,并通过反射动态执行它们。
<b>自定义业务注解:</b>在运行时通过反射获取类/方法上的注解,执行相应逻辑(如权限校验、日志记录)。
13、<font color="#e74f4c">Lambda 表达式</font>了解多少?
1、概述
Lambda 表达式是 <b>Java 8</b> 引入的重要特性,它标志着 Java <b>对函数式编程风格的支持</b>。简单来说,Lambda 允许我们<b>将一段代码(行为)像数据一样传递</b>,从而写出更简洁、灵活的代码。
2、核心概念
Lambda 表达式<b>本质</b>上是一个<b>匿名函数</b>:它没有名称,但有参数列表、函数主体和返回类型。它主要<b>用来简洁地表示函数式接口的实例</b>(即只有一个抽象方法的接口,如 Runnable、Comparator)。
3、基本语法
(参数列表) -> { 方法体 }
5、函数式接口
Lambda 表达式需要依赖函数式接口(Functional Interface)。Java 8 为常用场景提供了一些内置函数式接口,例如:
也可以自定义,加上 @FunctionalInterface 注解确保只有一个抽象方法。
14、<font color="#e74f4c">Optional</font>了解吗?
Optional是用于防范<font color="#e74f4c">NullPointerException</font>。
可以将 Optional 看做是<b>包装对象</b>(可能是 null, 也有可能非 null)的容器。当我们定义了 一个方法,这个方法返回的对象可能是空,也有可能非空的时候,我们就可以考虑用 Optional 来包装它,这也是在 Java 8 被推荐使用的做法。
15、<font color="#e74f4c">Stream </font>流用过吗?
Stream 流,简单来说,使用 java.util.Stream 对一个包含一个或多个元素的集合做各种操作。这些操作可能是<b>中间操作</b> 亦或是<b>终端操作</b>。 终端操作会返回一个结果,而中间操作会返回一个 Stream 流。
16、说说JDK <font color="#e74f4c">动态代理</font>和 <font color="#e74f4c">CGLIB 代理 </font>?
1、概述
<b>Spring</b>的<b>AOP</b>是通过<b>动态代理</b>来实现的,动态代理主要有两种方式JDK动态代理和Cglib动态代理,这两种动态代理的使用和原理有些不同。
2、<font color="#e74f4c">JDK 动态代理</font>
<b>1.原理:</b>基于接口代理。通过java.lang.reflect.Proxy类和InvocationHandler接口,在运行时为目标接口动态生成代理类。代理类实现目标接口,并将方法调用转发给InvocationHandler的invoke方法。
<b>2.要求:</b>目标对象必须实现至少一个接口。
<b>3.优点:</b>JDK原生支持,无需引入第三方库;性能较高(Java 8+后优化明显)。
<b>4.缺点:</b>只能代理接口中的方法,无法代理没有接口的类。
3、<font color="#e74f4c">CgLib 动态代理</font>
<b>1.原理:</b>基于继承代理。通过字节码生成框架(CGLIB)动态生成目标类的子类,子类重写父类方法,并在重写的方法中植入增强逻辑。
<b>2.要求:</b>目标类不能是final的,被代理的方法也不能是final或static。
<b>3.优点:</b>可以代理没有接口的普通类。
<b>4.缺点:</b>需要引入CGLIB依赖(Spring已内置);创建代理对象比JDK稍慢,但方法调用性能差异不大。
4、总结:
JDK动态代理是基于接口的官方方案,简洁高效;CGLIB是基于继承的补充方案,更灵活。选择哪种取决于目标类是否有接口。