一、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. list add() 和 addall()的区别

    http://blog.tianya.cn/post-4777591 如果有多个已经被实例化的List 集合,想要把他们组合成一个整体,并且,这里必须直接使用List 自身提供的一个方法List.ad ...

  2. react-native初体验(2) — 认识路由

    如果学习止步于 hello world, 那么人生也太没意思了.这次要做一个看起来真实的应用.多添加几个页面,让他们可以交互,动起来. react-native 官方推荐使用 react-naviga ...

  3. kubenetes无法创建pod/创建RC时无法自动创建pod的问题

    一.问题概述 问题1: 虽然每次通过yaml创建rc都显示成功了,但是 kubectl get pod却没显示任何的pod. 问题2: 直接通过yaml创建pod提示apixxx 问题3: 通过.js ...

  4. go vendor 安装失败的原因分析

    安装之前的配置 export GOPATH=$HOME/go export PATH=$PATH:$GOPATH/bin 1 2 安装 通常,我们查到的安装方法一般是下面这种 go get -u gi ...

  5. 2017秋软工 - 本周PSP

    1. PSP 2. PSP饼状图 3. 进度条 4. 累计进度图

  6. 第二阶段Sprint冲刺会议10

    进展:把所有功能整合到主界面,结果导致视频只能播放不能录制,闹钟加不进去,导致闹钟功能差点不能用,放弃整合.

  7. 《Spring1之第四次站立会议》

    <第四次站立会议> 昨天:我把小组成员找到的写关于登录界面的代码加到了我的项目工程里,并对它有了一定的了解,已经能够编译运行了,得到了登陆的界面: 今天:试着做了一下主框架里的在线人数的显 ...

  8. DataTime日期格式化

    C# DateTime日期格式化 在C#中DateTime是一个包含日期.时间的类型,此类型通过ToString()转换为字符串时,可根据传入给Tostring()的参数转换为多种字符串格式. 目录 ...

  9. BNUOJ 52318 Be Friends prim+Trie

    题目链接: https://acm.bnu.edu.cn/v3/problem_show.php?pid=52318 B. Be Friends Case Time Limit: 2500msMemo ...

  10. Beta 冲刺 (3/7)

    队名:日不落战队 安琪(队长) 过去两天完成了那些任务 上传个人信息. 接下来的任务 建立和上传收藏夹. 还剩下的任务 完善手写涂鸦. 社交模块. 遇到的困难 暂无. 有哪些收获和疑问 收获:okht ...