Java对象集合

java集合概述之Set

Abstract

  • Java的集合主要有SetListQueueMap四种体系。 这四种体系都是接口不能直接用,但是在这四种体系下包含了很多的实现类是可以直接使用的。
  • 集合类和定长数组的区别主要在于,定长数组不仅可以存储基本数据类型还有对象,但是集合类只能存储对象。这里的对象是指对象引用
  • 所有的集合类都位于java.util包下,后来为了处理多线程环境下的并发安全问题,java5还在java.util.concurrent包下提供了一些多线程支持的集合类。
  • java中集合类都是由两个接口派生出来的——Collection和Map,其中SetQueueList接口是Collection接口派生出来的子接口,他们分别代表了无序集合和有序集合。
  • Map接口的所有实现类用于保存具有映射关系的数据(关联数组)

Collection接口

  • boolean add(Object o) 失败返回false。
  • boolean addAll(Collection o) 用于把集合c中的所有元素添加到指定集合中,失败分会false。
  • void clear() 清除集合中所有元素,集合长度变成0。
  • boolean contains(Object o) 判断集合里是否包含指定元素。
  • boolean containsAll(Collection c) 判断集合中是否包含了集合c中的所有元素。
  • boolean isEmpty() 返回集合是否为空。
  • Iterator iterator() 返回一个iteratior对象,用于遍历集合中的所有元素。
  • boolean remove(Object o) 删除制定元素o,当集合中存在多个符合条件的元素,仅仅删除第一个并返回true
  • boolean removeAll(Collection c) 从集合中删掉集合c中的所有元素,如果有小于等于一个删除成功边返回true。
  • boolean retainAll(Collection c) 将集合中不是集合c的所有元素删除,如果有至少一个删除成功范湖true。
  • int size() 返回集合中的元素的个数。
  • Object[] toArray() 将集合转化为一个数组,所有的集合元素变成对应的数组元素。

1. Set

实际上Set就是Collection,因为本身就是其子接口。唯一的不同就是Set不允许包含重复元素。如果强行加入相同的元素,add()函数会返回false。 无序、不可重复的集合。

Set接口下有三个实现类分别是:HashSetTreeSetEnumSet,其中HashSet还有一个子类LinkedHashSet

1.1 HashSet类

HashSet是Set最常见的实现类。有以下特性:

  • 不能保证添加顺序,因为原理上HashSet是通过Hash算法来存储元素的,所以不能确定顺序。
  • HashSet不是同步的,假如有多个线程同时修改了HashSet的值必须通过代码来保证其同步
  • 集合元素值可以为NULL。

原理:

  • 重点一:添加的元素只能是对象。
  • 重点二:对象需要重写equals()函数和HashCode()函数。

根据重点有:

  • 向HashSet集合中添加一个元素的时候,首先判断是不是和集合中的某一个元素相等。
  • 判断相等的标准是两个元素的equals()函数相等。
  • 一般来说都需要重写equals()hashCode()函数,尤其注意的是在重写了hashCode()函数之后,该对象的HashCode值就和该对象的成员变量息息相关了(见后文),在进行任何与该对象的成员变量相关的函数操作的时候一定得注意HashCode的变化。虽然说成员量变量会改变,但是HashCode值却不会跟着改变!
  • 如果都不相等,那就根据对象新计算好的hashCode值选择存储位置。这里也应该注意的是,根据HashCode实际上就是根据成员变量————因为HashCode就是根据成员变量算出来的!
class A {

@Override
public int hashCode() {
return 1;
}
}

class  B {
@Override
public boolean equals(Object obj) {
return true;
}
}

class  C {
@Override
public boolean equals(Object obj) {
return true;
}

@Override
public int hashCode() {
return 2;
}
}

public class MyTest {

public static void main(String[] args) {
HashSet books = new HashSet();
books.add(new A());
books.add(new A());
books.add(new B());
books.add(new B());
books.add(new C());
books.add(new C());
System.out.println(books);
}
}

运行上面的代码并根据Set的不重复规则,我们可以想到如果集合即将添加的对象需要重写equals()函数,但是hashCode()函数并没有被重写,会导致两种结果:

要么不同hashCode的相同对象被存储在不同位置上导致集合中出现相同的元素,要么相同hashCode的不同对象被链式存储到同一个地方。

但是不管哪一种结果都是严重不符合Set定义的。

Note about overriding hashCode()

a.当两个对象在比较equals()函数返回true的时候,HashCode()函数也应该返回相等的值。

重写一个对象的equals()函数,通常情况下就是通过比较该对象中的所有实例变量。重写HashCode()也一样,只不过是使用一定的算法让实例变量相等变成hashCode相等,我们很容易就想到了线性运算————直接加起来。下面给出基本数据类型的hashCode计算方法:

实例变量类型 计算方式
boolean hashCpde = (f?0:1);
整数类型(byte, short, int , char) hashCode = (int)f;
long hashCode = (int)(f^(f>>>32));
float hashCode = Float.floatToBits(f);
double long l = Double.doubleToLongBits(f); hashCode = f.hashCode();
引用类型 hashCode = f.hashCode();

将每一个通过第一步计算出来的各个实例变量的值乘以一个质数相加(防止直接相加的冗余)得到该对象的新的HashCode值。

b.HashSet集合中同一个对象在程序运行过程中必须使用一个hashCode,一定要避免在过程中对该对象的一些实例变量进行修改。

主要是在程序运行的过程中,可能会有修改集合元素中的变量的可能,根据前面重写算法和原理部分就可以知道:成员变量HashCodeequals这三者基本等同起来了。


class A {

public int count;
public A(int count) {
this.count = count;
}

@Override
public boolean equals(Object obj) {
if(this == obj) {
return true;
}
if(obj != null && obj.getClass() == A.class) {
A a = (A)obj;
return this.count == a.count;
}
return false;
}

@Override
public int hashCode() {
return this.count;
}

@Override
public String toString() {
return "A[count] "+count + "]";
}

public class MyTest {

public static void main(String[] args) {
HashSet books = new HashSet();
books.add(new A(5));
books.add(new A(-3));
books.add(new A(9));
books.add(new A(-2));
System.out.println(books);
Iterator it = books.iterator();
A first = (A)it.next();
first.count = -3;
System.out.println(books);
books.remove(new A(-3));
System.out.println(books);
System.out.println(books.contains(new A(-3)));
System.out.println(books.contains(new A(5)));

}
}

(假设这里的第一个元素是5)看到上述代码中,首先将第一个元素的count值改成了-3,这时候便会有两个count = -3的元素存在,但是!

不要忘了,就算第一个元素的count被改成-3,它的HashCode是5!和最初加入HashSet的时候是一样的!这一点可以通过输出整个集合元素的HashCode的时候会发现。

所以当后面即将remove(-3)的时候,实际上集合首先会去找HashCode为-3的存储位置————这时候只有最初count为-3的那个元素满足条件,所以删除的还是正确的,但是之后判断集合中是否有-3?根据HashCode已经被删掉了返回false;是否有5?虽然可以根据5找到那个被修改的元素,但是因为它的count值被修改为-3,所以equals也返回false。

LinkedHashSet

  • 因为HashSet是按照Hash算法来存储元素的,所以元素的访问顺序往往和存储顺序不一致。有时候弧很不方便。LinkedHashsetHashSet的子类,它唯一的不同就是通过链表维护了元素的次序。
  • 但是因为使用了链表,所以性能稍差一些。

1.2 TreeSet类

原文地址:https://www.cnblogs.com/haotianmichael/p/8985175.html

时间: 2024-10-19 00:40:27

Java对象集合的相关文章

利用Apache的commons-beanutils和commons-collections包实现Java对象的按属性排序

在日常工作中经常用到需要对java对象集合或者Map集合中的某个属性做排序,这个需求可以利用Apache的commons-beanutils和commons-collections包来实现,主要实现方式如下: public static <T> void sort(List<T> list, String property, boolean asc) { Comparator<?> comparator = ComparableComparator.getInstanc

Java对象和集合与Json之间的互相转换

总结一下Java对象和集合与Json之间的互相转换: 1.创建的User类: package com.ghj.packageofdomain; public class User { private int id; private String name; private String gender; public User() { } public User(int id, String name, String gender) { this.id = id; this.name = name

实现java.util.Comparator接口,对对象集合进行多属性组合排序

Commons - BeanUtils 提供了很多功能,其中一个很有用的是对对象集合进行排序,如Collections.sort(peoples, new BeanComparator("age")); 另外,可以使用java.util.Collections的sort方法可以对collection集合进行排序,包括多列组合排序,下面是自己实现java.util.Comparator,定制对象属性排序规则的例子: package com.lph.test; import java.ut

java json数据转List对象的集合-----阿里巴巴插件---及原生json---JSON 与 对象 、集合 之间的转换 JSON字符串和java对象的互转【json-lib】

List<RunfastFullLess> list=(List<RunfastFullLess>)JSONArray.parseObject(activity.getFullLesss(),RunfastFullLess.class); 使用阿里巴巴的json插件 <!--json数据转换的阿里巴巴依赖库--><dependency> <groupId>com.alibaba</groupId> <artifactId>

Java对象和集合的拷贝/克隆/复制

昨天同事遇到了一个奇怪的问题,他需要将一个JavaBean拷贝一份,然后对新创建的Bean进行操作.但是他对新的Bean操作后,会影响旧的Bean的值.当听到这个问题的时候,我第一反应就是他的拷贝方法有问题,只是将aBean的内容复制给了bBean,但是在内存中指向的是同一个地址.这里就引出了两个关键词,浅拷贝和深拷贝. 浅拷贝(浅克隆) 被复制对象的所有变量值都和原来的对象的值相同,但是复制后的对象的引用仍然指向原来的对象.简单来说,就是对A进行拷贝生成B,只是将A的值复制给了B,内存中指向的

转载-------- JSON 与 对象 、集合 之间的转换 JSON字符串和java对象的互转【json-lib】

转载--*--*---- 在开发过程中,经常需要和别的系统交换数据,数据交换的格式有XML.JSON等,JSON作为一个轻量级的数据格式比xml效率要高,XML需要很多的标签,这无疑占据了网络流量,JSON在这方面则做的很好,下面先看下JSON的格式, JSON可以有两种格式,一种是对象格式的,另一种是数组对象, {"name":"JSON","address":"北京市西城区","age":25}//JS

Java:对象的强、软、弱和虚引用(转)

1.对象的强.软.弱和虚引用 在JDK 1.2以前的版本中,若一个对象不被任何变量引用,那么程序就无法再使用这个对象.也就是说,只有对象处于可触及(reachable)状态,程序才能使用它.从JDK 1.2版本开始,把对象的引用分为4种级别,从而使程序能更加灵活地控制对象的生命周期.这4种级别由高到低依次为:强引用.软引用.弱引用和虚引用.图1为对象应用类层次. 图1 ⑴强引用(StrongReference) 强引用是使用最普遍的引用.如果一个对象具有强引用,那垃圾回收器绝不会回收它.当内存空

JAVA对象转化JSON出现死循环问题

主要是解决JSON因Hibernate映射生成的集合的转化出现的死循环问题. 这个方法很重要 1 public String ajaxJsonByObjectDirecdt(Object obj, String[] filterNames){ 2 JsonConfig jsonConfig = new JsonConfig(); 3 jsonConfig.setIgnoreDefaultExcludes(false); 4 jsonConfig.setCycleDetectionStrategy

Java对象的生命周期与作用域的讨论(转)

导读: Java对象的生命周期大致包括三个阶段:对象的创建,对象的使用,对象的清除.因此,对象的生命周期长度可用如下的表达式表示:T = T1 + T2 +T3.其中T1表示对象的创建时间,T2表示对象的使用时间,而T3则表示其清除时间.由此,我们可以看出,只有T2是真正有效的时间,而T1.T3则是对象本身的开销.下面再看看T1.T3在对象的整个生命周期中所占的比例. 我们知道,Java对象是通过构造函数来创建的,在这一过程中,该构造函数链中的所有构造函数也都会被自动调用.另外,默认情况下,调用