一, 概述
static 关键字是 Java 诸多关键字中较常使用的一个, 从其本意可得其意: 静态, 何为静态呢? 静, 即不动, 静止, 固定不变之意 (其实可以理解为存储位置不变).
Java 中的静是相对于 "动" 而言的, 所谓的动就是可变化的内容.
当然这里指的是针对类而言的, 静态内容指的是在类被 JVM 加载的时候就确定的内容, 这部分内容只会被分配一次内存, 即在内存中保留一份存储, 动态内容则不同, 它们是随类的对象创建而动的, 每当创建一个对象的时候就会对这些内容分配一份内存, 即每个对象都有自己独有的内存存储空间 (其中保存着那些动态的内容).
静态的内容是属于类的, 动态的内容属于对象.
上面的描述是及其概括的描述, 下面我们仔细的了解下 static 的作用.
二, 作用
2.1 static 修饰变量
static 是一种修饰符, 最常用的就是修饰变量, static 修饰的变量含有全局的意味, 这个变量会变得脱颖而出, 不再受对象的桎梏, 它在类加载的时候就会分配内存来存储, 存储在运行时数据区中的方法区中, 属于类级别的存在, 可以使用类名点用.
如果我们在类 StaticTest 中定义一个如下的静态变量:
- public class StaticTest{
- static int i = 1;// 申明静态变量
- }
那么我们就可以使用下面的方式进行使用:
- public class StaticTest{
- static int i = 1;// 申明静态变量
- public static void main(String[] args){
- StaticTest.i = 3;// 类名点用
- }
- }
静态变量可被其他方法直接调用, 因为静态变量早于或同于其他变量, 方法而存在, 故而可被随意使用, 但非静态变量不可以, 因为非静态变量属于对象, 需要在对象创建的时候才能分配内存而存在, 明显在对象创建之前静态方法就无法直接调用非静态变量 (因为尚不存在这个变量), 当然在创建了对象之后就可以调用了, 为了确保正确性, 一律规定在静态方法中不能直接调用非静态变量, 所有的非静态变量必须使用对象来调用.
何时使用 static 变量呢?
根据 static 变量的储存方式, 我们可以看出, 这种变量只会存在一份, 但却可以被任意使用, 可以被所有的对象所拥有, 它的值的可变的, 但却是共享的, 一方改变, 多方共享.
那么我们不难想到, 我们在定义类的时候对于那些公共的, 共享的属性完全可以定义成 static 的, 这样一来, 不但节省的内存消耗, 而且操作性也变得非常容易, 需要修改的时候, 只需要修改一个, 那么所有对象都会得到这个修改后的新值.
2.2 static 修饰常量
常量是被 final 所修饰的变量的别称, final 修饰变量之后, 表示这个变量的值一旦赋值, 则不再发生改变. 如果在加上 static 修饰, 那么这个变量就会变成一个静态常量 (类常量), 这个常量会在类加载时分配内存到方法区中. 而仅使用 final 修饰的常量则是在对象创建时保存到方法区中. 因为他属于对象的常量, 而静态常量是属于公共的, 共享的常量.
具体可以查看《Java 基础系列 --final,finally 关键字》
2.3 static 修饰方法
static 修饰方法表示这些方法为静态方法, 静态方法和非静态方法一样都保存在方法区中, 不同之处在于动静之分, 静态方法中不能直接调用非静态变量和方法. 静态方法自身属于类级存在, 可以使用类名点用.
近来, static 方法一般用于定义工具方法, 一般在一个工具类中定义, 这个类内部全部为静态内容, 完全作为一个工具对外进行服务 (这貌似有些违背面向对象设计思想).
2.4 static 修饰代码块
代码块的存在, 一般用于初始化一些变量的值, 非静态代码块用于初始化非静态变量的值, 该代码块在每次创建对象时都会被调用, 而静态代码块用于初始化一些静态变量的值, 只会在类加载的时候调用执行一次.
详情见《JVM 基础系列 - 类加载器》
2.5 static 修饰内部类
内部类种类较多, 这里讲静态内部类, 静态内部类由于其静态特性, 可脱离外部类来创建对象, 普通内部类必须依据外部类对象来创建内部类对象.
静态内部类中可调用外部类中的静态内容, 其中包括 private 内容.
- class Invoke{
- static int i = 1;
- int j = 2;
- static class InnerClass1{
- public void innerMethod(){
- i = 3;
- new Invoke().j = 4;
- outMethod1();
- // outMethod2();// 报错
- // j = 4;// 报错
- }
- }
- class InnerClass2{
- public void innerMethod(){
- i = 3;
- outMethod1();
- outMethod2();
- j = 4;
- }
- }
- static void outMethod1(){}
- void outMethod2(){}
- }
我们需要使用如下方式创建内部类的对象:
- public class StaticTest {
- public static void main(String[] args){
- Invoke.InnerClass1 innerClass1 = new Invoke.InnerClass1();// 3-
- Invoke.InnerClass2 innerClass2 = new Invoke().new InnerClass2();//4-
- }
- }
注意第 3,4 行的创建方式的区别.
静态内部类和普通内部类的区别:
静态内部类可以有静态成员 (方法, 属性), 而非静态内部类则不能有静态成员 (方法, 属性).
静态内部类只能够访问外部类的静态成员, 而非静态内部类则可以访问外部类的所有成员 (方法, 属性).
2.6 static 导入
静态导入功能是一种较新的功能, 可以单独导入某个类中的静态方法.
- import static java.util.Collections.*;
- import static java.util.Collections.synchronizedList;
如上第一行表示导入 Collections 类中的所有静态方法, 而第二行仅仅导入指定的静态方法 synchronizedList().
来源: http://www.jianshu.com/p/f2b9aabb01c6