Java关键字之final和static
本篇文章主要对java中经常使用final
和static
两个关键字的用法做一下总结,主要参考了《Java编程思想》和网上的一些博客。
final
final应该是程序中经常使用的关键字之一,final关键字使用的对象是:类、方法、变量,下面依次介绍这几种使用final的情况。
final类
当一个类声明为final类,也就证明这个类是不能够被继承的,即禁止继承,因此final类的成员方法是没有机会被覆盖的,这个final类的功能是完整的。在Java中有很多类是final的,如String、Interger以及其他包装类。
final类的好处:
- 不可变类有很多的好处,它们的对象是只读的,可以在多线程环境下安全的共享,不用额外的开销。
下面是final类的实例:
1 | final class PersonalLoan{ |
final方法
如果一个类不允许其子类覆盖某个方法,即不能被重写,则可以把这个方法声明为final方法。(类中所有的private方法都隐式的指定为final)。
使用final方法的原因:
- 方法锁定,防止任何继承类修改它的含义,确保在继承中使方法行为保持不变且不被覆盖;
- 效率,将一个方法指明为final,就是同意编译器将针对该方法的所有调用都转化为内嵌调用(相当于在编译的时候已经静态绑定,不需要在运行时再动态绑定)。
下面是final方法的实例:
1 | public class Test1 { |
final变量
程序中有些数据的恒定不变是很有必要的,比如:
- 一个永不改变的编译时常量;
- 一个在运行时被初始化的值,而在程序的后面不希望它被改变。
这种类型的变量只能被赋值一次,一旦被赋值之后,就不能够再更改了。
有几点要注意的:
- 一个既是static又是final的域只占据一段不能改变的存储空间,一般用大写来表示;
- final使数值恒定不变,而当用于对象时,final使引用恒定不变(一旦引用指向一个对象,就无法再把它改为指向另一个对象);
final变量的好处:
- 提高性能,JVM和Java应用程序都会缓存final变量;
- final变量可以在安全的在多线程环境下进行共享,而不需要额外的开销。
下面是final类的实例:
1 | public class Test { |
final数据还有另外三个比较特殊的情况:与static合用,空白final和final参数。
static final
一个既是static又是final的域只占据一段不能改变的存储空间:
- 对于变量,它表示一旦给定就不可更改,并且可以通过类名直接访问(使用大写和下划线命名);
- 对于方法,表示不可覆盖,并且可以通过类名直接访问。
空白final
从上面的例子中,我们就可以看到空白final
的使用方法,它指的是:被声明为final但又未给出初值的域。无论什么情况下,编译器都确保空白final在使用前必须被初始化(在域的定义处或每个构造器中用表达式对final赋值)。
final参数
Java时允许在参数列表的声明中以声明的方式将参数指明为final。
- 当对象被指明为final时,这就意味着我们无法在方法中更改参数引用所指向的对象。
- 当基本类型的参数被指明为final时,我们可以读取参数但是无法修改参数。
总结
总结一下final关键字的一些重要特点:
- 本地变量必须在声明的时候赋值;
- 在匿名类中所有变量都必须是final变量;
- final方法不能被重写;
- final类不能被继承;
- final成员变量必须在声明的时候初始化或者在构造器中初始化,否则就会报编译错误;
- 接口中声明的所有变量本身是final的;
- final方法在编译阶段绑定,称为静态绑定(static binding);
- 对于集合对象声明为final指的是引用不能被更改,但是你可以向其中增加,删除或者改变内容;
static关键字
通常来说,当我们创建类时,就是在描述那个类的外观与行为。除非使用new
创建那个类的对象,否则并为获得任何对象。执行new
来创建对象时,数据存储空间才被分配,其方法才能被外界调用。
但是,试想在一种情况下,我们只想为某一特定区域分配单一存储空间,而不用去考虑它创建了多少对象。另一种情形是,希望某个方法不与包含它的类的任何对象联系在一起,也就是说,即使没有创建对象,也能够调用这个方法。这就是static
关键字主要使用的地方。
static一个很重要的用途就是多个对象可以共享一些存储空间,static关键字使用的对象为:类、方法、代码块。
static关键字有几个需要注意的地方:
- 被static修饰的成员变量和成员方法独立于该类的任何对象,它不依赖类的特定实例,被类的所有实例共享;
- 用public修饰的static成员变量和成员方法本质是全局变量和全局方法,当声明它类的对象市,不生成static变量的副本,而是类的所有实例共享同一个static变量;
- static变量前可以有private修饰,这时就不能使用类名直接访问流。
static修饰的成员变量和成员方法习惯上称为静态变量和静态方法,可以直接通过类名来访问,访问语法为:
- ClassName.Varibale
- ClassName.method()
static变量
按照是否静态的对类成员变量进行分类可分两种:
- 一种是被static修饰的变量,叫静态变量或类变量;
- 另一种是没有被static修饰的变量,叫实例变量。
两者的区别是:
- 对于静态变量在内存中只有一个拷贝(节省内存),JVM只为静态分配一次内存,在加载类的过程中完成静态变量的内存分配,可用类名直接访问(方便),当然也可以通过对象来访问;
- 对于实例变量,每创建一个实例,就会为实例变量分配一次内存,实例变量可以在内存中有多个拷贝,互不影响(灵活)。
一般在在对象之间使用共享值和方便访问变量时,就会去使用静态变量。
例子如下:
1 | public class Test { |
static方法
静态方法也叫做类方法,静态方法可以直接通过类名调用,任何的实例也都可以调用,因此静态方法中不能用this
和super
关键字,不能直接访问所属类的实例变量和实例方法(因为它们是与具体方法关联的),只能访问所属类的静态成员变量和成员方法。
因为static方法独立于任何实例,因此static方法必须被实现,而不能是抽象的abstract。
Java中很多使用static的方法,如Math类中所有的方法都是静态的,而一般类内部的static方法也是方便其它类对该方法的调用。
例子如下:
1 | public class Test { |
static代码块
static代码块也叫静态代码块,是在类中独立于类成员的static语句块,可以有多个,位置可以随便放,它不在任何的方法体内,JVM加载类时会执行这些静态的代码块,如果static代码块有多个,JVM将按照它们在类中出现的先后顺序依次执行它们,每个代码块只会被执行一次。
如:
1 | public class Test { |
总结
下面是关于静态变量和静态方法的一些总结:
- 一个类的静态方法只能访问其静态变量;
- 一个类的静态方法不能够直接调用非静态方法;
- 静态方法中不存在当前对象,因而不能使用 this,当然也不能使用 super;
- 静态方法不能被非静态方法覆盖;
- 构造方法不允许声明为 static 的;
- 局部变量不能使用static修饰。
公众号
个人公众号(柳年思水)已经上线,最新文章会同步在公众号发布,欢迎大家关注~