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

企业被网站骗做会员提高网站权重的作用

企业被网站骗做会员,提高网站权重的作用,俄罗斯局势最新消息,知名高端网站建设企业注意 equals 和 的区别 对基本类型#xff0c;比如 int、long#xff0c;进行判等#xff0c;只能使用 #xff0c;比较的是直接值。因为基本类型的值就是其数值。对引用类型#xff0c;比如 Integer、Long 和 String#xff0c;进行判等#xff0c;需要使用 equals 进…注意 equals 和 的区别 对基本类型比如 int、long进行判等只能使用 比较的是直接值。因为基本类型的值就是其数值。对引用类型比如 Integer、Long 和 String进行判等需要使用 equals 进行内容判等。因为引用类型的直接值是指针使用 的话比较的是指针也就是两个对象在内存中的地址即比较它们是不是同一个对象而不是比较对象的内容。 这就引出了我们必须必须要知道的第一个结论比较值的内容除了基本类型只能使用 外其他类型都需要使用 equals。 我们用下面的测试用例深入研究下 使用 对两个值为 127 的直接赋值的 Integer 对象判等用 对两个值为 128 的直接赋值的 Integer 对象判等使用 对一个值为 127 的直接赋值的 Integer 和另一个通过 new Integer 声明的值为 127 的对象判等使用 对两个通过 new Integer 声明的值为 127 的对象判等使用 对一个值为 128 的直接赋值的 Integer 对象和另一个值为 128 的 int 基本类型判等。 Integer a 127; //Integer.valueOf(127) Integer b 127; //Integer.valueOf(127) log.info(\nInteger a 127;\n Integer b 127;\n a b ? {},a b); // trueInteger c 128; //Integer.valueOf(128) Integer d 128; //Integer.valueOf(128) log.info(\nInteger c 128;\n Integer d 128;\n c d ? {}, c d); //falseInteger e 127; //Integer.valueOf(127) Integer f new Integer(127); //new instance log.info(\nInteger e 127;\n Integer f new Integer(127);\n e f ? {}, e f); //falseInteger g new Integer(127); //new instance Integer h new Integer(127); //new instance log.info(\nInteger g new Integer(127);\n Integer h new Integer(127);\n g h ? {}, g h); //falseInteger i 128; //unbox int j 128; log.info(\nInteger i 128;\n int j 128;\n i j ? {}, i j); //true 通过运行结果可以看到虽然看起来永远是在对 127 和 127、128 和 128 判等但 却没有永远给我们 true 的答复。原因是什么呢 第一个案例中编译器会把 Integer a 127 转换为 Integer.valueOf(127)。查看源码可以发现这个转换在内部其实做了缓存使得两个 Integer 指向同一个对象所以 返回 true。 public static Integer valueOf(int i) {if (i IntegerCache.low i IntegerCache.high)return IntegerCache.cache[i (-IntegerCache.low)];return new Integer(i); } 第二个案例中之所以同样的代码 128 就返回 false 的原因是默认情况下会缓存[-128, 127]的数值而 128 处于这个区间之外。 第三和第四个案例中New 出来的 Integer 始终是不走缓存的新对象。比较两个新对象或者比较一个新对象和一个来自缓存的对象结果肯定不是相同的对象因此返回 false。 第五个案例中我们把装箱的 Integer 和基本类型 int 比较前者会先拆箱再比较比较的肯定是数值而不是引用因此返回 true。 看到这里对于 Integer 什么时候是相同对象什么时候是不同对象就很清楚了吧。但知道这些其实意义不大因为在大多数时候我们并不关心 Integer 对象是否是同一个只需要记得比较 Integer 的值请使用 equals而不是 对于基本类型 int 的比较当然只能使用 。 其实我们应该都知道这个原则只是有的时候特别容易忽略。以我之前遇到过的一个生产事故为例有这么一个枚举定义了订单状态和对于状态的描述 enum StatusEnum {CREATED(1000, 已创建),PAID(1001, 已支付),DELIVERED(1002, 已送到),FINISHED(1003, 已完成);private final Integer status; //注意这里的Integerprivate final String desc;StatusEnum(Integer status, String desc) {this.status status;this.desc desc;} } 在业务代码中开发使用了 对枚举和入参 OrderQuery 中的 status 属性进行判等 Data public class OrderQuery {private Integer status;private String name; }PostMapping(enumcompare) public void enumcompare(RequestBody OrderQuery orderQuery){StatusEnum statusEnum StatusEnum.DELIVERED;log.info(orderQuery:{} statusEnum:{} result:{}, orderQuery, statusEnum, statusEnum.status orderQuery.getStatus()); } 因为枚举和入参 OrderQuery 中的 status 都是包装类型所以通过 判等肯定是有问题的。只是这个问题比较隐晦究其原因在于 只看枚举的定义 CREATED(1000, “已创建”)容易让人误解 status 值是基本类型因为有 Integer 缓存机制的存在所以使用 判等并不是所有情况下都有问题。在这次事故中订单状态的值从 100 开始增长程序一开始不出问题直到订单状态超过 127 后才出现 Bug。 在了解清楚为什么 Integer 使用 判等有时候也有效的原因之后我们再来看看为什么 String 也有这个问题。我们使用几个用例来测试下 对两个直接声明的值都为 1 的 String 使用 判等对两个 new 出来的值都为 2 的 String 使用 判等对两个 new 出来的值都为 3 的 String 先进行 intern 操作再使用 判等对两个 new 出来的值都为 4 的 String 通过 equals 判等。 String a 1; String b 1; log.info(\nString a \1\;\n String b \1\;\n a b ? {}, a b); //trueString c new String(2); String d new String(2); log.info(\nString c new String(\2\);\n String d new String(\2\); c d ? {}, c d); //falseString e new String(3).intern(); String f new String(3).intern(); log.info(\nString e new String(\3\).intern();\n String f new String(\3\).intern();\n e f ? {}, e f); //trueString g new String(4); String h new String(4); log.info(\nString g new String(\4\);\n String h new String(\4\);\n g h ? {}, g.equals(h)); //true 在分析这个结果之前我先和你说说 Java 的字符串常量池机制。首先要明确的是其设计初衷是节省内存。当代码中出现双引号形式创建字符串对象时JVM 会先对这个字符串进行检查如果字符串常量池中存在相同内容的字符串对象的引用则将这个引用返回否则创建新的字符串对象然后将这个引用放入字符串常量池并返回该引用。这种机制就是字符串驻留或池化。 再回到刚才的例子再来分析一下运行结果 第一个案例返回 true因为 Java 的字符串驻留机制直接使用双引号声明出来的两个 String 对象指向常量池中的相同字符串。第二个案例new 出来的两个 String 是不同对象引用当然不同所以得到 false 的结果。第三个案例使用 String 提供的 intern 方法也会走常量池机制所以同样能得到 true。第四个案例通过 equals 对值内容判等是正确的处理方式当然会得到 true。 实现一个 equals 没有这么简单 如果看过 Object 类源码你可能就知道equals 的实现其实是比较对象引用 public boolean equals(Object obj) {return (this obj); } 之所以 Integer 或 String 能通过 equals 实现内容判等是因为它们都重写了这个方法。比如String 的 equals 的实现 public boolean equals(Object anObject) {if (this anObject) {return true;}if (anObject instanceof String) {String anotherString (String)anObject;int n value.length;if (n anotherString.value.length) {char v1[] value;char v2[] anotherString.value;int i 0;while (n-- ! 0) {if (v1[i] ! v2[i])return false;i;}return true;}}return false; } 对于自定义类型如果不重写 equals 的话默认就是使用 Object 基类的按引用的比较方式。我们写一个自定义类测试一下。 假设有这样一个描述点的类 Point有 x、y 和描述三个属性 class Point {private int x;private int y;private final String desc;public Point(int x, int y, String desc) {this.x x;this.y y;this.desc desc;} } 定义三个点 p1、p2 和 p3其中 p1 和 p2 的描述属性不同p1 和 p3 的三个属性完全相同并写一段代码测试一下默认行为 Point p1 new Point(1, 2, a); Point p2 new Point(1, 2, b); Point p3 new Point(1, 2, a); log.info(p1.equals(p2) ? {}, p1.equals(p2)); log.info(p1.equals(p3) ? {}, p1.equals(p3)); 通过 equals 方法比较 p1 和 p2、p1 和 p3 均得到 false原因正如刚才所说我们并没有为 Point 类实现自定义的 equals 方法Object 超类中的 equals 默认使用 判等比较的是对象的引用。 我们期望的逻辑是只要 x 和 y 这 2 个属性一致就代表是同一个点所以写出了如下的改进代码重写 equals 方法把参数中的 Object 转换为 Point 比较其 x 和 y 属性 class PointWrong {private int x;private int y;private final String desc;public PointWrong(int x, int y, String desc) {this.x x;this.y y;this.desc desc;}Overridepublic boolean equals(Object o) {PointWrong that (PointWrong) o;return x that.x y that.y;} } 为测试改进后的 Point 是否可以满足需求我们定义了三个用例 比较一个 Point 对象和 null比较一个 Object 对象和一个 Point 对象比较两个 x 和 y 属性值相同的 Point 对象。 PointWrong p1 new PointWrong(1, 2, a); try {log.info(p1.equals(null) ? {}, p1.equals(null)); } catch (Exception ex) {log.error(ex.getMessage()); }Object o new Object(); try {log.info(p1.equals(expression) ? {}, p1.equals(o)); } catch (Exception ex) {log.error(ex.getMessage()); }PointWrong p2 new PointWrong(1, 2, b); log.info(p1.equals(p2) ? {}, p1.equals(p2)); 通过日志中的结果可以看到第一次比较出现了空指针异常第二次比较出现了类型转换异常第三次比较符合预期输出了 true。 [17:54:39.120] [http-nio-45678-exec-1] [ERROR] [t.c.e.demo1.EqualityMethodController:32 ] - java.lang.NullPointerException [17:54:39.120] [http-nio-45678-exec-1] [ERROR] [t.c.e.demo1.EqualityMethodController:39 ] - java.lang.ClassCastException: java.lang.Object cannot be cast to org.geekbang.time.commonmistakes.equals.demo1.EqualityMethodController$PointWrong [17:54:39.120] [http-nio-45678-exec-1] [INFO ] [t.c.e.demo1.EqualityMethodController:43 ] - p1.equals(p2) ? true 通过这些失效的用例我们大概可以总结出实现一个更好的 equals 应该注意的点 需要对另一方进行判空空对象和自身进行比较结果一定是 fasle需要判断两个对象的类型如果类型都不同那么直接返回 false确保类型相同的情况下再进行类型强制转换然后逐一判断所有字段。 修复和改进后的 equals 方法如下 Override public boolean equals(Object o) {if (this o) return true;if (o null || getClass() ! o.getClass()) return false;PointRight that (PointRight) o;return x that.x y that.y; } 改进后的 equals 看起来完美了但还没完。我们继续往下看。 hashCode 和 equals 要配对实现 我们来试试下面这个用例定义两个 x 和 y 属性值完全一致的 Point 对象 p1 和 p2把 p1 加入 HashSet然后判断这个 Set 中是否存在 p2 PointWrong p1 new PointWrong(1, 2, a); PointWrong p2 new PointWrong(1, 2, b);HashSetPointWrong points new HashSet(); points.add(p1); log.info(points.contains(p2) ? {}, points.contains(p2)); 按照改进后的 equals 方法这 2 个对象可以认为是同一个Set 中已经存在了 p1 就应该包含 p2但结果却是 false。 出现这个 Bug 的原因是散列表需要使用 hashCode 来定位元素放到哪个桶。如果自定义对象没有实现自定义的 hashCode 方法就会使用 Object 超类的默认实现得到的两个 hashCode 是不同的导致无法满足需求。 要自定义 hashCode我们可以直接使用 Objects.hash 方法来实现改进后的 Point 类如下 class PointRight {private final int x;private final int y;private final String desc;...Overridepublic boolean equals(Object o) {...}Overridepublic int hashCode() {return Objects.hash(x, y);} } 改进 equals 和 hashCode 后再测试下之前的四个用例结果全部符合预期。 [18:25:23.091] [http-nio-45678-exec-4] [INFO ] [t.c.e.demo1.EqualityMethodController:54 ] - p1.equals(null) ? false [18:25:23.093] [http-nio-45678-exec-4] [INFO ] [t.c.e.demo1.EqualityMethodController:61 ] - p1.equals(expression) ? false [18:25:23.094] [http-nio-45678-exec-4] [INFO ] [t.c.e.demo1.EqualityMethodController:67 ] - p1.equals(p2) ? true [18:25:23.094] [http-nio-45678-exec-4] [INFO ] [t.c.e.demo1.EqualityMethodController:71 ] - points.contains(p2) ? true 看到这里你可能会觉得自己实现 equals 和 hashCode 很麻烦实现 equals 有很多注意点而且代码量很大。不过实现这两个方法也有简单的方式一是后面要讲到的 Lombok 方法二是使用 IDE 的代码生成功能。IDEA 的类代码快捷生成菜单支持的功能如下 注意 compareTo 和 equals 的逻辑一致性 除了自定义类型需要确保 equals 和 hashCode 要逻辑一致外还有一个更容易被忽略的问题即 compareTo 同样需要和 equals 确保逻辑一致性。 我之前遇到过这么一个问题代码里本来使用了 ArrayList 的 indexOf 方法进行元素搜索但是一位好心的开发觉得逐一比较的时间复杂度是 O(n)效率太低了于是改为了排序后通过 Collections.binarySearch 方法进行搜索实现了 O(log n) 的时间复杂度。没想到这么一改却出现了 Bug。 我们来重现下这个问题。首先定义一个 Student 类有 id 和 name 两个属性并实现了一个 Comparable 接口来返回两个 id 的值 Data AllArgsConstructor class Student implements ComparableStudent{private int id;private String name;Overridepublic int compareTo(Student other) {int result Integer.compare(other.id, id);if (result0)log.info(this {} other {}, this, other);return result;} } 然后写一段测试代码分别通过 indexOf 方法和 Collections.binarySearch 方法进行搜索。列表中我们存放了两个学生第一个学生 id 是 1 叫 zhang第二个学生 id 是 2 叫 wang搜索这个列表是否存在一个 id 是 2 叫 li 的学生 GetMapping(wrong) public void wrong(){ListStudent list new ArrayList();list.add(new Student(1, zhang));list.add(new Student(2, wang));Student student new Student(2, li);log.info(ArrayList.indexOf);int index1 list.indexOf(student);Collections.sort(list);log.info(Collections.binarySearch);int index2 Collections.binarySearch(list, student);log.info(index1 index1);log.info(index2 index2); } 代码输出的日志如下 [18:46:50.226] [http-nio-45678-exec-1] [INFO ] [t.c.equals.demo2.CompareToController:28 ] - ArrayList.indexOf [18:46:50.226] [http-nio-45678-exec-1] [INFO ] [t.c.equals.demo2.CompareToController:31 ] - Collections.binarySearch [18:46:50.227] [http-nio-45678-exec-1] [INFO ] [t.c.equals.demo2.CompareToController:67 ] - this CompareToController.Student(id2, namewang) other CompareToController.Student(id2, nameli) [18:46:50.227] [http-nio-45678-exec-1] [INFO ] [t.c.equals.demo2.CompareToController:34 ] - index1 -1 [18:46:50.227] [http-nio-45678-exec-1] [INFO ] [t.c.equals.demo2.CompareToController:35 ] - index2 1 我们注意到如下几点 binarySearch 方法内部调用了元素的 compareTo 方法进行比较indexOf 的结果没问题列表中搜索不到 id 为 2、name 是 li 的学生binarySearch 返回了索引 1代表搜索到的结果是 id 为 2name 是 wang 的学生。 修复方式很简单确保 compareTo 的比较逻辑和 equals 的实现一致即可。重新实现一下 Student 类通过 Comparator.comparing 这个便捷的方法来实现两个字段的比较 Data AllArgsConstructor class StudentRight implements ComparableStudentRight{private int id;private String name;Overridepublic int compareTo(StudentRight other) {return Comparator.comparing(StudentRight::getName).thenComparingInt(StudentRight::getId).compare(this, other);} } 其实这个问题容易被忽略的原因在于两方面 一是我们使用了 Lombok 的 Data 标记了 StudentData 注解其实包含了 EqualsAndHashCode 注解的作用也就是默认情况下使用类型所有的字段参与到 equals 和 hashCode 方法的实现中。因为这两个方法的实现不是我们自己实现的所以容易忽略其逻辑。 二是compareTo 方法需要返回数值作为排序的依据容易让人使用数值类型的字段随意实现。 对于自定义的类型如果要实现 Comparable请记得 equals、hashCode、compareTo 三者逻辑一致。 小心 Lombok 生成代码的“坑” Lombok 的 Data 注解会帮我们实现 equals 和 hashcode 方法但是有继承关系时Lombok 自动生成的方法可能就不是我们期望的了。 我们先来研究一下其实现定义一个 Person 类型包含姓名和身份证两个字段 Data class Person {private String name;private String identity;public Person(String name, String identity) {this.name name;this.identity identity;} } 对于身份证相同、姓名不同的两个 Person 对象 Person person1 new Person(zhuye,001); Person person2 new Person(Joseph,001); log.info(person1.equals(person2) ? {}, person1.equals(person2)); 使用 equals 判等会得到 false。如果你希望只要身份证一致就认为是同一个人的话可以使用 EqualsAndHashCode.Exclude 注解来修饰 name 字段从 equals 和 hashCode 的实现中排除 name 字段 EqualsAndHashCode.Exclude private String name; 修改后得到 true。 但到这里还没完如果类型之间有继承Lombok 会怎么处理子类的 equals 和 hashCode 呢我们来测试一下写一个 Employee 类继承 Person并新定义一个公司属性 Data class Employee extends Person {private String company;public Employee(String name, String identity, String company) {super(name, identity);this.company company;} } 在如下的测试代码中声明两个 Employee 实例它们具有相同的公司名称但姓名和身份证均不同 Employee employee1 new Employee(zhuye,001, bkjk.com); Employee employee2 new Employee(Joseph,002, bkjk.com); log.info(employee1.equals(employee2) ? {}, employee1.equals(employee2)); 很遗憾结果是 true显然是没有考虑父类的属性而认为这两个员工是同一人说明 EqualsAndHashCode 默认实现没有使用父类属性。 为解决这个问题我们可以手动设置 callSuper 开关为 true来覆盖这种默认行为 Data EqualsAndHashCode(callSuper true) class Employee extends Person { 修改后的代码实现了同时以子类的属性 company 加上父类中的属性 identity作为 equals 和 hashCode 方法的实现条件实现上其实是调用了父类的 equals 和 hashCode。 重点回顾 首先我们要注意 equals 和 的区别。业务代码中进行内容的比较针对基本类型只能使用 针对 Integer、String 在内的引用类型需要使用 equals。Integer 和 String 的坑在于使用 判等有时也能获得正确结果。 其次对于自定义类型如果类型需要参与判等那么务必同时实现 equals 和 hashCode 方法并确保逻辑一致。如果希望快速实现 equals、hashCode 方法我们可以借助 IDE 的代码生成功能或使用 Lombok 来生成。如果类型也要参与比较那么 compareTo 方法的逻辑同样需要和 equals、hashCode 方法一致。 最后Lombok 的 EqualsAndHashCode 注解实现 equals 和 hashCode 的时候默认使用类型所有非 static、非 transient 的字段且不考虑父类。如果希望改变这种默认行为可以使用 EqualsAndHashCode.Exclude 排除一些字段并设置 callSuper true 来让子类的 equals 和 hashCode 调用父类的相应方法。
http://www.zqtcl.cn/news/178830/

相关文章:

  • 网站开发大致多少钱手机上怎么制作网站吗
  • 重庆网站seo营销模板wordpress学习 知乎
  • 桃子网站logowordpress post meta
  • 做网站一般需要什么青岛网络推广
  • 东莞网站建设 光龙wordpress4.6 nodejs
  • 宁海县建设局网站网站建设行业前景
  • 2003网站的建设谷歌seo新手快速入门
  • 网站建设服务开发网页制作下载链接怎么做
  • 网站更改域名河源建网站
  • 陕西培训网站建设校园网站建设目的
  • 做网站赚钱容易吗怎么创建自己网站平台
  • 肥料网站建设江门好的建站网站
  • 女朋友在互联网公司做网站规范网络直播平台的可行性建议
  • wordpress酷站微信推广平台自己可以做
  • 下载类网站如何做wordpress 文章分页 插件
  • 什么做书籍的网站好梅县区住房和城乡规划建设局网站
  • 网站开发的研究方法网站内容规划流程
  • 什么网站可以做数据调查深圳住房城乡建设局网站
  • 民治网站建设yihe kj程序外包公司
  • 男人与女人做视频网站wordpress无法上传图片
  • 二手手表回收网站海外推广渠道有哪些
  • 怎么把地图放到网站上如何做色流量网站
  • 常见的导航网站有哪些郑州核酸vip服务
  • 网站开发老板排名关键词优化师
  • 迈诺网站建设跨境电商平台网站建设
  • 做t恤的网站外贸仿牌网站建设
  • 网站建设的学习网站建站后维护需要做哪些
  • 为什么建设网站很多公司没有网站界面分析
  • 旅游网网站建设的管理大连淘宝网站建设
  • 无锡锡牛网站建设做汽配的外贸网站