文章目录
- 1、intern()方法
- 2、try...catch...finally
- 3、hashCode和equals的关系
- 4、什么是反射,反射有什么缺点?
- 5、BIO(同步阻塞)、NIO(同步非阻塞)、AIO(异步非阻塞)的区别
- 6、**面向对象的理解?**
- 7、什么是抽象类?
- 8、什么是接口?
- 9、抽象类和接口的区别?
- 10、什么是泛型?
- 11、异常
- 12、注解
- 13、反射
- 14、static和final的区别?以及分别存储在JVM的哪个区域?
- 15、Linux的五种IO模型
- 16、Reactor线程模型详解
- 17、IO零拷贝
1、intern()方法
“ab”.intern():这个方法会首先检查字符串常量池中是否有”ab”这个字符串,如果存在则返回这个字符串常量池中的引用,否则就将这个字符串在堆中的引用添加到字符串常量池中,然后返回这个常量常量池中字符串的引用。以下代码是在jdk1.8中测试,jdk1.6会有所不同。
publicstaticvoidmain(String[]args){// 创建2个对象,一个String对象在堆中,一个String常量在常量池Strings=newString("2");// 判断s是否在常量池中,存在则返回常量池中对象的引用,此时intern指向常量池中的对象Stringintern=s.intern();// s2字符串在常量池中,所以返回常量池中的对象引用Strings2="2";// s:为堆中对象 s2:为常量池对象 所以:falseSystem.out.println(s==s2);// false// intern和s2都是指向常量池中的字符串,所以:trueSystem.out.println(intern==s2);// trueSystem.out.println(s==intern);//falseSystem.out.println("------------------------");// 创建4个对象:堆中"33","3","3"对象,常量池:"3"对象Strings3=newString("3")+newString("3");// 判断s3是否在常量池中,不存在则将s3加入常量池中,并且常量池中保存的是s3的引用,返回常量池中对象的引用,此时s3和intern2指向同一个对象Stringintern2=s3.intern();// s4字符串在常量池中,所以返回常量池中的对象引用Strings4="33";// s3和intern2和s4指向的是同一个对象System.out.println(s3==s4);// trueSystem.out.println(intern2==s3);// trueSystem.out.println(intern2==s4);// trueSystem.out.println("------------------------");// 创建4个对象:堆中"33","3","3"对象,常量池:"3"对象Strings5=newString("3")+newString("3");// s6字符串不在常量池中,将字符串放入字符串常量池中,此时与堆中的引用不同Strings6="33";// 判断s5是否在常量池中,存在Stringintern3=s5.intern();System.out.println(s5==s6);// falseSystem.out.println(s6==intern3);// trueSystem.out.println(s5==intern3);//false}2、try…catch…finally
return 先把【要返回的值】保存起来;然后执行 finally;finally 里如果重新 return,会覆盖返回值;finally 仅修改变量不 return,不会改变已经保存好的返回值。
// 返回 40publicstaticintfun(){inta=10;try{System.out.println(a/0);a=20;// return a;}catch(Exceptione){a=30;returna;}finally{a=40;returna;}}// 返回 30publicstaticintfun(){inta=10;try{System.out.println(a/0);a=20;// return a;}catch(Exceptione){a=30;returna;}finally{a=40;}returna;}// 返回 30publicstaticintfun(){inta=10;try{System.out.println(a/0);a=20;returna;}catch(Exceptione){a=30;returna;}finally{a=40;}}3、hashCode和equals的关系
约定:
- 如果
equals(a,b) == true,那么a.hashCode()必须等于b.hashCode() - 如果
a.hashCode() == b.hashCode(),不代表equals(a,b)==true(哈希碰撞) - 如果
equals重写了,一定要重写 hashCode,否则破坏约定!
使用Object.hashCode,是根据随机算法生成的hashCode值(hash碰撞),无法保证两个对象equals相等的时候,hashCode也相等。
重写equals时,必须要重写hashCode原因:像一些集合容器map,在进行比较两个对象相等的判定条件是hashcode和equals都相等,所有在重写equals时,必须要重写hashCode,才能保证集合容器的正确使用。
Object 默认 hashCode ():native 方法,生成 identity hash code,存在对象头 mark word,不是内存地址;
Object默认equals():默认==,比较对象地址;
4、什么是反射,反射有什么缺点?
反射是指在程序运行时动态获取类的信息、调用类的方法、访问类的属性等操作能力。在Java中,反射允许程序在运行时检查和操作类、方法、字段等,使得程序可以在运行时动态地创建对象、调用方法、修改属性等。
优点:运行时动态操作类,解耦,实现通用框架,可以访问私有成员
缺点:性能低,破坏封装,编译不校验,问题运行才暴露;
setAccessible(true)是修改访问权限吗?
答案:不是修改源码的 private 修饰符,只是关闭 JDK 的访问权限检查。
5、BIO(同步阻塞)、NIO(同步非阻塞)、AIO(异步非阻塞)的区别
- 同步:应用线程主动发起 IO 拷贝,将内核数据拷贝到应用内存中(read/write)
- 异步:内核读完数据从内核到应用内存,才主动回调通知应用
- 阻塞:调用IO等API时没有数据,线程挂起
- 非阻塞:没有数据直接返回,不卡线程
同步异步关键:IO 数据拷贝是谁来做;阻塞非阻塞:调用 API 无数据会不会卡住线程。
BIO 是同步阻塞 IO,一连接一线程。来一个客户端就新建一个线程,线程阻塞在 read,连接多线程爆炸,适合连接数少场景。
NIO 是同步非阻塞 IO,基于多路复用(Linux 底层 epoll)。少量线程监听大量连接,Selector 监听 fd 就绪事件;内核通知就绪后,应用线程自己调用 read 拷贝数据,Netty 底层就是 NIO,适合高并发长连接。
AIO 是异步非阻塞 IO。应用发起读请求直接返回,内核把数据全部拷贝到用户缓冲区后回调通知程序;Linux 原生 AIO 有缺陷,Java 很少落地。
6、面向对象的理解?
面向对象(OOP)是一种编程思想,把程序看作多个对象的交互,面向对象的核心是将现实世界的实体抽象为代码中的’对象’,每个对象包含数据(属性)和操作数据的方法,形成高内聚低耦合的模块。这样设计更符合人类思维方式,让程序结构更清晰。它有四大特性:
- 封装:将数据和方法封装在类内部,隐藏内部细节,只暴露必要接口,提高安全性和维护性,降低耦合。
- 继承:子类复用父类代码,建立类之间的层次关系。extends关键字,Java只有单继承,接口可以多实现。
- 多态:同一接口(行为),不同对象有不同实现,提高代码灵活性、拓展性。extends/implement 都是实现方式。编译时多态:方法重载,运行时多态:方法重写。
- 抽象:抽取通用规范,只定义方法签名,让子类实现。抽象类(abstract class)、接口(interface)。
面向过程关注怎么做(步骤);面向对象关注谁来做(对象)。
在过往的项目中,面向对象的思想和特性帮助我们:快速响应需求变更、降低代码维护成本、提高代码质量。但我们也要平衡面向对象与其他范式(函数式编程)的优势,防止过度设计,增加系统的复杂度。
7、什么是抽象类?
抽象类是用来捕捉子类通用特性的类,它不能被实例化,只能作为其他类的父类。
抽象类特点:
- 用
abstract关键字声明 - 可以包含抽象方法和具体方法
- 可以有构造方法、成员变量
- 子类继承使用
extends - 一个类只能继承一个抽象类(单继承)
8、什么是接口?
接口是行为的抽象,定义了一组方法规范,实现类必须遵守这些规范。
接口特点:
- 用
interface关键字声明 - Java 8之前:只能有抽象方法和常量
- Java 8+:可以有默认方法、静态方法
- Java 9+:可以有私有方法
- 实现类使用
implements - 一个类可以实现多个接口
9、抽象类和接口的区别?
- 设计理念不同:抽象类是’is-a’关系(继承),接口是’has-a’关系(组合)
- 单继承 vs 多实现:Java中类只能继承一个父类,但可实现多个接口
- 抽象类可以有构造方法和具体实现,早期接口只能有抽象方法
- 成员变量方面,抽象类可以是普通变量,接口只能是常量
10、什么是泛型?
Java 泛型(generics)是 JDK 5 中引入的一个新特性, 泛型提供了编译时类型安全检测机制,该机制允许程序员在编译时检测到非法的类型。
泛型的本质是参数化类型,也就是说所操作的数据类型被指定为一个参数。
好处:1.可以将运行期的异常提前到编译期;2.消除强制类型转换;3.提高了类型安全
泛型的三种方式:泛型类,泛型接口,泛型方法
11、异常
Java中所有异常和错误的根类是Throwable,它有两个直接子类:Error和Exception(受检异常 or 非受检异常)。
- 定义:异常是程序运行过程中发生的不正常事件,会打断正常的指令流。
- 分类:分为受检异常和非受检异常(错误和运行时异常)。
- 异常处理机制:try-catch-finally,throw和throws。
- 自定义异常:可以通过继承Exception或RuntimeException来创建自定义异常。
- 最佳实践:例如,不要吞掉异常,不要使用异常控制流程,使用具体的异常类型等。
常见运行时异常:
NullPointerException
空指针异常,JAVA8中可用Optional来避免,一般是代码中出现了空对象时,抛出该异常IndexOutOfBoundsException
数组下标越界异常,当使用的数组下标超出数组允许范围时,抛出该异常ClassCastException
类型转换异常,当试图将对象强制转换为不是实例的子类时,抛出该异常NumberFormatException
数字格式化异常,当试图将一个String转换为指定的数字类型,而该字符串确不满足数字类型要求的格式时,抛出该异常JSONException
JSON异常,进行JSON格式化操作时出现异常,会抛出该异常ArithmeticException
算术异常
常见检查性异常:
- SQLException
SQL异常 - IOException
IO异常,在对流操作时有可能会出现的异常 - FileNotFoundException
找不到某个文件时,会抛出该异常 - ClassNotFoundException
找不到某个类时,会抛出该异常 - InterruptedException
中断异常
- SQLException
12、注解
Java 注解(Annotation)又称 Java 标注,是 JDK5.0 引入的一种注释机制。继承自java.lang.annotation.Annotation。注解本身不影响代码逻辑,但可以通过反射获取注解信息。
packagejava.lang.annotation;publicinterfaceAnnotation{booleanequals(Objectobj);inthashCode();StringtoString();Class<?extendsAnnotation>annotationType();}内置注解:
- @Override - 检查该方法是否是重写方法。如果发现其父类,或者是引用的接口中并没有该方法时,会报编译错误。
- @Deprecated - 标记过时方法。如果使用该方法,会报编译警告。
- @SuppressWarnings - 指示编译器去忽略注解中声明的警告。
- @SafeVarargs - Java 7 开始支持,忽略任何使用参数为泛型变量的方法或构造函数调用产生的警告。
- @FunctionalInterface - Java 8 开始支持,标识一个匿名函数或函数式接口。
- @Repeatable - Java 8 开始支持,标识某注解可以在同一个声明上使用多次。
自定义注解:
@Documented@Target(ElementType.TYPE)@Retention(RetentionPolicy.RUNTIME)public@interfaceMyAnnotation1{}元注解:
元注解的作用就是负责注解其他注解,Java定义了4个标准的meta-annotation类型,他们被用来提供对其他annotion类型作说明。
- @Retention - 标识这个注解怎么保存,是只在代码中,还是编入class文件中,或者是在运行时可以通过反射访问。
- @Documented - 标记这些注解是否包含在用户文档中。
- @Target - 标记这个注解应该是哪种 Java 成员。
- @Inherited - 标记这个注解是继承于哪个注解类(默认 注解并没有继承于任何子类)
@Retention 的取值:
publicenumRetentionPolicy{SOURCE,/* Annotation信息仅存在于编译器处理期间,编译器处理完之后就没有该Annotation信息了 */CLASS,/* 编译器将Annotation存储于类对应的.class文件中。默认行为 */RUNTIME/* 编译器将Annotation存储于class文件中,并且可由JVM读入 */}@Target的取值:
publicenumElementType{TYPE,/* 类、接口(包括注释类型)或枚举声明 */FIELD,/* 字段声明(包括枚举常量) */METHOD,/* 方法声明 */PARAMETER,/* 参数声明 */CONSTRUCTOR,/* 构造方法声明 */LOCAL_VARIABLE,/* 局部变量声明 */ANNOTATION_TYPE,/* 注释类型声明 */PACKAGE/* 包声明 */}注解的主要价值:
- 编译检查:如@Override确保正确重写方法
- 框架配置:如Spring的@Autowired、@Service简化配置
- 代码生成:如Lombok的@Data自动生成代码
- 测试标记:如JUnit的@Test
13、反射
反射就是在运行状态能够动态的获取该类的属性和方法,并且能够任意的使用该类的属性和方法,这种动态获取类信息以及动态的调用对象的方法的功能就是反射。它让Java在运行时具有像动态语言一样的特性。
核心功能包括:
- 动态获取类信息(Class对象)
- 创建对象(newInstance)
- 调用方法(invoke)
- 访问/修改字段(get/set)
- 处理注解和泛型
关键类:
- Class:类的元数据入口
- Field:字段信息
- Method:方法信息
- Constructor:构造方法
- Modifier:修饰符信息
实际应用场景:
- 框架开发:Spring通过反射实现依赖注入
- 动态代理:AOP切面编程
- 序列化工具:Jackson/GSON处理JSON
- 测试框架:JUnit发现并运行测试方法
- 插件系统:动态加载和扩展功能
优点:
- 灵活性高,实现动态编程
- 框架开发的基础设施
- 支持运行时类型检查
缺点:
- 性能开销:反射操作比直接调用慢
- 安全问题:可以绕过访问控制
- 代码复杂:降低可读性和维护性
- 编译检查缺失:错误在运行时才发现
性能优化:
- 缓存反射对象
- 使用setAccessible(true)减少检查
- 避免在热点代码中使用反射
获取class对象三种方式:
- 类名.class如:Person.class 该方式安全可靠,程序性能最高
- 对象.getClass()如:person.getClass()
- Class.forName(全类名)如:Class.forName(“ldc.org. demo.person”)
总结:
反射是Java在运行时动态获取和操作类信息的能力。通过Class对象可以获取字段、方法、构造器等信息,并能创建对象、调用方法、访问字段。它广泛应用于框架开发(如Spring)、动态代理、序列化等场景。优点是灵活性高,缺点是性能差、安全性低。实际使用中需要注意性能优化和安全控制。
14、static和final的区别?以及分别存储在JVM的哪个区域?
| 维度 | static | final |
|---|---|---|
| 语义 | 类级成员,与对象无关 | 值/引用只能赋一次 |
| 内存份数 | 整个 JVM 只有一份 | 与普通字段份数相同 |
| 生命周期 | 类加载即分配,卸载才回收 | 一旦赋值就冻结 |
| 可变性 | 可反复修改 | 不可再改(基本类型值不变,引用类型地址不变) |
| 能否叠加 | ✅ 可单独用 | ✅ 可单独用 |
| 叠加后 | 类级常量(编译期或运行期确定) | 仍是“只能一次”语义 |
| 类型 | static存储位置 | 实例 final存储位置 | static final存储位置(优化后,值直接内联到使用处,引用存在堆(Class对象中)) | 局部变量 |
|---|---|---|---|---|
| 基本类型变量 | 堆(Class对象中) | 堆对象中 | 元空间(运行时常量池) | 栈 |
| 字符串变量 | 堆(Class对象中的引用) + 堆(字符串常量池) | 堆对象的引用 --> 堆(字符串常量池) | 元空间(运行时常量池)–> 堆(字符串常量池) | 栈引用–> 堆(字符串常量池) |
| 对象引用 | 堆(Class对象中的引用) + 堆对象 | 堆对象的引用 + 堆对象 | 元空间(运行时常量池)–> 堆对象 | 栈引用 --> 堆对象 |
| 方法 | 元空间 | 元空间 | ||
| 类 | 元空间 | 元空间 | ||
| 代码块 | 元空间 | – |
15、Linux的五种IO模型
https://blog.csdn.net/Linging_24/article/details/134984317?spm=1001.2014.3001.5501
16、Reactor线程模型详解
https://blog.csdn.net/Linging_24/article/details/134984818?spm=1001.2014.3001.5501
17、IO零拷贝
https://blog.csdn.net/Linging_24/article/details/134984466?spm=1001.2014.3001.5501