集合框架

什么是集合框架?

尽管这些类非常好用,但是却不能集中和统一管理.

集合框架是为了表示和操作集合而规定的一种统一的标准的体系结构,任何集合框架都包含三大块内容:对外的借口,借口的实现和对集合运算的算法.

 

为什么需要集合框架?

1):提供功能的复用(java.util包)

2):专注于业务开发,而不是数据结构和算法.

 

常用的框架类:

1): Set  集合中的对象,不按特定方式排序,不允许元素重复

2): List  集合中的对象,按照索引位置排序,允许元素重复

3): Map 集合中每一个元素都包含一对key和value对象,不允许key重复,对象重复,值对象可以重复.

Vector框架

 

集合类常用方法:

增加:

1):boolean add(Object e) 将制定元素添加到此向量的末尾,等价于addElement方法.

2):void add(int index,Object e) 在此向量的指定位置插入指定元素.

3):boolean addAll(Collection c)c集合中的元素块添加到当前集合对象中.

删除:

1):Object remove(int index)删除此向量中指定位置的元素

2):void clear() 从此Vector中删除所有元素。

3):boolean remove(Object o)删除此向量中指定元素的第一个出现如果Vector不包含元素,则它不会更改。

4):boolean removeAll(Collection<?> c)从此Vector中删除指定集合中包含的所有元素。

5):boolean retainAll(Collection<?> c)仅保留此向量中包含在指定集合中的元素。(仅保留num1中拥有的num2的元素(简称num1跟num2的集合))

 

修改:

Object set(int index, Object element)用指定的元素替换此Vector中指定位置的元素。

 

查询:

1):int size()返回此向量中的元素的个数

2):boolean isEmpty() 判断当前集合中元素个数是否为0.

3):Object get(int index) 查询index位置的元素.

4):Object toArray();把集合对象转换为Object数组.

 

 

ArrayList

ArrayListjava集合框架出现之后用来取代Vector类的

二者底层的原理算法都是基于数组的算法,一模一样

----------------------------

区别:

Vector:所有的方法都使用了synchronized修饰符  线程安全但是性能较低,适用于多线程环境

ArrayList:所有的方法都没有使用synchronized修饰

即使以后在多线程环境下,我们也不使用Vector类

如果多个线程同时访问884457282749实例,并且至少有一个线程在结构上修改列表,则必须在外部进行同步。 (结构修改是添加或删除一个或多个元素的任何操作,或明确调整后台数组的大小;仅设置元素的值不是结构修改。)这通常是通过在一些自然地封装了列表。 如果没有这样的对象存在,列表应该使用Collections.synchronizedList方法“包装”。 这最好在创建时完成,以防止意外的不同步访问列表:

 

  List list = Collections.synchronizedList(new ArrayList(...));

 

ArrayList(不唯一有序): 实现了长度可变的数组,在内存中分配连续的空间.遍历元素和堆积访问元素的效率比较高.

常用方法参照与Vector类。

使用步骤:

1):声明集合:       List list = new ArrayLtis();

ArrayList list = new ArrayList();

2):添加操作:       list.add(对象名)从列表的末尾添加元素.  / list.add(索引位置,对象名)索引位置必须结余0-列表中元素个数之间.

3):删除操作:       list.remove(指定位置)/list.remove(对象名)

4):遍历对象:       list.size()代表集合的个数,输出需要强转为对象类型

5):判断是否包含指定元素:    boolean contains(Object o)如果此列表包含指定的元素,则返回true 。

6):Object get(int index):   返回指定索引位置处的元素.去除的元素是object类型,使用前需进行强制转换.

VectorArrayList的异同

实现原理,功能相同,可以互用

主要区别

Vector线程安全,ArrayList中速度轻安全,线程非安全

长度需增长时,Vector 默认增长一倍,ArrayList增长50%

 

 

HashtableHashMap的异同

实现原理,功能相同,可以互用

主要区别:

Hashtable继承Dictionary,HashMap实现Map接口

Hashtable线程安全, HashMap线程非安全.

Hashtable不允许null, HashMap允许null.

 

LinkedList类的操作

 

LinkedList类是双向链表,单项队列,栈的实现类

LinkedList类实现了单项队列和双向队列的接口,自身提高了栈操作的方法,链表操作的方法.

特殊的方法:

Void addFirst(Object e) 在该列表开头插入指定的元素。

Void addLast(Object e) 将指定的元素追加到此列表的末尾。

Object  getFirst() 返回此列表中的第一个元素。 

Object  getLast() 返回此列表中的最后一个元素。

Object  removeFirst() 从此列表中删除并返回第一个元素。

Object  removeLast() 从此列表中删除并返回最后一个元素。

总结:ArrayList:查询,更改较快;新增和删除较慢

 LinkedList:查询,更改较慢;新增和删除较快.

 

Set接口

/Set接口实现方法详解
public class SetDome {
public static void main(String[] args) {
School school = new School("张三", "春熙路");
School school2 = new School("张三", "春熙路");
Set<School> set = new HashSet<>();
set.add(school);
set.add(school2);
for (School obj : set) {
System.out.println(obj.getName() + obj.getSite());
}
/**
* HashSet类
* 1):不允许元素重复
* 2):不会记录元素的先后添加顺序
*/
Set<String> sets = new HashSet<>();
sets.add("A");
sets.add("B");
sets.add("C");
sets.add("1");
sets.add("2");
sets.add("3");
for (String str : sets) {
System.out.print(str + " ");
}
System.out.println();
/**
* LinkedHashSet类
* 1):不允许元素重复
* 2):记录元素的先后添加顺序
*/
Set<String> set1 = new LinkedHashSet<>();
set1.add("A");
set1.add("B");
set1.add("C");
set1.add("1");
set1.add("2");
set1.add("3");
for (String str : set1) {
System.out.print(str + " ");// A B C 1 2 3
}
System.out.println();
/**
* TreeSet类
* 集合底层采用红黑树算法,会对储存的元素默认使用自然排序(从小到大)
* 必须保证TreeSet集合中的元素是同一个对象(否则报错)
*/
Set seb = new TreeSet<>();
seb.add(1);
seb.add(3);
System.out.println(seb);
}
}

Setcollection子接口,模拟了数学上的集的概念

Set集合储存特点:

1):不允许元素重复

2):不会记录元素的先后添加顺序.

 

HashSet

 

HashSet是Set的接口,最常用的实现类,顾名思义,底层才用了哈希表算法

其底层其实也是一个数组,存在的意义是提供查询速度.插入速度也比较快,只针对于少量数据.数据越多,速度越慢.涉及到扩容的问题

 

案例:

自定义类中,要求存在hashSet中的对象元素全部覆盖equals和hashCode方法

 

不同数据类型如何来计算hashCode

LinkedHashSet

 

作用:不允许元素重复,但是能保证先后添加的顺序.

LinkedHashSet:底层才有哈希表算法(保证唯一性)链表算法(记录元素的先后添加顺序).

案例:

TreeSet

 

TreeSet: 集合底层采用红黑树算法,会对储存的元素默认使用自然排序(从小到大)

必须保证TreeSet集合中的元素是同一个对象

集合底层采用红黑树算法,会对储存的元素默认使用自然排序(从小到大)

必须保证TreeSet集合中的元素是同一个对象(否则报错)

      Set seb = new TreeSet<>();

      seb.add(1);

      seb.add(3);

      System.out.println(seb);

 

TreeSet的排序规则:

自然排序:

TreeSet调用集合元素的compareTo方法来比较元素大小关系,然后将集合元素按照升序排列

注意:要求TreeSet集合中元素得实现java.lang.Comparable接口

实现comparable后,覆盖int compareTo(Object)方法,在该方法中编写比较规则.

在该方法中,比较当前对象this和参数对象o做比较(严格上说比较的是对象中的数据)下列案例分析,对比基本数据是比较的数据值,对比字符串是比较字符串对应的hashCode值

升序排列 : o > this 则返回-1; o < this 则返回 1; o == this 则返回 0 

 迭代器Iterator

 

作用:遍历集合对象,它隐藏了各种集合实现类的内部细节,提供了遍历集合的统一编程接口.

迭代器对象:

Iterator:迭代器对象,只能从上往下迭代

方法:boolean hasNext();判断是否存在可遍历的元素

 Object next():遍历下一个元素

ListIterator: 是iterator接口的子接口,支持双向迭代.

Enumeration:古老的迭代器对象,已经被Iterator所取代,适用于古老的vertor类

 

遍历集合的方式方法

泛型操作

为什么需要使用泛型

1):储存任意类型的数据在集合中,但是取出来都是Object类型的,此时就得强转

2):约束储存到集合中的元素必须是相同数据类型,相同的数据类型才能拿来做比较(比如TreeSet类)

3):设计一个点类,来封装坐标位置,要求坐标位置支持多种数据类型,此时则需要定义多个成员变量不同类型的类,这样非常不雅观,存在重复定义.

 

泛型(Gennerk Type):从java5开始的新的语法

什么是泛型:

1):广泛通用的类型.

2):代码末班中类型不确定,谁调用该段代码,谁指明类型是什么

泛型方法:在方法上声明泛型

情况1):泛型类中的泛型只能适用于非静态方法,如果需要给静态方法设计泛型,此时使用泛型方法.

情况2):泛型类中的泛型应该适用于整个类中多个方法,有时候只对某一个方法设置泛型即可

-----------------------------------------------

一般的,把自定义的泛型作为该方法的返回类型才有意义,而且此时的泛型必须是由参数设置进来的,如果没有参数来设置泛型的具体类型,此时的方法一般返回设计为Object即可.

public static <T>T asty(T a){

         return a;

}

 

泛型的通配符和上限,下限:
  
泛型的通配符(主要用于接收使用):不知道使用什么类型来接收,此时可以使用?来表示  ?表示未知,通配符

此时只能接受数据,不能往该集合中储存数据.

public static void rap(List<?> list) {

         System.out.println(list);

   }

 

泛型的上限和下限:用来限定元素的类型必须是X类的子类或相同,X类的父类或相同.

//泛型的上限:此时该泛型?,必须是Number类和Number的子类

   public static void rap(List<? extends Number> list) {

     

   }

   //泛型的下限:此时该泛型?,必须是Number类和Number的父类

   public static void rad(List<? super Number> list) {

     

   }

Map(映射)接口的操作

Map接口是储存两个集合组成一对键值对象,提供K(key) V(value)的映射.

K():不要求有序,不允许重复

V():不要求有序,允许重复.

//测试hashmap中的多个方法
public class HashMapDome {
public static void main(String[] args) {
//声明Map接口下的类
Map<Object, Object> hast = new HashMap<>();
//添加put(Object 键名,Object 键名对应值)
hast.put("one", "中华人民共和国");
hast.put("two", "美利坚");
hast.put("three", "俄罗斯");
hast.put("fore", "印度");
hast.put("frive", "小日本");
/**
* 迭代遍历操作
* 先转换为单个的Set集合,然后才能进行遍历操作.因为Map属于两个集合的映射关系,不直接继承于collection接口
*/
Set<Map.Entry<Object, Object>> set= hast.entrySet(); //先用Map里面类的entrySet方法转换
Iterator<Map.Entry<Object, Object>> iterator = set.iterator();
while(iterator.hasNext()){
System.out.println(iterator.next());;
}
//通过键名key来获得值
System.out.println(hast.get("one"));//返回值类型Object
//显示集合中的个数
System.out.println("Map接口中的数据个数是:" + hast.size());
//判断Map接口中是否存在-某个键名
System.out.println(hast.containsKey("123"));//返回值类型boolean
System.out.println(hast.containsKey("one"));//有返回true,没有返回false
//判断Map接口中是否存在-某个键名值
System.out.println(hast.containsValue("俄罗斯"));//有返回true,没有返回false
//删除小日本
hast.remove("frive");
//测试是否删除成功引出遍历
System.out.println(hast.keySet() + " ");//输出键名的集合
System.out.println(hast.values() + " ");//输出键值得集合 返回值类型为collection
System.out.println(hast.entrySet());//输出hast其实默认调用的是entrySet方法输出
System.out.println(hast);
//一键清空
hast.clear();
if (hast.isEmpty()) { //判断该映射里面是否还有对象
System.out.println("已经清空...");
}else{
System.out.println("没有清空...");
}
System.out.println(hast);//已经为空

}
}

Object put(K key , V value);使用HashMap储存多组键值对.        key - 指定值与之关联的键

value - 与指定键相关联的值

Object  get(Object key);返回到指定键所映射的值,或 null如果此映射包含该键的映射。

Int size()  返回此地图中键值映射的数量。

Boolean  containsKey(Object key)   如果此映射包含指定键的映射,则返回 true 。

Boolean  containsValue(Object value) 如果此地图将一个或多个键映射到指定的值,则返回 true 。

Object  remove(Object key) 如果存在(从可选的操作),从该地图中删除一个键的映射。

Object 

Object  keySet()返回此地图中包含的键名(集合)的Set视图。

Object  values() 返回此地图中包含的键名相关联的值(集合)的Collection视图。

new HashMap()  返回键值集合.

遍历对象,通过键名keySet()方法来遍历对象.

Void clear() 一键清空.

集合的工具类

集合造作的工具类:

Arrays类

Collections类

 

一.Arrays

把数组转换成list(集合)对象

List<Object> list = Arrays.asList(数组名)

通过asList方法得到的List对象的长度是固定的,不能增加,也不能删除.

因为:asList方法返回的是ArrayList对象,不是Java.util.ArrayList而是Arrays类中的内部类对象.

 

 

把集合转换成数组对象:

一.Collections

封装了List.Set.Map的操作的工具方法.

常用的集合类:

ArrayList/HashSet/HashMap都是线程不安全的,在多线程环境下不安全.

在collections类中有获取线程安全的集合方法:

 

 

 

Collections类常用操作方法:

 

1.自然排序:

        static <T extends Comparable<? super T>> void sort(List<T> list)
自然排序是对指定的列表按升序排列,如果排序的是类对象,那么该类必须实现Comparable接口.
        然后重写Comparable接口中的compareTo(T e)方法实现需要排序的规则

 

2.根据指定的比较器进行排序:

 

        static <T> void sort(List<T> list, Comparator<? super T> c)
创建指定的构造器必须实现Comparator接口,然后重写compare方法,我们要想实现多种排序优先选择使用匿名内部类,重写compare()方法实现我们需要达到的排序效果

 

3.在集合中查找指定的元素位置

 

        static <T> int binarySearch(List<? extends Comparable<? super T>> list,T key)

在执行查找指定的元素之前必须先对集合里面的元素进行序列化,否则抛出ClassCastException 异常,

 

4.实现集合元素的反转

 

        static void reverse(List<?> list)

反转指定列表中的元素,此方法以线性时间运行.

 

5.求元素的最大值和最小值

 

        static <T extends Object & Comparable<? super T>> max(Collection<? extends T> coll)

根据元素的自然排序返回给定集合中的最大元素

        static <T extends Object & Comparable<? super T>> min(Collection<? extends T> coll)

根据元素的自然排序返回给定集合中的最小元素

 

6.交换集合中元素的位置

 

        static void swap(List<?> list,int i, int j)

在指定列表的指定位置处交换元素

/**
* Collections类方法的使用
* @author Mr.Bai
* 说明:Collections类中的方法全部是静态方法,所以直接用类名调用即可
*/
class Student implements Comparable<Student>{
private int num;
private String name;
private int age;
public Student(String name, int age, int num) {
this.name = name;
this.age = age;
this.num = num;
}

@Override
public String toString() {
return "Student [num=" + num + ", name=" + name + ", age=" + age + "]";
}

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;
}
public int getNum() {
return num;
}
public void setNum(int num) {
this.num = num;
}
@Override
public int compareTo(Student o) {
return this.num - o.num;
}

}
public class CollectionsDemo {
public static void main(String[] args) {
/*List<String> list = new ArrayList<>();
list.add("AAA");
list.add("FFF");
list.add("DDD");
list.add("BBB");
list.add("QQQ");
//将集合元素进行(升序)排序
Collections.sort(list);
System.out.println(list);
//查找指定的元素
int index = Collections.binarySearch(list, "BBB");
System.out.println(index);
//实现集合的元素反转
Collections.reverse(list);
System.out.println(list);
//求元素集合中的最大最小值
String max = Collections.max(list);
String min = Collections.min(list);
System.out.println("该集合元素中的最大值为:" + max + ",最小值为:" + min);
//交换元素位置
Collections.swap(list, 2, 3);
System.out.println(list);
//清空集合中的元素
list.clear();*/
List<Student> list = new ArrayList<Student>();
list.add(new Student("张三", 25, 1));
list.add(new Student("李四", 48, 3));
list.add(new Student("赵六", 22, 4));
list.add(new Student("王五", 35, 2));
for (Student student : list) {
System.out.println(student);
}
//集合储存对象的重写compareTo方法后的排序
Collections.sort(list);
System.out.println("自然排序后的结果:");
for (Student student : list) {
System.out.println(student);
}
//指定比较器(此处设置年龄)进行排序
Collections.sort(list,new Comparator<Student>(){

public int compare(Student o1, Student o2) {
return o1.getAge()-o2.getAge();
}
});
System.out.println("指定比较器(年龄)后的结果:");
for (Student student : list) {
System.out.println(student);
}
//实现集合元素的反转
Collections.reverse(list);
System.out.println("反转后的结果:");
for (Student student : list) {
System.out.println(student);
}
//交换集合中元素的位置
Collections.swap(list, 0, 1);
System.out.println("交换后的结果:");
for (Student student : list) {
System.out.println(student);
}
//求元素的最大最小值
System.out.println("得到的最大最小值:");
System.out.println(Collections.max(list));
System.out.println(Collections.min(list));
}
}

posted on 2017-12-21 15:20  听风醉  阅读(255)  评论(0编辑  收藏  举报

导航

因为不可能,所以才值得相信。