一、final

(一)、final的使用

final关键字可以用来修饰类、方法和变量(包括成员变量和局部变量)

1. 当用final修饰一个类时,表明这个类不能被继承。
2. 当用final修饰一个方法时,表明这个方法不能被重写。
3. 当用final修饰一个变量时,表明这个变量初始化后就不能再被修改。

final可以理解为"最后的、最终的"。与类而言,是不能被继承;与方法而言,是不能被覆盖;与变量而言,是不能再修改。

参考:浅谈Java中的final关键字

使用final修饰类的原因:
1. 设计原因(Design)
从设计的角度来考虑为final类,此时final 的语义表明为:这个类不想在关系结构上做出任何的改变,也不希望有任何人可以继承自这个类,除此之外,就没有更多的限制了。
2. 效率原因(Efficiency)
这里涉及到内联机制。一个类被final修饰后,它的方法默认被修饰为final ,这时方法的内联起到作用了。会将所有对方法的调用转化为inline调用的机制,大大提高执行效率。

final的实现原理:

1. final修饰域(基本数据类型、引用类型)
在一个类中被final修饰的域会在编译时放入常量池。
在编译后得到的.class文件中,有这么一块内容,叫常量池。常量池中的确包含了常量,当然还有其他的内容。一个类中被final修饰的域在这个时候就会被放入这个大池子中。
至于为什么这么做?原因很简单,为了效率。 其实将一个基本数据类型修饰为final的目的最单纯最美好,就是希望它不要变。这样系统有就可以做一些优化操作,将这些常量值装在需要计算的过程中,让它们充当类似于宏的身份,换句话说,编译器可以在编译期间提前完成一些计算工作,省去了在运行时对于变量的相对复杂的操作。那么到这里就完成了么?其实不是的,这里要补充的一点就是一个编译期间的类文件中,常量池中的基本数据类型的常量是不知道具体的值是什么,换句话说,在文件编译过后,虽然知道一个域是常量,但是至于这个常量的具体内容是什么,此时是无从知晓的。
只有当运行时,常量才会真正的被赋值,对于static和没有static修饰的基本数据类型来说,是有差异的,差异就在于static修饰的域是在类载入的时候进行初始化的,所有实例共享同一个常量,同时Java虚拟机没有把它当作类变量,在使用它的任何类的常量池或者字节码流中直接存放的是它表示的常量值。

2. final修饰类和方法
Java的沙箱为了保证装载的类文件的安全性,会在验证阶段对字节码流做多次的验证,那么其中就包括对各个类之间的二进制兼容的检查,其中就包括,
1. 检查final的类不能拥有子类
2. 检查final的方法不能被覆盖

参考:Final of Java,这一篇差不多了

(二)、final域的内存语义

final域是基础数据类型时的重排序规则:
写final域的重排序规则:在构造函数内对一个final域的写入,与随后把这个被构造对象的引用赋值给一个引用对象,这个两个操作之间不能重排序。(禁止把final域的写重排序到构造函数之外)
写final域的重排序规则可以确保:在对象引用为任意线程可见之前,对象的final域已经被正确初始化过了,而普通域不具有这个保障。
读final域的重排序规则:初次读一个包含final域的对象的引用,与随后初次读这个对象包含的final域,这两个操作之间不能重排序。(在一个线程中,初次读对象引用,与初次读该对象包含的final域,JMM禁止处理器重排序这两个操作)
读final域的重排序规则可以确保:在读一个对象的final域之前,一定会先读包含这个final域的对象的引用。

final域是引用类型时的重排序规则:(相比final域是基础数据类型的情况,增加了以下约束)
写final域的重排序规则:在构造函数内对一个final引用的对象的成员域的写入,与随后在构造函数外把这个被构造对象的引用赋值给一个引用变量,这两个操作之间不能重排序。

为什么final引用不能冲构造函数内“逸出”(可以看出写final域的重排序规则保证了final域的写入被限定在构造函数内执行)
在构造函数返回前,被构造对象的引用还不能为其他线程所见,因为此时的final域可能还没有被初始化。

参考:《Java并发编程的艺术》

final类型的变量可以保证在多线程发布某个对象时,这个对象的final域变量能够被正常的初始化(在写final变量后加了storestore屏障,在读final变量前加了loadload屏障),而普通类型的变量可能不会被正确的初始化,这样导致该对象在多个线程之间出现不一致的情况,这也就是我们所说的引用溢出。

参考:说说final关键字(好像有干货)

二、static

(一)、static的使用(可以在没有创建任何对象的前提下,仅仅通过类本身来调用static方法)

static可以用来修饰类的成员方法、类的成员变量,另外可以编写static代码块来优化程序性能。

1. static方法,static方法一般称为静态方法,静态方法不依赖于任何对象就可以进行访问
2. static变量,static变量也称作静态变量,静态变量和非静态变量的区别是:静态变量被所有的对象所共享,在内存中只有一个副本,它当且仅当在类初次加载时会被初始化。而非静态变量是对象所拥有的,在创建对象的时候被初始化,存在多个副本,各个对象拥有的副本互不影响。
static成员变量的初始化顺序按照定义的顺序进行初始化。
3. static代码块,static块可以置于类中的任何地方,类中可以有多个static块。在类初次被加载的时候,会按照static块的顺序来执行每个static块,并且只会执行一次。(因为只在类加载的时候执行一次,因此可以用static代码块来优化程序性能)

参考:Java中的static关键字解析

另外这里还有一个例子

class Parent {
static String name = "hello"; //非静态代码块
{
System.out.println("parent block");
} static {
System.out.println("parent static block");
} public Parent(String name) {
System.out.println("name");
System.out.println("parent constructor");
}
} class Child extends Parent {
static String childName = "hello";
{
System.out.println("child block");
}
static {
System.out.println("child static block");
} public Child() {
super("name");
System.out.println("child constructor");
}
} public class TestStatic { public static void main(String[] args) {
new Child();// 语句(*)
}
}

运行结果:

parent static block
child static block
parent block
parent constructor
child block
child constructor

分析:当执行new Child()时,它首先去看父类里面有没有静态代码块,如果有,它先去执行父类里面静态代码块里面的内容,当父类的静态代码块里面的内容执行完毕之后,接着去执行子类(自己这个类)里面的静态代码块,当子类的静态代码块执行完毕之后,它接着又去看父类有没有非静态代码块,如果有就执行父类的非静态代码块,父类的非静态代码块执行完毕,接着执行父类的构造方法;父类的构造方法执行完毕之后,它接着去看子类有没有非静态代码块,如果有就执行子类的非静态代码块。子类的非静态代码块执行完毕再去执行子类的构造方法,这个就是一个对象的初始化顺序。

总结:
对象的初始化顺序:首先执行父类静态的内容,父类静态的内容执行完毕后,接着去执行子类的静态的内容,当子类的静态内容执行完毕之后,再去看父类有没有非静态代码块,如果有就执行父类的非静态代码块,父类的非静态代码块执行完毕,接着执行父类的构造方法;父类的构造方法执行完毕之后,它接着去看子类有没有非静态代码块,如果有就执行子类的非静态代码块。子类的非静态代码块执行完毕再去执行子类的构造方法。总之一句话,静态代码块内容先执行,接着执行父类非静态代码块和构造方法,然后执行子类非静态代码块和构造方法。

注意:子类的构造方法,不管这个构造方法带不带参数,默认的它都会先去寻找父类的不带参数的构造方法。如果父类没有不带参数的构造方法,那么子类必须用supper关键子来调用父类带参数的构造方法,否则编译不能通过。

三、final和static在一起使用(他们同时使用时既可修饰成员变量,也可修饰成员方法。)

1. 对于成员变量,该变量一旦赋值就不能改变,该变量被类的所有实例共享,我们称它为“全局常量”。可以通过类名直接访问。
2. 对于成员方法,表示该方法不可继承和改变。可以通过类名直接访问。

对final和static的理解的更多相关文章

  1. 理解Java中的final和static关键字

    回顾这两个关键字前,先考虑一个问题: Static变量存储在JVM中的位置,或者说static变量是如何被加载的? JVM会把类的静态方法和静态变量在类加载的过程中读入方法区(Method Area) ...

  2. 深入理解final和static关键字

    深入理解final和static关键字 参考:http://blog.csdn.net/qq1028951741/article/details/53418852 final关键字 final关键字可 ...

  3. 【转】Java关键字final、static使用总结

    转自:http://lavasoft.blog.51cto.com/62575/18771/   Java关键字final.static使用总结   一.final        根据程序上下文环境, ...

  4. Java关键字final、static使用总结

    Java关键字final.static使用总结   一.final        根据程序上下文环境,Java关键字final有“这是无法改变的”或者“终态的”含义,它可以修饰非抽象类.非抽象类成员方 ...

  5. 转!Java关键字final、static使用总结

    Java关键字final.static使用总结   一.final 根据程序上下文环境,Java关键字final有“这是无法改变的”或者“终态的”含义,它可以修饰非抽象类.非抽象类成员方法和变量.你可 ...

  6. Java关键字final、static使用总结(转)

    Java关键字final.static使用总结   一.final        根据程序上下文环境,Java关键字final有“这是无法改变的”或者“终态的”含义,它可以修饰非抽象类.非抽象类成员方 ...

  7. Java:final、static关键字 详解+两者结合使用

    一  final关键字 1) 关于final的重要知识点 final关键字可以用于成员变量.本地变量.方法以及类. final成员变量必须在声明的时候初始化或者在构造器中初始化,否则就会报编译错误. ...

  8. Java中static、final、static final的区别(转)

    说明:不一定准确,但是最快理解. final: final可以修饰:属性,方法,类,局部变量(方法中的变量) final修饰的属性的初始化可以在编译期,也可以在运行期,初始化后不能被改变. final ...

  9. 每天写两个的java常见面试题—final 和static 的用法

    第一次写随笔,可能写的比较乱,更多的是作为自己记忆一些知识的方式.所有记录的东西都是自己的一些理解,很多语言可能还是从其他大牛的博客里面搬过来的. 一.static的作用: static的的作用从三个 ...

随机推荐

  1. [Mark]Windows Server 2008 R2 防火墙之SQL Server 2008 R2

    今天新装了一个DBServer (Windows Server 2008 R2),但是在客户端跑之前的应用时却发现出错了,Debugg后发现的错误如下:   由InnerException可知时DB ...

  2. js数组的比较

    如果两个数组元素个数都相等,但排序不同,那么它两个相等吗?结果肯定是否定的.但如果先调用sort()方法进行排序,结果就是true了. console.log(a.sort().toString()= ...

  3. Datawhale MySQL 训练营 Task4 表联结

    学习内容 MySQL别名 列别名,将查询或者筛选出来列用AS 命名,如果有空格则需要引号 '' SELECT xxx AS xxxx FROM WHERE GROUP BY HAVING 表别名, 把 ...

  4. python3 拼接字符串的7种方法

    1.直接通过(+)操作符拼接 1 2 >>> 'Hello' + ' ' + 'World' + '!' 'Hello World!' 使用这种方式进行字符串连接的操作效率低下,因为 ...

  5. Performance — 前端性能监控利器

    Performance是一个做前端性能监控离不开的API,最好在页面完全加载完成之后再使用,因为很多值必须在页面完全加载之后才能得到.最简单的办法是在window.onload事件中读取各种数据. 大 ...

  6. Daily Srum 10.30

    Android那一组打算用SQL Server这个关系型数据库,而王鹿鸣他们一组却是依赖于Hbase,这是一件很麻烦的事,所以我打算在这两方面都建立一个数据库.虽然挺麻烦,但是还是为了扩展性所做的必要 ...

  7. OO第四次作业-对前三次作业总结

    第一次作业由于直接没怎么学过java,全靠一星期速成,前几天看了java的语法,但是因为光看没有打代码,学习效果并不是特别好.由面向过程转向面向对象,不是特别清楚该怎么办,虽然写的是两个类,但实际上是 ...

  8. RocEDU.阅读.写作选择书目

    很高兴加入这样一个专门于读书.写作的群. 一.选择图书 通识类: <你的灯亮着吗> 作者: 高斯 (Donald C. Gause) / 温伯格 (Gerald M.Weinberg) 出 ...

  9. Scapy 网段中ping扫描

    安装scapy pip3 install scapy-python3 交互式ip包构造 #scapy >>> ping = sr(IP(dst='202.100.1.1')/ICMP ...

  10. keil51下使用sprintf问题

    测试环境:keil c51 + STC89C52说明: 1.keil的不定参数只有15个字节也就是说sizeof(...) 加起来总共不能超过15字节,否则会出错 2.当不定参数中有常数时,你也会得不 ...