关于这两个关键字,应该是在开发工做中比较常见的,使用频率上来讲也比较高。接口中、常量、静态方法等等。可是,使用频繁却不表明必定是可以清晰明白的了解,能说出个子丑演卯来。下面,对这两个关键字的常见用法作点总结记录,方便以后的回顾以及突击知识点。java
final,一如字面意思 “最终的”,大致在 Java 中表示 “不可变的”。可用来修饰类、方法、方法参数以及变量。ide
一、修饰类性能
final 在修饰类的时候,表明的是此类不能被继承。也就是说若是一个类肯定不会被继承使用,则能够设计成 final类型的。典型的例子就是 String 类。优化
二、修饰方法this
final 修饰的方法,能被继承,可是不能重写。能够重载。spa
三、修饰方法参数设计
final 在修饰方法参数的时候,表示的是在执行方法的内部,不可以去改变参数的值。可是若是是引用对象,是能够改变应用对象的属性值。code
四、修饰变量对象
final 在修饰变量,表明的是不可变,也便是常说的 “常量”。 final 在修饰的时候,容许一次赋值,以后在生命周期类,不容许对其进行修改。blog
修饰变量存在两种状况:基本类型的数据 和 对象数据。在修饰基本类型数据的时候,值是不可变的。在修饰对象数据的是,对象的引用是不可改变的,可是,能够修改对象内部的属性值。
final 修饰的变量必须在使用前进行初始化,一种方式是在声明的时候就给出默认值。还有一种就是经过构造方法去设置。
五、代码示例
package com.cfang; import java.util.Calendar; import lombok.Data; import lombok.extern.slf4j.Slf4j; @Slf4j public class T3 { public static void main(String[] args) { // -- 修饰变量 final int b = 0; /** * 编译报错:The final local variable b cannot be assigned. It must be blank and not using a compound assignment */ // b = 2; // -- 修饰方法参数 DemoCls cls = new DemoCls(); cls.setAge(10); log.info("democls age : {}", cls.getAge()); int a = 10; sayHello(a, cls); log.info("after call sayHello, democls age : {}", cls.getAge()); } private static void sayHello(final int a, final DemoCls cls) { /** * 编译报错:The final local variable a cannot be assigned. It must be blank and not using a compound assignment */ // a = 11; // cls = new DemoCls(); cls.setAge(11); } } @Data class DemoCls{ private int age; } // -- 修饰方法 @Slf4j class Person { public final void saySth() { log.info("i am person"); } } @Slf4j class Male extends Person{ /** * 编译出错 : Cannot override the final method from Person * 修饰的方法不可以被重写 */ // public final void saySth() { // log.info("i am male"); // } public final void saySth(String msg) { log.info("i am male"); } }
其中,修饰方法参数,若是是引用对象,是能够改变对象的属性值,这一点也很好理解:cls 是引用变量,final 修饰引用变量,只是限定了此引用变量 cls 的引用不能改变,而实际引用的对象的自己的值是能够进行修改的。文字语言组织可能不是很清晰,以下图所示,一目了然的就知道说要表述的意思了。
static,静态的。在 Java 中,static 一般可被用于修饰 变量、方法以及代码块。
一、修饰变量
static 修饰的变量,叫作静态变量。static 变量被全部类对象共享,在内存中仅一份,随着类的初始化而被加载。与之对应的非静态变量,是属于每一个实例对象自己,内存中存在多份,相互间不影响。
二、修饰方法
static 修饰的方法,叫作静态方法。调用静态方法,不依赖于实例对象就能够进行访问,因此,静态方法是没有 this的。因为此特性以及非静态方法依赖于实例对象调用,因此静态方法中是不可以直接使用非静态的成员属性和方法。与之相反的是,非静态方法是能够直接访问使用静态成员变量和方法。一样的,静态方法也是没有 super 的。能够一句话总结下:因为 static 和具体的实例对象无关,而 this、super和具体的实例对象息息相关,因此,static 和 this、super 势如水火,一如白天与黑夜。
三、修饰代码块
static 修饰代码块,在类初始化加载的时候,会按照 static 块的顺序进行加载,而且,生命周期内,只加载一次。基于此特性,能够设计优化程序的性能,一些只须要一次性初始化加载的内容,就能够放在 static 块中进行。
四、代码示例
package com.cfang; import lombok.extern.slf4j.Slf4j; @Slf4j public class T4 { private static int a; private static int b; private static int c; static { log.info("init value a"); a = 10; } { /** * 普通代码块,依赖于实例对象 */ log.info("init value c"); c = 12; } public static void main(String[] args) { // -- 静态方法调用非静态 /** * 不可直接访问 */ // sayHello1(); new T4().sayHello1(); // -- 静态方法直接调用 sayHello(); // -- 静态代码块初始化资源 log.info("value a : {}", a); log.info("value b : {}", b); log.info("value c : {}", c); } private static void sayHello() { log.info("say hello"); } private void sayHello1() { log.info("say hello1"); // -- 非静态方法直接调用 sayHello(); } static { log.info("init value b"); b = 11; } }
五、static 常见误区
package com.cfang; import lombok.Data; import lombok.extern.slf4j.Slf4j; @Slf4j public class T5 { private static int a = 10; public static void main(String[] args) { new T5().printVal(); //-- The field DemoCls01.b is not visible DemoCls01.b; } private void printVal() { int a = 11; log.info("value a : {}", this.a); } } @Data class DemoCls01{ private static int b; }
5.一、static 的 this
上述代码中,最终运行 printVal 方法,输出的结果是 :value a : 10 。 其实这也很好理解: this 指代的当前对象,而经过 new T5().printVal() 调用的话,this 指代的就是当前新建立的实例对象,static 修饰的变量自己是被全部类对象所共享的,而 printVal 方法中 a 属于局部变量,跟 this 实例对象并无关联。因此,输出的就是 10。
5.二、static 与 可见性
static 并不能改变变量或者方法的可见性。上述代码中,main 方法中,DemoCls01.b 会编译报错。
5.三、static 与 局部变量
Java规范中,明确说明了 :static 关键字不可修饰局部变量。
4、总结
final 和 static ,联合使用修饰属性表示一旦给值,就不可修改,而且能够经过类名访问;修饰方法,表示该方法不能重写,能够在不new对象的状况下调用。
忽然想到,接口 interface 中,成员变量的默认修饰符为 public static final,方法的默认修饰符 public abstract 。