集合

in 编程
关注公众号【好便宜】( ID:haopianyi222 ),领红包啦~
阿里云,国内最大的云服务商,注册就送数千元优惠券:https://t.cn/AiQe5A0g
腾讯云,良心云,价格优惠: https://t.cn/AieHwwKl
搬瓦工,CN2 GIA 优质线路,搭梯子、海外建站推荐: https://t.cn/AieHwfX9

类集框架被设计用于适应几个目的。首先,这种框架是高 性能的。对基本类集(动态数组,链接表,树和散列表) 的实现是高效率的。一般很少需要人工去对这些“数据引 擎”编写代码(如果有的话)。第二点,框架必须允许不 同类型的类集以相同的方式和高度互操作方式工作。第三 点,类集必须是容易扩展和/或修改的。为了实现这一目 标,类集框架被设计成包含一组标准的接口。对这些接口, 提供了几个标准的实现工具(例如LinkedList,HashSet和 TreeSet),通常就是这样使用的。如果你愿意的话,也可 以实现你自己的类集。为了方便起见,创建用于各种特殊 目的的实现工具。一部分工具可以使你自己的类集实现更 加容易。最后,增加了允许将标准数组融合到类集框架中 的机制

算法(Algorithms)是类集机制的另一个重 要部分。算法操作类集,它在Collections类 中被定义为静态方法。因此它们可以被所 有的类集所利用。每一个类集类不必实现 它自己的方案,算法提供了一个处理类集 的标准方法

由类集框架创建的另一项是Iterator接口。一 个迭代程序(iterator)提供了一个多用途的, 标准化的方法,用于每次访问类集的一个 元素。因此迭代程序提供了一种枚举类集 内容(enumerating the contents of a collection)的方法。因为每一个类集都实现 Iterator,所以通过由Iterator定义的方法,任 一类集类的元素都能被访问到。

除了类集之外,框架定义了几个映射接口 和类。映射(Maps)存储键/值对。尽管映 射在对项的正确使用上不是“类集”,但 它们完全用类集集成。在类集框架的语言 中,可以获得映射的类集“视图” (collection-view)。这个“视图”包含了 从存储在类集中的映射得到的元素。因此, 如果选择了一个映射,就可以将其当做一 个类集来处理

对于由java.util定义的原始类,类集机制被 更新以便它们也能够集成到新的系统里。 所以理解下面的说法是很重要的:尽管类 集的增加改变了许多原始工具类的结构, 但它却不会导致被抛弃。类集仅仅是提供 了处理事情的一个更好的方法

最后的一点:如果你对C++比较熟悉的话, 那么你可以发现Java的类集技术与在C++中 定义的标准模板库(STL)相似。 • 在C++中叫做容器(container),而在Java 中叫做类集

所谓框架就是一个类库的集合。集合框架就是一个用来表示和操作集合的统 一的架构,包含了实现集合的接口与类。

集合中的接口

除了类集接口之外,类集也使用Comparator, Iterator和ListIterator接口。 • 简单地说,Comparator接口定义了两个对象 如何比较;Iterator和ListIterator接口枚举类 集中的对象。

为了在它们的使用中提供最大的灵活性, 类集接口允许对一些方法进行选择。可选 择的方法使得使用者可以更改类集的内容。 支持这些方法的类集被称为可修改的 (modifiable)。不允许修改其内容的类集 被称为不可修改的(unmodifiable)。如果 对一个不可修改的类集使用这些方法,将 引发一个UnsupportedOperationException异 常。所有内置的类集都是可修改的。

Collection接口是构造类集框架的基础。它声明所 有类集都将拥有的核心方法。因为所有类集实现 Collection,所以熟悉它的方法对于清楚地理解框 架是必要的。其中几种方法可能会引发一个 UnsupportedOperationException异常。正如上面解 释的那样,这些发生在当类集不能被修改时。当 一个对象与另一个对象不兼容,例如当企图增加 一个不兼容的对象到一个类集中时。将产生一个 ClassCastException异常

调用add( )方法可以将对象加入类集。注意 add( )带一个Object类型的参数。因为Object 是所有类的超类,所以任何类型的对象可 以被存储在一个类集中。然而原始类型不 行。例如,一个类集不能直接存储类型int, char,double等的值。当然如果想存储这些 对象,也可以使用原始类型包装器。可以 通过调用addAll( )方法将一个类集的全部内 容增加到另一个类集中。

可以通过调用remove( )方法将一个对象删 除。为了删除一组对象,可以调用 removeAll( )方法。调用retainAll( )方法可以 将除了一组指定的元素之外的所有元素删 除。为了清空类集,可以调用clear( )方法

通过调用contains( )方法,可以确定一个类 集是否包含了一个指定的对象。 • 为了确定一个类集是否包含了另一个类集 的全部元素,可以调用containsAll( )方法 • 当一个类集是空的时候,可以通过调用 isEmpty( )方法来予以确认。 • 调用size( )方法可以获得类集中当前元素的 个数

toArray( )方法返回一个数组,这个数组包 含了存储在调用类集中的元素。通过在类 集和数组之间提供一条路径,可以充分利 用这两者的优点

一个更加重要的方法是iterator( ),该方法对 类集返回一个迭代程序。当使用一个类集 框架时,迭代程序对于成功的编程来说是 至关重要的

Collection:集合层次中的根接口,JDK没 有提供这个接口直接的实现类。 • Set:不能包含重复的元素。SortedSet是 一个按照升序排列元素的Set。 • List:是一个有序的集合,可以包含重复的 元素。提供了按索引访问的方式。 • Map:包含了key-value对。Map不能包 含重复的key。SortedMap是一个按照升 序排列key的Map。

list接口

List接口扩展了Collection并声明存储一系列 元素的类集的特性。使用一个基于零的下 标,元素可以通过它们在列表中的位置被 插入和访问。一个列表可以包含重复元素

除了由Collection定义的方法之外,List还定 义了一些它自己的方法。再次注意当类集 不能被修改时,其中的几种方法引发 UnsupportedOperation Exception异常。当一 个对象与另一个不兼容,例如当企图将一 个不兼容的对象加入一个类集中时,将产 生ClassCastException异常

对于由Collection定义的add( )和addAll( )方 法,List增加了方法add(int, Object)和 addAll(int, Collection)。这些方法在指定的 下标处插入元素。由Collection定义的 add(Object)和addAll(Collection)的语义也被 List改变了,以便它们在列表的尾部增加元 素

为了获得在指定位置存储的对象,可以用 对象的下标调用get( )方法。为了给类表中 的一个元素赋值,可以调用set( )方法,指 定被改变的对象的下标。调用indexOf( )或 lastIndexOf( )可以得到一个对象的下标 • 通过调用subList( )方法,可以获得列表的 一个指定了开始下标和结束下标的子列表。 subList( )方法使得列表处理十分方便。

Set接口

• 集合接口定义了一个集合。它扩展了 Collection并说明了不允许复制元素的类集 的特性。因此,如果试图将复制元素加到 集合中时,add( )方法将返回false。它本身 并没有定义任何附加的方法

SortedSet接口

SortedSet接口扩展了Set并说明了按升序排 列的集合的特性。当没有项包含在调用集 合中时,其中的几种方法引发 NoSuchElementException异常。当对象与调 用集合中的元素不兼容时,引发 ClassCastException异常。如果试图使用null 对象,而集合不允许null时,引发 NullPointerException异常

SortedSet定义了几种方法,使得对集合的处 理更加方便。调用first( )方法,可以获得集 合中的第一个对象。调用last( )方法,可以 获得集合中的最后一个元素。调用subSet( ) 方法,可以获得排序集合的一个指定了第 一个和最后一个对象的子集合。如果需要 得到从集合的第一个元素开始的一个子集 合,可以使用headSet( )方法。如果需要获 得集合尾部的一个子集合,可以使用 tailSet( )方法。

 ArrayList

ArrayList:我们可以将其看作是能够自动 增长容量的数组。 • 利用ArrayList的toArray()返回一个数组。 • Arrays.asList()返回一个列表。 • 迭代器(Iterator) 给我们提供了一种通用 的方式来访问集合中的元素。

ArrayList类扩展AbstractList并执行List接口。 ArrayList支持可随需要而增长的动态数组。在Java 中,标准数组是定长的。在数组创建之后,它们 不能被加长或缩短,这也就意味着你必须事先知 道数组可以容纳多少元素。但是,你直到运行时 才能知道需要多大的数组。为了解决这个问题, 类集框架定义了ArrayList。本质上,ArrayList是 对象引用的一个变长数组。也就是说,ArrayList 能够动态地增加或减小其大小。数组列表以一个 原始大小被创建。当超过了它的大小,类集自动 增大。当对象被删除后,数组就可以缩小

ArrayList有如下的构造函数 – ArrayList( ) – ArrayList(Collection c) – ArrayList(int capacity) – 第一个构造函数建立一个空的数组列表。 – 第二个构造函数建立一个数组列表,该数组列表由类 集c中的元素初始化。 – 第三个构造函数建立一个数组列表,该数组有指定的 初始容量(capacity)。容量是用于存储元素的基本数 组的大小。当元素被追加到数组列表上时,容量会自 动增加

– 使用由toString( )方法提供的默认的转换显示类 集的内容,toString( )方法是从 AbstractCollection继承下来的。尽管它对简短 的例子程序来说是足够了,然而很少使用这种 方法去显示实际中的类集的内容。通常编程者 会提供自己的输出程序。但在下面的几个例子 中,仍将采用由toString( )方法创建的默认输出

尽管当对象被存储在ArrayList对象中时,其 容量会自动增加。仍可以通过调用 ensureCapacity( )方法来人工地增加 ArrayList的容量。如果事先知道将在当前能 够容纳的类集中存储许许多多的项时,你 可能会想这样做。在开始时,通过一次性 地增加它的容量,就能避免后面的再分配。 因为再分配是很花时间的,避免不必要的 处理可以改善性能

ensureCapacity( )方法如下所示 – void ensureCapacity(int cap) – 这里,cap是新的容量 • 相反地,如果想要减小在ArrayList对象之下 的数组的大小,以便它有正好容纳当前项 的大小,可以调用trimToSize( )方法。该方 法如下 – void trimToSize( )

当使用ArrayList时,有时想要获得一个实际 的数组,这个数组包含了列表的内容。可 以通过调用方法toArray( )来实现它。下面 是几个为什么可能想将类集转换成为数组 的原因 – 对于特定的操作,可以获得更快的处理时间 – 为了给方法传递数组,而方法不必重载去接收 类集 – 为了将新的基于类集的程序与不认识类集的老 程序集成

1.      集合中存放的依然是对象的引用而不是对象本身。

2.      ArrayList底层采用数组实现,当使用不带参数的构造方法生成ArrayList对象时,实际上会在底层生成一个长度为10的Object类型数组

3.      如果增加的元素个数超过了10个,那么ArrayList底层会新生成一个数组,长度为原数组的1.5倍+1,然后将原数组的内容复制到新数组当中,并且后续增加的内容都会放到新数组当中。当新数组无法容纳增加的元素时,重复该过程。

4.      对于ArrayList元素的删除操作,需要将被删除元素的后续元素向前移动,代价比较高。

5.      集合当中只能放置对象的引用,无法放置原生数据类型(但是)JDK1.5版本以后,java虚拟机添加了自动装箱和自动解封,你往里面add基本类型的数据,java的JVM将它自动装箱成为它的对应封装类),我们需要使用原生数据类型的包装类才能加入到集合当中


import java.util.ArrayList;

public class ArrayListTest3
{
	public static void main(String[] args)
	{
		ArrayList list = new ArrayList();
		
		list.add(3);
       System.out.println(list.get(0));
}

}

//这句话在JDK1.5前是错误的
//JDK1.5后java的JVM将基本数据类型自动装箱成为它的对应封装类


//output:3

6.      集合当中放置的都是Object类型,因此取出来的也是Object类型,那么必须要使用强制类型转换将其转换为真正的类型(放置进去的类型)。

public class ArrayListTest3
{
	public static void main(String[] args)
	{
		ArrayList list = new ArrayList();
		
		list.add(3);
		list.add(4);
		list.add(5);
		list.add(6);
		
     	int value = (list.get(3)
		
		System.out.println(value);
	}
}
/*
 错误: 不兼容的类型: Object无法转换为int
              int value = list.get(2);

*/
                                  ^

 

public class ArrayListTest3
{
	public static void main(String[] args)
	{
		ArrayList list = new ArrayList();
		
		list.add(3);
		list.add(4);
		list.add(5);
		list.add(6);
		
     	Object value = list.get(3)
		
		System.out.println(value);
	}
}
// output; 6

 把value向下转型为Integer 类型  

int value = ((Integer)list.get(3)).intValue

 其中 (Integer)list.get(3)是一个包含3的包装类    调用其inValue()方法  以 int 类型返回该 Integer 的值。

 


import java.util.ArrayList;

public class ArrayListTest3
{
	public static void main(String[] args)
	{
		ArrayList list = new ArrayList();
		
		list.add(3);
		list.add(4);
		list.add(5);
		list.add(6);
	    int value = ((Integer)list.get(3)).intValue();
//      int value = (Integer)list.get(3);这样也行
//      int value = ((Integer)(list.get(3)));这样也行
//      int value = ((Integer)(list.get(3))).invalue();错误:找不到符号???????
		System.out.println(value);
	}
}

//output:  6

linkedlist

LinkedList类扩展AbstractSequentialList并执 行List接口。它提供了一个链接列表数据结 构。它具有如下的两个构造函数,说明如 下 – LinkedList( ) – LinkedList(Collection c) – 第一个构造函数建立一个空的链接列表。 – 第二个构造函数建立一个链接列表,该链接列 表由类集c中的元素初始化

除了它继承的方法之外,LinkedList类本身 还定义了一些有用的方法,这些方法主要 用于操作和访问列表。使用addFirst( )方法 可以在列表头增加元素;使用addLast( )方 法可以在列表的尾部增加元素。它们的形 式如下所示 – void addFirst(Object obj) – void addLast(Object obj) – 这里,obj是被增加的项

调用getFirst( )方法可以获得第一个元素。调用 getLast( )方法可以得到最后一个元素。它们的形 式如下所示: – Object getFirst( ) – Object getLast( ) • 为了删除第一个元素,可以使用removeFirst( )方 法;为了删除最后一个元素,可以调用 removeLast( )方法。它们的形式如下所示 – Object removeFirst( ) – Object removeLast( )

LinkedList是采用双向循环链表实现的。 • 利用LinkedList实现栈(stack)、队列 (queue)、双向队列(double-ended queue )。

1.       当向ArrayList添加一个对象时,实际上就是将该对象放置到了ArrayList底层所维护的数组当中;当向LinkedList中添加一个对象时,实际上LinkedList内部会生成一Node个对象,该Node对象的结构为:

 

private static class Node<E> {
        E item;
        Node<E> next;
        Node<E> prev;

其中的Object类型的元素element就是我们向LinkedList中所添加的元素,然后Node又构造好了向前与向后的引用pre、next,最后将生成的这个Node对象加入到了链表当中。换句话说,LinkedList中所维护的是一个个的Node对象

 

 

HashSet

public class SetTest1
{
		public static void main(String[] args)
		{
			HashSet set = new HashSet();
			
			System.out.println(set.add("a"));
			set.add("b");
			set.add("c");
			set.add("d");
			System.out.println(set.add("a"));
			
			System.out.println(set);
			
			
			
			
		}
	}
/*
 output:  true
           false
          [a, b, c, d]
*/

 

1.       关于Object类的equals方法的特点

a)      自反性:x.equals(x)应该返回true  。。以下x不为null

b)      对称性:x.equals(y)为true,那么y.equals(x)也为true。

c)       传递性:x.equals(y)为 true并且y.equals(z)为true,那么x.equals(z)也应该为true。

d)      一致性:x.equals(y)的第一次调用为true,那么x.equals(y)的第二次、第三次、第n次调用也应该为true,前提条件是在比较之间没有修改x也没有修改y。

e)      对于非空引用x,x.equals(null)返回false。

2.       关于Object类的hashCode()方法的特点:

a)      在Java应用的一次执行过程当中,对于同一个对象的hashCode方法的多次调用,他们应该返回同样的值(前提是该对象的信息没有发生变化)。执行第二次值会发生变化

b)      对于两个对象来说,如果使用equals方法比较返回true,那么这两个对象的hashCode值一定是相同的。

c)       对于两个对象来说,如果使用equals方法比较返回false,那么这两个对象的hashCode值不要求一定不同(可以相同,可以不同),但是如果不同则可以提高应用的性能。

d)      对于Object类来说,不同的Object对象的hashCode值是不同的(Object类的hashCode值表示的是对象的地址)。

3.       当使用HashSet时,hashCode()方法就会得到调用,判断已经存储在集合中的对象的hash code值是否与增加的对象的hash code值一致;如果不一致,直接加进去;如果一致,再进行equals方法的比较,equals方法如果返回true,表示对象已经加进去了,就不会再增加新的对象,否则加进去。

如果我们重写equals方法,那么也要重写hashCode方法,反之亦然。

public class SetTest2
{
	public static void main(String[] args)
	{
		HashSet set = new HashSet();
/*		
		set.add(new People("zhangsan"));
		set.add(new People("lisi"));
		set.add(new People("zhangsan"));
		System.out.println(set);
//output:[com.yy.People@7852e922, com.yy.People@70dea4e, com.yy.People@4e25154f]
		People p1 = new People("zhangsan");
		
		set.add(p1);
		set.add(p1);
		System.out.println(set);
//output[com.yy.People@7852e922,com.yy.People@5c647e05,com.yy.People@70dea4e,com.yy.People@4e251]
		
 */       
        String s1 = new String("a");
		String s2 = new String("a");
		
		System.out.println("hash code: " + (s1.hashCode() == s2.hashCode()));
//output: hash code: true
		
		set.add(s1);
		set.add(s2);
		
		System.out.println(set);//output: [a]
	}
}

class People
{
	String name;

	public People(String name)
	{
		this.name = name;		
	}

}

 

public class SetTest3
{
	public static void main(String[] args)
	{
		HashSet set = new HashSet();

		Student s1 = new Student("zhangsan");
		Student s2 = new Student("zhangsan");

		set.add(s1);
		set.add(s2);

		System.out.println(set);

	}
}

class Student
{
	String name;

	public Student(String name)
	{
		this.name = name;
	}

	

	 public int hashCode()
	 {
	 return this.name.hashCode();
	 }

	
	 public boolean equals(Object obj)
	 {
	 if(this == obj)
	 {
	    return true;
	 }
	 if(null != obj && obj instanceof Student)
     {
	        Student s = (Student)obj;
	
	        if(name.equals(s.name))
	 {
	        return true;
	 }
	 }
	
	        return false;
	 }

}

TreeSet

TreeSet为使用树来进行存储的Set接口提供 了一个工具,对象按升序存储。访问和检 索是很快的。在存储了大量的需要进行快 速检索的排序信息的情况下,TreeSet是一 个很好的选择。

下面的构造函数定义为:

TreeSet( )
//式构造一个空的树集合,该树集合将根据其元素的自然顺序按升序排序。
TreeSet(Collection c)
//构造一个包含了c的元素的树集合。
TreeSet(Comparator comp)
//构造一个空的树集合,它按照由comp指定的比较函数进行排序(比较函数将在后面介绍)
 TreeSet(SortedSet ss)
//构造一个包含了ss的元素的树集合

 因为TreeSet按树存储其 元素,它们被按照升序排序次序自动安排,如程序 输出所示

public class TreeSetTest
{
	public static void main(String[] args)
	{
		TreeSet set = new TreeSet();
		
		set.add("C");
		set.add("A");
		set.add("B");
		set.add("E");
		set.add("F");
		set.add("D");
		
		System.out.println(set);
		
	}
}
//output;[A, B, C, D, E, F]

改变TreeSet按树存储其 元素,它们被按照降序排序次序自动安排,如程序 输出所示

public class TreeSetTest3
{
	public static void main(String[] args)
	{
		TreeSet set = new TreeSet(new MyComparator());
		
		set.add("C");
		set.add("A");
		set.add("B");
		set.add("E");
		set.add("a");
		set.add("F");
		set.add("D");
		
		for(Iterator iter = set.iterator(); iter.hasNext();)
		{
			String value = (String)iter.next();
			
			System.out.println(value);
					
		}
		
	}
}



class MyComparator implements Comparator
{
	public int compare(Object arg0, Object arg1)
	{
		String s1 = (String)arg0;
		String s2 = (String)arg1;
		
		return s2.compareTo(s1);
	}
}
/*output:a
         F
         E
         D
         C
         B
         A*/
public class TreeSetTest2
{
	public static void main(String[] args)
	{
		TreeSet set = new TreeSet();

		Person p1 = new Person(10);
		Person p2 = new Person(20);
		Person p3 = new Person(30);
		Person p4 = new Person(40);

		set.add(p1);
	//	set.add(p2);
	//	set.add(p3);
	//	set.add(p4);

		
			System.out.println(set);
		

	}
}

class Person
{
	int score;

	public Person(int score)
	{
		this.score = score;
	}
	public String toString()
	{
		return String.valueOf(this.score);
	}
}

/*


Exception in thread "main" java.lang.ClassCastException: com.yy.Person cannot be cast to java.lang.Comparable
	at java.util.TreeMap.compare(TreeMap.java:1294)
	at java.util.TreeMap.put(TreeMap.java:538)
	at java.util.TreeSet.add(TreeSet.java:255)
	at com.yy.TreeSetTest2.main(TreeSetTest2.java:17)













*/
	
public class TreeSetTest2
{
	public static void main(String[] args)
	{
		TreeSet set = new TreeSet(new PersonComparator());

		Person p1 = new Person(10);
		Person p2 = new Person(20);
		Person p3 = new Person(30);
		Person p4 = new Person(40);

		set.add(p1);
		set.add(p2);
		set.add(p3);
		set.add(p4);

		for(Iterator iter = set.iterator(); iter.hasNext();)
		{
			Person p = (Person)iter.next();
			System.out.println(p.score);
		}

	}
}

class Person
{
	int score;

	public Person(int score)
	{
		this.score = score;
	}

	public String toString()
	{
		return String.valueOf(this.score);
	}
}

class PersonComparator implements Comparator
{
	public int compare(Object arg0, Object arg1)
	{
		Person p1 = (Person) arg0;
		Person p2 = (Person) arg1;

		return p2.score - p1.score;
	}
}
/*


40
30
20
10



*/

 

关注公众号【好便宜】( ID:haopianyi222 ),领红包啦~
阿里云,国内最大的云服务商,注册就送数千元优惠券:https://t.cn/AiQe5A0g
腾讯云,良心云,价格优惠: https://t.cn/AieHwwKl
搬瓦工,CN2 GIA 优质线路,搭梯子、海外建站推荐: https://t.cn/AieHwfX9
扫一扫关注公众号添加购物返利助手,领红包
Comments are closed.

推荐使用阿里云服务器

超多优惠券

服务器最低一折,一年不到100!

朕已阅去看看