Java面向对象————集合框架(Collection)


Java面向对象——集合框架(Collection)

面向对象

集合概述:

Java是面向对象语言,如果我们要针对多个对象进行操作,就必须对多个对象进行存储。

而对多个元素进行存储,前面我们学习过数组,数组的弊端,长度固定。这样,数组将不能满足变化的要求。所以,Java就提供了集合供我们使用。

集合的特点:

长度可以发生改变。
只能存储对象。
可以存储多种类型对象(一般存储的还是同一种,因为1.5JDK的新特性 泛型)。

集合和数组的区别:

长度问题

数组固定。

集合可变。

存储元素问题

数组可以是基本类型,也可以是引用类型。

集合只能是引用类型。(JDK1.5以后还可以存储基本数据类型,因为JDK1.5自动装箱拆箱)

是否同一类型

数组元素类型一致。

集合元素类型可以不一致。(建议还是同一种类型,因为JDK1.5出现了泛型)

功能是否一致

数组只能对数据进行存取操作,当然删除数组中的元素还可以删除,就是null。

集合不但可以对数据进行基本操作,还提供了更强大的功能,比如删除 修改...。

集合体系的由来

集合是存储多个元素的容器,但是,由于数据结构不同,Java就提供了多种集合类。

而这多种集合类有共性的功能,所以,通过不断的向上抽取,最终形成了集合体系

结构。

为什么会出现这么多的容器呢?

因为每一个容器对数据的存储方式都有不同,这个存储方式称之为:数据结构。

数据结构:数据存储的方式。

如何学习和使用一个继承体系呢?

学习顶层:因为顶层定义的是共性内容。
使用底层:因为底层才是具体的实现。

简单一句话:参阅顶层内容,建立底层对象。
Collection:定义了集合框架的共性功能。
|------List(列表):元素是有序的,元素可以重复,因为该集合体系有索引。

|--ArrayList:底层是数组数据结构,查询速度很快,但是增删稍慢,线程不同步,默认10个元素。(线程不同步)

|--LinkedList:底层是链表数据结构,查询很慢,增删速度很快。(线程不同步)

|--Vector:底层是数组数据结构,和ArrayList一样,查询,增删,都很慢,Vector是1.0出现,ArrayList是1.2出现,(线程同步)但已经不用了。

|------Set(集):元素是无序的(存入和取出顺序不一定一致),元素不可以重复。

|--HashSet底层数据结构是哈希表。线程是不同步的。

采用散列函数对元素进行排序Asiic),是专门为快速查询而设计的。存入HashSet的对象必须定义hashCode方法。

|--LinkedHashSet:有序。

内部使用散列以加快查询速度,同时使用链表维护元素插入的次序,在使用迭代器遍历Set时,结果会按元素插入的次序显示。 

|--TreeSet:底层的数据结构是二叉树。线程是不同步的。

Set集合中的元素的进行指定(我们指定的比较器)顺序的排序。不同步。TreeSet底层的数据结构就是二叉树。

采用红黑树的数据结构进行排序元素,使用它可以从Set中提取有序(升序或者降序)的序列。

需要注意的是,存入自定义类时,TreeSet需要维护元素的存储顺序,因此自定义类要实现Comparable接口并定义compareTo方法。 

注意:集合只能保存引用数据类型,也就是存储的是对象的地址值,而不是对象本身。集合中的元素相当于引用类型变量。

注意:如果使用的集合涉及到了频繁的插入,建议使用LinkedList。

Collection

布尔型add(E e) 此处的E现在可以当成Object去理解
将指定的元素添加到此列表的尾部。
布尔型addAll(Collection<? extendsE> c)
          将指定 collection 中的所有元素都添加到此 collection 中(可选操作)。
无返回值clear()
移除此列表中的所有元素。
布尔型contains(Object o)
          如果此列表中包含指定的元素,则返回 true
布尔型containsAll(Collection<?> c)
          如果此 collection 包含指定 collection 中的所有元素,则返回 true
布尔型equals(Object o)
          比较此 collection 与指定对象是否相等。
整数hashCode()
          返回此 collection 的哈希码值。
布尔型isEmpty()
          如果此 collection 不包含元素,则返回 true
迭代器iterator()
          返回在此 collection 的元素上进行迭代的迭代器。
布尔型remove(Object o)
          从此 collection 中移除指定元素的单个实例,如果存在的话(可选操作)。
布尔型removeAll(Collection<?> c)
          移除此 collection 中那些也包含在指定 collection 中的所有元素(可选操作)。
布尔型retainAll(Collection<?> c)
          仅保留此 collection 中那些也包含在指定 collection 的元素(可选操作)。
整数size()
          返回此 collection 中的元素数。
对象[]toArray()
          返回包含此 collection 中所有元素的数组。
<T> T[]
toArray(T[] a)
          返回包含此 collection 中所有元素的数组;返回数组的运行时类型与指定数组的运行时类型相同。

ArrayList特有方法:既然是对数据进行操作的,当然就有 增、删、改、查 这四个方法。

无返回值add(int index,E element)
          将指定的元素插入此列表中的指定位置。

布尔型addAll(Collection<? extendsE> c)
          按照指定 collection 的迭代器所返回的元素顺序,将该 collection 中的所有元素添加到此列表的尾部。
布尔值addAll(int index,Collection<? extendsE> c)
          从指定的位置开始,将指定 collection 中的所有元素插入到此列表中。


 Eget(int index) 
          返回此列表中指定位置上的元素。
整数indexOf(Object o)
          返回此列表中首次出现的指定元素的索引,或如果此列表不包含元素,则返回 -1。
整数lastIndexOf(Object o)
          返回此列表中最后一次出现的指定元素的索引,或如果此列表不包含索引,则返回 -1。
 Eset(int index, E element) 
          用指定的元素替代此列表中指定位置上的元素。

代码示例:

import java.util.List;

import java.util.ArrayList;

public class Test{

public static void main(String[] args){

ArrayList al = new ArrayList();

al.add("黑马程序员——Java01");//添加了一个元素

al.add("黑马程序员——Java02");

al.add("黑马程序员——Java03");

al.add("黑马程序员——Java04");

sop(al.get(1));

al.remove("黑马程序员——Java04");//删除一个元素

sop(al.size());//打印下集合的长度 结果为3.因为删了一个

al.clear();//清空集合

sop(al.contains("黑马程序员——Java03"));

sop(al.isEmpty);

method();

}

public static void method(){

List list1 = new ArrayList();

list1.add("黑马程序员——Java01");

list1.add("黑马程序员——Java02");

list1.add("黑马程序员——Java03");

list1.add("黑马程序员——Java04");

List list2 = new ArrayList();

list2.add("黑马程序员——Java01");

list2.add("黑马程序员——Java02");

list2.add("黑马程序员——Java05");

list2.add("黑马程序员——Java06");

//list1.retainAll(list2);//取焦急。拿list1元素跟list2的元素比,如果相同就保留。调用父类的方法

//sop(list1);

list1.removeAll(list2);//删除焦急。拿list1的元素跟list2的元素比,如果相同就删除。调用父类的方法

sop(list1);

}

public static void sop(Object obj){

System.out.println(obj);

}

}

 注意:Test.java 使用了未经检查或不安全的操作。    注意:要了解详细信息,请使用 -Xlint:unchecked 重新编译。

集合注意:

1、直接存储基本类型值也是可以的,因为JDK1.5后,有自动装箱技术,会将基本数据类转换成数据对象。JDK1.4绝对不行,因为集合中存放的对象的引用,当直接存放基本类型值的时候,会将这个基本类型值变成一个对象(自动装箱)。

2、集合对象中存储的其实都是元素对象的引用。

3、add方法的参数是Object类型可以接受所有类型的对象。但会出现向上转型,取出元素时的类型还是Object,不能使用具体对象的特有内容,想要是有特有内容,必须向下转型。集合框架中存放的都是对象的地址。当我们想用对象的特有方法的时候必须向下转型。

当我们想直接打印一个集合,其实是调用了这个对象的toString方法,当我们要打印一个对象的长度的时候,首先我们会想到length方法。但是由于我们添加数据的时候用的add方法,而add方法的参数类型是Object,也就说把存进去的数据向上转型了。但是我们都知道Object是没有length方法,此时无法使用length方法。那么就要向下转型才可以,只有使用子类的特有方法size。


迭代器(Iterator)

1、什么是迭代器?其实就是集合的取出元素的方式。

就把取出方式定义在集合的内部,这样取出方式就可以直接访问结合内容的元素。那么取出方式就定义成了内部类。

而每一个容器的数据结构不同,所以取出的动作细节也不一样,但是都有共性内容:取出。那么可以写共性取出。

那么这些内部类都符合一个规则。该规则是Iterator

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

如何获取集合的取出对象呢?

通过一个对外提供的方法:iterator()



Iterator

布尔型hasNext()
          如果仍有元素可以迭代,则返回 true
 Enext()
          返回迭代的下一个元素。
无返回值remove()
          从迭代器指向的 collection 中移除迭代器返回的最后一个元素(可选操作)。


迭代器的使用
1.使用步骤
1)通过集合对象获取迭代器对象。
2)通过迭代器对象判断。
3)通过迭代器对象获取。
2.迭代器原理
由于多种集合的数据结构不同,所以存储方式不同,所以,取出方式也不同。
这个时候,我们就把判断和获取功能定义在了一个接口中,将来,遍历哪种

集合的时候,只要该集合内部实现这个接口即可。

3.集合的常见使用步骤

1)创建集合对象。

2)创建元素对象。

3)把元素添加到集合中。

4)遍历集合。

1.通过集合对象获取迭代器对象。

2.通过迭代器对象判断。

3.通过迭代器对象获取。

4.Collection存储字符串和自定义对象并遍历。

存储字符串代码示例:

import java.util.List;

import java.util.ArrayList;

import java.util.Iterator;

public class Test{

public static void main(String[] args){
ArrayList al = new ArrayList();
al.add("黑马程序员——Java01");
al.add("黑马程序员——Java02");
al.add("黑马程序员——Java03");
al.add("黑马程序员——Java04");

for(Iterator iter = al.iterator();iter.hasNext();){

sop(iter.next());

}

}

public static void sop(Object obj){

System.out.println(obj);

}

}

存储自定义对象代码示例:

import java.util.List;

import java.util.ArrayList;

import java.util.Iterator;

class Student{

private String name;

privateint age;

Student(String name,int age){

this.name=name;

this.age=age;

}

public String toString(){

return "姓名:"+name+"...年龄:"+age;

}

}

public class Test{

public static void main(String[] args){

List list = new ArrayList();

list.add(new Student("黑马程序员——张三",23));

list.add(new Student("黑马程序员——李四",24));

list.add(new Student("黑马程序员——王五",25));

list.add(new Student("黑马程序员——赵六",26));

for(Iterator iter = list.iterator();iter.hasNext();){

sop(iter.next());

}

}

public static void sop(Object obj){

System.out.println(obj);

}

}

由于Iterator迭代器对数据的操作功能太少,只有对数据进行获取和删除等功能,所以就有了ListIterator迭代器。

ListIterator迭代器不仅可以对迭代器进行获取和删除,还可以对迭代器进行添加和修改。

ListIterator

无返回值add(E e)
          将指定的元素插入列表(可选操作)。

布尔型hasNext()
          以正向遍历列表时,如果列表迭代器有多个元素,则返回 true(换句话说,如果 next 返回一个元素而不是抛出异常,则返回true)。
布尔型hasPrevious()
          如果以逆向遍历列表,列表迭代器有多个元素,则返回 true
 Enext()
          返回列表中的下一个元素。
整数nextIndex()
          返回对 next 的后续调用所返回元素的索引。
 Eprevious()
          返回列表中的前一个元素。
整数previousIndex()
          返回对 previous 的后续调用所返回元素的索引。
无返回值remove()
          从列表中移除由 next 或 previous 返回的最后一个元素(可选操作)。
无返回值set(E e)
          用指定元素替换 next 或 previous 返回的最后一个元素(可选操作)。

List集合的遍历方式有俩种:一种是Iterator 一种是ListIterator

ListIterator代码示例:

import java.util.List;

import java.util.ArrayList;

import java.util.ListIterator;

public class Test{

public static void main(String[] args){

List list = new ArrayList();

list.add("黑马程序员——Java01");

list.add("黑马程序员——Java02");

list.add("黑马程序员——Java03");

list.add("黑马程序员——Java04");

for(ListIterator listIter = list.listIterator();listIter.hasNext();){

String name = listIter.next();

sop(name);

}

}

public static void sop(Object obj){

System.out.println(obj);

}

}

ListIterator迭代器
Iterator的子接口。有自己的特有功能,可以逆向遍历数据,但是需要先正向遍历。一般不用。
面试题:并发修改异常
并发修改异常的产生原因:用迭代器遍历集合,用集合去操作集合。
解决方案:
使用集合操作。

使用列表迭代器操作。

常见的数据结构
加钱:数据结构+算法+UML+设计模式。

数据结构:

栈,队列,数组,链表。

栈:先进后出。    如同一个杯子
队列:先进先出。如同一个水管
数组:查询快,增删慢。

链表:查询慢,增删快。

LinkedList特有方法:

无返回值addFirst(E e)
          将指定元素插入此列表的开头。

无返回值addLast(E e)
          将指定元素添加到此列表的结尾。

 Eelement()
          获取但不移除此列表的头(第一个元素)。
 EgetFirst()
          返回此列表的第一个元素。
 EgetLast()
          返回此列表的最后一个元素。
布尔型offerFirst(E e)
          在此列表的开头插入指定的元素。
布尔型offerLast(E e)
          在此列表末尾插入指定的元素。
 EremoveLast()
          移除并返回此列表的最后一个元素。

 EremoveLast()
          移除并返回此列表的最后一个元素。

1.6出现了替换方法

布尔型offer(E e)
          将指定元素添加到此列表的末尾(最后一个元素)。
布尔型offerFirst(E e)
          在此列表的开头插入指定的元素。
布尔型offerLast(E e)
          在此列表末尾插入指定的元素。
 Epeek()
          获取但不移除此列表的头(第一个元素)。
 EpeekFirst()
          获取但不移除此列表的第一个元素;如果此列表为空,则返回 null
 EpeekLast()
          获取但不移除此列表的最后一个元素;如果此列表为空,则返回 null
 Epoll()
          获取并移除此列表的头(第一个元素)
 EpollFirst()
          获取并移除此列表的第一个元素;如果此列表为空,则返回 null
 EpollLast()
          获取并移除此列表的最后一个元素;如果此列表为空,则返回 null


集合框架(LinkedList练习)

/*

使用LinkedFirst模拟一个堆栈或者队列数据结构

堆栈:先进后出   如同一个罐子

队列:先进先出   如同一个水管

*/

import java.util.LinkedList;

class Duilie{

private LinkedList link;

Duilie(){

link = new LinkedList();

}

public void myAdd(Object obj){

link.addFirst(obj);

}

public Object myGet(){

return link.removeLast();

}

public boolean isNull(){

return link.isEmpty();

}

}

public class Test{

public static void main(String args[]){

Duilie dl = new Duilie();

dl.myAdd("Java01");

dl.myAdd("Java02");

dl.myAdd("Java03");

dl.myAdd("Java04");

while(!dl.isNull()){

System.out.println(dl.myGet());

}


}

}

集合框架(ArrayList练习)

/*

去除ArrayList集合的重复元素。

*/

import java.util.ArrayList;

import java.util.Iterator;

public class Test{

public static void main(String args[]){

ArrayList al = new ArrayList();

al.add("Java01");

al.add("Java02");

al.add("Java03");

al.add("Java02");

al.add("Java04");

al = singleElement(al);

System.out.println(al);

}

public static ArrayList singleElement(ArrayListal){

ArrayList newAl = new ArrayList();

for(Iterator it = al.iterator();it.hasNext();){

Object obj = it.next();

if(!newAl.contains(obj)){//如果是同一个元素,那么就不存入。

newAl.add(obj);

}

}

return newAl;

}

}

集合框架(ArrayList练习2)

/*

将自定义对象作为元素存到ArrayList集合中,并去除重复元素

比如,存人对象,视为同一个人,为重复元素。

思路:

1、对人描述,将数据封装进人对象

2、定义容器,将人进行存入

3、取出

List集合判断是否包含其实是根据这个对象判断是否和内部的对象, equals,可以复写这个equals,写自己的判断

当List remove 删除时候,也是i先equals判断有没有,如果所以要注意

*/

import java.util.ArrayList;

import java.util.Iterator;

class Person{

private String name;

private int age;

Person(String name,int age){

this.name = name;

this.age = age;

}

public boolean equals(Object obj){

if(!(obj instanceof Person))

return false;

Person p = (Person)obj;

returnname.equals(p.name) && this.age==p.age;

}

public String getName(){

return name;

}

public int getAge(){

return age;

}

}

public class Test{

public static void main(String args[]){

ArrayList al = new ArrayList();

al.add(new Person("list01",31));

al.add(new Person("list02",32));

al.add(new Person("list02",32));

al.add(new Person("list03",33));

al.add(new Person("list04",34));

al.add(new Person("list04",34));

al.add(new Person("list05",35));

al = singleElement(al);

for(Iterator it = al.iterator();it.hasNext();){

Person p = (Person)it.next();

sop(p.getName()+":"+p.getAge());

}

}

public static void sop(Object obj){

System.out.println(obj.toString());

}

public static ArrayList singleElement(ArrayList al){

ArrayList newAl = new ArrayList();

for(Iterator it = al.iterator();it.hasNext();){

Object obj = it.next();

if(!newAl.contains(obj)){

newAl.add(obj);

}

}

return newAl;

}

}

集合框架(Vector中的枚举)

迭代器elements()
          返回此向量的组件的枚举。

import java.util.Vector;

import java.util.Enumeration;

public class Test{

public static void main(String[] args){

Vector v = new Vector();

v.add("Java01");

v.add("Java02");

v.add("Java03");

v.add("Java04");

for(Enumeration en = v.elements();en.hasMoreElements();){

sop(en.nextElement());

}

}

public static void sop(Object obj){

System.out.println(obj);

}

}

枚举就是 Vector 特有的取出方式

发现枚举和迭代器很像。

其实枚举和迭代器是一样的。

因为枚举的名称以及方法的名称都过长。所以被迭代器取代了。枚举郁郁而终了。


VectorArrayList在使用上非常相似,都可用来表示一组数量可变的对象应用的集合,并且可以随机地访问其中的元素。   

Vector的方法都是同步的(Synchronized),是线程安全的,而ArrayList的方法不是,由于线程的同步必然要影响性能,因此,ArrayList的性能比Vector好。(建议使用ArrayList,因为高效,就算是多线程咱们也不用怕,因为可以自己加锁)

VectorArrayList中的元素超过它的初始大小时,Vector会将它的容量翻倍,而ArrayList只增加50%的大小,这样,ArrayList就有利于节约内存空间。 


Set :元素是无序的(存入和取出顺序不一定一致),元素不可以重复。

booleanadd(E e)
          如果 set 中尚未存在指定的元素,则添加此元素(可选操作)。
booleanaddAll(Collection<? extendsE> c)
          如果 set 中没有指定 collection 中的所有元素,则将其添加到此 set 中(可选操作)。
voidclear()
          移除此 set 中的所有元素(可选操作)。
booleancontains(Object o)
          如果 set 包含指定的元素,则返回 true
booleancontainsAll(Collection<?> c)
          如果此 set 包含指定 collection 的所有元素,则返回 true
booleanequals(Object o)
          比较指定对象与此 set 的相等性。
 inthashCode()
          返回 set 的哈希码值。
booleanisEmpty()
          如果 set 不包含元素,则返回 true
Iterator<E>iterator()
          返回在此 set 中的元素上进行迭代的迭代器。
booleanremove(Object o)
          如果 set 中存在指定的元素,则将其移除(可选操作)。
booleanremoveAll(Collection<?> c)
          移除 set 中那些包含在指定 collection 中的元素(可选操作)。
booleanretainAll(Collection<?> c)
          仅保留 set 中那些包含在指定 collection 中的元素(可选操作)。
 intsize()
          返回 set 中的元素数(其容量)。
 Object[]toArray()
          返回一个包含 set 中所有元素的数组。
<T> T[]
toArray(T[] a)
          返回一个包含此 set 中所有元素的数组;返回数组的运行时类型是指定数组的类型。


HashSet 底层数据结构是哈希表。

布尔型add(E e) 
          如果此 set 中尚未包含指定元素,则添加指定元素。
无返回值clear() 
          从此 set 中移除所有元素。

布尔型contains(Object o)
          如果此 set 包含指定元素,则返回 true
布尔型isEmpty()
          如果此 set 不包含任何元素,则返回 true
迭代器iterator()
          返回对此 set 中元素进行迭代的迭代器。
布尔型remove(Object o)
          如果指定元素存在于此 set 中,则将其移除。
整数size()
          返回此 set 中的元素的数量(set 的容量)。

HashSet是如何保证元素唯一性的呢?

是通过两个方法,hashCode和equals来完成。

如果元素hashCode值相同,才会判断equals是否为true

如果元素的hashCode不同,不会调用equals方法。

怎么重写hashCode()和equals()方法呢?

hashCode():把对象的所有成员变量值相加即可。

如果是基本数据类型,就加值。如果是引用类型,就加哈希值。
return name.hasCode()+ age * 27;
equals(obj):先判断是否是同一类型的对象,再把传递进来的对象进行向下转型。再判断对象的内容是否相同。

if(!(obj instanceof Student)) ;

Student stu = (Student)obj; 

return this.name.equals(stu.name) && this.age == stu.age;

所有成员变量的值比较。基本类型用==,引用类型用equals()。

注意:对于判断元素是否存在,以及删除等操作,依赖的方法是元素的hashCode和equals方法。

举例:

public int hashCode(){

return name.hashCode()+age*21;

}

public boolean equals(Object obj){

if(!obj instanceof Person)

return false;

Person p=(Person)obj;

return name.equals(p.name)  &&  age==p.age;

}

TreeSet :底层的数据结构是二叉树。线程是不同步的。
比较器comparator()
          返回对此 set 中的元素进行排序的比较器;如果此 set 使用其元素的自然顺序,则返回null

存储字符串对象代码示例:

import java.util.TreeSet;

import java.util.Iterator;

public class Test{

public static void main(String args[]){

TreeSet ts =new TreeSet();

ts.add("Java01");

ts.add("Java03");

ts.add("Java02");

ts.add("Java04");

for(Iterator it = ts.iterator();it.hasNext();){

sop(it.next());

}

}

public static void sop(Object obj){

System.out.println(obj);

}

}

TreeSet集合两种实现排序方式:

自然排序(元素具备比较性)
TreeSet的无参构造,要求对象所属的类实现Comparable接口。
比较器排序(集合具备比较性)

TreeSet的带参构造,要求构造方法接收一个实现了Comparator接口的对象。

Comparable

整数compareTo(T o)
          比较此对象与指定对象的顺序。
Comparator
整数compare(T o1, T o2) 
          比较用来排序的两个参数。
布尔值equals(Object obj) 
          指示某个其他对象是否“等于”此 Comparator。


Comparable存储自定义对象代码示例:

/*

需求:往 TreeSet 集合中存储自定义对象学生。

想按照学生的年龄进行排序。

*/

import java.util.Iterator;

import java.util.TreeSet;

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;

int num = this.age-s.age;

if(num==0)
return this.name.comparTo(s.name);

else

return num;

}

public String toString(){

return name +"..."+age;

}

}

public class Test{

public static void main(String[] args){

TreeSet ts =new TreeSet();

ts.add(new Student("黑马程序员——张三",21));

ts.add(new Student("黑马程序员——王五",23));

ts.add(new Student("黑马程序员——周七",19));

ts.add(new Student("黑马程序员——赵六",18));

for(Iterator iter = ts.iterator();iter.hasNext();){

sop(iter.next());

}

}

public static void sop(Object obj){

System.out.println(obj);

}

}

Comparator 存储自定义对象代码示例:
import java.util.Iterator;

import java.util.TreeSet;

import java.util.Comparator;

class Student{

private String name;

private int age;

Student(String name,int age){

this.name=name;

this.age=age;

}

public String getName(){

return name;

}

public int getAge(){

return age;

}

}

class MyCompare implements Comparator{

public int compare(Object obj1,Object obj2){

Student s1 = (Student)obj1;

Student s2 = (Student)obj2;

int num =new Integer(s1.getAge()).compareTo(new Integer(s2.getAge()));

if(num==0)

return s1.getName().compareTo(s2.getName());

returnnum;

}

}

public class Test{

public static void main(String[] args){

TreeSet ts = new TreeSet(new MyCompare());

ts.add(new Student("黑马程序员——张三",21));

ts.add(new Student("黑马程序员——王五",23));

ts.add(new Student("黑马程序员——周七",19));

ts.add(new Student("黑马程序员——赵六",18));

for(Iterator iter = ts.iterator();iter.hasNext();){

Student stu = (Student)iter.next();

sop(stu.getName()+"..."+stu.getAge());

}

}

public static void sop(Object obj){

System.out.println(obj);

}

}

注意:如果同时有两种方案,以谁为主呢?以比较器为主。


集合框架(TreeSet练习)
 /*
练习,按照字符串长度排序
字符串本身具备比较器,但是他的比较方式不是所需要的
这时就只能使用比较器。
也可以不定义类,写匿名内部类也可以。
*/

import java.util.TreeSet;

import java.util.Iterator;

import java.util.Comparator;

public class Test{
public static void main(String args[]){

TreeSet ts =new TreeSet(new Comparator(){

public int compare(Object obj1,Object obj2){

String s1 = (String)obj1; 
String s2 = (String)obj2;
int num =  s1.length()-s2.length();
if(num==0)
return s1.compareTo(s2);
return num;

}

});

ts.add("黑马");
ts.add("csdn");
ts.add("黑马论坛");
ts.add("云计算");
for(Iterator it = ts.iterator();it.hasNext();){

sop(it.next());

}

}

public static void sop(Object obj){
System.out.println(obj);
}

}

集合框架(泛型概述)

/*

泛型:JDK1.5 以后出现的新特性,用于解决安全问题,是一个安全机制。

好处:

1、将运行时期出现的问题(classCastException),转移到了编译时期。

方便于程序员解决问题。让运行时期问题减少,安全。

2、避免了强制转换的麻烦。

泛型格式:通过 <> 来定义要操作的引用数据类型。

什么时候使用泛型呢?

通常在集合框架中很常见。

只要见到<>就要定义泛型

其实<>就是用来接收类型的。

当使用集合时,将集合中要存储的数据类型作为参数传递到尖括号中即可,和函数传参数一样。

*/

import java.util.ArrayList;

import java.util.List;

import java.util.Iterator;

public class Test{

public static void main(String args[]){

List<Integer> al = new ArrayList<Integer>();

al.add(4);//自动装箱功能,现在作为了解。以后会学到的,包括泛型。

al.add(new Integer(4));

int x=5;

al.add(x);

for(Iterator<Integer> it = al.iterator();it.hasNext();){

sop(it.next());

}

}

public static void sop(Object obj){

System.out.println(obj);

}

}

集合框架(泛型类)

 /*
泛型类
舍呢么时候定义泛型类?
当类中要操作的引用数据类型不确定的时候
早起定义Object 来完成扩展

现在,定义泛型来完成扩展。

*/

//JDK1.5之前的做法

class Tool{

private Object obj;

public void setObject(Object obj){

this.obj=obj;

}

public Object getObject(){

return obj;

}

}

//JDK1.5泛型出现后,用泛型的做法
//泛型类
class Utils<E>{

private E o;

public void setObject(E o){

this.o = o;

}

public E getObject(){

return o;

}

}

class Worker{    

}
class Student{
}

public class Test{

public static void main(String args[]){

//JDK1.4做法。

Tool t = new Tool();

//可以传入Student

t.setObject(new Student());

Objectobj = t.getObject();

Student stu = (Student)obj;

//泛型出现以后的做法

Utils<Worker> u = new Utils<Worker>();

u.setObject(new Worker());

Worker w = u.getObject();

}

public static void sop(Object obj){

System.out.println(obj);

}

}
泛型可以让程序员避免强制转换的麻烦,并且把运行时强转问题转化到了编译时期。

集合框架(泛型方法)

/*
泛型类定义的泛型,在整个类中有效,如果被方法是用到泛型,类的对象明确。操作的具体类型后,所有要操作的类型就已经固定了。为了让不同方法可以操作不同类型,而且类型还不确定,那么可以将泛型定义在方法上,而不定义在类上。

public <T> void show(T t){
}
*/

//类型已经确定.

class GenericTest<T>{

public void show(T t){

sop("show:"+t);

}

public void print(T t){

sop("print:"+t);

}

public static void sop(Objectobj){

System.out.println(obj);

}

}
//类型不确定,使用泛型方法
class GenericTest2{

//泛型方法

public <Q>void show(Q q){

sop("show_2:"+q);

}

public <Q> void print(Q q){

sop("print_2:"+q);

}

public static void sop(Object obj){

System.out.println(obj);

}

}

public class Test{

public static void main(String args[]){

//泛型确定

GenericTest<String> d = new GenericTest<String>();

d.show("黑马程序员");

d.print("csdn社区");

//泛型不确定

GenericTest2 d2 = new GenericDemo_2();

d2.show("黑马程序员");

d2.print(new Integer(4));

d2.print(4);

}

public static void sop(Objectobj){

System.out.println(obj);

}

}

集合框架(静态方法泛型)

泛型类中也可以定义泛型方法

特殊之处:静态方法不可以访问类上定义的泛型,因为只有在实例化的时候,才会使用泛型

如果静态方法操作的引用数据类型不确定,可以将泛型定义在方法上。

<T> 泛型写在返回值前。

/*
public static <T> void setName(T t){
}

*/

集合框架(泛型接口)

interface Inter<T>{

void show(T t);

}
class InterImpl implements Inter<String>{

void show(Stringt)//这里只能是 String{

}

}


class InterImpl2<T> implements Inter<T>{

void show(T t);//这里类型不固定{

}

}

集合框架(泛型通配符)

import java.util.ArrayList;

import java.util.List;

import java.util.Iterator;

public class Test{

public static voidmain(String args[]){

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

al.add("黑马程序员");

al.add("CSDN社区");

al.add("黑马程序员论坛");

List<Integer> al1 = newArrayList<Integer>();

al1.add(1);

al1.add(2);

al1.add(3);

printCollection(al);

printCollection(al1);

}

public static void printCollection(List<?> al){

for(Iterator<?> it = al.iterator();it.hasNext();){

System.out.println(it.next());

}

}

}

集合框架(泛型限定(上限))

/*
? 通配符
? extends E:可以接收 E 类型或者 E 的子类型。上限。
? super E:可以接收E类型或者E的父类型,下限
*/

import java.util.ArrayList;

import java.util.List;

import java.util.Iterator;

class Person{

private String name;

Person(String name){

this.name = name;

}

public String getName(){

return name;

}

}
class Student extends Person{

Student(String name){

super(name);

}

}

public class Test{

public static void main(String args[]){

List<Person> al =newArrayList<Person>();

al.add(new Person("张三"));

al.add(new Person("李四"));

al.add(new Person("王五"));

List<Student> al1 = new ArrayList<Student>();

al1.add(new Student("赵六"));

al1.add(new Student("周七"));

al1.add(new Student("郑八"));

printCollection(al);

printCollection(al1);

}

//printCollection(al1);这是错误的,不能直接写

//public static void printCollection(ArrayList<Person> al)这样只能接受person

public static void printCollection(List<? extends Person> al){/*这样可以接收Person和Person的子类为了面向接口编程,而且上面定义的容器也是面向接口编程,这里写成List,否则编译不通过。因为ArrayList子类不能接收List父类。*/

for(Iterator<? extends Person> it = al.iterator();it.hasNext();){

System.out.println(it.next().getName());

}

}

}

集合框架(泛型限定(下限))

/*
? 通配符
? extends E:可以接收 E 类型或者 E 的子类型。上限。
?  super E:   可以接收E类型或者E的父类型,下限
*/

import java.util.ArrayList;

import java.util.List;

import java.util.Iterator;

class Person{

private String name;

Person(String name){

this.name = name;

}

public String toString(){

return name;

}

}
class Student extends Person{

Student(String name){

super(name);

}

}


public class Test{

public static void main(String args[]){

List<Person> al =new ArrayList<Person>();

al.add(new Person("张三"));

al.add(new Person("李四"));

al.add(new Person("王五"));

List<Student> al1 = new ArrayList<Student>();

al1.add(new Student("赵六"));

al1.add(new Student("周七"));

al1.add(new Student("郑八"));

printCollection(al);

printCollection(al1);

}

public static void printCollection(List<? super Student> al){

for(Iterator<? super Student> it = al.iterator();it.hasNext();){

System.out.println(it.next());

}

}

}


使用泛型的时制:

是么时候定义泛型类?

当类中要操作的引用数据类型不确定的时候,

早期定义的Object来完成扩展。现在定义泛型类来完成扩展

泛型类定义的泛型,在整个类中有效。如果被方法使用,

那么泛型类的对象明确要操作的具体类型后,所有要操作的类型就已经固定了。
为了让相同方法可以操作不同类型,而且类型还不确定。
那么可以将泛型定义在方法上。


特殊之处:
静态方法不可以访问类上定义的泛型。因为只有在实例化的时候,才会使用泛型。

如果静态方法操作的应用数据类型不确定,可以将泛型定义在方法上。


? 通配符。也可以理解为占位符。
泛型的限定:

extends E: 可以接收E类型或者E的子类型。上限。

 super    E: 可以接收E类型或者E的父类型。下限

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值