当前位置: 首页 > news >正文

手机付费咨询网站建设汽车企业网站开发方案

手机付费咨询网站建设,汽车企业网站开发方案,企业网站建设一条,服装生产厂商网站建设方案final实现原理 简介 final关键字#xff0c;实际的含义就一句话#xff0c;不可改变。什么是不可改变#xff1f;就是初始化完成之后就不能再做任何的修改#xff0c;修饰成员变量的时候#xff0c;成员变量变成一个常数#xff1b;修饰方法的时候#xff0c;方法不允…final实现原理 简介 final关键字实际的含义就一句话不可改变。什么是不可改变就是初始化完成之后就不能再做任何的修改修饰成员变量的时候成员变量变成一个常数修饰方法的时候方法不允许被重写修饰类的时候类不允许被继承修饰参数列表的时候入参的对象也是不可以改变。这个就是不可变无论是引用新的对象重写还是继承都是改变的方法而final就是把这个变更的路给堵死 用法 final修饰变量 final成员变量表示常量只能被赋值一次赋值后值不再改变final要求地址值不能改变当final修饰一个基本数据类型时表示该基本数据类型的值一旦在初始化后便不能发生变化如果final修饰一个引用类型时则在对其初始化之后便不能再让其指向其他对象了但该引用所指向的对象的内容是可以发生变化的。本质上是一回事因为引用的值是一个地址final要求值即地址的值不发生变化。final修饰一个成员变量属性必须要显示初始化。这里有两种初始化方式。 一种是在变量声明的时候初始化。第二种方法是在声明变量的时候不赋初值但是要在这个变量所在的类的所有的构造函数中对这个变量赋初值。 final修饰方法 使用final方法的原因有两个。 第一个原因是把方法锁定以防任何继承类修改它的含义不能被重写第二个原因是效率final方法比非final方法要快因为在编译的时候已经静态绑定了不需要在运行时再动态绑定。 注类的private方法会隐式地被指定为final方法 final修饰类 当用final修饰一个类时表明这个类不能被继承。 final类中的成员变量可以根据需要设为final但是要注意final类中的所有成员方法都会被隐式地指定为final方法。 在使用final修饰类的时候要注意谨慎选择除非这个类真的在以后不会用来继承或者出于安全的考虑尽量不要将类设计为final类。 final关键字的好处 final关键字提高了性能。JVM和Java应用都会缓存final变量。final变量可以安全的在多线程环境下进行共享而不需要额外的同步开销。使用final关键字JVM会对方法、变量及类进行优化。 注意事项 final关键字可以用于成员变量、本地变量、方法以及类。final成员变量必须在声明的时候初始化或者在构造器中初始化否则就会报编译错误。你不能够对final变量再次赋值。本地变量必须在声明时赋值。在匿名类中所有变量都必须是final变量。final方法不能被重写。final类不能被继承。final关键字不同于finally关键字后者用于异常处理。final关键字容易与finalize()方法搞混后者是在Object类中定义的方法是在垃圾回收之前被JVM调用的方法。接口中声明的所有变量本身是final的。final和abstract这两个关键字是反相关的final类就不可能是abstract的。final方法在编译阶段绑定称为静态绑定(static binding)。没有在声明时初始化final变量的称为空白final变量(blank final variable)它们必须在构造器中初始化或者调用this()初始化。不这么做的话编译器会报错“final变量(变量名)需要进行初始化”。将类、方法、变量声明为final能够提高性能这样JVM就有机会进行估计然后优化。按照Java代码惯例final变量就是常量而且通常常量名要大写。对于集合对象声明为final指的是引用不能被更改但是你可以向其中增加删除或者改变内容。 原理 内存语义 写内存语义可以确保在对象的引用为任意线程可见之前final 域已经被初始化过了。 读内存语义可以确保如果对象的引用不为 null则说明 final 域已经被初始化过了。 总之final 域的内存语义提供了初始化安全保证。 写内存语义在构造函数内对一个 final 域的写入与随后将对象引用赋值给引用变量这两个操作不能重排序。读内存语义初次读一个包含 final 域的对象的引用与随后初次读这个 final 域这两个操作不能重排序。 写 final 域的重排序规则 写 final 域的重排序规则禁止把 final 域的写重排序到构造函数之外。这个规则的实现包含下面 2 个方面 JMM 禁止编译器把 final 域的写重排序到构造函数之外。编译器会在 final 域的写之后构造函数 return 之前插入一个 StoreStore 屏障。这个屏障禁止处理器把 final 域的写重排序到构造函数之外。 现在让我们分析 writer () 方法。writer () 方法只包含一行代码finalExample new FinalExample ()。这行代码包含两个步骤 构造一个 FinalExample 类型的对象把这个对象的引用赋值给引用变量 obj。 假设线程 B 读对象引用与读对象的成员域之间没有重排序马上会说明为什么需要这个假设下图是一种可能的执行时序 在上图中写普通域的操作被编译器重排序到了构造函数之外读线程 B 错误的读取了普通变量 i 初始化之前的值。而写 final 域的操作被写 final 域的重排序规则“限定”在了构造函数之内读线程 B 正确的读取了 final 变量初始化之后的值。 写 final 域的重排序规则可以确保在对象引用为任意线程可见之前对象的 final 域已经被正确初始化过了而普通域不具有这个保障。以上图为例在读线程 B“看到”对象引用 obj 时很可能 obj 对象还没有构造完成对普通域 i 的写操作被重排序到构造函数外此时初始值 2 还没有写入普通域 i。 读 final 域的重排序规则 读 final 域的重排序规则如下 在一个线程中初次读对象引用与初次读该对象包含的 final 域JMM 禁止处理器重排序这两个操作注意这个规则仅仅针对处理器。编译器会在读 final 域操作的前面插入一个 LoadLoad 屏障。 初次读对象引用与初次读该对象包含的 final 域这两个操作之间存在间接依赖关系。由于编译器遵守间接依赖关系因此编译器不会重排序这两个操作。大多数处理器也会遵守间接依赖大多数处理器也不会重排序这两个操作。但有少数处理器允许对存在间接依赖关系的操作做重排序比如 alpha 处理器这个规则就是专门用来针对这种处理器。 reader() 方法包含三个操作 初次读引用变量 obj;初次读引用变量 obj 指向对象的普通域 j。初次读引用变量 obj 指向对象的 final 域 i 现在我们假设写线程 A 没有发生任何重排序同时程序在不遵守间接依赖的处理器上执行下面是一种可能的执行时序 在上图中读对象的普通域的操作被处理器重排序到读对象引用之前。读普通域时该域还没有被写线程 A 写入这是一个错误的读取操作。而读 final 域的重排序规则会把读对象 final 域的操作“限定”在读对象引用之后此时该 final 域已经被 A 线程初始化过了这是一个正确的读取操作。 读 final 域的重排序规则可以确保在读一个对象的 final 域之前一定会先读包含这个 final 域的对象的引用。在这个示例程序中如果该引用不为 null那么引用对象的 final 域一定已经被 A 线程初始化过了。 如果 final 域是引用类型 上面我们看到的 final 域是基础数据类型下面让我们看看如果 final 域是引用类型将会有什么效果 请看下列示例代码 COPYpublic class FinalReferenceExample {final int[] intArray; //final 是引用类型 static FinalReferenceExample obj;public FinalReferenceExample () { // 构造函数 intArray new int[1]; //1intArray[0] 1; //2}public static void writerOne () { // 写线程 A 执行 obj new FinalReferenceExample (); //3}public static void writerTwo () { // 写线程 B 执行 obj.intArray[0] 2; //4}public static void reader () { // 读线程 C 执行 if (obj ! null) { //5int temp1 obj.intArray[0]; //6}} }这里 final 域为一个引用类型它引用一个 int 型的数组对象。对于引用类型写 final 域的重排序规则对编译器和处理器增加了如下约束 在构造函数内对一个 final 引用的对象的成员域的写入与随后在构造函数外把这个被构造对象的引用赋值给一个引用变量这两个操作之间不能重排序。 对上面的示例程序我们假设首先线程 A 执行 writerOne() 方法执行完后线程 B 执行 writerTwo() 方法执行完后线程 C 执行 reader () 方法。下面是一种可能的线程执行时序 在上图中1 是对 final 域的写入2 是对这个 final 域引用的对象的成员域的写入3 是把被构造的对象的引用赋值给某个引用变量。这里除了前面提到的 1 不能和 3 重排序外2 和 3 也不能重排序。 JMM 可以确保读线程 C 至少能看到写线程 A 在构造函数中对 final 引用对象的成员域的写入。即 C 至少能看到数组下标 0 的值为 1。而写线程 B 对数组元素的写入读线程 C 可能看的到也可能看不到。JMM 不保证线程 B 的写入对读线程 C 可见因为写线程 B 和读线程 C 之间存在数据竞争此时的执行结果不可预知。 如果想要确保读线程 C 看到写线程 B 对数组元素的写入写线程 B 和读线程 C 之间需要使用同步原语lock 或 volatile来确保内存可见性。 为什么 final 引用不能从构造函数内“逸出” 前面我们提到过写 final 域的重排序规则可以确保在引用变量为任意线程可见之前该引用变量指向的对象的 final 域已经在构造函数中被正确初始化过了。其实要得到这个效果还需要一个保证在构造函数内部不能让这个被构造对象的引用为其他线程可见也就是对象引用不能在构造函数中“逸出”。为了说明问题让我们来看下面示例代码 COPYpublic class FinalReferenceEscapeExample {final int i;static FinalReferenceEscapeExample obj;public FinalReferenceEscapeExample () {i 1; //1 写 final 域 obj this; //2 this 引用在此“逸出”}public static void writer() {new FinalReferenceEscapeExample ();} public static void reader {if (obj ! null) { //3int temp obj.i; //4}} }假设一个线程 A 执行 writer() 方法另一个线程 B 执行 reader() 方法。这里的操作 2 使得对象还未完成构造前就为线程 B 可见。即使这里的操作 2 是构造函数的最后一步且即使在程序中操作 2 排在操作 1 后面执行 read() 方法的线程仍然可能无法看到 final 域被初始化后的值因为这里的操作 1 和操作 2 之间可能被重排序。实际的执行时序可能如下图所示 从上图我们可以看出在构造函数返回前被构造对象的引用不能为其他线程可见因为此时的 final 域可能还没有被初始化。在构造函数返回后任意线程都将保证能看到 final 域正确初始化之后的值。 final 语义在处理器中的实现 现在我们以 x86 处理器为例说明 final 语义在处理器中的具体实现。 上面我们提到写 final 域的重排序规则会要求译编器在 final 域的写之后构造函数 return 之前插入一个 StoreStore 障屏。读 final 域的重排序规则要求编译器在读 final 域的操作前面插入一个 LoadLoad 屏障。 由于 x86 处理器不会对写 - 写操作做重排序所以在 x86 处理器中写 final 域需要的 StoreStore 障屏会被省略掉。同样由于 x86 处理器不会对存在间接依赖关系的操作做重排序所以在 x86 处理器中读 final 域需要的 LoadLoad 屏障也会被省略掉。也就是说在 x86 处理器中final 域的读 / 写不会插入任何内存屏障 为什么要增强 final 的语义 在旧的 Java 内存模型中 最严重的一个缺陷就是线程可能看到 final 域的值会改变。比如一个线程当前看到一个整形 final 域的值为 0还未初始化之前的默认值过一段时间之后这个线程再去读这个 final 域的值时却发现值变为了 1被某个线程初始化之后的值。最常见的例子就是在旧的 Java 内存模型中String 的值可能会改变。 为了修补这个漏洞JSR-133 专家组增强了 final 的语义。通过为 final 域增加写和读重排序规则可以为 java 程序员提供初始化安全保证只要对象是正确构造的被构造对象的引用在构造函数中没有“逸出”那么不需要使用同步指 lock 和 volatile 的使用就可以保证任意线程都能看到这个 final 域在构造函数中被初始化之后的值。 final、finally、 finalize区别 final可以用来修饰类、方法、变量分别有不同的意义final修饰的class代表不可以继承扩展final的变量是不可以修改的而final的方法也是不可以重写的override。finally则是Java保证重点代码一定要被执行的一种机制。我们可以使用try-finally或者try-catch-finally来进行类似关闭JDBC连接、保证unlock锁等动作。finalize是基础类java.lang.Object的一个方法它的设计目的是保证对象在被垃圾收集前完成特定资源的回收。finalize机制现在已经不推荐使用并且在JDK 9开始被标记为deprecated。 本文由传智教育博学谷狂野架构师教研团队发布。 如果本文对您有帮助欢迎关注和点赞如果您有任何建议也可留言评论或私信您的支持是我坚持创作的动力。 转载请注明出处
http://www.hyszgw.com/news/92167.html

相关文章:

  • 目录型搜索引擎有哪些seo插件wordpress
  • 如何运用网站模板福建省建设执业注册管理中心网站
  • 重庆好的网站制作公司wordpress 文章自动分页
  • 怎样做_网站做seo利用百度快照搜索消失的网站
  • 永州网站建设哪家好网页设计素材1000像素个人
  • 网站开发 哪家好网站的版式
  • 网站建设属于什么职位类别龙岩网站建设套餐服务
  • 给别人做的网站要复杂做安全扫描深圳建设网站费用
  • 济南网站建设优化百家号网站上传空间的ip地址
  • 网站交接需要哪些html注册登录界面代码
  • php实战做网站视频教程安卓开发基础
  • 青岛网站建设订做wordpress设置导航条
  • 精品网站建设费用 在线磐石网络北京网站建设哪家强
  • 站长工具seo排名wordpress添加一个论坛
  • 昆明建网站要多少钱电商未来发展趋势前景
  • 东莞凤岗做网站上海工商登记查询系统
  • dw做网站背景图片设置国内域名网站有那些
  • 做网站组服务器那个网站seo做的好的
  • 给网站做友情链接免费网站统计代码
  • 汽车门户网站管理系统的详细设计与实现页面置换算法课程设计
  • 怎么让百度蜘蛛围着网站爬取手机模块网站
  • 网站建设投放广告沈阳工程信息网官网
  • 湖南响应式网站建设公司深圳网页搜索排名提升
  • 广州网站推广制作128m vps wordpress
  • 电子商务网站建设岗位要求文创产品设计稿
  • 建站开发软件网站做ppt模板下载
  • 珠宝网站源码下载wordpress mysql 分表
  • 专门更新最新设计的网站临沂建设局官方网站
  • 公司网站开源源码主机屋
  • 网站制作的困难与解决方案wordpress开发视频网站