JAVA关键字final、static详解
final关键字
Java关键字final有“这是无法改变的”或者“终态的”含义,它可以修饰非抽象类、非抽象类成员方法和变量。
- final类不能被继承,没有子类,final类中的方法默认是final的。
- final方法不能被子类的方法覆盖,但可以被继承。
- final成员变量表示常量,只能被赋值一次,赋值后值不再改变。
- final不能用于修饰构造方法。
注意:父类的private成员方法是不能被子类方法覆盖的,因此private类型的方法默认是final类型的。
- final类
final类不能被继承,因此final类的成员方法没有机会被覆盖,默认都是final的。在设计类时候,如果这个类不需要有子类,类的实现细节不允许改变,并且确信这个类不会载被扩展,那么就设计为final类。 - final方法
如果一个类不允许其子类覆盖某个方法,则可以把这个方法声明为final方法。 - final变量(常量)
用final修饰的成员变量表示常量,值一旦给定就无法改变!
final修饰的变量有三种:静态变量、实例变量和局部变量,分别表示三种类型的常量。
final变量定义的时候,可以先声明,而不给初值,这种变量也称为final空白,无论什么情况,编译器都确保空白final在使用之前必须被初始化。但是,final空白在final关键字final的使用上提供了更大的灵活性,为此,一个类中的final数据成员就可以实现依对象而有所不同,却有保持其恒定不变的特征。
public class Demo1 {
private final String S = "final实例变量S";
private final int A = 100;
public final int B = 90;
public static final int C = 80;
private static final int D = 70;
public final int E; // final空白,必须在初始化对象的时候赋初值
public Demo1(int e) {
E = e;
}
public static void main(String[] args) {
Demo1 demo = new Demo1(66);
// demo.A=101; //出错,final变量的值一旦给定就无法改变
// demo.B=91; //出错,final变量的值一旦给定就无法改变
// demo.C=81; //出错,final变量的值一旦给定就无法改变
// demo.D=71; //出错,final变量的值一旦给定就无法改变
System.out.println(demo.A);
System.out.println(demo.B);
System.out.println(demo.C); // 不推荐用对象方式访问静态字段
System.out.println(demo.D); // 不推荐用对象方式访问静态字段
System.out.println(Demo1.C);
System.out.println(Demo1.D);
// System.out.println(Demo1.E); //出错,因为E为final空白,依据不同对象值有所不同.
System.out.println(demo.E);
Demo1 t1 = new Demo1(3);
System.out.println(t1.E); // final空白变量E依据对象的不同而不同
}
private void test() {
System.out.println(new Demo1(1).A);
System.out.println(Demo1.C);
System.out.println(Demo1.D);
}
public void test1() {
final int a; // final空白,在需要的时候才赋值
final int b = 4; // 局部常量--final用于局部变量的情形
final int c; // final空白,一直没有给赋值.
a = 3;
//a=4; // 出错,已经给赋过值了.
//b=2; // 出错,已经给赋过值了.
}
}
- final参数
当函数参数为final类型时,你可以读取使用该参数,但是无法改变该参数的值。
public void fun(final int a) {
// a++; //a是final类型的,值不允许改变的.
System.out.println(a);
}
static关键字
static方法就是没有this的方法。在static方法内部不能调用非静态方法,反过来是可以的。而且可以在没有创建任何对象的前提下,仅仅通过类本身来调用static方法。被static关键字修饰的方法或者变量不需要依赖于对象来进行访问,只要类被加载了,就可以通过类名去进行访问。
static可以用来修饰类的成员方法、类的成员变量,另外可以编写static代码块来优化程序性能。
- static方法
static方法一般称作静态方法,由于静态方法不依赖于任何对象就可以进行访问,因此对于静态方法来说,是没有this的,因为它不依附于任何对象,既然都没有对象,就谈不上this了。并且由于这个特性,在静态方法中不能访问类的非静态成员变量和非静态成员方法,因为非静态成员方法/变量都是必须依赖具体的对象才能够被调用。但是在非静态成员方法中是可以访问静态成员方法/变量的。
public class Demo1 {
private static String str1 = "张三";
private String str2 = "李四";
public void print1() {
System.out.println(str1);
System.out.println(str2);
print2();
}
public static void print2() {
System.out.println(str1);
// System.out.println(str2);//静态方法不能访问非静态变量
// print1();//静态方法不能调用非静态方法
}
}
- static变量
static变量也称作静态变量,静态变量和非静态变量的区别是:静态变量被所有的对象所共享,在内存中只有一个副本,它当且仅当在类初次加载时会被初始化。而非静态变量是对象所拥有的,在创建对象的时候被初始化,存在多个副本,各个对象拥有的副本互不影响。static成员变量的初始化顺序按照定义的顺序进行初始化。 - static代码块
static关键字还有一个比较关键的作用就是 用来形成静态代码块以优化程序性能。static块可以置于类中的任何地方,类中可以有多个static块。在类初次被加载的时候,会按照static块的顺序来执行每个static块,并且只会执行一次。
class Person{
private Date birthDate;
private static Date startDate,endDate;
static{
startDate = Date.valueOf("1946");
endDate = Date.valueOf("1964");
}
public Person(Date birthDate) {
this.birthDate = birthDate;
}
boolean isBornBoomer() {
// Date startDate = Date.valueOf("1946");//使用static之前
// Date endDate = Date.valueOf("1964");
return birthDate.compareTo(startDate)>=0 && birthDate.compareTo(endDate) < 0;
}
}
- static笔试题
public class Test {
Person person = new Person("Test");
static{
System.out.println("test static");
}
public Test() {
System.out.println("test constructor");
}
public static void main(String[] args) {
new MyClass();
}
}
class Person{
static{
System.out.println("person static");
}
public Person(String str) {
System.out.println("person "+str);
}
}
class MyClass extends Test {
Person person = new Person("MyClass");
static{
System.out.println("myclass static");
}
public MyClass() {
System.out.println("myclass constructor");
}
}
输出内容
test static
myclass static
person static
person Test
test constructor
person MyClass
myclass constructor
首先加载Test类,因此会执行Test类中的static块。接着执行new MyClass(),而MyClass类还没有被加载,因此需要加载MyClass类。在加载MyClass类的时候,发现MyClass类继承自Test类,但是由于Test类已经被加载了,所以只需要加载MyClass类,那么就会执行MyClass类的中的static块。在加载完之后,就通过构造器来生成对象。而在生成对象的时候,必须先初始化父类的成员变量,因此会执行Test中的Person person = new Person(),而Person类还没有被加载过,因此会先加载Person类并执行Person类中的static块,接着执行父类的构造器,完成了父类的初始化,然后就来初始化自身了,因此会接着执行MyClass中的Person person = new Person(),最后执行MyClass的构造器。
博客参考:
https://blog.51cto.com/lavasoft/18771
感谢作者。