type
status
date
slug
summary
tags
category
icon
password
Java基础知识面试题
final的作用
- 被final修饰的类不可以被继承
- 被final修饰的方法不可以被重写
- 被final修饰的变量不可以被改变,被final修饰不可变的是变量的引用,而不是引用指向的内容,引用指向的内容是可以改变的,示例代码如下
try-catch-finally执行顺序
try块:首先执行try块中的代码。如果try块中的代码执行到return aa;,则try块会尝试返回aa的值,但在返回之前会先执行finally块中的代码。
finally块:无论try块中是否发生异常,finally块中的代码都会执行。在finally块中,你有一个return bb;。这个return会覆盖try块中return aa;的结果。因此,最终的返回值是bb。
catch块:如果在try块中发生了异常,catch块中的代码会执行。如果catch块中有一个return cc;,它也会在finally块执行之前尝试返回cc。但是,finally块中的return bb;仍然会覆盖catch块中的return cc;。
总结:
finally块中的return bb;会覆盖try块和catch块中的任何返回值。
- 无论
try块是否成功执行,或者catch块是否被触发,最终都会返回finally块中的值bb。
所以,最终返回的值是
bb。抽象类和接口的区别
特性 | 抽象类 (Abstract Class) | 接口 (Interface) |
声明 | 使用 abstract 关键字声明 | 使用 interface 关键字声明 |
实现 | 子类使用 extends 关键字继承抽象类。如果子类不是抽象类,它需要提供所有抽象方法的实现。 | 子类使用 implements 关键字实现接口,并且需要提供所有接口方法的实现。 |
构造器 | 可以有构造器 | 不能有构造器 |
访问修饰符 | 方法可以使用任意的访问修饰符 | 方法默认是 public,且不能是 private 或 protected。 |
多继承 | 一个类最多只能继承一个抽象类 | 一个类可以实现多个接口 |
字段声明 | 字段声明可以是任意的 | 字段默认是 static 和 final |
Java8中接口中引入默认方法和静态方法,以此来减少抽象类和接口之间的差异
创建一个对象用什么关键字?对象实例与对象引用有何不同?
new关键字,new创建对象实例(对象实例在堆内存中),对象引用指向对象实例(对象引用存放在栈内存中)。一个对象引用可以指向0个或1个对象(一根绳子可以不系气球,也可以系一个气球);一个对象可以有n个引用指向它(可以用n条绳子系住一个气球)
this与super的区别
- super: 它引用当前对象的直接父类中的成员(用来访问直接父类中被隐藏的父类中成员数据或函数,基类与派生类中有相同成员定义时如:super.变量名 super.成员函数据名(实参)
- this:它代表当前对象名(在程序中易产生二义性之处,应使用this来指明当前对象;如果函数的形参与类中的成员数据同名,这时需用this来指明成员变量名)
- super()和this()类似,区别是,super()在子类中调用父类的构造方法,this()在本类内调用本类的其它构造方法。
- super()和this()均需放在构造方法内第一行。
- 尽管可以用this调用一个构造器,但却不能调用两个。
- this和super不能同时出现在一个构造函数里面,因为this必然会调用其它的构造函数,其它的构造函数必然也会有super语句的存在,所以在同一个构造函数里面有相同的语句,就失去了语句的意义,编译器也不会通过。
- this()和super()都指的是对象,所以,均不可以在static环境中使用。包括:static变量,static方法,static语句块。
- 从本质上讲,this是一个指向本对象的指针, 然而super是一个Java关键字。
成员变量与局部变量的区别
特性 | 成员变量 (Member Variable) | 局部变量 (Local Variable) |
作用域 | 针对整个类有效 | 只在某个范围内有效(通常是方法或语句块内) |
存储位置 | 随着对象的创建而存在,存储在堆内存中 | 方法调用或语句执行时存在,存储在栈内存中 |
生命周期 | 随着对象的创建而存在,随着对象的消失而消失 | 方法调用结束或语句执行完毕后自动释放 |
初始值 | 有默认初始值 | 没有默认初始值,使用前必须显式赋值 |
匿名内部类
- 匿名内部类必须继承一个抽象类或者实现一个接口。
- 匿名内部类不能定义任何静态成员和静态方法。
- 当所在的方法的形参需要被匿名内部类使用时,必须声明为 final。
- 匿名内部类不能是抽象的,它必须要实现继承的类或者实现的接口的所有抽象方法。
局部内部类和匿名内部类访问局部变量的时候,为什么变量必须要加上final?
因为生命周期不一致, 局部变量直接存储在栈中,当方法执行结束后,非final的局部变量就被销毁。而局部内部类对局部变量的引用依然存在,如果局部内部类要调用局部变量时,就会出错。加了final,可以确保局部内部类使用的变量与外层的局部变量区分开,解决了这个问题。
== 和 equals 的区别是什么
- == : 它的作用是判断两个对象的地址是不是相等。即,判断两个对象是不是同一个对象。(基本数据类型 == 比较的是值,引用数据类型 == 比较的是内存地址)
- equals() : 它的作用也是判断两个对象是否相等。但它一般有两种使用情况:
情况1:类没有覆盖 equals() 方法。则通过 equals() 比较该类的两个对象时,等价于通过“==”比较这两个对象。
情况2:类覆盖了 equals() 方法。一般,我们都覆盖 equals() 方法来两个对象的内容相等;若它们的内容相等,则返回 true (即,认为这两个对象相等)。
String中的equals方法是被重写过的,因为object的equals方法是比较的对象的内存地址,而String的equals方法比较的是对象的值。当创建String类型的对象时,虚拟机会在常量池中查找有没有已经存在的值和要创建的值相同的对象,如果有就把它赋给当前引用,如果没有就在常量池中重新创建一个String对象。
hashCode()与equals()的相关规定
- 如果两个对象相等,则hashcode一定也是相同的
- 两个对象相等,对两个对象分别调用equals方法都返回true
- 两个对象有相同的hashcode值,它们也不一定是相等的
因此,equals 方法被覆盖过,则 hashCode 方法也必须被覆盖,hashCode() 的默认行为是对堆上的对象产生独特值。如果没有重写 hashCode(),则该 class 的两个对象无论如何都不会相等(即使这两个对象指向相同的数据)
值传递和引用传递有什么区别
- 值传递:指的是在方法调用时,传递的参数是按值的拷贝传递,传递的是值的拷贝,也就是说传递后就互不相关了。
- 引用传递:指的是在方法调用时,传递的参数是按引用进行传递,其实传递的引用的地址,也就是变量所对应的内存空间的地址。传递的是值的引用,也就是说传递前和传递后都指向同一个引用(也就是同一个内存空间)。
反射机制
在运行状态中,动态获取的信息以及动态调用对象的方法的功能称为java的反射机制。
反射机制的应用场景
- 我们在使用JDBC连接数据库时使用Class.forName()通过反射加载数据库的驱动程序。
- Spring框架也用到很多反射机制,最经典的就是xml的配置模式。Spring 通过 XML 配置模式装载 Bean 的过程:
1) 将程序内所有 XML 或 Properties 配置文件加载入内存中;
2)Java类里面解析xml或properties里面的内容,得到对应实体类的字节码字符串以及相关的属性信息;
3)使用反射机制,根据这个字符串获得某个类的Class实例;
4)动态配置实例的属性
获取反射的三种方法
- 通过new对象实现反射机制
- 通过路径实现反射机制
- 通过类名实现反射机制
字符串常量池
字符串常量池位于堆内存中,专门用来存储字符串常量,可以提高内存的使用率,避免开辟多块空间存储相同的字符串,在创建字符串时 JVM 会首先检查字符串常量池,如果该字符串已经存在池中,则返回它的引用,如果不存在,则实例化一个字符串放到池中,并返回其引用。
在使用 HashMap 的时候,用 String 做 key 有什么好处?
HashMap 内部实现是通过 key 的 hashcode 来确定 value 的存储位置,因为字符串是不可变的,所以当创建字符串时,它的 hashcode 被缓存下来,不需要再次计算,所以相比于其他对象更快。
String和StringBuffer、StringBuilder的区别是什么
特性 | String | StringBuilder | StringBuffer |
可变性 | 不可变 ( final char[] value) | 可变 ( char[] value) | 可变 ( char[] value) |
线程安全性 | 线程安全 | 非线程安全 | 线程安全 |
性能 | 较低(每次修改都生成新对象) | 高(操作原对象) | 较高(但略低于StringBuilder) |
适用场景 | 适用于少量字符串拼接或需要线程安全的场景(操作少量的数据) | 适用于单线程中需要频繁修改字符串的场景(单线程操作字符串缓冲区下操作大量数据) | 适用于多线程中需要频繁修改字符串的场景(多线程操作字符串缓冲区下操作大量数据) |
java基本数据类型
类型 | 类型名称 | 关键字 | 占用内存 | 取值范围 | 作为成员变量的默认值 |
整形 | 字节型 | byte | 1 字节 | -128 (2^7) ~ 127 (2^7 - 1) | 0 |
整形 | 短整型 | short | 2 字节 | -32,768 (2^15) ~ 32,767 (2^15 - 1) | 0 |
整形 | 整型 | int | 4 字节 | -2,147,483,648 (2^31) ~ 2,147,483,647 (2^31 - 1) | 0 |
整形 | 长整型 | long | 8 字节 | -9,223,372,036,854,775,808 (2^63) ~ 9,223,372,036,854,775,807 (2^63 - 1) | 0L |
浮点型 | 单精度浮点型 | float | 4 字节 | -3.403E38 ~ 3.403E38 | 0.0F |
浮点型 | 双精度浮点型 | double | 8 字节 | -1.798E308 ~ 1.798E308 | 0.0D |
字符型 | 字符型 | char | 2 字节 | 表示一个字符,如 'a', 'A', '家' | '\u0000' |
布尔型 | 布尔型 | boolean | 1 字节 | 只有两个值:true 或 false | false |
封箱和拆箱
- 作者:JackJame
- 链接:https://notion.qjit1314.eu.org/article/example-1
- 声明:本文采用 CC BY-NC-SA 4.0 许可协议,转载请注明出处。


