Set<String> names = new HashSet<>();
names.add("张三");
names.add(new String("张三")); Iterator<String> iterator = names.iterator();
while(iterator.hasNext()) {
System.out.println(iterator.next());
}

以上代码输出只有一个:张三

惊不惊喜,意不意外???

下面我们来看原因

按住ctrl键点击add进入到public interface Set<E> extends Collection<E> Set接口中的add抽象方法

boolean add(E e);

然后按住ctrl键盘点击到HashSet类中重新的add方法

 public boolean add(E e) {
return map.put(e, PRESENT)==null;
}

按住ctrl键点击put  进入到HashMap类中的put方法

  public V put(K key, V value) {
return putVal(hash(key), key, value, false, true);
}

其中的hash(key)是HashMap中的方法

static final int hash(Object key) {
int h;
return (key == null) ? 0 : (h = key.hashCode()) ^ (h >>> 16);
}

返回的值是key.hashCode()的相关转换,我们就看key.hashCode()的值是什么了  那我们来看一下这个方法

    public native int hashCode();//是Object类中的一个抽象方法

其中有继承重写这个方法的,但是打开Eclipse就会bug 试了两次了  ,那我们就不打开了

但是我们可以得到一个结论:

本身HashSet中的hashCode()方法就是同一个对象的hashCode()的返回值是相等的

我们可以自己重写hashCode()方法来判断他返回的值

并且其中putVal()方法也在HashMap方法中final V putVal(int hash, K key, V value, boolean onlyIfAbsent,boolean evict) {

        Node<K,V>[] tab; Node<K,V> p; int n, i;
if ((tab = table) == null || (n = tab.length) == 0)
n = (tab = resize()).length;
if ((p = tab[i = (n - 1) & hash]) == null)
tab[i] = newNode(hash, key, value, null);
else {
Node<K,V> e; K k;
      /*
      怎么判断相等的就是用下面的红色代码
        p.hash==hash 就是调用hash(key)方法后的值,只要是同一个对象,返回值就相同(可以重写hashCode()方法)
    
        (k = p.key) == key判断两个对象的地址是否相同
        
          key.equals(k)默认调用Object类中的equals方法判断地址是否相同,可以重写equals方法
        如果以上满足
            if (p.hash == hash &&
((k = p.key) == key || (key != null && key.equals(k))))
          那么这两个值就是相同的,后来的就会覆盖前面的。

       */
if (p.hash == hash &&
((k = p.key) == key || (key != null && key.equals(k))))
e = p;
else if (p instanceof TreeNode)
e = ((TreeNode<K,V>)p).putTreeVal(this, tab, hash, key, value);
else {
for (int binCount = 0; ; ++binCount) {
if ((e = p.next) == null) {
p.next = newNode(hash, key, value, null);
if (binCount >= TREEIFY_THRESHOLD - 1) // -1 for 1st
treeifyBin(tab, hash);
break;
}
if (e.hash == hash &&
((k = e.key) == key || (key != null && key.equals(k))))
break;
p = e;
}
}
        
if (e != null) { // existing mapping for key
V oldValue = e.value;
if (!onlyIfAbsent || oldValue == null)
e.value = value;
afterNodeAccess(e);
return oldValue;
}
}
++modCount;
if (++size > threshold)
resize();
afterNodeInsertion(evict);
return null;
}

分析:为上面青色字体

java——HashSet中add()方法不能加重复值得原因理解(我们一起来看底层代码吧)的更多相关文章

  1. java Queue中 add/offer,element/peek,remove/poll区别

    转自https://blog.csdn.net/u012050154/article/details/60572567 java Queue中 add/offer,element/peek,remov ...

  2. 用HashSet的add方法谈hashcode和equals方法重写

    本文主要通过用HashSet的add方法讲一下hashCode和equals方法重写.错误的地方望指正. 1.了解HashSet的add方法 了解一个方法的好办法是看源码,所以先看源码 private ...

  3. thymeleaf模板引擎调用java类中的方法(附源码)

    前言 <Docker+SpringBoot+Mybatis+thymeleaf的Java博客系统开源啦> 由于开源了项目的缘故,很多使用了My Blog项目的朋友遇到问题也都会联系我去解决 ...

  4. Jsp中如何通过Jsp调用Java类中的方法

    Jsp中如何通过Jsp调用Java类中的方法 1.新建一个项目,在src文件夹下添加一个包:如:cn.tianaoweb.com; 2.再在包中添加一个类:如 package com; public ...

  5. 【转载】C#中Add方法将往List集合末尾添加相应元素对象

    在C#的List集合操作中,有时候需要将符合条件的对象添加到已有List集合中的末尾,此时就需要使用到List集合的Add方法,Add方法的作用为将对应的元素添加到List集合末尾,Add方法签名为v ...

  6. HashSet的add()方法源码解析(jdk1.8)

    HashSet 实现了Set接口 实际上是HashMap 可以存null,但只能有一个 不保证元素是有序的,取决于hash后,在确定索引结果 add源码 //核心操作putVal final V pu ...

  7. 第6章 Java类中的方法

    1.如何定义java的方法 什么是方法:方法使用来解决一类问题的代码集合,是一个功能模块在类中定义个方法的方法是: 访问修饰符 返回值类型 方法名(参数列表){ 方法体 } 1.访问修饰符,是限制该方 ...

  8. Java接口中的方法

    接口中可以含有变量和方法.但是,接口中的变量会被隐式地指定为public static final变量(并且只能是public static final变量,用private修饰会报编译错误),而方法 ...

  9. jsp中怎么调用java类中的方法

    在jsp页面中先要,引入java类 例如: <%@page import="javabean.DbConn"%><!-- 引入包中的"类" - ...

随机推荐

  1. pm2 配置方式

    1.命令生产默认示例配置文件pm2 ecosystem或pm2 init,运行默认会生成ecosystem.config.js配置文件 module.exports = { apps: [ { nam ...

  2. Linux 查看网卡速率及版本

    查看网卡速率:ethtool 网卡名  如ethtool eth0 查看网卡驱动版本号:ethtool -i 网卡名   如ethtool -i eth0 示例: [root@nt3 ~]# etht ...

  3. pytorch-VGG网络

    VGG网络结构 第一层: 3x3x3x64, 步长为1, padding=1 第二层: 3x3x64x64, 步长为1, padding=1 第三层: 3x3x64x128, 步长为1, paddin ...

  4. linux下如何找出交叉编译器的某个库路径?

    答: 使用选项-print-file-name=<lib_name> 如列出libstdc++.so.6的库路径:aarch64-linux-gnu-gcc -print-file-nam ...

  5. C++继承中的属性

    class A { public: int a; A() { } void print() { cout<<a; } }; class B:public A { public: int a ...

  6. mybatis之动态SQL操作之更新

    1)  更新条件不确定,需要根据情况产生SQL语法,这种情况叫动态SQL /** * 持久层*/ public class StudentDao { /** * 动态SQL--更新 */ public ...

  7. hive端建表中文注释乱码

    背景:mysql编码是utf-8,mysql中建库建表中文显示都正常,但在hive窗口中建表时字段中文注释均乱码的问题. 问题:hive中建表后字段中文注释显示异常. 1. 定位 mysql 端问题 ...

  8. 安装php的sphinx扩展模块

    转自 http://blog.csdn.net/fenglailea/article/details/38115821 首先你必须已经安装过了sphinx 如何安装sphinx请看:http://bl ...

  9. Git(4):远程仓库

    添加\连接远程库 目前我们使用到的 Git 命令都是在本地执行,如果你想通过 Git 分享你的代码或者与其他开发人员合作. 你就需要将数据放到一台其他开发人员能够连接的服务器上. 远程仓库可以是Git ...

  10. phpstudy批量getshell工具

    phpstudy批量getshell工具,最新phpstudygetshell,配合精确采集实现每天轻松上万! 详情可加QQ:1743685523