热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

Java面试中经常遇到的类执行顺序

引言:记得以前面试的时候,会直接给一段代码,这段代码很多地方都有print,所以让我写出现打印出什么,后打印出什么。今天我整理一下单类的情况,继承的情况

引言:

记得以前面试的时候,会直接给一段代码,这段代码很多地方都有print,所以让我写出现打印出什么,后打印出什么。今天我整理一下单类的情况,继承的情况和一些特殊情况,希望大家看了之后,在面试过程中举一反三,成功规避错误。笔者目前整理的一些blog针对面试都是超高频出现的。大家可以点击链接:http://blog.csdn.net/u012403290

单类执行顺序:

下面是我写的一个demo:

package com.bw;

/**
* @author brickworker
* 关于类Color的描述:测试单个类的执行顺序问题
*/

public class Color {

//构造函数
public Color() {
System.out.println("构造函数执行");
}

//静态代码块
static{
System.out.println("静态代码块执行");
}

//非静态代码块
{
System.out.println("非静态代码块执行");
}


//一般方法
void run(){
System.out.println("一般方法执行");
}


public static void main(String[] args) {
System.out.println("main方法执行");//这个一定要写在最上面,程序一进入马上就执行,不然会导致结果不准确
Color color = new Color();
color.run();
}



}
//执行结果:
//静态代码块执行
//main方法执行
//非静态代码块执行
//构造函数执行
//一般方法执行

真的觉得是对的么?因为我们main的入口写在了类本身之中。导致结果其实是不准确的。我们换个方式,信建立一个Rundemo来触发执行:

package com.bw;

public class RunDemo {

public static void main(String[] args) {
System.out.println("main方法执行");//这个一定要写在最上面,程序一进入马上就执行,不然会导致结果不准确
Color color = new Color();
color.run();
}
}
//执行结果:
//main方法执行
//静态代码块执行
//非静态代码块执行
//构造函数执行
//一般方法执行

是吧,是不是main方法执行顺序跑到最前面去了呢?前面一种情况是因为main方法放在了目标类中,如果要执行这个main方法,虚拟机会先初始化这个主类,所以会先执行static静态代码块,关于这部分,以后我会写一篇关于虚拟机类加载机制的博文。总之,在看面试题的时候一定要看清楚main方法到底是放在哪里。

继承类执行顺序:

接下来,我们看看继承的情况是如何的,以下是我写的一个继承的demo,这里要强调一点,有写小伙伴为了看的更清楚,父类用system.err.println来打印,导致结果不同,两种输出方式是存在很大差别的,而且实验一定要建立在公平公正的前提下:


//父类
package com.bw;

/**
*
* @author brickworker
* 关于类Father的描述:测试继承执行顺序父类
*/

public class Father {

//构造函数
public Father() {
System.out.println("父类构造函数执行");
}

//静态代码块
static{
System.out.println("父类静态代码块执行");
}

//非静态代码块
{
System.out.println("父类非静态代码块执行");
}

//一般方法
void run(){
System.out.println("父类一般方法");
}
}


//子类
package com.bw;



/**
*
* @author brickworker
* 关于类Son的描述:测试继承执行顺序子类
*/

public class Son extends Father{

//构造函数
public Son() {
System.out.println("子类构造方法");
}

//静态代码块
static{
System.out.println("子类静态代码块");
}

//非静态代码块
{
System.out.println("子类非静态代码块");
}

//子类重写一般方法
@Override
void run() {
System.out.println("子类重写一般方法执行");
}

public static void main(String[] args) {
System.out.println("main方法执行");
Son son = new Son();
son.run();
}


}


//执行顺序:
//父类静态代码块执行
//子类静态代码块
//main方法执行
//父类非静态代码块执行
//父类构造函数执行
//子类非静态代码块
//子类构造方法
//子类重写一般方法执行

现在,我们把main方法单独拿出来,和上面一样,看看执行结果:

main方法执行
父类静态代码块执行
子类静态代码块
父类非静态代码块执行
父类构造函数执行
子类非静态代码块
子类构造方法
子类重写一般方法执行

总结一下:标准的执行顺序是:当前主程序>父类静态代码块>子类静态代码块>父类非静态代码块>父类构造函数>子类非静态代码块>子类构造方法>子类一般方法。那么把上面的顺序中关于父类执行的去掉,其实也符合我们前面讨论的单个类执行顺序。

注意了!注意了!(敲黑板),上面的也许大家在别的文章中看了不止一遍,那么下面的特殊情况你可能就不太清楚了,因为出现的少,但是我们一次看个透彻。

特殊执行顺序:

其实在类加载机制中,类加载存在主动加载和被动加载(可以不用知道,对下面文章理解不妨碍,只是希望知其然更要知其所以然),在被动加载过程中很多并不会触发初始化,所以在判断被动引用的时候,执行顺序会难很多,主要分为3中情况来具体说明:

一、通过子类调用了父类的静态字段,子类不会被初始化

//父类
package com.bw;

/**
*
* @author brickworker
* 关于类Father的描述:测试继承执行顺序父类
*/

public class Father {


public static int father = 100;
//静态代码块
static{
System.out.println("父类静态代码块执行");
}

}
//子类
package com.bw;
/**
*
* @author brickworker
* 关于类Son的描述:测试继承执行顺序子类
*/

public class Son extends Father{


static{
System.out.println("子类静态代码块");
}

}

//测试类:
package com.bw;

public class RunDemo {

public static void main(String[] args) {
System.out.println("main方法执行");
System.out.println(Son.father);//用子类去调去父类的静态字段
}

}
//执行结果:
//main方法执行
//父类静态代码块执行
//100

从上面可以看出,子类的静态代码都没有执行,说明子类完全没有初始化。

二、类作为数组的组件类型不会触发类初始化:

借用上面单类的Color类:

package com.bw;

public class RunDemo {

public static void main(String[] args) {
System.out.println("main方法执行");
Color[] colors = new Color[5];
}

}
//执行结果:
//main方法执行

上面用Color做为数组的组件,没有执行color的静态方法,说明也没有被初始化。

三、常量池引用也会导致不初始化类

package com.bw;

/**
* @author brickworker
* 关于类Color的描述:测试单个类的执行顺序问题
*/

public class Color {
public static final String color = "red";//新增一段常量,编译阶段户直接放入常量池
//静态代码块
static{
System.out.println("静态代码块执行");
}
}

//
package com.bw;

public class RunDemo {

public static void main(String[] args) {
System.out.println("main方法执行");
System.out.println(Color.color);
}

}
//执行结果:
//main方法执行
//red

从上面的结果可以看出,虽然调用了red,但是并有执行color的静态代码块,说明它没有被初始化。

综上所述,如果把类加载时机和顺序进行结合,那么这样的面试题可能就会难倒一大批人,所以合理分析和总结是非常重要的。关于为什么后面类没有初始化,我想后面如果写java虚拟机类加载机制的时候我们再一起探究下。

好啦,如果你看到了这里,谢谢你对我辛苦劳动肯定,同时祝愿你学习进步,事业顺心。


推荐阅读
  • Iamtryingtomakeaclassthatwillreadatextfileofnamesintoanarray,thenreturnthatarra ... [详细]
  • Java太阳系小游戏分析和源码详解
    本文介绍了一个基于Java的太阳系小游戏的分析和源码详解。通过对面向对象的知识的学习和实践,作者实现了太阳系各行星绕太阳转的效果。文章详细介绍了游戏的设计思路和源码结构,包括工具类、常量、图片加载、面板等。通过这个小游戏的制作,读者可以巩固和应用所学的知识,如类的继承、方法的重载与重写、多态和封装等。 ... [详细]
  • [大整数乘法] java代码实现
    本文介绍了使用java代码实现大整数乘法的过程,同时也涉及到大整数加法和大整数减法的计算方法。通过分治算法来提高计算效率,并对算法的时间复杂度进行了研究。详细代码实现请参考文章链接。 ... [详细]
  • 本文介绍了iOS数据库Sqlite的SQL语句分类和常见约束关键字。SQL语句分为DDL、DML和DQL三种类型,其中DDL语句用于定义、删除和修改数据表,关键字包括create、drop和alter。常见约束关键字包括if not exists、if exists、primary key、autoincrement、not null和default。此外,还介绍了常见的数据库数据类型,包括integer、text和real。 ... [详细]
  • Java中包装类的设计原因以及操作方法
    本文主要介绍了Java中设计包装类的原因以及操作方法。在Java中,除了对象类型,还有八大基本类型,为了将基本类型转换成对象,Java引入了包装类。文章通过介绍包装类的定义和实现,解答了为什么需要包装类的问题,并提供了简单易用的操作方法。通过本文的学习,读者可以更好地理解和应用Java中的包装类。 ... [详细]
  • 先看官方文档TheJavaTutorialshavebeenwrittenforJDK8.Examplesandpracticesdescribedinthispagedontta ... [详细]
  • Java容器中的compareto方法排序原理解析
    本文从源码解析Java容器中的compareto方法的排序原理,讲解了在使用数组存储数据时的限制以及存储效率的问题。同时提到了Redis的五大数据结构和list、set等知识点,回忆了作者大学时代的Java学习经历。文章以作者做的思维导图作为目录,展示了整个讲解过程。 ... [详细]
  • 本文介绍了如何在给定的有序字符序列中插入新字符,并保持序列的有序性。通过示例代码演示了插入过程,以及插入后的字符序列。 ... [详细]
  • 如何用UE4制作2D游戏文档——计算篇
    篇首语:本文由编程笔记#小编为大家整理,主要介绍了如何用UE4制作2D游戏文档——计算篇相关的知识,希望对你有一定的参考价值。 ... [详细]
  • 本文详细介绍了Java中vector的使用方法和相关知识,包括vector类的功能、构造方法和使用注意事项。通过使用vector类,可以方便地实现动态数组的功能,并且可以随意插入不同类型的对象,进行查找、插入和删除操作。这篇文章对于需要频繁进行查找、插入和删除操作的情况下,使用vector类是一个很好的选择。 ... [详细]
  • Android源码深入理解JNI技术的概述和应用
    本文介绍了Android源码中的JNI技术,包括概述和应用。JNI是Java Native Interface的缩写,是一种技术,可以实现Java程序调用Native语言写的函数,以及Native程序调用Java层的函数。在Android平台上,JNI充当了连接Java世界和Native世界的桥梁。本文通过分析Android源码中的相关文件和位置,深入探讨了JNI技术在Android开发中的重要性和应用场景。 ... [详细]
  • Java学习笔记之面向对象编程(OOP)
    本文介绍了Java学习笔记中的面向对象编程(OOP)内容,包括OOP的三大特性(封装、继承、多态)和五大原则(单一职责原则、开放封闭原则、里式替换原则、依赖倒置原则)。通过学习OOP,可以提高代码复用性、拓展性和安全性。 ... [详细]
  • 多维数组的使用
    本文介绍了多维数组的概念和使用方法,以及二维数组的特点和操作方式。同时还介绍了如何获取数组的长度。 ... [详细]
  • 数组的排序:数组本身有Arrays类中的sort()方法,这里写几种常见的排序方法。(1)冒泡排序法publicstaticvoidmain(String[]args ... [详细]
  • Whatsthedifferencebetweento_aandto_ary?to_a和to_ary有什么区别? ... [详细]
author-avatar
素手红裳000_367
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有