Java 中 static 和 final 关键字
一、static 关键字
在Java中,使用 static 关键字有四个方面的作用:
- 修饰属性
- 修饰方法
- 修饰代码块
- 修饰类
1. 修饰属性
-
被static修饰的变量属于类变量,所有类共享,且不属于对象,可以通过类名.变量名直接引用。
-
Java静态属性和类相关,和具体的实例 / 对象无关,即就是说同一个类的不同实例共用同一个静态属性。
-
代码举例
class Test{ public int a; public static int count; } public class Main{ public static void main(String[] args) { Test t1 = new Test(); t1.a++; Test.count++; System.out.println(t1.a); System.out.println(Test.count); System.out.println("============"); Test t2 = new Test(); t2.a++; Test.count++; System.out.println(t2.a); System.out.println(Test.count); } }
输出结果为:(本代码中count被static所修饰,所有类共享,且不属于对象,其访问方式为:类名 . 属性。)
1
1
============
1
2
2. 修饰方法
-
被static修饰的方法属于类方法,称为静态方法,可以通过类名.方法名直接引用。
-
静态方法属于类,而不属于类的对象。
-
可以直接调用静态方法,而无需创建类的实例。
-
静态方法可以访问静态数据成员,并可以更改静态数据成员的值。
-
代码举例
class TestDemo{ public int a; public static int count; public static void change() { count = 100; //a = 10; error 不可以访问非静态数据成员 } } public class Main{ public static void main(String[] args) { TestDemo.change();//无需创建实例对象 就可以调用 System.out.println(TestDemo.count); } }
输出结果:
100
静态方法和实例无关, 而是和类相关. 因此这导致了两个情况:
- 静态方法不能直接使用非静态数据成员或调用非静态方法(非静态数据成员和方法都是和实例相关的).
- this和super两个关键字不能在静态上下文中使用(this 是当前实例的引用, super是当前实例父类实例的引用,也是和当前实例相关).
3. 修饰代码块
-
被static所修饰的代码块称为静态代码块,静态代码块中的内容只在程序启动(即类加载)时运行一次。
-
多个静态代码块时按程序顺序进行执行。
-
静态代码块可用来初始化静态成员。
-
静态代码块不管生成多少个对象,其只会执行一次,且是最先执行的。
-
静态代码块执行完毕后, 实例代码块(构造块)执行,再然后是构造函数执行。
-
代码举例
static{ ... }
4. 修饰类
- static一般情况下来说是不可以修饰类的,如果static要修饰一个类,说明这个类是一个静态内部类(static只能修饰一个内部类),也就是匿名内部类。
小结:
- 被static所修饰的属性或方法 ——>均与类相关 ——>类属性或静态方法 ——>不依赖于对象 ——>在JVM的方法区中。
- 没有被static修饰的属性 ——>与实例 / 对象相关——>实例属性——>在JVM 的堆上 ——> 引用时先需new出类的实例。
5.static变量和普通成员变量的区别:
- 所属不同。static变量属于类,不单属于任何对象;普通成员变量属于某个对象
- 存储区域不同。static变量位于方法区;普通成员变量位于堆区。
- 生命周期不同。static变量生命周期与类的生命周期相同;普通成员变量和其所属的对象的生命周期相同。
- 在对象序列化时(Serializable),static变量会被排除在外(因为static变量是属于类的,不属于对象)。
二、final 关键字
在Java中,final关键字可以用来修饰变量(包括成员变量和局部变量)、方法和类。
1. 修饰变量
-
修饰一个变量或者字段的时候, 表示常量 (不能修改).
-
final修饰基本数据类型的变量,则其数值一旦在初始化之后便不能更改;
-
final修饰引用类型的变量,则在对其初始化之后便不能再让其指向另一个对象。
final int a = 10; a = 20; // 编译出错`
-
final变量和普通变量的区别
当final变量是基本数据类型以及String类型时,如果在编译期间能知道它的确切值,则编译器会把它当做编译期常量使用。也就是说在用到该final变量的地方,相当于直接访问的这个常量,不需要在运行时确定。
2.修饰类
-
final 关键字也能修饰类, 此时表示被修饰的类就不能被继承。(final 关键字的功能即就是限制类被继承)
final public class Animal { ... } public class Bird extends Animal { ... } // 编译出错。Animal被final修饰,子类不可继承。
3. 修饰方法
- 使用final修饰方法,将方法锁定,以防任何继承类修改它的含义。
- 只有在想明确禁止该方法在子类中被覆盖的情况下才将方法设置为final。
- 类的private方法会隐式地被指定为final方法。