JAVA集合的概念总结-单列集合

  • 集合我们首先分为单列集合和键值对集合(双列集合)
  • 单列集合
  • ArrayList集合 初始容量为10 底层是可变数组,特点是查询快,增删慢。查询快的原因就是应为底层是数组,具有 索引!
  • LinkedList集合是线程不安全的,但是效率高,底层是链表,特点是增删快,查询慢,原因是应为没有索引,所以查询慢!
  • set集合
  • 只是个人总结,如有不全,或者错误,希望大家指出!谢谢


集合我们首先分为单列集合和键值对集合(双列集合)

单列集合

单列集合(Collection)又两个子类List和Set,我们首先说下List集合
1.List集合的特点

  1. 有顺序
  2. 有顺序:存取顺序一致
  3. 元素可重复

2.List集合遍历方式

  1. 普通for
  2. 增强for
  3. 迭代器

3.List集合常用实现类

  1. ArrayList
  2. LinkedList
  3. Vector

3.List集合常用方法

  1. List接口的常用方法
    * boolean add(E e)
    * E remove(int index)
    * boolean remove(Object o)
    * E set(int index, E element)
    * E get(int index)
    * int size()

ArrayList集合 初始容量为10 底层是可变数组,特点是查询快,增删慢。查询快的原因就是应为底层是数组,具有 索引!


成员方法
 1.1: 添加元素 :
   public boolean add(E  e); 添加元素,添加到集合的最后 .
   Public void add( int index , E element ); 在指定的索引处添加一个元素
 1.2 获取元素 : 
   public E get ( int index );  返回指定索引处的元素(E是一种返回值类型)
   集合长度 :  public int size () ;  返回集合中的元素的个数
 1.3 删除元素 : 
    public E remove (int  index);  删除指定处的元素 ,返回删除是否成功
    public E remove (int index , E element ) 修改指定索引处的元素, 返回被被删除的元素
 1.4 修改元素 :  
   public E set ( int index , E element ) ; 修改指定索引处的元素, 返回被修改的元素
   集合中的泛型只能是引用类型。集合中要存储基本数据类型的时候  泛型要使用其包装类

LinkedList集合是线程不安全的,但是效率高,底层是链表,特点是增删快,查询慢,原因是应为没有索引,所以查询慢!


LinkedList提供了方便首尾操作的方法
		void addFirst(E e):将指定元素插入此列表的开头
		void addLast(E e):将指定元素插入此列表的结尾
		E getFirst():返回此列表的第一个元素
		E getLast():返回此列表的最后一个元素
		E removeFirst():移除并返回此列表的第一个元素
		E removeLast():移除并返回此列表的最后一个元素

set集合

1.set接口特点
	Set接口的特点:
				*无序:存取顺序不一致,但不随机(LinkedHashSet是有序的)
				*元素不可重复
				*没有索引
				*包含方法:
					boolean add(E e)
					void clear()
					boolean remove(Object o)
				没有获取单个元素和修改单个元素的方法
2.Set集合的遍历方式
	*增强for
	*迭代器
3.Set集合常用子类
	*HashSet
	*LinkedHashSet
		*继承于HashSet,但是能包装存取顺序一致
4.HashSet的特点
	*无序,无索引,元素不可重复
	*底层结构:哈希表
5.HashSet的基本使用
	*HashSet是Set接口的实现类:不包含重复元素,没有索引,且无序
	*LinkedSet继承于HashSet,但是Set接口的实现类:不包含重复元素,没有索引,但有序						
6.HashSet存储字定义对象
	当自定义对象要放入到集合中时都要重写hashCode()和equals()方法,来保证元素的唯一性。
	*示例代码
		需求:
		- 定义一个学生类,包含姓名和年龄。
		- 创建多个Student对象存储到HashSet集合中。
		- 要求属性值完全相同的对象只存储一个。
		-
public class Student {
 private String name;
 private int age;
 public Student(String name, int age) {
 super();
this.name = name;
 this.age = age;
 }
 public Student() {
 super();
 }
 public String getName() {
 return name;
 }
 public void setName(String name) {
this.name = name;
 }
 public int getAge() {
 return age;
 }
 public void setAge(int age) {
 this.age = age;
 }
 @Override
 public String toString() {
 return “Student [name=” + name + “, age=” + age + “]”;
 }
 @Override
 public int hashCode() {
 final int prime = 31;
 int result = 1;
 result = prime * result + age;
 result = prime * result + ((name == null) ? 0 : name.hashCode());
 return result;
 }
 @Override
 public boolean equals(Object obj) {
 if (this == obj)
 return true;
 if (obj == null)
 return false;
 if (getClass() != obj.getClass())
 return false;
 Student other = (Student) obj;
 if (age != other.age)
 return false;
 if (name == null) {
 if (other.name != null)
 return false;
 } else if (!name.equals(other.name))
 return false;
 return true;
 } 
 }
 public class HashSetDemo03 {
 public static void main(String[] args) {
 // 创建集合对象:存储学生
 HashSet stus = new HashSet<>();
 stus.add(new Student(“jack”,23)); // 3456445 % 16 = 1
 stus.add(new Student(“rose”,24)); // 3456445 % 16 = 1
 stus.add(new Student(“jack”,23)); // 3454556 % 16 = 1
 System.out.println(stus);
 }
 }
 7.LinkedHashSet的特点
 Set:元素不重复,没有索引,添加和删除元素都比较快
 *HashSet:元素不重复,没有索引,元素无序
 *LinkedHashSet:元素不重复(哈希表实现),没有索引,元素有序(链表实现)
 8.LinkedHashSet的使用
特点:继承HashSet,能够保证存取顺序一致
示例代码
 /
 LinkedHashSet存储元素
 */
 public class LinkedHashSetDemo4 {
 public static void main(String[] args) {
 // 创建集合对象:存储学生
 LinkedHashSet set = new LinkedHashSet<>();
 set.add(“fdsaf”);
 set.add(“xxxr”);
 set.add(“3213f”);
 set.add(“aadfasf”);
 set.add(“435fdsaf”);
 set.add(“435fdsaf”);
 System.out.println(set);
 }
 }
* 小结
  - 当使用HashSet存储自定义类型,如果没有重写该类的hashCode与equals方法,
  则判断是否重复的依据是根据对象地址值,如果想通过内容比较元素是否相同,
  需要重写该类的hashcode与equals方法

哈希表数据结构

1.哈希表数结构:数组+链表实现,添加和查询都比较快
	2.查看API对比set进行迭代所需时间和HashSet实例的大小(元素的数量)和底层HashMap实例(
	桶的数量)的“容量”的合成比例
	3.LinkedList的元素数量越多,迭代需要的时间就越多,LinkedList查询慢
	4.如果迭代性能很重要,则不要将初始容量设置的太高(或将加载因子设置的太低)
		*.初始容量:创建HashSet时的数组大小,默认是16
		*.加载因子:默认0.75,当元素大于“容量”加载因子时会创建一个新的数组将HashSet扩容

对象的哈希值

*就是一个十进制整数。是通过Object类的hashCode()方法获得:int hashCode();
	*默认Object类的hashCode的方法返回的哈希值是该对象在内存的地址值。
	*哈希值是对象存储到哈希表的重要依据。
		PS.Object的hashcode方法
			*对象存储在HashSet的数组哪个位置和对象的HashCode有关
			*Object类:
				public int hashCode();是一个Native方法(c/c++),默认情况下对象的hashcode其实
				是对象的内存地址值的十进制
			*String,类重写过hashCode

哈希表的存储过程

哈希表的存储过程(存取原理):每存入一个新的元素都要走以下五步
	* (1)调用对象的hashCode()方法,获得要存储元素的哈希值。
	* (2)将哈希值与表的长度(即数组的长度)进行求余运算得到一个整数值,该值就是新元素要存放的
		位置(即是索引值)。
	  - 如果索引值对应的位置上没有存储任何元素,则直接将元素存储到该位置上。
	  - 如果索引值对应的位置上已经存储了元素,则执行第3步。
	*(3)遍历该位置上的所有旧元素,依次比较每个旧元素的哈希值和新元素的哈希值是否相同。
	  - 如果有哈希值相同的旧元素,则执行第4步。
	  - 如果没有哈希值相同的旧元素,则执行第5步。
	* (4)比较新元素和旧元素的地址是否相同
	  - 如果地址值相同则用新的元素替换老的元素。停止比较。
	  - 如果地址值不同,则新元素调用equals方法与旧元素比较内容是否相同。
		- 如果返回true,用新的元素替换老的元素,停止比较。
		- 如果返回false,则回到第3步继续遍历下一个旧元素。
	* (5)说明没有重复,则将新元素存放到该位置上并让新元素记住之前该位置的元素。
			.哈希表的存储过程
				1.判断hashCode
					*不相同
						-->2.直接存储
					*相同
						-->2.判断equals方法
								*相同-->判断为同一元素
									
								*不相同-->直接存储

*ArrayList的contains方法判断元素是否重复原理。

*调用传入元素的equals方法依次与集合中的旧元素所比较,从而根据返回的布尔值判断是否有重复元素。
  * 当ArrayList存放自定义类对象时,当自定义类在未重写equals方法前,判断是否重复的依据是地址值。
	如果想根据内容判断是否为重复元素,则需要重写自定义类的equals方法。
  * 底层依赖于equals()方法。

HashSet判断对象是否重复的原理

HashSet的add/contains等方法判断元素是否重复原理?
  - 将新元素与集合中已有的旧元素的HashCode值进行比较。
		- 哈希值相同,再通过比较地址值或equals方法比较内容是否相同。
			·只要地址或内容相同,则表示包含。否则表示不包含。
		- 哈希值不同,直接返回false表示不包含。
* 底层依赖于hashCode()和equals()。

HashSet构造方法分析

比如:加载因子是0.75,数组的长度为16,其中存入16 * 0.75 = 12个元素。如果再存入第十三个(>12)元素。
那么此时会扩充哈希表(再哈希),底层会开辟一个长度为原长度2倍的数组。把老元素拷贝到新数组中,
 再把新元素添加数组中。当存入元素数量 > 哈希表长度 * 加载因子,就要扩容,因此加载因子决定扩容时机。

hashCode和equals方法面试题

* 两个Person对象p1和p2,如果p1.hashCode() == p2.hashCode(),则p1.equals(p2)一定是true吗?
       答: 不一定
-  两个Person对象p1和p2,如果p1.equals(p2)为true。则 p1.hashCode() == p2.hashCode()一定是true吗?
   答:一定
- hashCode的官方协定
  1. 如果根据equals(Object)方法,两个对象是相等的。那么对这两个对象中的每个对象调用hashCode方法
  都必须生成相同的整数结果。 
  2. 如果根据equals(java.lang.Object)方法,两个对象不相等,那么对这两个对象中的任一对象上调用
  hashCode 方法不要求一定生成不同的整数结果。但是,程序员应该意识到,为不相等的对象生成不同整
  数结果可以提高哈希表的性能。

只是个人总结,如有不全,或者错误,希望大家指出!谢谢