本文首先介绍几个基本的名次,然后介绍了三种代码块的特性和使用方法。
在面试大型公司时,如果遇到大型国企或者大的互联网私企,笔试中经常遇到代码块和代码加载顺序的笔试题。这里做一个总结,也方便各位小伙伴飙车不会飘。
  1. 名词解释

代码块: 由 { } 包起来的代码,称为代码块
静态代码块: 由 static { } 包起来的代码,称为静态代码块。
 
不同类型变量定义示例:
class Demo{
String x;// 非静态成员变量,又称为属性,对该类不同的对象来说,属性互不相同
static int y = 32;// 类变量,一个类中只有一个该变量,该类不同的对象共享同一个静态成员变量
public static void main(String[] args){
int z = 0;// 局部变量,只在方法内部可见,在方法结束后由垃圾收集器自动回收
}
}
 
  1. 局部代码块

位置:局部位置(方法内部)。
作用:限定变量的生命周期,尽早释放,节约内存。
调用:调用其所在的方法时执行。
方法中的局部代码块一般进行一次性地调用,调用完立刻释放空间,避免在接下来的调用过程中占用栈空间。栈空间内存有限,方法调用可能会生成很多局部变量导致栈内存不足,使用局部代码块可以避免此缺陷。

public class 局部代码块 {
   public static void go() {
        // 局部代码块
        {
            int age = 30;
            System.out.print("go: " + age);
        }
    }
    public static void main(String[] args) {
        go();
    }
}
  1. 构造代码块

位置:类成员的位置,即类中方法之外的位置。
作用:把多个构造方法共同的部分提取出来,共用构造代码块。
调用:每次调用构造方法时,都会优先于构造方法执行,也就是每次new一个对象时自动调用,实现对象初始化。

public class A {
int i = 1;
int initValue;//成员变量,初始化交给代码块来完成
A(){
System.out.println("构造方法在代码块执行后运行");
}
{
System.out.println("代码块从上至下依次运行");
//代码块的作用体现于此:在调用构造方法之前,用某段代码对成员变量进行初始化。
//而不是在构造方法调用时再进行。
for (int i = 0;i < 100;i ++) {
initValue += i;
}
}
{
System.out.println(initValue);
System.out.println(i);//此时会打印1
int i = 2;//局部变量,和成员变量不冲突,但会优先使用代码块的变量
System.out.println(i);//此时打印2
//System.out.println(j);//提示非法向后引用,因为此时j的的初始化还没开始。
}
int j = 2;
{
System.out.println(j);
System.out.println(i);//代码块中的变量运行后自动释放,不会影响代码块之外的代码
} }
public class 构造代码块 {
@Test
public void test() {
A a = new A();
}
}

执行结果

代码块从上至下依次运行
4950
1
2
2
1
构造方法在代码块执行后运行
  1. 静态代码块

位置:类成员位置。
作用:对类进行一些初始化,只加载一次。当new多个对象时,只有第一次会调用静态代码块,因为静态代码块和类变量一样,是属于类的,所有对象共享一份。
调用: new 一个对象时自动调用。
public class 静态代码块 {
@Test
public void test() {
C c1 = new C();
C c2 = new C();
//结果,静态代码块只会调用一次,类的所有对象共享该代码块
System.out.println("我是普通方法");
}
}
class C{
C(){
System.out.println("构造方法调用");
}
{
System.out.println("代码块调用");
}
static {
System.out.println("静态代码块调用");
}
}

调用结果:

静态代码块调用
代码块调用
构造方法调用
代码块调用
构造方法调用
我是普通方法
执行顺序 静态代码块 —–> 构造代码块 ——-> 构造方法
  1. 笔试题

写出下列程序输出结果:
public class HelloA {
public HelloA(){
System.out.println("HelloA");
}
{
System.out.println("I'm A class");
}
static {
System.out.println("static A");
}
}
public class HelloB extends HelloA {
public HelloB(){
System.out.println("HelloB");
}
{
System.out.println("I'm B class");
}
static {
System.out.println("static B");
}
public static void main(String[] args) {
new HelloB();
}
}

执行结果:

分析:首先要知道静态代码块是随着类的加载而加载,而构造代码块和构造方法都是随着对象的创建而加载。
1,在编译HelloB.java时,由于HelloB 继承 HelloA,先加载了HelloA类,因此HelloA类的静态代码块首先执行,而后加载HelloB类,HelloB类的静态代码块执行,这没什么好说的。
2,然后创建HelloB的对象,大家都知道构造代码块优先于构造方法执行,这时候问题来了,这时应该先看HelloB类的构造方法,HelloB类里的构造方法里有一句隐式的super()首先被执行,所以找到HelloA类的构造方法,而HelloA类的构造方法中也有一句隐式的super()执行(调用Object类的构造方法),并没有什么返回结果,接下来才是在执行HelloA类构造方法的方法体前先执行了HelloA类的构造代码块(I'm A class),再执行HelloA类构造方法的方法体(也就是Hello A),最后又回到HelloB类的构造方法中,这时HelloB类的super()已经执行完了,在执行HelloB类构造方法的方法体前先执行HelloB类的构造代码块(I'm B class),再执行子类构造方法的方法体(HellB)。
无继承初始化顺序:
有继承初始化顺序:
接下来看一道阿里笔试题:

public class B{
public static B t1 = new B();
public static B t2 = new B();
{
System.out.println("构造块");
}
static {
System.out.println("静态块");
}
public static void main(String[] args) {
B t =new B();
}
}

执行结果:

  1. 总结

Java代码初始化顺序
由 static 关键字修饰的,如类变量和静态代码块,将在类创建实例之前被初始化,而且是按顺序从上到下依次被执行。(类变量、静态代码块)属于类本身,不依赖于类的实例。
没有 static 关键字修饰的(如:实例变量(非静态变量)、非静态代码块)初始化实际上是会被提取到类的构造器中被执行的,但是会比类构造器中的代码块优先执行。实例变量、非静态代码块的地位是相等的,它们将按顺序被执行。
容易混淆的一个知识点
静态方法只允许直接访问静态成员,而实例方法中可以访问静态成员和实例成员,原因是类还没有实例化,所以实例成员也没有被创建,静态方法中因此也不能用this。
  1. Reference

 
 

Java 代码块与代码加载顺序的更多相关文章

  1. java中静态变量,静态代码块,静态方法,实例变量,匿名代码块等的加载顺序

    转自:http://blog.csdn.net/mrzhoug/article/details/51581994 一.在Java中,使用”{}”括起来的代码称为代码块,代码块可以分为以下四种: 1.普 ...

  2. Java代码执行顺序(静态变量,非静态变量,静态代码块,代码块,构造函数)加载顺序

    //据说这是一道阿里巴巴面试题,先以这道题为例分析下 public class Text { public static int k = 0; public static Text t1 = new ...

  3. Java 类中各成分加载顺序 和 内存中的存放位置

    参加一个笔试,有一个关于类的静态代码块.构造代码块.构造函数的执行顺序的问题.不太清楚,网上百度了一下.在这里记录一下. 一.什么时候会加载类?使用到类中的内容时加载:有三种情况1.创建对象:new ...

  4. 【java虚拟机系列】java中类与对象的加载顺序

    首先了解一下Java虚拟机初始化的原理. JVM通过加装.连接和初始化一个Java类型,使该类型可以被正在运行的Java程序所使用.类型的生命周期如下图所示: 装载和连接必须在初始化之前就要完成. 类 ...

  5. java类中属性的加载顺序,以及内存分配情况介绍

    看下面例子及说明: /** 假如有外部类调用了该类,代码为:new StaticTest(); 那么下面是类属性的加载顺序 */ public class StaticTest{ public int ...

  6. java 启动查看jar包加载顺序并设置classpath

    本文为博主原创,转载请注明出处: 1.idea查看jar包加载顺序 jdk8 可以通过     -XX:+TraceClassPaths    参数进行查看jar包的加载顺序 jdk11 可以通过  ...

  7. Java中类及方法的加载顺序

    1. 虚拟机在首次加载Java类时,会对静态代码块.静态成员变量.静态方法进行一次初始化(静态间按顺序执行). 2. 只有在调用new方法时才会创建类的实例. 3. 类实例创建过程:父子继承关系,先父 ...

  8. Java类实例化时候的加载顺序

    面试试题中经常考到此问题,现在做进一步的总结: public class Student { public Student(String name){ System.out.println(name) ...

  9. Tomcat启动时加载数据到缓存---web.xml中listener加载顺序(例如顺序:1、初始化spring容器,2、初始化线程池,3、加载业务代码,将数据库中数据加载到内存中)

    最近公司要做功能迁移,原来的后台使用的Netty,现在要迁移到在uap上,也就是说所有后台的代码不能通过netty写的加载顺序加载了. 问题就来了,怎样让迁移到tomcat的代码按照原来的加载顺序进行 ...

  10. Java笔记(十二)……类中各部分加载顺序及存放位置问题

    什么时候会加载类 使用到类中的内容时加载,三种情况: 创建对象:new StaticDemo(); 使用类中的静态成员:StaticCode.num = 9;  StaticCode.getNum() ...

随机推荐

  1. laravel-echo-server 启动报错 [ioredis] Unhandled error event: ReplyError: NOAUTH Authentication required.

    可以在 .env 文件加上以下配置 LARAVEL_ECHO_SERVER_REDIS_HOST= LARAVEL_ECHO_SERVER_REDIS_PASSWORD= LARAVEL_ECHO_S ...

  2. Mqtt集成与设计

    Mqtt集成 集成mqtt,我们首先得明白什么是mqtt: MQTT(Message Queuing Telemetry Transport)是一种轻量级.基于发布-订阅模式的消息传输协议,适用于资源 ...

  3. docker swarm CA证书到期

    1.现象 在portain平台查看日志,发现一些节点日志无法查看报错为:Error grabbing logs: rpc error: code = Unknown desc = warning: i ...

  4. 开发app步骤总结

    以下是用IDEA后端Java开发(如Spring Boot)与Android Studio前端开发app的逻辑实现步骤详解: 一.技术选择 通信协议:推荐使用RESTful API(HTTP/HTTP ...

  5. 【uniapp】文本控件多余文字省略号代替

    多余文字使用省略号效果 代码 .l-dd-content{ width: 100%; color: #8b8b8b; display: -webkit-box; /** 对象作为伸缩盒子模型显示 ** ...

  6. Readers and Writers JSON Framework(2)

    我们关心json的读写.特别在datasnap中,关于使用stream更是显得重要.其实轮子都帮你做好了,你不知道整经再研究就是一个悲哀.除非你要研究. 回正题: 处理json有二套框架. JSON ...

  7. SpringAI用嵌入模型操作向量数据库!

    嵌入模型(Embedding Model)和向量数据库(Vector Database/Vector Store)是一对亲密无间的合作伙伴,也是 AI 技术栈中紧密关联的两大核心组件,两者的协同作用构 ...

  8. TCP延迟调优之PSH参数与passt延迟问题修复

    qemu中使用passt来作为虚拟机的网卡NAT实现,希望能够利用它IP地址与host一致的优点.这本来是没有啥问题的,但是不知道为什么它的TCP入口流量的延迟很严重. 好吧,反正以后总是要改pass ...

  9. 9. RabbitMQ 消息队列幂等性,优先级队列,惰性队列的详细说明

    9. RabbitMQ 消息队列幂等性,优先级队列,惰性队列的详细说明 @ 目录 9. RabbitMQ 消息队列幂等性,优先级队列,惰性队列的详细说明 1. RabbitMQ 消息队列的 " ...

  10. Spring 的 resolveBeforeInstantiation 方法作用详解

    一.定义 resolveBeforeInstantiation 是 Spring 框架中 AbstractAutowireCapableBeanFactory 类的核心方法之一,它在 Bean 的实例 ...