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. ESXi 5.1 识别GPT问题

    使用paredUtil命令 partedUtil mklabel /dev/disks/eui.227c000155707e0b msdospartedUtil mklabel /dev/disks/ ...

  2. 关于本电脑qt5.11+vs2017+opencv3.4的配置问题

    本人想用qt5.11+vs2017+opencv3.4开发程序,配置了很久才成功,现在把配置后的环境变量记录一下,以供自己以后参考,同时也供大家参考. qt5.11+vs2017+opencv3.4的 ...

  3. CSS 优先级法则

    样式的优先级 多重样式(Multiple Styles):如果外部样式.内部样式和内联样式同时应用于同一个元素,就是使多重样式的情况. 一般情况下,优先级如下: (外部样式)External styl ...

  4. Oracle 中的进制转换

    Oracle 中的进制转换 */--> Oracle 中的进制转换 Table of Contents 1. 进制名 2. 10进制与16进制互相转换 2.1. 10进制转换为16进制 2.2. ...

  5. 基于MybatisUtil工具类,完成CURD操作

    package loaderman; import java.io.IOException; import java.io.Reader; import java.sql.Connection; im ...

  6. easyUI之progressbar进度条

    <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"> <html> <hea ...

  7. python之NLP词性标注

    1.知识点 包括中文和英文的词性标注主要使用的库是nltk和jiaba 2.代码 # coding = utf-8 import nltk from nltk.corpus import stopwo ...

  8. ssm整合的springmvc.xml的配置

    <?xml version="1.0" encoding="UTF-8"?><beans xmlns="http://www.spr ...

  9. lumen中间件中设置响应header

    <?php namespace App\Http\Middleware; use Closure; class BeforeMiddleware { public function handle ...

  10. 测试ssh转发

    端口转发提供: 1.加密 SSH Client 端至 SSH Server 端之间的通讯数据. 2.突破防火墙的限制完成一些之前无法建立的 TCP 连接. 但是只能转发tcp连接,想要转发UDP,需要 ...