Hello,你好呀,我是
灰小猿
!一个超会写bug的程序猿! 用坚持缔造技术、用指尖敲动未来! 和很多小伙伴们一样,我也是一名奔波在Java道路上的“创造者
”。也想靠技术来改未来,改变世界!因为我们坚信每一次敲动键盘都能让生活变得更智能、世界变得更有趣
! 在此专栏《Java核心面试宝典》记录我们备战梦想的【day 7】
!
上一篇文章和大家分享在面向对象方面的一些常见面试题,但是比较多就只分享了在构造方法和静态实例方面的题目,今天就继续来和大家总结剩下的面试题。
静态初始化块的优先级最高,会最先执行,
在非静态初始化块之前执行,静态初始化块只在类第一次被加载时执行,
非静态初始化块会在每次创建对象时执行一次,
因此创建了多少个对象,就会执行多少次非静态初始化块。
静态初始化块会在类第一次被加载时执行,而main方法是在类中定义的方法,所以静态初始化块会在main方法执行之前执行。
如果存在继承关系,则在子类进行类加载和创建对象时,也会对父类进行类加载和创建对象,执行顺序仍然是静态初始化块、非静态初始化块、构造器。
如对于两个类,一个子类一个父类的情况,执行顺序如下:
对于多个类之间的继承,执行顺序如下:
可能逻辑性有些有些强,我通过一个实例代码给大家演示一下:
以下代码可以说明初始化块和构造器的执行顺序。代码中定义了四个类,分别是 Main、Class1、Class2 和 Class3,其中 Class2 是 Class1 的子类,Class3 是 Class2 的子类,每个类都有静态初始化块、非静态初始化块和构造器。静态方法 main 定义在 Main 中,创建了 Class3 的实例。
public class Main {
static {
System.out.println("Static initialization of Main");
}
{
System.out.println("Instance initialization of Main");
}
public Test() {
System.out.println("Constructor of Main");
}
public static void main(String[] args) {
new Class3();
}
}
class Class1 {
static {
System.out.println("Static initialization of Class1");
}
{
System.out.println("Instance initialization of Class1");
}
Class1() {
System.out.println("Constructor of Class1");
}
}
class Class2 extends Class1 {
static {
System.out.println("Static initialization of Class2");
}
{
System.out.println("Instance initialization of Class2");
}
Class2() {
System.out.println("Constructor of Class2");
}
}
class Class3 extends Class2 {
static {
System.out.println("Static initialization of Class3");
}
{
System.out.println("Instance initialization of Class3");
}
Class3() {
System.out.println("Constructor of Class3");
}
}
由于没有创建 Main 的实例,因此 Main 的非静态初始化块不会被执行,但是由于程序的入口即静态方法 main 定义在 Main 中,因此 Main 的静态初始化块首先被执行。
在方法 main 中创建了 Class3 的实例,按照父类到子类的顺序,依次执行每个类的静态初始化块,因此 Class1、Class2 和 Class3 的静态初始化块被依次执行。
在所有类的静态初始化块被执行之后,按照父类到子类的顺序,依次执行每个类的非静态初始化块和构造器,因此按照 Class1、Class2 和 Class3 的顺序,每个类的非静态初始化块和构造器被执行。
关键字this代表当前对象的引用,当前对象指的是调用类中的属性或方法的对象。
关键字this可以用于引用对象的属性,在方法和构造方法中都可以通过关键字this来引用对象的属性,在构造方法中,通过this还可以引用其他的构造方法。
关键字this不可以在静态方法中使用,
因为关键字this代表的是对象的引用,而静态方法不依赖于类的具体对象。
不加任何可见性的修饰符为默认修饰符,在同一个包下的任何类都可以访问。
可见性修饰符 | 类内访问 | 包内访问 | 从不同包访问 |
---|---|---|---|
public | 可以 | 可以 | 可以 |
默认 | 可以 | 可以 | 不可以 |
private | 可以 | 不可以 | 不可以 |
可见性修饰符public
表示可以从任何类中访问,可见性修饰符private
表示类成员只能从自身所在的类中访问。
数据域封装是对数据域使用private
修饰符,将数据域声明为私有域,使用数据域封装的目的是避免从类的外部直接修改数据域的值。
可以编写get
方法获取数据域的值,编写set
方法修改数据域的值。
由于String源码中,存储字符串内容的数组使用关键字final修饰的,因此String类型的值不可变,
对String类型的值进行修改没有修改String的内容,而是创建了新的String对象。
补充:
关于String类型的值不能修改的原因还有另外一种说法,因为我们知道final修饰的数组的value内容有时候也是可以修改的,只是value不能指向其他的数组对象,具体为什么不能修改,其实是因为String中存储字符串内容的数组是private类型的,并且String类中并没有对外提供修改内容的方法,
所以字符串对象才无法修改。
StringBuilder
的效率更高,因为 StringBuffer
对方法加了同步锁,而 StringBuilder
没有对方法加同步锁。虽然StringBuilder
的效率更高,但是因为没有对方法加同步锁,因此在多线程环境下不保证线程安全,只适合单线程环境,而 StringBuffer
可以用于多线程环境。
今天和大家总结了在面向对象的考察点上一些常见的面试题,在这一篇中我们需要掌握初始化块的调用顺序
、this关键字的使用
、三种修饰符的作用范围
以及字符串的三个常用操作类String、StringBuilder、StringBuffer
。
面向对象的面试题比较多,之后还会继续总结,如果小伙伴们有遇到其他相关的面试题,欢迎在评论区留言提出,我会把大家提出的总结到文章内, 欢迎小伙伴们一起评论区打卡学习!小伙伴们可也在左方加我好友一起探讨学习!
我是灰小猿,我们下期见!