HashMap深度分析

7.3 空间矢量调制(SVM)整数算法 本文提出了一种基于整数运算的空间矢量调制(SVM)优化实现方案,适用于计算资源有限的Cortex-M0平台。针对传统SVM算法中复杂的三角函数和浮点运算问题,重点优化了扇区判断和占空比计算两个关键环节。在扇区判断方面,采用基于电压分量符号和相对大小的三变量法,避免了角度计算;在占空比计算方面,通过几何关系将作用时间表示为电压分量的线性组合,并采用定点数实现。方案还详细讨论了系数定点化、死区补偿等实现细节,在保证精度的同时显著降低了计算复杂度。实验结果表明,优化后的整数算法在M0平台上仅需50-80个周期即可 阅读详情

 

 java.util.HashMap是很常见的类,前段时间公司系统由于对HashMap使用不当,导致cpu百分之百,在并发环境下使用HashMap 而没有做同步,可能会引起死循环,关于这一点,sun的官方网站上已有阐述,这并非是bug。

HashMap的数据结构
         HashMap主要是用数组来存储数据的,我们都知道它会对key进行哈希运算,哈系运算会有重复的哈希值,对于哈希值的冲突,HashMap采用链表来解决的。在HashMap里有这样的一句属性声明:
transient Entry[] table;
Entry就是HashMap存储数据所用的类,它拥有的属性如下
final K key;
V value;
final int hash;
Entry<K,V> next;
看到next了吗?next就是为了哈希冲突而存在的。比如通过哈希运算,一个新元素应该在数组的第10个位置,但是第10个位置已经有Entry,那么好吧,将新加的元素也放到第10个位置,将第10个位置的原有Entry赋值给当前新加的 Entry的next属性。数组存储的是链表,链表是为了解决哈希冲突的,这一点要注意。


几个关键的属性
存储数据的数组
transient Entry[] table; 这个上面已经讲到了
默认容量
static final int DEFAULT_INITIAL_CAPACITY = 16;
最大容量
static final int MAXIMUM_CAPACITY = 1 << 30;
默认加载因子,加载因子是一个比例,当HashMap的数据大小>=容量*加载因子时,HashMap会将容量扩容
static final float DEFAULT_LOAD_FACTOR = 0.75f;
当实际数据大小超过threshold时,HashMap会将容量扩容,threshold=容量*加载因子
int threshold;
加载因子
final float loadFactor;


HashMap的初始过程
构造函数1

Java代码 
  1. public HashMap(int initialCapacity, float loadFactor) {  
  2.     if (initialCapacity < 0)  
  3.         throw new IllegalArgumentException("Illegal initial capacity: " +  
  4.                                            initialCapacity);  
  5.     if (initialCapacity > MAXIMUM_CAPACITY)  
  6.         initialCapacity = MAXIMUM_CAPACITY;  
  7.     if (loadFactor <= 0 || Float.isNaN(loadFactor))  
  8.         throw new IllegalArgumentException("Illegal load factor: " +  
  9.                                            loadFactor);  
  10.   
  11.     // Find a power of 2 >= initialCapacity  
  12.     int capacity = 1;  
  13.     while (capacity < initialCapacity)  
  14.         capacity <<= 1;  
  15.   
  16.     this.loadFactor = loadFactor;  
  17.     threshold = (int)(capacity * loadFactor);  
  18.     table = new Entry[capacity];  
  19.     init();  
  20. }  
 



重点注意这里 

Java代码 
  1. while (capacity < initialCapacity)  
  2.             capacity <<= 1;  
 


capacity才是初始容量,而不是initialCapacity,这个要特别注意,如果执行new HashMap(9,0.75);那么HashMap的初始容量是16,而不是9,想想为什么吧。

构造函数2

Java代码 
  1. public HashMap(int initialCapacity) {  
  2.         this(initialCapacity, DEFAULT_LOAD_FACTOR);  
  3.     }  
 


构造函数3,全部都是默认值

Java代码 
  1. public HashMap() {  
  2.      this.loadFactor = DEFAULT_LOAD_FACTOR;  
  3.      threshold = (int)(DEFAULT_INITIAL_CAPACITY * DEFAULT_LOAD_FACTOR);  
  4.      table = new Entry[DEFAULT_INITIAL_CAPACITY];  
  5.      init();  
  6.  }  
 


构造函数4

Java代码 
  1. public HashMap(Map<? extends K, ? extends V> m) {  
  2.       this(Math.max((int) (m.size() / DEFAULT_LOAD_FACTOR) + 1,  
  3.                     DEFAULT_INITIAL_CAPACITY), DEFAULT_LOAD_FACTOR);  
  4.       putAllForCreate(m);  
  5.   }  
 



如何哈希
        HashMap并不是直接将对象的hashcode作为哈希值的,而是要把key的hashcode作一些运算以得到最终的哈希值,并且得到的哈希值也不是在数组中的位置哦,无论是get还是put还是别的方法,计算哈希值都是这一句:
int hash = hash(key.hashCode());
hash函数如下:

Java代码 
  1. static int hash(int h) {  
  2.   return useNewHash ? newHash(h) : oldHash(h);  
  3.   }  
 


useNewHash声明如下:
  

Java代码 
  1. private static final boolean useNewHash;  
  2.    static { useNewHash = false; }  
 

这说明useNewHash其实一直为false且不可改变的,hash函数里对 useNewHash的判断真是多余的。

Java代码 
  1. private static int oldHash(int h) {  
  2.     h += ~(h << 9);  
  3.     h ^=  (h >>> 14);  
  4.     h +=  (h << 4);  
  5.     h ^=  (h >>> 10);  
  6.     return h;  
  7. }  
  8.   
  9. private static int newHash(int h) {  
  10.     // This function ensures that hashCodes that differ only by  
  11.     // constant multiples at each bit position have a bounded  
  12.     // number of collisions (approximately 8 at default load factor).  
  13.     h ^= (h >>> 20) ^ (h >>> 12);  
  14.     return h ^ (h >>> 7) ^ (h >>> 4);  
  15. }  
 



其实HashMap的哈希函数会一直都是oldHash。


如果确定数据的位置
看下面两行
  

Java代码 
  1. int hash = hash(k.hashCode());  
  2.   int i = indexFor(hash, table.length);  
 

第一行,上面讲过了,是得到哈希值,第二行,则是根据哈希指计算元素在数组中的位置了,位置的计算是将哈希值和数组长度按位与运算。

Java代码 
  1. static int indexFor(int h, int length) {  
  2.      return h & (length-1);  
  3.  }  
 


“h & (length-1)”其实这里是很有讲究的,为什么是和(length-1)进行按位与运算呢?这样做是为了提高HashMap的效率。什么?这样能提高效率?且听我细细道来。

首先我们要确定一下,HashMap的数组长度永远都是偶数,即使你在初始化的时候是这样的new HashMap(15,0.75);因为在构造函数内部,上面也讲过,有这样的一段代码:

Java代码 
  1. while (capacity < initialCapacity)  
  2.             capacity <<= 1;  
 


所以length-1一定是个奇数,假设现在长度为16,减去1后就是15,对应的二进制是:1111。

假设有两个元素,一个哈希值是8,二进制是1000,一个哈希值是9,二进制是1001。和1111与运算后,分别还是1000和1001,它们被分配在了数组的不同位置,这样,哈希的分布非常均匀。

那么,如果数组长度是奇数,减去1后就是偶数了,偶数对应的二进制最低位一定是0了,例如14二进制1110。对上面两个数子分别与运算,得到1000和1000。看到了吗?都是一样的值,哈希值8和9的元素多被存储在数组同一个位置的链表中。在操作的时候,链表中的元素越多,效率越低,因为 要不停的对链表循环比较。所以,一定要哈希均匀分布,尽量减少哈希冲突,减少了哈希冲突,就减少了链表循环,就提高了效率。

 

 

 


put方法到底作了什么?

Java代码 
  1. public V put(K key, V value) {  
  2.  if (key == null)  
  3.      return putForNullKey(value);  
  4.      int hash = hash(key.hashCode());  
  5.      int i = indexFor(hash, table.length);  
  6.      for (Entry<K,V> e = table[i]; e != null; e = e.next) {  
  7.          Object k;  
  8.          if (e.hash == hash && ((k = e.key) == key || key.equals(k))) {  
  9.              V oldValue = e.value;  
  10.              e.value = value;  
  11.              e.recordAccess(this);  
  12.              return oldValue;  
  13.          }  
  14.      }  
  15.   
  16.      modCount++;  
  17.      addEntry(hash, key, value, i);  
  18.      return null;  
  19.  }  
 


如果key为NULL,则是单独处理的,看看putForNullKey方法:
  

Java代码 
  1. private V putForNullKey(V value) {  
  2.       int hash = hash(NULL_KEY.hashCode());  
  3.       int i = indexFor(hash, table.length);  
  4.   
  5.       for (Entry<K,V> e = table[i]; e != null; e = e.next) {  
  6.           if (e.key == NULL_KEY) {  
  7.               V oldValue = e.value;  
  8.               e.value = value;  
  9.               e.recordAccess(this);  
  10.               return oldValue;  
  11.           }  
  12.       }  
  13.   
  14.       modCount++;  
  15.       addEntry(hash, (K) NULL_KEY, value, i);  
  16.       return null;  
  17.   }  
 

NULL_KEY的声明:static final Object NULL_KEY = new Object();
这一段代码是处理哈希冲突的,就是说,在数组某个位置的对象可能并不是唯一的,它是一个链表结构,根据哈希值找到链表后,还要对链表遍历,找出key相等的对象,替换它,并且返回旧的值。
   

Java代码 
  1. for (Entry<K,V> e = table[i]; e != null; e = e.next) {  
  2.          if (e.key == NULL_KEY) {  
  3.              V oldValue = e.value;  
  4.              e.value = value;  
  5.              e.recordAccess(this);  
  6.              return oldValue;  
  7.          }  
  8.      }  
 

如果遍历完了该位置的链表都没有找到有key相等的,那么将当前对象增加到链表里面去

Java代码 
  1. modCount++;  
  2. addEntry(hash, (K) NULL_KEY, value, i);  
  3. return null;  
 

且看看addEntry方法

Java代码 
  1. void addEntry(int hash, K key, V value, int bucketIndex) {  
  2. Entry<K,V> e = table[bucketIndex];  
  3.     table[bucketIndex] = new Entry<K,V>(hash, key, value, e);  
  4.     if (size++ >= threshold)  
  5.         resize(2 * table.length);  
  6. }  
 

table[bucketIndex] = new Entry<K,V>(hash, key, value, e);新建一个Entry对象,并放在当前位置的Entry链表的头部,看看下面的 Entry构造函数就知道了,注意红色部分。

Java代码 
  1. Entry(int h, K k, V v, Entry<K,V> n) {  
  2.        value = v;  
  3.        next = n;  
  4.        key = k;  
  5.        hash = h;  
  6.    }  
 


如何扩容?
        当put一个元素时,如果达到了容量限制,HashMap就会扩容,新的容量永远是原来的2倍。
上面的put方法里有这样的一段:

Java代码 
  1. if (size++ >= threshold)  
  2.             resize(2 * table.length);  
 

这是扩容判断,要注意,并不是数据尺寸达到HashMap的最大容量时才扩容,而是达到 threshold指定的值时就开始扩容, threshold=最大容量*加载因子。 看看resize方法
  

Java代码 
  1. void resize(int newCapacity) {  
  2.       Entry[] oldTable = table;  
  3.       int oldCapacity = oldTable.length;  
  4.       if (oldCapacity == MAXIMUM_CAPACITY) {  
  5.           threshold = Integer.MAX_VALUE;  
  6.           return;  
  7.       }  
  8.   
  9.       Entry[] newTable = new Entry[newCapacity];  
  10.       transfer(newTable);  
  11.       table = newTable;  
  12.       threshold = (int)(newCapacity * loadFactor);  
  13.   }  
 

重点看看红色部分的 transfer方法
  

Java代码 
  1. void transfer(Entry[] newTable) {  
  2.       Entry[] src = table;  
  3.       int newCapacity = newTable.length;  
  4.       for (int j = 0; j < src.length; j++) {  
  5.           Entry<K,V> e = src[j];  
  6.           if (e != null) {  
  7.               src[j] = null;  
  8.               do {  
  9.                   Entry<K,V> next = e.next;  
  10.                   int i = indexFor(e.hash, newCapacity);  
  11.                   e.next = newTable[i];  
  12.                   newTable[i] = e;  
  13.                   e = next;  
  14.               } while (e != null);  
  15.           }  
  16.       }  
  17.   }  
 

tranfer方法将所有的元素重新哈希,因为新的容量变大,所以每个元素的哈希值和位置都是不一样的。

 

如何寻找元素

       通 过上面代码的分析,应该可以很清楚的看到,HashMap的元素查找大致分为三步:

根据key的hasocde()得到哈希值

根据哈希值确定元素在数组中的位置

找到指定位置 的链表,循环比较,先“==”比较,如果不等,再“equals”比较,如果有一个比较相等,就说明找到元素了。

所以说到这里,我想大家也明白了,为什么要把一个对象放进HashMap的时候,最好是重写hashcode()方法和equals 方法呢?根据前面的分析,hashcode()可以确定元素在数组中的位置,而equals方法在链表的比较时要用到。

 

正确的使用HashMap
1:不要在并发场景中使用HashMap
           HashMap是线程不安全的,如果被多个线程共享的操作,将会引发不可预知的问题,据sun的说法,在扩容时,会引起链表的闭环,在get元素时,就会无限循环,后果是cpu100%。
看看get方法的红色部分

Java代码 
  1. public V get(Object key) {  
  2.     if (key == null)  
  3.         return getForNullKey();  
  4.         int hash = hash(key.hashCode());  
  5.         for (Entry<K,V> e = table[indexFor(hash, table.length)];  
  6.              e != null;  
  7.              e = e.next) {  
  8.             Object k;  
  9.             if (e.hash == hash && ((k = e.key) == key || key.equals(k)))  
  10.                 return e.value;  
  11.         }  
  12.         return null;  
  13.     }  
 


2:如果数据大小是固定的,那么最好给HashMap设定一个合理的容量值
        根据上面的分析,HashMap的初始默认容量是16,默认加载因子是0.75,也就是说,如果采用HashMap的默认构造函数,当增加数据时,数据实际容量超过10*0.75=12时,HashMap就扩容,扩容带来一系列的运算,新建一个是原来容量2倍的数组,对原有元素全部重新哈希,如果你的数据有几千几万个,而用默认的HashMap构造函数,那结果是非常悲剧的,因为HashMap不断扩容,不断哈希,在使用HashMap的场景里,不会是多个线程共享一个HashMap,除非对HashMap包装并同步,由此产生的内存开销和cpu开销在某些情况下可能是致命的。

 

Modis数据处理工具:MRT百度网盘下载和手把手图文安装教程 如下图所示为MODIS Reprojection Tool(MRT)的软界面,看似简单,却是Modis遥感影像必不可少的处理工具,如投影变换等。本文以图文并茂的形式,详细讲解MRT软件在Windows10平台上的安装过程,并附MRT软件百度网盘下载地址。 Modis Tool主界面: 一、安装过程 1、安装Java运行环境 双击Java.exe,安装运行环境。默认的安装路径为C:\Program Files (x86)\Java\jre6\bin,后面需要用到这个路径。 等待... 阅读详情

相关推荐

保姆级教程:在ROS Noetic下,手把手教你将自定义A*全局规划器打包成插件(附避坑指南)

本文提供了一份详细的ROS Noetic下自定义A*全局规划器插件开发指南,涵盖从环境准备、算法优化到插件配置与调试的全流程。通过实战案例和避坑技巧,帮助开发者高效实现机器人导航中的全局路径规划,特别适合需要优化ROS导航栈的开发者。

weixin_29168675的博客 284

(新手必看)HashMap是什么?

那么HashMap什么时候进行扩容呢?当hashmap中的元素个数超过数组大小*loadFactor时,就会进行数组扩容,loadFactor的默认值为0.75,也就是说,默认情况下,数组大小为16,那么当hashmap中元素个数超过16*0.75=12的时候,就把数组的大小扩展为2*16=32

xyk:的博客 1万+

从原理图到GDSII:Virtuoso+Pcell实战避坑指南(以TSMC65nm振荡器为例)

本文以TSMC65nm工艺下的振荡器设计为例,详细解析了Virtuoso环境中Pcell的最佳实践方案,涵盖变量管理、版图设计、Calibre验证等关键环节。通过实战案例和避坑指南,帮助工程师高效完成从原理图到GDSII的转化,特别针对LVS验证和参数化单元设计提供了实用解决方案。

fff88的博客 899

HashMap详解

一、HashMap集合简介 HashMap 基于哈希表的 Map 接口实现,是以 key-value 存储形式存在,即主要用来存放键值对。HashMap 的实现不是同步的,这意味着它不是线程安全的。它的 key、value 都可以为 null,此外,HashMap 中的映射不是有序的。 jdk1.8 之前 HashMap 由 数组 + 链表 组成,数组是 HashMap 的主体,链表则是主要为了解决哈希冲突(两个对象调用的 hashCode 方法计算的哈希值经哈希函数算出来的地址被别的元素占用)而存

java123456111的博客 5万+

基于STM32环境温湿度监测系统设计

基于STM32环境温湿度监测系统设计1. 实验目的2. 任务和要求3. proteus仿真图4. 实验代码 1. 实验目的 (1) 掌握使用 KEIL MDK5 进行软件开发的具体流程; (2) 掌握硬件电路的设计方法; (3) 掌握 STM32 微控制器的程序设计及代码编写方法。 2. 任务和要求 (1)在 STM32F103 平台下,通过温度传感器 DS18B20 和湿度传感器 DHT11 实现环境温湿度信息的采集; (2)将温度传感器和湿度传感器所采集的数据在 LCD 液晶屏幕上显示出来,超

唯一的博客 2万+

fpga在线升级 linux_仅5000行Verilog代码、可在FPGA上跑轻量级Linux系统的RISC-V内核

本文发布于www.hackster.io,由东京理工大学的计算机学院开发,专用于教学与加速用(苏老师也一直认为这是RISC-V当前的主要方向)。目前市场上开源的RISC-V内核已经很多,但很少有公开的RISC-V计算系统是非常轻型且能跑Linux系统的。这一款RISC-V内核就可以运行在FPGA上,用Verilog编写的,需要很少硬件的资源就能跑起来,所以可以运行在一个低成本的FPGA上。来看一下...

weixin_34083807的博客 1867

HashMap详解 Java [ 基础 ] ✅

HashMap是Java中一个强大且高效的集合类,用于快速查找和存储键值对。理解其工作原理和常用操作对于提高编程效率和解决复杂问题非常有帮助。

lenyan~的博客 2万+

LightGBM参数调优实战:从基础到高级技巧

本文深入探讨了LightGBM参数调优的实战技巧。文章从理解其Leaf-wise生长策略的核心逻辑出发,系统性地介绍了分层调参策略:首先调整控制模型结构的参数(如num_leaves),其次优化学习能力参数(如learning_rate),最后通过正则化与随机化参数提升泛化能力。文中还提供了从建立基线到最终微调的完整实战流程与高级避坑指南,帮助读者高效提升模型性能。

i8j9k0l1的博客 262

【Java集合】HashMap源码深度分析

本文将通过Debug流程分析,解读HashMap类的底层源码。在之前我写了一篇HashSet的源码分析,而HashSet的底层其实就是HaspMap,只不过HashSet是单列集合,所以相当于只使用了HashMap的key(键),而没有使用value(值)罢了。所以,强烈建议看本文之前对于HashSet的源码比较了解或者看过我的这篇博文:【Java集合】HashSet源码深度分析-优快云博客本篇博文是对单列集合Set的实现类HashSet的内容补充。

m0_55908255的博客 1237

【VTKExamples::PolyData】第十六期 GradientFilter

本文分享VTK样例GradientFilter,并解析接口vtkGradientFilter & vtkAssignAttribute,希望对各位小伙伴有所帮助!

qq_40041064的博客 319

QT6实现USB摄像头接入显示与抓拍功能实现

QT实现USB摄像头接入显示 一、UVC协议简介 UVC全称是USB Video Class(USB视频类),是一种标准化的USB视频设备通信协议,它定义了摄像头与主机之间的数据传输协议和格式。 UVC协议的出现,解决了摄像头厂商之间互不兼容,以及摄像头应用开发与平台之间的散乱问题。 UVC标准是由USB-IF主导制定的,目前最新的版本是UVC 1.5,UVC的缺省设置类容易实现,不需要额外的驱动程序。

热土程序园,利他愉己~ 3416

HashMap 源码深度分析

HashMap 源码分析 在Map集合中, HashMap 则是最具有代表性的,也是我们最常使用到的 Map 集合。由于 HashMap 底层涉及了很多的知识点,可以比较好的考察一个人的Java的基本功,所以HashMap颇受面试官的青睐,所以我们接下来就去分析一下HashMap的源码,看看它到底有什么。 概述 首先对 HashMap 的知识点进行下概述: HashMap 存储数据是根据 键值对 存储数据的,并且存储多个数据时,数据的键不能相同,如果相同该键之前对应的值将被覆盖。注意如果想要保证 Hash

博客 538

微信小程序 - 强力解决播放视频卡顿问题,小程序使用video组件播放视频或第三方视频插件,会出现卡顿或者无法播放的各种奇怪问题(微信小程序苹果ios/安卓播放视频很卡不流畅、视频太长或文件大等情况)

微信小程序视频组件播放卡顿,微信小程序video组件出现无法播放或卡顿,微信小程序video组件播放时会出现卡顿,微信小程序使用video组件播放视频的时候,会出现卡顿或者无法播放的问题,微信小程序安卓视频播放卡顿问题,微信小程序苹果ios手机播放视频不流畅很卡,加cdn还是卡,uniapp播放视频会有明显的卡顿问题,video视频时卡顿不流畅问题,为什么video组件播放视频卡顿?苹果微信小程序通过video组件播放视频时卡顿,怎么解决?微信小程序video组件出现无法播放或卡顿,设置custom-cac

🏆 前端领域优质创作者 1万+

hashmap怎么取值_HashMap深度分析

这次主要是分析下HashMap的工作原理,为什么我会拿这个东西出来分析,原因很简单,以前我面试的时候,偶尔问起HashMap,99%的程序员都知道HashMap,基本都会用Hashmap,这其中不仅仅包括刚毕业的大学生,也包括已经工作5年,甚至是10年的程序员。HashMap涉及的知识远远不止put和get那么简单。本次的分析希望对于面试的人起码对于面试官的问题有所应付** 一、先来回忆下我的面试...

weixin_39939661的博客 181

ET2012新版免狗免安装绿色软件

ET2012新版免狗免安祖昂绿色软件。,新界面,新视觉,

廖雪峰Python教程[完整版]

廖雪峰的python教程整理的,已经排好版了,而且还是完整的,适合小白

hashMap深度分析

Java的世界里,无论类还是各种数据,其结构的处理是整个程序的逻辑以及性能的关键。由于本人接触了一个有关性能与逻辑同时并存的问题,于是就开始研究这方面的问题。找遍了大大小小的论坛,也把《Java 虚拟机规范》,《apress,.java.collections.(2001),.bm.ocr.6.0.shareconnector》,和《Thinking in Java》翻了也找不到很好的答案,于是一

岳汐的专栏 1683

文档:亲测可用解决vnc灰屏,黑屏,鼠标大黑叉情况

主要解决vnc-viewer灰屏,黑屏,鼠标大黑叉等现象,详细见文档。

Java中对HashMap的深度分析

Java的世界里,无论类还是各种数据,其结构的处理是整个程序的逻辑以及性能的关键。由于本人接触了一个有关性能与逻辑同时并存的问题,于是就开始研究这方面的问题。找遍了大大小小的论坛,也把《Java 虚拟机规范》,《apress,.java.collections.(2001),.bm.ocr.6.0.shareconnector》,和《Thinking in Java》翻了也找不到很好的答案,于是一

sunwukong的专栏 1271

jre9下载 jdk9

(Java SE Runtime Environment 9.0) 9.0u175 官方最新版 【x86|x64】

HashMap深度分析详解

1.HashMap的实现原理? HashMap采用Entry数组来存储key-value对,每一个键值对组成了一个Entry实体,Entry类实际上是一个单向的链表结构,它具有Next指针,可以连接下一个Entry实体。只是在JDK1.8中,链表长度大于8的时候,链表会转成红黑树! 1.1 为什么用数组+链表? 数组是用来确定桶的位置,利用元素的key的hash值对数组长度取模得到 链表是用...

枕上~诗书闲 802

HashMap的深度分析

在Java的世界里,无论类还是各种数据,其结构的处理是整个程序的逻辑以及性能的关键。由于本人接触了一个有关性能与逻辑同时并存的问题,于是就开始研究这方面的问题。找遍了大大小小的论坛,也把《Java 虚拟机规范》,《apress,.java.collections.(2001),.bm.ocr.6.0.shareconnector》,和《Thinking in Java》翻了也找不到很好的答案,于是

autoinspired的专栏 730
上一篇: 面对大公司和小公司,应届毕业生如何选择
下一篇: Java 位运算符
GetStudyMessages
博客等级 码龄17年 9粉丝 17原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值