文章目录
1、intern()方法
“ab”.intern():这个方法会首先检查字符串池中是否有”ab”这个字符串,如果存在则返回这个字符串的引用,否则就将这个字符串添加到字符串池中,然后返回这个常量池中字符串的引用。以下代码是在jdk1.8中测试,jdk1.6会有所不同。
public static void main(String[] args) {
// 创建2个对象,一个String对象在堆中,一个String常量在常量池
String s = new String("2");
// 判断s是否在常量池中,存在则返回常量池中对象的引用,此时intern指向常量池中的对象
String intern = s.intern();
// s2字符串在常量池中,所以返回常量池中的对象引用
String s2 = "2";
// s:为堆中对象 s2:为常量池对象 所以:false
System.out.println(s == s2); // false
// intern和s2都是指向常量池中的字符串,所以:true
System.out.println(intern == s2); // true
System.out.println("------------------------");
// 创建4个对象:堆中"33","3","3"对象,常量池:"3"对象
String s3 = new String("3") + new String("3");
// 判断s3是否在常量池中,不存在则将s3加入常量池中,并且常量池中保存的是s3的引用,返回常量池中对象的引用,此时s3和intern2指向同一个对象
String intern2 = s3.intern();
// s4字符串在常量池中,所以返回常量池中的对象引用
String s4 = "33";
// s3和intern2和s4指向的是同一个对象
System.out.println(s3 == s4); // true
System.out.println(intern2 == s3); // true
System.out.println(intern2 == s4); // true
}
2、try…catch…finally
// 返回 40
public static int fun(){
int a = 10;
try{
System.out.println(a / 0);
a = 20;
// return a;
}catch (Exception e){
a = 30;
return a;
}finally {
a = 40;
return a;
}
}
// 返回 30
public static int fun(){
int a = 10;
try{
System.out.println(a / 0);
a = 20;
// return a;
}catch (Exception e){
a = 30;
return a;
}finally {
a = 40;
}
return a;
}
// 返回 30
public static int fun(){
int a = 10;
try{
System.out.println(a / 0);
a = 20;
return a;
}catch (Exception e){
a = 30;
return a;
}finally {
a = 40;
}
}
3、hashCode和equals的关系
- equals相等的两个对象,hashCode一定相等
- hashCode相等的两个对象,equals不一定相等
使用Object.hashCode,是根据随机算法生成的hashCode值,无法保证两个对象equals相等的时候,hashCode也相等。
像一些集合容器map,在进行比较两个对象相等的判定条件是hashcode和equals都相等,所有在重写equals时,必须要重写hashCode,才能保证集合容器的正确使用。
4、什么是反射,反射有什么缺点?
反射是指在程序运行时动态获取类的信息、调用类的方法、访问类的属性等操作能力。在Java中,反射允许程序在运行时检查和操作类、方法、字段等,使得程序可以在运行时动态地创建对象、调用方法、修改属性等。
反射的缺点包括:
- 性能问题:由于反射涉及到动态查找和调用,相比直接调用方法,反射的性能会有一定的损耗。反射操作通常比直接操作更慢,因此在性能要求较高的场景下,应该谨慎使用反射。
- 安全问题:反射可以访问和修改类的私有方法和属性,可能会破坏类的封装性,导致安全隐患。使用反射时需要格外小心,确保不会对程序的安全性造成影响。
- 可读性和维护性差:由于反射是在运行时动态获取类信息,代码的可读性和维护性可能会受到影响。反射使得代码结构不够清晰,增加了代码的复杂性,降低了代码的可读性和维护性。
- 编译器检查失效:使用反射可以绕过编译器的类型检查,可能导致运行时的类型错误,增加了程序出错的可能性。因此,在使用反射时需要格外小心,确保类型安全。
- 不利于性能优化:由于反射的灵活性和动态性,使得程序的结构和行为不够明确,不利于编译器进行优化,可能影响程序的性能表现。
5、BIO、NIO、AIO的区别
6、面向对象的理解?
面向对象的核心是将现实世界的实体抽象为代码中的’对象’,每个对象包含数据(属性)和操作数据的方法,形成高内聚低耦合的模块。这样设计更符合人类思维方式,让程序结构更清晰。它有四大特性:
- 封装:将数据和方法封装在类内部,隐藏内部细节,只暴露必要接口,提高安全性和维护性
- 继承:实现代码复用,建立类之间的层次关系
- 多态:同一接口多种实现,提高代码灵活性、拓展性
- 抽象:简化复杂系统,如定义业务接口契约
在过往的项目中,面向对象的思想和特性帮助我们:快速响应需求变更、降低代码维护成本、提高代码质量。但我们也要平衡面向对象与其他范式(函数式编程)的优势,防止过度设计,增加系统的复杂度。
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。注解本身不影响代码逻辑,但可以通过反射获取注解信息。
package java.lang.annotation;
public interface Annotation {
boolean equals(Object obj);
int hashCode();
String toString();
Class<? extends Annotation> annotationType();
}
内置注解:
- @Override - 检查该方法是否是重写方法。如果发现其父类,或者是引用的接口中并没有该方法时,会报编译错误。
- @Deprecated - 标记过时方法。如果使用该方法,会报编译警告。
- @SuppressWarnings - 指示编译器去忽略注解中声明的警告。
- @SafeVarargs - Java 7 开始支持,忽略任何使用参数为泛型变量的方法或构造函数调用产生的警告。
- @FunctionalInterface - Java 8 开始支持,标识一个匿名函数或函数式接口。
- @Repeatable - Java 8 开始支持,标识某注解可以在同一个声明上使用多次。
自定义注解:
@Documented
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
public @interface MyAnnotation1 {
}
元注解:
元注解的作用就是负责注解其他注解,Java定义了4个标准的meta-annotation类型,他们被用来提供对其他annotion类型作说明。
- @Retention - 标识这个注解怎么保存,是只在代码中,还是编入class文件中,或者是在运行时可以通过反射访问。
- @Documented - 标记这些注解是否包含在用户文档中。
- @Target - 标记这个注解应该是哪种 Java 成员。
- @Inherited - 标记这个注解是继承于哪个注解类(默认 注解并没有继承于任何子类)
@Retention 的取值:
public enum RetentionPolicy {
SOURCE, /* Annotation信息仅存在于编译器处理期间,编译器处理完之后就没有该Annotation信息了 */
CLASS, /* 编译器将Annotation存储于类对应的.class文件中。默认行为 */
RUNTIME /* 编译器将Annotation存储于class文件中,并且可由JVM读入 */
}
@Target的取值:
public enum ElementType {
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

1277

被折叠的 条评论
为什么被折叠?



