Java的static关键字和static final

一、介绍

在这篇文章中,我们将探索一下java语言中的static的细节。我们会演示如何在变量、方法、代码块,内部类中使用static关键字,以及他们的区别。

二、解剖static关键字

在java中,static关键字表明了这个特殊的成员是属于一个类而不仅仅是一个类的实例对象。这也就是意味着,一旦该static成员的实例被创建,它就会被这个类的所有实例共享。

三、static域(或者称 类变量)

在java中,如果一个域成员被声明为static,那么仅仅只会有一个该域成员的拷贝被创建,并且它还会在该类的所有实例对象中共享。
不管这个类你初始化多少次,都仅仅只会有一个该static域的拷贝。这个static域的值会在该类的所有实例对象中共享。

从JVM内存的视角来看,static变量会存储在jvm的一个特殊池里面这个特殊池被称为 Metaspace(在java8以前,这个池被称为Permanent Generation 或PermGen,现在PermGen已经被移除了,取而代之的是Metaspace)。

在java8之前,我们从jvm内存的角度来看一下:
这是jvm的架构图


jvmArch

那么Class的static域变量到底在哪个内存区域存储着呢??
在Runtime Data Areas中有5个区域:
1、Method Area 2、Heap 3、Java Thread 4、PC 5、Native
其中Heap区占据着举足轻重的作用:

Heap区的构成

The heap is broken up into smaller generations
the heap parts are:
(1). Young Gen
(2). Old Gen
(3). Perm Gen

PermGen里面存的是: 已装载的类的元信息,静态内容(包括:static mathod、static基本类型变量,以及对static对象的引用),字节码,JIT信息。

可见,在java8之前static域变量是被存储在Heap的PermGen区域中,在java8之后被存储在Metaspace中。

3.1 static域的案例

假设我们有一个Car类,这个Car类有多个实例变量。那么不管什么时候,只要我们创建一个该类的对象,每一个新对象都会拥有这些实例变量的不同拷贝。 然而,假设我们需要这样一个变量,该变量记录了Car对象的个数,并且要在这些Car对象之间共享这个变量,它们都能访问这个变量,并且在它们初始化时,令该变量的值自增。

      public class Car {
        private String name;
        private String engine;
         
        public static int numberOfCars;
         
        public Car(String name, String engine) {
        this.name = name;
        this.engine = engine;
        numberOfCars++;
        }
 
    // getters and setters
}
    

现在对于这个类的的每个对象被初始化时,都会令numberOfCars 变量的值增加。
因此,在这个例子中,下面的断言都是true:

@Test
public void whenNumberOfCarObjectsInitialized_thenStaticCounterIncreases() {
    new Car("Jaguar", "V8");
    new Car("Bugatti", "W16");
  
    assertEquals(2, Car.numberOfCars);
}

3.2.什么时候使用static域

.当变量的值不依赖于对象时

.当该变量的值应该在该类的所有对象间共享时

3.3 要记住的关键点

 .由于static变量属于类,所以它们可以直接通过类名来访问而不需要使用对象句柄。

 .static 变量只能在类级别上被声明


 .static域在没有对象初始化时,也能访问

 .虽然我们可以通过对象句柄来访问static域,但是我们不推荐这样做。

四、static final

当一个成员变量被static final修饰时,这个变量就是编译期常量:

If a primitive type or a string is defined as a constant and the value is known at compile time, the compiler replaces the constant name everywhere in the code with its value. This is called a compile-time constant.
If the value of the constant in the outside world changes (for example, if it is legislated that pi actually should be 3.975), you will need to recompile any classes that use this constant to get the current value.

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。