在Java中,static和final是使用频率非常高的关键字,之前也简单地用过static和final,但是始终觉得没有从深层次上理解这两个关键字。本文将从class文件和类的初始化机制出发理解这两个关键字。
一、编译时常量:
很多人包括我最开始有这种误解,是不是被final修饰的变量就是编译时常量呢,非也。顾名思义,编译时常量是指变量在编译期间就可以确定了,下面我举两个例子说明一下什么是编译时常量。
public class Test{
public final int a=100;
}
看一下,编译之后的class文件:
此时,变量a是编译时常量,在构造方法中,对变量a分配内存空间之后,将常量111赋值给a。
public class Test{
public final int a;
public Test(int a){
this.a=a;
}
}
编译之后的class文件如下:
此时,变量a在编译时期并不知道要赋什么值,只有在运行期间实例化Test对象时,去调用构造方法的时候才能知道a的值。这时候a就不是编译时常量。
二、static变量
static修饰的变量为类(静态)变量,static成员变量是对于整个类而不是类实例而存在的。一个static变量对于每个类来说都只有一份存储空间。而非static变量(实例变量)对于每个对象都有一份存储空间。
在我们实例化一个Java对象之前,这个对象的类型信息必须已经存放在了Java虚拟机的方法区。Java虚拟机通过装载、连接和初始化一个Java类型,使该类型可以被正在运行的Java程序所使用。其中装载就是把二进制的class文件读入Java虚拟机中;而连接就是把这种已经读入虚拟机的二进制形式的类型数据合并到虚拟机的运行时数据区中,连接分为三个子步骤:验证、准备和解析。验证工作是确认class文件符合Java语言的语义规范。在准备阶段,Java虚拟机为类变量分配内存,设置默认初始值。解析过程是在类型的常量池中寻找类、接口、字段和方法的符号引用,把这些符号引用替换成直接引用。最后一个步骤就是初始化,也就是为类变量赋予正确的初始值。
下面我们来看一下类(静态)变量的初始化过程。
所有的类变量初始化语句和类型的静态初始化器都被Java编译器收集在一起,放到一个特殊的方法。在class文件中,这个方法被称为"<clinit>"。通常的java程序时无法调用这个<clinit>方法。这个方法只能被java虚拟机调用,专门用把类型的静态变量设置为它们的正确初始值。以下两种方式产生的字节码文件时相同的。
public class Test{
public static int a=111;
}
public class Test{
public static int a;
static{
a=111;
}
}
并非所有的类都在class文件中拥有一个<clinit>()方法。如果类没有声明任何类变量,也没有静态初始化语句,那么它就不会有<clinit>()方法。若果类声明了类变量,但是没有明确使用类变量初始化语句或者静态初始化语句初始化它们,那么类不会有<clinit>()方法。如果类仅包含静态final变量的类变量初始化语句,而且这些类变量初始化语句采用编译时常量表达式,类也不会有<clinit>()方法。在编译的时候,java编译器把编译时常量(用final声明以及编译时已知的值初始化的类变量)则和一般的类变量的处理方式不同,每个使用编译时常量的类型都会复制它的所有常量到自己的常量池中,或嵌入到它的字节码中。也就是Java虚拟机会将常量直接保存到类文件中。
public class Test{
public static final int a=11;
}
分享到:
相关推荐
### Java深度历险——Java字节代码的操纵 #### 引言 随着Java技术的不断发展与完善,越来越多的开发者开始关注于如何更深入地理解Java内部机制及其高级特性。本篇将聚焦于Java字节码层面的操作,为读者提供一个...
这部分内容对于理解和应用Java的OOP设计原则至关重要。此外,还可能涉及访问修饰符、构造器、this关键字、static关键字以及final关键字的用法。 接下来,书中的章节很可能会涵盖异常处理,这是Java程序健壮性的重要...
Java程序员在准备考试时,需要关注的关键点集中在深入理解和应用面向对象编程思想,熟悉Java语言的基础概念和细节,以及通过实践和交流来增强自己的技能。以下是对这些关键点的详细阐述: 1. 面向对象思想的深度...
- 接口中的方法默认是`public`的,变量默认是`public static final`,即全局静态常量。 - 接口可用来实现多继承,一个类可以实现多个接口,以扩展其功能。 通过深入理解这些基础概念,开发者能够更好地编写和维护...
Java面试中的陷阱往往涉及到对语言核心概念的深度理解,这些陷阱涵盖了从基本语法特性到高级设计模式的应用。面试官通常会通过一些看似简单但实际上需要深入理解的问题来测试候选人的技能和经验。 首先,我们来看看...
第二周,实习生专注于Java的基础语法学习,包括类之间的关系(关联、聚合、继承、实现和多态)、基本数据类型、逻辑和循环语句、修饰符、static关键字、final关键字、this关键字、String和StringBuilder的特性等。...
Java是一种广泛使用的面向对象的编程语言,其设计目标包括简单性、面向对象、健壮性、安全性等。在准备Java面试时,理解并熟练掌握一些...在面试中,能够深入讨论和应用这些知识将有助于展示你的专业技能和深度理解。
Java期末考试试题是检验学生对Java编程语言理解深度和广度的重要方式,涵盖了从基础语法到高级特性的各个层面。以下是一些可能出现在这些试题中的关键知识点,它们可以帮助备考者进行复习和准备。 1. **Java基础...
ring 框架是一个开源的应用于Java平台的全面企业级应用开发框架,它旨在简化Java EE(Enterprise Edition)应用的开发工作。Spring 提供了一个丰富的IOC...对于准备面试的求职者,理解和掌握这些知识点是至关重要的。
本篇文章将深入探讨五个这样的“黑魔法”知识点,并提供相关的源代码示例,帮助你更好地理解和掌握它们。下面我们将逐个分析这些Java中的奇妙之处。 1. 反射(Reflection) 反射是Java中的一种强大工具,允许程序...
6. **关键字与操作符**: 关键字如static、final、volatile、transient等的作用,以及操作符如==、!=、&&、||等的逻辑和用法。 7. **基础类型**: 深入理解int、char、boolean等基础类型,以及它们的包装类,包括自动...
变量则根据其作用范围和生命周期有不同的修饰符,如final、static等。覆盖和重载是面向对象编程的重要概念,它们分别涉及到方法和构造函数的重写。 控制流是程序执行路径的管理,包括条件语句(if-else)、循环...
在Java工程师的面试中,单例模式和多线程是两个非常重要的知识点,它们既是基础,也是进阶技能,往往能体现一个开发者的编程素养和技术深度。以下将详细阐述这两个主题。 **单例模式** 单例模式是一种设计模式,它...
- 了解并精通Java的基础语法是必要的,包括关键字如`static`, `final`, `transient`等的用法。例如,`static`可以用来修饰变量、方法、静态内部类和静态导包。面试中,深入理解这些概念可以展示你的技术深度。 2. ...
例如,了解哪种数据结构适合哪种操作(ArrayList vs LinkedList),理解面向接口编程的优势,以及如何利用JVM特性优化代码,这些都是评价Java程序员技术深度的重要指标。同时,熟悉JVM内存模型、垃圾回收机制、多...
### 机器学习与深度学习面试精华之C++新特性详解 #### 一、C++11新特性概览 在2011年发布的C++11标准中,C++语言经历了一次重大的更新,引入了许多新特性,极大地提高了程序的可读性和效率,同时也使得开发变得...
了解Java关键字(如final, static, abstract, interface)的用法。 2. 内存管理:理解Java内存模型,包括堆内存、栈内存、方法区和本地方法栈。深入理解垃圾回收机制(GC)和内存泄漏问题。 3. 集合框架:掌握...
3. **关键字理解**:`this`、`static`和`final`在Java中的作用至关重要,它们分别用于引用当前对象、声明静态成员和创建不可变变量。 4. **参数传递机制**:理解值传递和引用传递的区别,避免常见的误区,对于编写...
- 关键字与数据类型:掌握基本和引用数据类型,如int、String等,了解final、static、void等关键字的用途。 - 控制流:熟练使用if、switch、for、while等控制结构,以及break、continue语句。 - 异常处理:理解...