黑马程序员——Java基础---集合框架

时间:2023-02-18 18:04:50
                                    ------Java培训、Android培训、iOS培训、.Net培训、期待与您交流! -------


集合框架


 一、概述

     在Java世界中,人们认为所有的事物都可以用类来描述,而对该事物的一个具体的个体是可以用类的实例化-对象来描述的。对开发一个工程来说,我们使用的肯定不止一个类,对同一个类的实例化过程中也会产生多个对象。在这过程中,人们会发现我们根本无法对产生的如此众多的类和对象进行管理和规划,导致整个程序看起来阅读性非常的差,所以我们需要一个管理对象的工具!根据万物都是对象的思想,我们将管理对象的这个工具也封装成一个类,这就是我们的集合类。


 二、集合框架的构成以及分类

    对对象进行操作的类-集合类同样是类,那么它必然就有类的3大特点-封装、继承、多态。根据JavaApi 的描述,集合类被划分成一个集合框架的体系,在我们阅读的过程中,可以先看父类的功能再看子类对象对父类功能的实现。其体系如下图:
黑马程序员——Java基础---集合框架
其中包括从Collection和Map两个最上层的接口延伸下来的集合体系以及工具类Collections和Arrays,比较器Compatable和Comparator,迭代器Iterator等,下面我们将一一介绍以上各种类。

 三、Collection类系列

          Collection接口

          所谓的Collection接口就是存储单一对象的容器。它可以存储任何类型的对象且容器长度可以变化。它是一个抽象的接口,它内部只定义了抽象的方法而不具体实现,需要子类去实现。其下可被List和Set类所实现。其内部主要的方法为:

//添加元素
boolean add(Object obj);//添加一个对象
boolean addAll(Collection ct);//在该容器末尾添加另一个容器的所有元素。

//删除元素
boolean remove(e);
boolean removeAll(collection);//移除调用该方法的对象中相对于参数集合的相同元素(对象)
void clear();清除所有元素(对象)

//判断元素
boolean contains(Object e);//是否包含元素e
boolean isEmpty();//该容器是否为空

//获取
Iterator iterator();//迭代器
int size();//获取容器存储元素个数

//获取交集。
Collection retainAll(Collection co);//获取交集

//集合变数组。
Object[] toArray(Object[] obj);//将集合元素存入数组

         Collection系列的取出方式

              其中特别要注意的是Iterator-迭代器。什么是迭代器?其实就是集合的取出元素的方式。如同抓娃娃游戏机中的夹子。迭代器是取出方式,会直接访问集合中的元素。所以将迭代器通过内部类的形式来进行描述。

         通过容器的iterator()方法获取该内部类的对象。迭代器的一般使用格式为:

        for(Iterator it = al.iterator(); it.hasNext() ; )
{
sop(it.next());//注意,如果不加泛型的话,it.next()是一定返回的是一个Object类对象,而且在循环中调用一次next()方法就是获取一次容器中元素。所以一定要注意调用该方法的次数!
}

         List接口

           List接口是Collection的子接口,是一个列表形式的容器,它有角标且存储的是一系列有序且可以重复的元素。它常用的方法有:

/*
//增
add(index,element);在index角标位置添加一个元素
addAll(index,Collection);在index角标后将集合中的元素添加

//删
remove(index);将index角标位置的元素移除

//改
set(index,element);将index角标位置的元素修改
//查
get(index):
subList(from,to);
listIterator();
int indexOf(obj)://获取指定元素的位置。
ListIterator listIterator();

List集合特有的迭代器。ListIterator是Iterator的子接口。在迭代时,不可以通过集合对象的方法操作集合中的元素。因为会发生ConcurrentModificationException异常。
所以,在迭代器时,只能用迭代器的放过操作元素,可是Iterator方法是有限的,只能对元素进行判断,取出,删除的操作,如果想要其他的操作如添加,修改等,就需要使用其子接口,ListIterator。
该接口只能通过List集合的listIterator方法获取。

//在迭代过程中,准备添加或者删除元素。

Iterator it = al.iterator();

while(it.hasNext())
{
Object obj = it.next();

if(obj.equals("java02"))
//al.add("java008");
it.remove();//将java02的引用从集合中删除了。

sop("obj="+obj);


}
              ArrayList类

               ArrayList是一个可以实例化的类。它是我们在使用Collection系列类是常用的一种容器。它实现了Collection和List接口,复写了接口中的抽象方法。其底层调用的是Array-数组数据结构来存储我们所需要的对象的。对象的获取方法为iterator和listIterator迭代器。

            LinkedList类

          LinkedList也是一个可以实例化的类。它是我们在使用Collection系列类是常用的一种容器。它实现了Collection和List接口,复写了接口中的抽象方法。其底层调用的是数据链表形式的数据结构来存储我们所需要的对象的获取方法为iterator和listIterator迭代器。但是它有它自己独特的方法:

/*
LinkedList:特有方法:
addFirst();
addLast();
<pre name="code" class="java">添加元素。

getFirst();
getLast();
获取元素,但不删除元素。如果集合中没有元素,会出现NoSuchElementException

removeFirst();
removeLast();
获取元素,但是元素被删除。如果集合中没有元素,会出现NoSuchElementException

在JDK1.6出现了替代方法。

offerFirst();
offerLast();
添加元素

peekFirst();
peekLast();
获取元素,但不删除元素。如果集合中没有元素,会返回null。

pollFirst();
pollLast();
获取元素,但是元素被删除。如果集合中没有元素,会返回null。
*/


       Set接口

        所谓Set接口,描述的是一类可以存储任何类型的对象的容器,但是该容器没有角标,不可存储相同元素且是无序存储。Set接口并没有他的特有方法,它下面可以实现的两个类分别为:HashSet和TreeSet

          HashSet类

        对HashSet类来说,它是一个可以实例化的类,该实例化对象存储的是一些不可重复和无序的对象,它没有自己独特的方法,主要方法是调用Collection中的方法,其底层封装的是哈希表数据类型来存放元素的。在把对象存储到该容器中时,容器会判定对象的哈希值(调用对象的hashCode()方法),如果哈希值相同则会判断对象是否和容器中已有对象相同(调用对象的equals()方法)如果相同,则该对象不会被存储。

        所以,在对一些自定义的类实例化对象进行存储是,我们需要在类定义中重写该类继承自Object类中的Hashcode()方法equals()方法以保证该容器能够很好的对元素进行比较。对象的获取方法为iterator迭代器

       列子:

class HashSetTest 
{
public static void sop(Object obj)
{
System.out.println(obj);
}
public static void main(String[] args)
{
HashSet hs = new HashSet();

hs.add(new Person("a1",11));
hs.add(new Person("a2",12));
hs.add(new Person("a3",13));
//hs.add(new Person("a2",12));
//hs.add(new Person("a4",14));

//sop("a1:"+hs.contains(new Person("a2",12)));

//hs.remove(new Person("a4",13));


Iterator it = hs.iterator();

while(it.hasNext())
{
Person p = (Person)it.next();
sop(p.getName()+"::"+p.getAge());
}
}
}
class Person
{
private String name;
private int age;
Person(String name,int age)
{
this.name = name;
this.age = age;
}
public int hashCode()//重写hashCode()方法
{
System.out.println(this.name+"....hashCode");
return name.hashCode()+age*37;
}
public boolean equals(Object obj)//重写equals()方法
{

if(!(obj instanceof Person))
return false;

Person p = (Person)obj;
System.out.println(this.name+"...equals.."+p.name);

return this.name.equals(p.name) && this.age == p.age;
}
public String getName()
{
return name;
}
public int getAge()
{
return age;
}
}

       TreeSet类

         对TreeSet类来说,它是一个可以实例化的类,该实例化对象存储的是一些不可重复和无序的对象,它没有自己独特的方法,主要方法是调用Collection中的方法,其底层封装的是二叉树数据类型来存放元素的。在把对象存储到该容器中时,容器会调用对象的compareTo()方法对对象进行判定是否和已有的对象相同,若相同则不会存入集合。

         所以,在存储一些我们自定义类的时,如何很好的存入TreeSet容器中呢?有两种方法:继承和实现:

         1、所谓继承,就是在自定义类中继承Comparable类,该类内部封装了compareTo()方法,所以可以使得该类产生的对象变得具有比较性。

         2、所谓实现,重新定义一个类实现了Comparator类,该类内部封装了compare()方法,该类叫做比较器,在实例化一个TreeSet容器时可以将比较器传入构造函数中,在将对象加入容器时就会按照比较器进行相同元素比较。

        对象的获取方法为iterator迭代器。列子:    

class Student implements Comparable//该接口强制让学生具备比较性。
{
private String name;
private int age;
Student(String name,int age)
{
this.name = name;
this.age = age;
}

public int compareTo(Object obj)
{
if(!(obj instanceof Student))
throw new RuntimeException("不是学生对象");
Student s = (Student)obj;

//System.out.println(this.name+"....compareto....."+s.name);
if(this.age>s.age)
return 1;
if(this.age==s.age)
{
return this.name.compareTo(s.name);
}
return -1;
}
public String getName()
{
return name;

}
public int getAge()
{
return age;
}
}
class TreeSetDemo2
{
public static void main(String[] args)
{
TreeSet ts = new TreeSet();

ts.add(new Student("lisi02",22));
ts.add(new Student("lisi02",21));
ts.add(new Student("lisi007",20));
ts.add(new Student("lisi09",19));
ts.add(new Student("lisi06",18));
ts.add(new Student("lisi06",18));
ts.add(new Student("lisi007",29));
//ts.add(new Student("lisi007",20));
//ts.add(new Student("lisi01",40));

Iterator it = ts.iterator();
while(it.hasNext())
{
Student stu = (Student)it.next();
System.out.println(stu.getName()+"..."+stu.getAge());
}
}
}
class MyCompare implements Comparator//比较器形式
{
public int compare(Object o1,Object o2)
{
Student s1 = (Student)o1;
Student s2 = (Student)o2;

int num = s1.getName().compareTo(s2.getName());
if(num==0)
{

return new Integer(s1.getAge()).compareTo(new Integer(s2.getAge()));
/*
if(s1.getAge()>s2.getAge())
return 1;
if(s1.getAge()==s2.getAge())
return 0;
return -1;
*/
}
return num;
}
}

  四、Map类系列

            Map接口

          Map接口及其以下一系列容器不同于Collection系列,它们存储的不是一个一个的对象而是一对一对的键值对,一对键值对就是一个元素,而键和值又分别是一个对象。Map集合存储元素是通过调用put()方法而不是add()方法来实现的。相对于Collection系列容器利用内部类Iterator来取出元素,Map并没有直接取出元素的办法,而是先转换成Set集合在通过迭代器来取出元素,在Map集合中键需要保证唯一性。它有自己的不同于Collection的方法,列子:

import java.util.*;
class MapDemo
{
public static void main(String[] args)
{
Map<String,String> map = new HashMap<String,String>();

//添加元素,添加元素,如果出现添加时,相同的键。那么后添加的值会覆盖原有键对应值。
//并put方法会返回被覆盖的值。
System.out.println("put:"+map.put("01","zhangsan1"));
System.out.println("put:"+map.put("01","wnagwu"));
map.put("02","zhangsan2");
map.put("03","zhangsan3");

System.out.println("containsKey:"+map.containsKey("022"));
//System.out.println("remove:"+map.remove("02"));

System.out.println("get:"+map.get("023"));

map.put("04",null);
System.out.println("get:"+map.get("04"));
//可以通过get方法的返回值来判断一个键是否存在。通过返回null来判断。

//获取map集合中所有的值。
Collection<String> coll = map.values();

System.out.println(coll);
System.out.println(map);
}
}<span style="font-size:18px;">        </span>

         HashMap

            对HashMap类来说,它是一个可以实例化的类,它存储的是一系列不可重复的键值对对于它的学习,可以类比HashSet来因为它底层存储时也是调用了哈希表的数据结构,不同的是HashSet是对象比较,HashMap使用键来比较的,当键对象的哈希值和内容都相同的时候,该键相对应的值会被新值所替换!同样要重写键对象的hashCode()方法和equals()方法。

         TreeMap类

            对TreeMap类来说,它是一个可以实例化的类,它存储的是一系列不可重复的键值对。对于它的学习,可以类比TreeSet来,因为它底层存储时也是用了二叉树的数据结构,不同的是TreeSet是对象比较,TreeMap使用键来比较的,当键的对象的内容相同时,该键相对应的值会被新值替换同样要传入比较器或者使键对象具有比较性。

         如何获取Map集合中的元素?

            Map集合中的元素都是一对对的键值对,不同于Collection中的元素,可以使用迭代器的形式进行遍历获取每一个对象,Map集合有它独有的两种获取形式:

             1、调用Map集合产生的对象的keySet()方法,该方法返回的是一个内部容纳了该集合所有键对象的Set集合!然后我们可以使用迭代器来获取每一个键对象,在通过Map中的get()方法获取到相对应的值

                       2、调用Map集合产生的对象的entrySet()方法,该方法返回的是一个内部容纳了该集合所有映射关系的Set集合!该Set集合中对象类型为映射关系类型Map.entry,可以通过迭代Set集合获取映射关系,在通过该Map.entry接口(内部接口)的方法getKey()和getValue()来获取对应的键值。列子:

class MapDemo2 
{
public static void main(String[] args)
{
Map<String,String> map = new HashMap<String,String>();

map.put("02","zhangsan2");
map.put("03","zhangsan3");
map.put("01","zhangsan1");
map.put("04","zhangsan4");

//将Map集合中的映射关系取出。存入到Set集合中。
Set<Map.Entry<String,String>> entrySet = map.entrySet();

Iterator<Map.Entry<String,String>> it = entrySet.iterator();

while(it.hasNext())
{
Map.Entry<String,String> me = it.next();
String key = me.getKey();
String value = me.getValue();
System.out.println(key+":"+value);

}

/*
//先获取map集合的所有键的Set集合,keySet();
Set<String> keySet = map.keySet();

//有了Set集合。就可以获取其迭代器。
Iterator<String> it = keySet.iterator();
while(it.hasNext())
{
String key = it.next();
//有了键可以通过map集合的get方法获取其对应的值。
String value = map.get(key);
System.out.println("key:"+key+",value:"+value);
}
*/
}
}

 五、工具类Collections以及Arrays系列类

           Collections类

              Collections类就是我们最常用到的工具类,它没有提供其构造函数,但是内部封装了很多的静态方法来方便人们使用,该类提供方法主要是为了便利的操作List集合 其主要方法有:

              1、对List集合进行排序,若是没有自定义对象没有比较性,则需要传入比较器。列子:

public static void binarySearchDemo()
{
List<String> list = new ArrayList<String>();

list.add("abcd");
list.add("aaa");
list.add("zz");
list.add("kkkkk");
list.add("qq");
list.add("z");
Collections.sort(list,new StrLenComparator());//自定义类,传入比较器,改String类也可以使用自己的compareTo()方法进行排序

sop(list);
}
<pre name="code" class="java">class StrLenComparator implements Comparator<String>
{
public int compare(String s1,String s2)
{
if(s1.length()>s2.length())
return 1;
if(s1.length()<s2.length())
return -1;
return s1.compareTo(s2);
}
}

          2、对集合求最大的元素。由于也是比较,所以要么元素具有比较性或者传入比较器,列子(比较器已在上一个列子中列出):

public static void maxDemo()
{
List<String> list = new ArrayList<String>();

list.add("abcd");
list.add("aaa");
list.add("zz");
list.add("kkkkk");
list.add("qq");
list.add("z");
Collections.sort(list);
sop(list);
String max = Collections.max(list/*,new StrLenComparator()*/);
sop("max="+max);
}
          3、对集合进行二分查找。在查找过程中也是要比较,那么元素要具备比较性或者传入比较器,列子:

public static void binarySearchDemo()
{
List<String> list = new ArrayList<String>();

list.add("abcd");
list.add("aaa");
list.add("zz");
list.add("kkkkk");
list.add("qq");
list.add("z");
Collections.sort(list,new StrLenComparator());
sop(list);
int index = Collections.binarySearch(list,"aaaa");
sop("index="+index);
}
       4、将集合中某一个元素替换成另外一个元素。

public static void replaceAllDemo()
{


List<String> list = new ArrayList<String>();

list.add("abcd");
list.add("aaa");
list.add("zz");
list.add("kkkkk");

sop(list);

Collections.replaceAll(list,"aaa","pp");

sop(list);
Collections.reverse(list);

sop(list);
}
       5、将集合中的元素倒序。

public static void orderDemo()
{
TreeSet<String> ts = new TreeSet<String>(Collections.reverseOrder(new StrLenComparator()));

ts.add("abcde");
ts.add("aaa");
ts.add("k");
ts.add("cc");

Iterator it = ts.iterator();
while(it.hasNext())
{
System.out.println(it.next());
}
}
       6、强制将比较器颠倒,然后使用颠倒的比较器进行比较以达到排序的颠倒。
public static void orderDemo(){TreeSet<String> ts = new TreeSet<String>(Collections.reverseOrder(new StrLenComparator()));ts.add("abcde");ts.add("aaa");ts.add("k");ts.add("cc");Iterator it = ts.iterator();while(it.hasNext()){System.out.println(it.next());}}
       7、将集合中的元素随机排序。
public static void shuffleDemo(){List<String> list = new ArrayList<String>();list.add("abcd");list.add("aaa");list.add("zz");list.add("kkkkk");list.add("qq");list.add("z");sop(list);Collections.shuffle(list);sop(list);}

        Arrays工具类

           Arrays也是一个工具类,其主要是对数组进行操作的工具类,内部封装了众多的静态工具方法,主要运用的有两种:

           1、将数组变成集合

     

public static void main(String[] args) 
{
//int[] arr = {2,4,5};
//
//System.out.println(Arrays.toString(arr));
String[] arr = {"abc","cc","kkkk"};
//把数组变成list集合有什么好处?
/*
可以使用集合的思想和方法来操作数组中的元素。

注意:将数组变成集合,不可以使用集合的增删方法。
因为数组的长度是固定。
contains。
get
indexOf()
subList();

如果你增删。那么会反生UnsupportedOperationException,
*/
List<String> list = Arrays.asList(arr);
//sop("contains:"+list.contains("cc"));
//list.add("qq");//UnsupportedOperationException,
//sop(list);
//int[] nums = {2,4,5};
Integer[] nums = {2,4,5};
List<Integer> li = Arrays.asList(nums);
/*
如果数组中的元素都是对象。那么变成集合时,数组中的元素就直接转成集合中的元素。
如果数组中的元素都是基本数据类型,那么会将该数组作为集合中的元素存在。
*/
sop(li);
}
           2、将数组的元素直接字符串化

class Arraysdemo
{
public static void main(String[] args)
{
int[] arr = new int[3]{1,2,3};
System.out.println(Arrays.toString(arr));
}
}



------Java培训、Android培训、iOS培训、.Net培训、期待与您交流! -------