基于价值的类

在Java 8中,某些类在Javadoc中有一个小注释,说明它们是基于值的类 。 其中包括简短说明的链接,以及有关不使用它们的限制。 这很容易被忽略,如果这样做,则可能会在将来的Java版本中以微妙的方式破坏代码。 为了避免这种情况,我想在自己的文章中介绍基于价值的类,尽管我已经在其他文章中提到了最重要的部分。

总览

在详细说明这些限制之前,本文将首先探讨为什么存在基于值的类以及为什么限制了它们的使用(如果您不耐烦,请跳至此处 )。 它将以关于FindBugs的注释结束,不久便可以为您提供帮助。

背景

让我们快速了解为什么引入了基于值的类以及JDK中存在的类。

他们为什么存在?

Java的未来版本很可能包含值类型。 我将在未来几周内写他们( 所以 留 调整 ),并会在一些细节呈现出来。 尽管它们肯定有好处,但本博文未涉及这些好处,这可能会使限制显得毫无意义。 相信我,他们不是! 或者不要相信我自己去看 。

现在,让我们看看我已经写了一些关于值类型的内容:

该想法的最大简化是,用户可以定义一种不同于类和接口的新型类型。 它们的主要特征是它们将不会通过引用(如类)来处理,而是通过值(如基元)来处理。 或者,正如Brian Goetz在他的介绍性文章《价值观的状态》中所说的那样:

像类一样的代码,像int一样工作!

重要的是要添加值类型将是不变的-就像今天的原始类型一样。

在Java 8中,值类型之前是基于值的类 。 未来它们的精确关系尚不清楚,但可能与装箱和拆箱原语(例如Integerint )相似。

设计Optional时,现有类型与将来值类型之间的关系变得很明显。 在指定和记录基于价值的类的局限性时也是如此。

存在哪些基于价值的类?

这些都是我在JDK中找到的所有标记为基于值的类:

  • java.util: 可选 , OptionalDouble , OptionalLong , OptionalInt
  • java.time: 持续时间 , 即时 , LOCALDATE的 , LocalDateTime , 本地时间 , MONTHDAY , OffsetDateTime , OffsetTime , 期间 , 年 , YearMonth , ZonedDateTime , 了zoneid , ZoneOffset
  • java.time.chrono: HijrahDate , JapaneseDate , MinguaDate , ThaiBuddhistDate

我无法保证此列表是完整的,因为我没有找到列出所有列表的官方来源。

由Jeremy Schultz在CC-BY 2.0下发布。

发布时间由杰里米·舒尔茨在CC-BY 2.0 。

另外,还有一些非JDK类应该被认为是基于值的,但不要这样说。 一个例子是Guava的Optional 。 还可以安全地假设大多数代码库将包含旨在基于值的类。

有趣的是,现有的拳击类(如IntegerDouble等)未标记为基于值。 这样做似乎很可取-毕竟它们都是此类的原型-但这样做会破坏向后兼容性,因为它将使与新限制相抵触的所有用途追溯无效。

Optional是新的,而免责声明在第一天就到了。另一方面, Integer可能受到了无可救药的污染,而且我确信,如果Integer不再是可锁定的,它将破坏重要代码的空子(尽管我们可能会这样认为)练习。)

Brian Goetz – 2015年1月6日(格式化我的)

不过,它们非常相似,因此我们称它们为“价值至上”。

特点

在这一点上,尚不清楚如何实现值类型,它们的确切属性是什么以及它们如何与基于值的类交互。 因此,对后者施加的限制不是基于现有要求,而是源自某些所需的值类型特征。 这些限制是否足以在将来与值类型建立关系还不清楚。

话虽如此,让我们继续上面的引用:

在Java 8中,值类型之前是基于值的类 。 未来它们的精确关系尚不清楚,但可能与装箱和拆箱原语(例如Integerint )相似。 此外,编译器可能会自由地在两者之间进行静默切换以提高性能。 恰恰是,来回切换(即删除并稍后重新创建引用)也禁止将基于身份的机制应用于基于值的类。

这样实现的JVM不再需要跟踪基于值的实例的身份,这可以带来实质性的性能改进和其他好处。

身分识别

身份一词在这种情况下很重要,因此让我们仔细看看。 考虑一个可变对象,该对象会不断更改其状态(例如正在修改的列表)。 即使对象总是“看起来”不同,我们仍然会说它是同一对象。 因此,我们区分对象的状态和身份。 在Java中,状态相等由equals (如果适当实现)和身份相等通过比较引用来确定。 换句话说,对象的身份由其引用定义。

现在假设JVM将如上所述处理值类型和基于值的类。 在那种情况下,两者都不会具有有意义的身份。 值类型将没有一个开始,就像int一样。 相应的基于值的类仅仅是值类型的盒子,JVM可以随意销毁和随意创建它们。 因此,尽管当然有对单个盒子的引用,但完全不能保证它们将如何存在。

这意味着,即使程序员可以查看代码并遵循在各处传递的基于值的类的实例,JVM的行为也可能有所不同。 它可能会删除引用(从而破坏对象的标识)并将其作为值类型传递。 如果是身份敏感操作,则可能会重新创建一个新引用。

关于身份,最好考虑基于值的类,例如整数:谈论“ 3”的不同实例( int )是没有意义的,谈论“ 11:42 pm”的不同实例也没有意义( LocalTime )。

如果基于值的类的实例没有标识,则只能通过比较它们的状态(通过实现equals来确定)来确定其equals 。 这具有重要的含义,即状态相同的两个实例必须完全可互换,这意味着用另一个实例替换一个这样的实例必须不会产生任何明显的影响。

这间接确定了应将哪些内容视为基于值的实例状态的一部分。 所有类型为基本类型或其他基于值的类的字段都可以成为其一部分,因为它们也可以完全互换(所有“ 3”和“ 11:42 pm”的行为都相同)。 普通班比较棘手。 由于操作可能取决于它们的身份,因此如果基于vale的实例都引用相同但不相同的实例,则通常无法将其交换。

例如,考虑锁定String ,然后将其包装在Optional 。 在其他地方,将使用相同的字符序列创建另一个String并将其包装。 然后,这两个Optionals不可互换,因为即使它们都包装了相等的字符序列,这些String实例也不相同,一个实例用作锁,而另一个实例则充当锁。

严格解释这意味着基于值的类必须考虑引用本身,而不是将引用字段的状态包括在其自身的状态中。 在上面的示例中,仅当Optionals实际指向同一字符串时,才应将其视为相等。

但是,这可能过于严格,因为必须对给定的以及其他有问题的示例进行某种程度的解释。 强制基于值的类忽略诸如StringInteger类的“值-ish”类的状态非常违反直觉。

值类型框

被计划为值类型的框会增加一些其他要求。 如果不深入探讨值类型,这些将很难解释,因此我现在不再这样做。

局限性

首先,需要注意的是,在Java 8中,所有限制都是纯人工的。 JVM并不了解这类类的第一件事,并且您可以忽略所有规则而不会出错。 但这在引入值类型时可能会发生巨大变化。

正如我们在上面看到的,基于值的类的实例没有保证的身份,在定义相等性方面的宽松程度较低,并且应该符合值类型框的预期要求。 这有两个含义:

  • 该类必须相应地构建。
  • 该类的实例不得用于基于身份的操作。

这是Javadoc中所述限制的基础,因此可以将其分为对类的声明和其实例的使用的限制。

申报地点

直接来自文档(编号和格式编号):

基于值的类的实例:

  1. 是最终的且不可变的(尽管可能包含对可变对象的引用);
  2. 具有equalshashCodetoString实现,这些实现仅根据实例的状态而不是根据其标识或任何其他对象或变量的状态计算;
  3. 不使用身份敏感的操作,例如实例之间的引用相等( == ),实例的身份哈希码或实例的固有锁上的同步;
  4. 仅基于equals()而不是基于引用相等( == )被视为相等;
  5. 没有可访问的构造函数,而是通过工厂方法实例化的,该方法对提交的实例的身份不作任何承诺;
  6. 在相等时可以自由替换,这意味着在任何计算或方法调用中互换equals()任意两个实例xy都不会在行为上产生任何可见的变化。

通过上面讨论的内容,大多数这些规则都是显而易见的。

规则1的动机是基于价值的类,即价值类型的框。 出于技术和设计原因,这些必须是最终的且不可更改,并将这些要求转移到其包装盒中。

规则2 模糊地解决了有关如何定义基于值的类的状态的问题。 规则的精确效果取决于对“实例状态”和“任何其他变量”的解释。 读取它的一种方法是在状态中包括“值-ish”类,并将典型的引用类型视为其他变量。

第3到第6个数字考虑丢失的身份。

有趣的是, Optional打破了规则2,因为它在包装的值上调用了equals 。 同样, java.timejava.time.chrono所有基于值的类都通过可序列化(这是一个基于身份的操作,请参见下文) java.time.chrono打破规则3。

使用网站

再次从文档中:

如果程序尝试直接通过引用相等性或通过呼吁同步,身份哈希,序列化或任何其他身份敏感机制间接地将两个引用区分为基于值的类的相等值,则可能会产生不可预测的结果。

考虑到丢失的身份,直接区分参考是不言而喻的。 但是,没有任何解释说明为什么列出的示例违反了该规则,所以让我们仔细看看。 我列出了所有可以解决的违规事项,并给出了简短的解释和具体案例( vbi代表基于值的类的实例 ):

参考比较:这显然根据实例的身份来区分实例。

vbi的序列化:希望使值类型可序列化,并且有意义的定义似乎很简单。 但是,今天,序列化对对象身份做出了承诺,这与基于身份的无价值类的概念相冲突。 在当前的实现中,序列化在遍历对象图时也使用对象标识。 因此,目前,必须将其视为基于身份的操作,应避免使用。

情况:

  • 可序列化类中的非临时字段
  • 通过ObjectOutputStream.writeObject直接序列化

锁定vbi:使用对象标头访问实例的监视器–基于值的类的标头可以自由删除和重新创建,并且基本/值类型没有标头。

情况:

  • 在同步块中使用
  • 调用Object.wait,Object.notify或Object.notifyAll

身份哈希码:要求该哈希码在实例的生存期内保持不变。 由于基于价值的类的实例可以自由删除并重新创建,因此对于开发人员来说有意义的意义不能得到保证。

情况:

  • System.identityHashCode的参数
  • 键入IdentityHashMap

突出强调其他违规或改进说明的评论,深表感谢!

查找错误

当然,了解所有这一切是很好的,但这并不意味着阻止您超越规则的工具并不会真正有帮助。 作为FindBugs的重度用户,我决定要求项目实施此功能,并创建了功能请求 。 该票证涵盖了使用场所的限制,并将帮助您在JDK以及您自己的基于值的类(带有注释的类)中维护它们。

出于对FindBugs的好奇并希望做出贡献,我决定着手尝试自己实施它。 因此,如果您要问为什么花这么长时间准备好该功能,现在您知道了:这是我的错。 但是谈话很便宜,所以为什么不加入我的行列呢? 我在GitHub上放置了一个FindBugs克隆 ,您可以看到此pull请求中的进度。

一旦完成,我计划也要实现声明站点的规则,因此可以确保在值类型最终出现时,正确编写了基于值的类并准备就绪。

反射

我们已经看到,基于值的类是值类型的先驱。 随着Java的变化,这些实例将没有有意义的身份,并且定义它们的状态的可能性也将受到限制,这将对其声明和使用产生限制。 这些限制已详细讨论。

翻译自: https://www.javacodegeeks.com/2015/02/value-based-classes.html

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/360691.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

REST API的演变

每个开发人员都以某种方式接触到API 。 要么为一家大公司集成一个主要系统,或者使用最新的图形库生成一些精美的图表,要么直接与他喜欢的编程语言进行交互。 事实是,API无处不在! 它们实际上代表了当今Internet的基本构建块&#…

Oracle MAF中的LOV

我们都喜欢最强大的ADF功能值列表之一。 使用它们,我们可以在ADF应用程序中声明性地轻松构建非常复杂的功能。 一件好事是,我们在Oracle MAF中也有类似的方法。 在ADF BC中,我们在业务服务级别(基本上在实体或VO级别)定…

怎么移动矩形选框工具选中的东西_ps矩形选框工具怎么用,你值得一看的技巧...

PS是一款非常好用的图片制作软件,我们可以使用矩形选框工具,选择自己需要的区域进行操作,下面小编就教大家ps矩形选框工具怎么用,希望可以帮助到大家。操作方法01首先我们打开PS进入到主界面,如图所示。02之后我们需要…

stream 过滤俩个字段_Java8 Stream:2万字20个实例,玩转集合的筛选、归约、分组、聚合...

点波关注不迷路,一键三连好运连连!先贴上几个案例,水平高超的同学可以挑战一下:从员工集合中筛选出salary大于8000的员工,并放置到新的集合里。统计员工的最高薪资、平均薪资、薪资之和。将员工按薪资从高到低排序&…

一个JSF清单示例

这是使用JSF 2.0(JavaServer Faces)构建的示例列表应用程序。 该应用程序是待办事项列表。 该应用程序具有添加,编辑或删除列表中项目的功能。 待办事项具有名称和描述属性。 完成的应用程序的JSF页面具有: 使用h:selectOneList…

hdu 2444(二分图的判断以及求最大匹配)

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid2444思路:首先要判断能否构成二分图,用bfs对当前点u染色,对u的邻接点v的颜色进行判断,如果为染色,则染色后入队列,否则,判断co…

Delta架构:统一Lambda架构并利用Hadoop / REST中的Storm

最近,一群人要求我详细介绍我为我们的书《分布式实时计算的风暴蓝图》撰写的Druid / Storm集成。 德鲁伊很棒。 风暴很大。 两者一起解决了实时维查询/聚合问题。 实际上,人们正在将其视为主流,将其称为RAD Stack ,并添加了“ La…

activiti mysql 版本_Mysql8.0.17版本不能自动创建activiti表的坑

maven项目如下:配置好数据库,和activiti的配置之后,开始执行流程部署package com.yuanqiao.first_activiti.deployment;import java.util.List;import org.activiti.engine.ProcessEngine;import org.activiti.engine.ProcessEngines;import …

Linux Kernel 多个本地信息泄露漏洞

漏洞名称:Linux Kernel 多个本地信息泄露漏洞CNNVD编号:CNNVD-201306-028发布时间:2013-06-04更新时间:2013-06-04危害等级: 漏洞类型: 威胁类型:本地CVE编号: 漏洞来源&#xff1a…

Spinner 学习笔记

Adapter 适配器//方法一&#xff1a;直接使用字符串数组//String[] sSexList new String[]{"男", "女"};//方法二&#xff1a;使用资源文件String[] sSexList getResources().getStringArray(R.array.Sexarray);//实例化一个集合适配器ArrayAdapter<S…

Java 8发布一年后,IDE和编译器尚未完全就绪

一年前&#xff0c;即2014年3月18日 &#xff0c;发布了Java SE 8&#xff0c;并伴随着通过lambda表达式和streams API实现了功能性编程的幸福。 这对于我们所有的Java生态系统都是个好消息&#xff0c;许多人已经升级到Java8。Stack Overflow已经提出了大约2500个有关Java 8的…

mysql注入提取邮件_【sql注入教程】mysql注入直接getshell

Mysql注入直接getshell的条件相对来说比较苛刻点把1:要知道网站绝对路径&#xff0c;可以通过报错&#xff0c;phpinfo界面&#xff0c;404界面等一些方式知道2:gpc没有开启&#xff0c;开启了单引号被转义了&#xff0c;语句就不能正常执行了3:要有file权限&#xff0c;默认情…

使用WildFly 8.2.0.Final,Primefaces 5.1和MySQL 5的JDBC领域和基于表单的身份验证

我会不时查看我博客上最受欢迎的内容&#xff0c;并尽力满足您的最佳需求。 因此&#xff0c;阅读我的博客是其他读者推动内容的一种方式。 另一种方法是通过评论或电子邮件与我联系。 今天&#xff0c;我将使用Primefaces修改我的JDBC Realm示例并将其更新到最新的WildFly服务…

【转】代码里的命名规则:错误的和正确的对比

原文出处&#xff1a; goyello 译文出处&#xff1a; 外刊IT评论 编程初学者总是把大量的时间用在学习编程语言&#xff0c;语法&#xff0c;技巧和编程工具的使用上。他们认为&#xff0c;如果掌握了这些技术技巧&#xff0c;他们就能成为不错的程序员。然而&#xff0c;计算…

您的Apache Camel应用程序现在包括现成的文档

几个月前&#xff0c;我在博客中发布了有关即将发布的2.15版本的信息&#xff0c;该功能包括获取有关在端点上配置的每个属性的详细信息的功能-Apache Camel&#xff0c;请向我解释这些端点选项的含义 。 我们沿着这条道路继续前进&#xff0c;今天&#xff0c;我们将其从端点…

具有Spring Boot和数据功能的Java头优先弹性搜索

在本文中&#xff0c;我将为您提供有关如何在Java项目中使用Elastic Search的简单介绍。 由于Spring Boot是开始我们项目的最简单&#xff0c;最快的方法&#xff0c;因此我选择使用它。 此外&#xff0c;我们将大量使用心爱的Spring Data的Repository Goods。 首先&#xff0…

python 表单中值为空的还需要传入么_牛掰!100行Python,自动动手打造一款多国语言翻译软件...

大家在平时的学习或者工作中&#xff0c;往往少不了要阅读外文的文献&#xff0c;或者将外文的文献翻译成中文。这时候就需要打开网页&#xff0c;然后进行搜索&#xff0c;非常的麻烦。既然是玩Python&#xff0c;小编就带领大家来打造一款多种语言翻译的软件&#xff0c;无需…

使用Visual Studio 2010 一步一步创建Powershell Module 和 Cmdlet

之前写了一个C# 调用PowerShell方法&#xff0c; 那么怎么反过来操作呢&#xff0c;也就是怎么样用C#写一个powershell命令呢&#xff1f; 现在就用C#写一个超级简单的Module和Cmdlet 1. 在VS中创建一个Library的项目 文件->新建->项目->C#->Class Library 在这里给…

休眠锁定模式– PESSIMISTIC_FORCE_INCREMENT锁定模式如何工作

介绍 在我以前的文章中 &#xff0c;我介绍了OPTIMISTIC_FORCE_INCREMENT锁定模式&#xff0c;并将其应用于将子实体版本更改传播到锁定的父实体。 在本文中&#xff0c;我将介绍PESSIMISTIC_FORCE_INCREMENT锁定模式&#xff0c;并将其与乐观的锁定模式进行比较。 相像多于不…

实用程序类与函数式编程无关

最近&#xff0c;我被指控反对函数式编程&#xff0c;因为我将实用程序类称为反模式 。 绝对是错的&#xff01; 好吧&#xff0c;我确实认为它们是一种糟糕的反模式&#xff0c;但是它们与函数式编程无关。 我相信有两个基本原因。 首先&#xff0c;函数式编程是声明性的&…