static

类的成员分为两类,静态成员(static member)和实例成员(instance member)。静态成员属于类;实例成员则属于对象,即类的实例。

这是什么意思呢?

Java 把内存分为栈内存和堆内存,其中栈内存用来存放一些基本类型的变量、数组和对象的引用,堆内存主要存放一些对象。在 JVM 加载一个类的时候,若该类存在 static 修饰的成员变量和成员方法,则会为这些成员变量和成员方法在固定的位置开辟一个固定大小的内存区域,有了这些“固定”的特性,那么 JVM 就可以非常方便地访问他们。同时如果静态的成员变量和成员方法不出作用域的话,它们的句柄都会保持不变。同时 static 所蕴含“静态”的概念表示着它是不可恢复的,即在那个地方,你修改了,他是不会变回原样的,你清理了,他就不会回来了。

所以,static修饰的内容是属于类的,在加载类的时候就开辟好了一块内存空间来存放这些内容,创建的新的对象中的static内容都是相同的。

而static可以修饰什么呢?
  1. 变量 static修饰的变量被称为静态变量,在Java中,并不存在全局变量的概念,所以我们可以通过声明一个静态变量,来实现一个”全局变量“的作用。
  2. 方法 静态方法,同样,被static修饰的内容在类被加载的时候就已经创建好了,不依赖于实例对象,所以static方法不能是abstract的,必须被实现,我们可以通过访问类名来访问他。
  3. 代码块 随着类的加载被创建,一般可以用来提前进行一些操作,可以实现单例模式
static与线程安全

多线程是否会影响到静态成员呢?这时候我们就应该先理解线程不安全出现的前提:多个线程共享操作同一块内存区域,并且没有进行任何的保护

所以我们只需要弄清楚使用多线程的时候,是否共享同一块内存就可以了,而static成员在类被加载的时候就开辟了一块固定的内存空间, 所以当我们多线程访问static变量的时候,是有可能发生线程不安全的。

而当我们使用static方法的时候,虽然我们运行的是相同的内存中的方法,但如果我们static方法内进行操作的变量是局部变量(每个线程调用时,都会新建一个,不会共享一个内存区域),此时就不会有线程安全的问题。

总结

由于static成员是在类加载的时候提前准备好的,所以它是属于类的,所以我们在static方法或代码块中,我们只能调用静态方法和静态变量,不能引用成员变量、this、super等。