JAVA单列集合
概述
-
作用:了保存数量不确定的数据,以及保存具有映射关系的数据(也被称为关联数组),Java提供了集合类。集合类主要负责保存、盛装其他数据,因此集合类也被称作容器类。
-
所在的包:java.util包,后来为了处理多线程环境下的并发安全问题,JAVA5还在java.util.concurrent包下提供了一些多线程支持的集合类。
-
保存的数据:只可以保存对象(实际上只是保存对象的引用变量,但通常习惯上认为集合里保存的是对象)。
-
重点:
Java中常见数据结构:list与map -底层如何实
这里引用了别人的博客,将collection各个类和接口的区别都很清楚的写出来了
Collection < E > 接口
1、概述
-
所在的包:java.util
-
Collection 层次结构 中的根接口。Collection 表示一组对象,这些对象也称为 collection的元素。一些 collection 允许有重复的元素,而另一些则不允许。一些 collection 是有序的,而另一些则是无序的。JDK 不提供此接口的任何直接实现:它提供更具体的子接口(如 Set 和 List)实现。此接口通常用来传递 collection,并在需要最大普遍性的地方操作这些 collection。
-
由于Collection是接口所以无法进行实例化,如果要使用,必须是父类调用指向子类的对象
如:Collection c=new ArrayList(); Collection c=new TreeSet();
2、方法
- public boolean add(E e) 确保此 collection 包含指定的元素(可选操作)。
- public boolean addAll(Collection<? extends E> c) 将指定 collection 中的所有元素都添加到此 collection 中(可选操作)。
- public void clear() 移除此 collection 中的所有元素(可选操作)。
- public boolean contains(Object o) 如果此 collection 包含指定的元素,则返回 true
- public boolean containsAll(Collection<?> c) 如果此 collection 包含指定 collection 中的所有元素,则返回 true。
- public boolean equals(Object o) 比较此 collection 与指定对象是否相等。
- public boolean isEmpty() 如果此 collection 不包含元素,则返回 true。
- public Iterator iterator() 返回在此 collection 的元素上进行迭代的迭代器。
- public boolean remove(Object o) 从此 collection 中移除指定元素的单个实例,如果存在的话(可选操作)。
- public boolean removeAll(Collection<?> c) 移除此 collection 中那些也包含在指定 collection 中的所有元素(可选操作)。
- public boolean retainAll(Collection<?> c) 仅保留此 collection 中那些也包含在指定 collection 的元素(可选操作)。
- public int size() 返回此 collection 中的元素数。
- public Object[ ] toArray() 返回包含此 collection 中所有元素的数组。
3、方法实例
public class Collection {
public static void main(String[] args) {
demo1();
demo2();
demo3();
demo4();
demo5();
demo6();
demo7();
demo8();
demo9();
}
public static void demo9() {
Collection c=new ArrayList();
c.add("a");
c.add("b");
c.add("c");
c.add("d");
Iterator it =c.iterator();//引用集合中的迭代器,返回值也是Iterator类型的
/*boolean b=it.hasNext();//判断集合中是否还有元素可以迭代
System.out.println(b);
System.out.println(it.next());//打印迭代的元素*/
while(it.hasNext()) {
System.out.println(it.next());
}
}
public static void demo8() {
Collection c1=new ArrayList();
c1.add("a");
c1.add("b");
c1.add("c");
c1.add("d");
Collection c2=new ArrayList();
c2.add("a");
c2.add("b");
c2.add("z");
//c2.add("c");
//c2.add("d");
boolean b=c1.retainAll(c2);//获取的是两个集合的交集
System.out.println(b);
System.out.println(c1);
//如果两个集合有交集,那么c1就会变成二者的交集,
//如果交集为空集,那么c1就会变成空集合,且返回true
//如果交集为c1本身,则c1不改变,返回false
}
public static void demo7() {
Collection c1=new ArrayList();
c1.add("a");
c1.add("b");
c1.add("c");
c1.add("d");
Collection c2=new ArrayList();
c2.add("a");
c2.add("b");
c2.add("z");
boolean b=c1.removeAll(c2);//删除的是两个集合的交集,一旦c1集合被改变,则返回true,否则位false
System.out.println(b);
System.out.println(c1);
}
public static void demo6() {
Collection c1=new ArrayList();
c1.add("a");
c1.add("b");
c1.add("c");
c1.add("d");
Collection c2=new ArrayList();
c2.add("a");
c2.add("b");
c2.add("z");
boolean b=c1.containsAll(c2);//true
//在c2中加入“z”,结果就是false,因为并没有全部包含
//如果c2中没有元素,结果也是true,因为c1中等于包含了全部的c2
System.out.println(b);
}
public static void demo5() {
Collection c1=new ArrayList();
c1.add("a");
c1.add("b");
c1.add("c");
c1.add("d");
Collection c2=new ArrayList();
c2.add("1");
c2.add("2");
c2.add("3");
c2.add("4");
boolean b=c1.addAll(c2);//返回值为true
System.out.println(b);
System.out.println(c1);//将c2中的全部元素加入c1中后的集合
}
public staitc void demo4() {
Collection c=new ArrayList();
c.add(new Student("张娜",23));
c.add(new Student("里斯",24));
c.add(new Student("王五",25));
c.add(new Student("赵六",26));
Object [] arr=c.toArray();
for(int i=0;i<arr.length;i++) {
//System.out.println(arr[i]);
//System.out.println(arr[i].getName()+"..."+arr[i].getAge());
//为什么没有getName()和getAge()方法?
//因为上述等同于 Object arr[i]=new Student("张三",23);父类引用指向子类的对象
//故而父类无法使用子类中的特殊的方法,要想使用,必须向下转型(强制转换)
Student s=(Student)arr[i];
System.out.println(s.getName()+"..."+s.getAge());
}
}
public static void demo3 () {
Collection c=new ArrayList();
c.add("a");
c.add("b");
c.add("c");
c.add("d");
//c.remove("c");//将集合中的c删除
//c.clear();//将集合中的所有元素清空
int a=c.size();//获取集合中元素的个数
boolean b=c.contains("d");//看集合中是否包含所给元素
boolean b1=c.isEmpty();//看集合是否为空
System.out.println(c);
System.out.println(b);//true
System.out.println(b1);
System.out.println(a);
}
public static void demo2() {
Collection c=new ArrayList();//父类引用指向子类的对象
boolean b1=c.add("abc");
boolean b2=c.add(100);//自动封装成Integer
boolean b3=c.add(true);//自动封装成new Boolean(true)
boolean b4=c.add(new Student("张三",23));
boolean b5=c.add("abc");
System.out.println(b1);
System.out.println(b2);
System.out.println(b3);
System.out.println(b4);
System.out.println(b5);
System.out.println(c.toString());//在集合里面有元素的时候打印字符串,没有的时候打印[]
}
public static void demo1() {
Collection c=new ArrayList();
c.add("a");
c.add("b");
c.add("c");
c.add("d");
Object [] arr=c.toArray();
for(int i=0;i<arr.length;i++) {
System.out.println(arr[i]);
}
}
}
List < E >接口
- 所在的包: java.util 接口 List
- 有序的 collection(也称为序列)。此接口的用户可以对列表中每个元素的插入位置进行精确地控制。用户可以根据元素的整数索引(在列表中的位置)访问元素,并搜索列表中的元素。
- 与 set 不同,列表通常允许重复的元素。更确切地讲,列表通常允许满足 e1.equals(e2) 的元素对 e1 和 e2,并且如果列表本身允许 null 元素的话,通常它们允许多个 null 元素。难免有人希望通过在用户尝试插入重复元素时抛出运行时异常的方法来禁止重复的列表,但我们希望这种用法越少越好。
方法(相较于Collection的特殊方法)
- public static void add(int index, E element)在列表的指定位置插入指定元素(可选操作)。
- public E set(int index, E element)用指定元素替换列表中指定位置的元素(可选操作)。
- public E get(int index) 返回列表中指定位置的元素。
- public E remove(int index)移除列表中指定位置的元素(可选操作)。
方法实例
public static void demo1() {
List list=new ArrayList();
list.add("a");
list.add("b");
list.add("c");
list.add("d");
list.add(4, "z");
//list.add(5, "z");//java.lang.IndexOutOfBoundsException
//索引越界异常,0<=index&&index<=list.size()
System.out.println(list);//将指定元素添加在指定的位置上
}
public static void demo2() {
List list=new ArrayList();
list.add("a");
list.add("b");
list.add("c");
list.add("d");
Object obj=list.set(3, "abc");
System.out.println(obj);//返回的是索引位置对应的元素
System.out.println(list);//将改变后的list输出
}
public static void demo3() {
List list=new ArrayList();
list.add("a");
list.add("b");
list.add("c");
list.add("d");
list.add(111);
Object obj=list.remove(2);
//Object obj=list.remove(111);java.lang.IndexOutOfBoundsException指针越界异常
//删除时不具备自动装箱的能力,故而数字都是索引值,否则就乱了
System.out.println(obj);//返回删除索引处的元素
System.out.println(list);//输出删除后的列表
}
public static void demo4() {
List list=new ArrayList();
list.add("a");
list.add("b");
list.add("c");
list.add("d");
list.add(111);
Object obj=list.get(2);
System.out.println(obj);
System.out.println(list);
//可以通过get方法获取元素从而遍历数组
for(int i=0;i<list.size();i++) {
System.out.println(list.get(i));
}
}
经典例题
//需求:我有一个集合,我想判断有没有“world”这个元素,如果有,我就添加一个“javaee”元素
public static void main(String[] args) {
List list=new ArrayList();
list.add("a");
list.add("b");
list.add("world");
list.add("c");
list.add("d");
list.add("e");
/*Iterator it=list.iterator();
while(it.hasNext()) {
String str=(String)it.next();//向下转型
if("world".equals(str)) {
list.add("javaee");//遍历的同时在添加,出现并发修复异常java.util.ConcurrentModificationException
}
}*/
//ListIterator<E> listIterator()返回此列表元素的列表迭代器(按适当顺序)。
//void add(E e)将指定的元素插入列表(可选操作)。
ListIterator lit=list.listIterator();
while(lit.hasNext()) {
String str=(String)lit.next();//必须向下转型,否则类型不匹配
if("world".equals(str)) {
//list.add("=javaee");//依旧是相同的错误,所以应该用迭代器内的添加方法
lit.add("javaee");//bingo
}
}
System.out.println(list);
}
Vector类
- 所在的包:java.util
- Vector 类可以实现可增长的对象数组。与数组一样,它包含可以使用整数索引进行访问的组件。但是,Vector 的大小可以根据需要增大或缩小,以适应创建 Vector 后进行添加或移除项的操作。
特殊的方法
public void addElement (E obj) 将指定的组件添加到此向量的末尾,将其大小增加 1。
方法实例
//vector中特殊的方法
public static void main(String[] args) {
Vector v=new Vector();
v.addElement("a");
v.addElement("b");
v.addElement("c");
v.addElement("d");
v.addElement("e");
Enumeration en=v.elements();//获取枚举
while(en.hasMoreElements()) {//判断集合中是否有元素
System.out.println(en.nextElement());//获取集合中的元素
}
}
Set < E > 接口
- 所在的包 : java.util
- 一个不包含重复元素的 collection。更确切地讲,set 不包含满足 e1.equals(e2) 的元素对e1 和 e2,并且最多包含一个 null 元素。正如其名称所暗示的,此接口模仿了数学上的set 抽象
HashSet < E > 类
- 所在的包 : java.util
- 此类实现 Set 接口,由哈希表(实际上是一个 HashMap 实例)支持。它不保证 set的迭代顺序;特别是它不保证该顺序恒久不变。此类允许使用 null 元素。
实例
public static void demo2() {
HashSet <Person> hs=new HashSet<> ();
hs.add(new Person("张三",23));
hs.add(new Person("张三",23));
hs.add(new Person("里斯",24));
hs.add(new Person("里斯",24));
hs.add(new Person("张三",23));
hs.add(new Person("里斯",24));
System.out.println(hs);
System.out.println(hs.size());//6
//原因:每个new的对象都会有自己新的地址值,而equals对于引用数据类型比较的就是地址值
//重写了equals方法后还是保留原来的元素不变,但重写hashcode方法后,就成功了
//原因:每个新元素加入集合后都会获得一个随机的hashcode值,
//然而hashcode值不同的时候就不需要调用equals方法,因而无法判断元素是否相同
//改写hashcode值变成10,将所有的新元素的hashcode值都改为10,
//从而每一次都调用equals方法判断是否相同,当相同时就不添加,但为了提高效率,
//会对hashcode返回的值做一个改变,利用本来Person的一些属性,相同元素的Hashcode相同再进行判断
//不同元素hashcode不同就不用调用equals方法判断啦
for(Person person : hs) {
System.out.println("123");
System.out.println(person);
}
public static void demo1() {
HashSet<String> hs=new HashSet<> ();//创建HashSet对象
boolean b1= hs.add("a");
boolean b2= hs.add("a");
hs.add("b");
hs.add("f");
hs.add("s");
hs.add("z");//[a,b,s,f,z]
//Set集合,无索引,不可以重复,无序(存取不一)
System.out.println(hs);//重写了toString方法
System.out.println(b1);//true
System.out.println(b2);//false
//原因:set集合不允许有重复值,当添加重复元素时会返回false
for(String string : hs) {
System.out.println(string);
}//只要能用迭代器迭代的,就可以使用增强for循环来遍历
}
TreeSet< E >类
- 所在的包:java.util
- 基于 TreeMap 的 NavigableSet 实现。使用元素的自然顺序对元素进行排序,或者根据创建 set 时提供的 Comparator 进行排序,具体取决于使用的构造方法
方法实例
//treeset是set集合的一个子类,不仅可以保证元素的唯一,还可以用来给对象元素排序
//重写Comparable里的compareTo方法后,
//返回值为0时,集合中只有1个元素
//返回值为正整数时,集合中元素怎么存就怎么取
//返回值为负整数时,集合中的元素是倒着存储的
public static void main(String[] args) {
//demo1();
//demo2();
//demo3();
//需求:将字符串按照长度排序(利用比较器)
/*Comparator<String> comp=new CompareByLength();//父类调用指向子类的对象
TreeSet<String> ts=new TreeSet<> (comp); */
TreeSet<String> ts=new TreeSet<> (new CompareByLength());//构造方法中传入构造器,但有一构造器无法实例化,可以传入构造器的子类
ts.add("aaaaaaaaaaa");
ts.add("bbd");
ts.add("c");
ts.add("asdad");
ts.add("bscbscaskcsk");
System.out.println(ts);//按照字典顺序排序
//有构造器后就是用长度排序
}
public static void demo3() {
TreeSet <Person> ts=new TreeSet<> ();
ts.add(new Person("zhangsan",12));
ts.add(new Person("lisi",23));
ts.add(new Person("wangwu",18));
ts.add(new Person("zhaoliu",9));
ts.add(new Person("adad",17));
System.out.println(ts);
}
public static void demo2() {
TreeSet<Person> ts=new TreeSet<> ();
ts.add(new Person("张三",43));
ts.add(new Person("里斯",24));
ts.add(new Person("周器",43));
ts.add(new Person("王五",55));
ts.add(new Person("赵六",16));
System.out.println(ts);//报错了,因为没有重写Comparable方法,系统不知道对哪个进行比较
}
public static void demo1() {
TreeSet<Integer> ts=new TreeSet<> ();
ts.add(2);
ts.add(3);
ts.add(1);
ts.add(3);
ts.add(1);
System.out.println(ts);//[1, 2, 3]
}
//Comparator是一个接口,是比较器,用来比较,但由于无法实例化,故而要构造一个新的类作为子类重写接口中的方法
class CompareByLength implements Comparator<String> {
@Override
public int compare(String o1, String o2) {
int num=o1.length()-o2.length();
return num==0? o1.compareTo(o2) : num;
}
}
ArrayList< E >类
- 所在的包:java.util
- 每个 ArrayList 实例都有一个容量。该容量是指用来存储列表元素的数组的大小。它总是至少等于列表的大小。随着向ArrayList 中不断添加元素,其容量也自动增长。并未指定增长策略的细节,因为这不只是添加元素会带来分摊固定时间开销那样简单。在添加大量元素前,应用程序可以使用 ensureCapacity 操作来增加 ArrayList 实例的容量。这可以减少递增式再分配的数量。
LinkedList 类
- 所在的包:java.util
- List 接口的链接列表实现。实现所有可选的列表操作,并且允许所有元素(包括 null)。除了实现
List 接口外,LinkedList 类还为在列表的开头及结尾 get、remove和 insert 元素提供了统一的命名方法。这些操作允许将链接列表用作堆栈、队列或双端队列。此类实现 Deque 接口,为 add、poll 提供先进先出队列操作,以及其他堆栈和双端队列操作。所有操作都是按照双重链接列表的需要执行的。在列表中编索引的操作将从开头或结尾遍历列表(从靠近指定索引的一端)。
特殊方法
- public static void addFirst(E e)将指定元素插入此列表的开头。
- public static void addLast(E e) 将指定元素添加到此列表的结尾。
- public E getFirst()返回此列表的第一个元素。
- public E getLast() 返回此列表的最后一个元素。
- public E removeFirst()移除并返回此列表的第一个元素。
- public E removeLast() 移除并返回此列表的最后一个元素。
- public E get(int index) 返回此列表中指定位置处的元素。
方法实例
public static void main(String[] args) {
//demo1();
LinkedList l=new LinkedList();
l.addFirst("a");//插入的是列表的开头
l.addFirst("b");
l.addFirst("c");
l.addFirst("d");
l.addLast("z");
System.out.println(l.get(0));//根据索引获取元素
/* System.out.println(l.removeFirst());//返回移除的列表首元素
System.out.println(l.removeLast());//返回移除的列表尾元素*/
System.out.println(l);//输出删除后的列表
}
public static void demo1() {
LinkedList l=new LinkedList();
l.addFirst("a");//插入的是列表的开头
l.addFirst("b");
l.addFirst("c");
l.addFirst("d");
l.addLast("z");//插入的是列表的末尾
System.out.println(l.getFirst());//获取列表头元素
System.out.println(l.getLast());//获取列表尾元素
System.out.println(l);
}