------- android培训、java培训、期待与您交流! ----------
@@(day14)Collection和泛型****************************************************************
数据多了用对象存,对象多了用集合存。
数组和集合类都是容器,有何不同?
--数组虽然也可以存储对象,但长度是固定的,集合长度是可变的。
--数组中可以存储基本数据类型,集合只能存储对象。
==集合只用于存储对象,集合长度可变,集合可以存储不同类型的对象。
Collection || Map(键值对)
-List有序,可重复 -Set无序,不可重复||
--*ArrayList底层数组,不同步 --*HashSet哈希表 ||-*HashMap哈希表 -TreeMap二叉树
--*LinkedList底层链表 --TreeSet二叉树 ||
--Vector同步
Collection
|-List:元素是有序的,元素可以重复。因为该集合体系有索引。
||--ArrayList:底层的数据结构使用的是数组结构。特点:查询速度很快。但是增删稍慢。线程不同步。
||--LinkedList:底层使用的链表数据结构。特点:增删速度很快,查询稍慢。线程不同步。
||--Vector:底层是数组数据结构。线程同步。被ArrayList替代了。因为效率低。
|--Set:元素是无序(存入和取出的顺序不一定一致),元素不可以重复。、
||--HashSet:底层数据结构是哈希表。是线程不安全的。不同步。
HashSet是如何保证元素唯一性的呢?
是通过元素的两个方法,hashCode和equals来完成。
如果元素的HashCode值相同,才会判断equals是否为true。
如果元素的hashcode值不同,不会调用equals。
********复写public int hashCode()和public boolean equals(Object obj)
注意,对于判断元素是否存在,以及删除等操作,依赖的方法是元素的hashcode和equals方法。
||--TreeSet:可以对Set集合中的元素进行排序。
底层数据结构是二叉树。
保证元素唯一性的依据:
compareTo方法return 0.
********TreeSet排序的第一种方式:让元素自身具备比较性。
implements Comparable接口,覆盖public int compareTo(Object obj)方法。
也种方式也成为元素的自然顺序,或者叫做默认顺序。
********TreeSet的第二种排序方式。
当元素自身不具备比较性时,或者具备的比较性不是所需要的。
这时就需要让集合自身具备比较性。
在集合初始化时,就有了比较方式。
注意:ArrayList构造一个初始容量为10的空列表,不够用的话,依次%50增加。节约空间。
Vector构造一个初始容量为10的空列表,不够用的话,依次%100增加。
@@Collection定义了集合框架(List和Set)的共性功能。……%……%……%……%……%……%……%……%
1,添加
add(Object e);//增加任意类型的元素,实际存放的是元素的地址。
addAll(collection);//增加一个集合的元素。
2,删除
remove(e);//移除元素
removeAll(collection);//移除交集
clear();//清空
3,判断。
contains(e);//判断是否包含某元素
isEmpty();//判断是否为空
4,获取
for(Iterator it = al.iterator(); it.hasNext() ; )
{sop(it.next());}
size();//集合的大小,元素个数
5,获取交集。
retainAll();//取出交集
6,集合变数组。
toArray();//转成数组
1,add方法的参数类型是Object。以便于接收任意类型对象。
2,集合中存储的都是对象的引用(地址)。**********
@@接口Iterator<迭代器><迭代器><迭代器><迭代器>
/*
Itr是AbstractList的内部类并实现了Iterator接口。
public Iterator<E> iterator() {
return new Itr();
}
private class Itr implements Iterator<E>{...}
*/
======for(Iterator it = al.iterator(); it.hasNext() ; )//打印元素
{sop(it.next());}
boolean hasNext()
如果仍有元素可以迭代,则返回 true。
E next()
返回迭代的下一个元素。
void remove()
从迭代器指向的 collection 中移除迭代器返回的最后一个元素
什么是迭代器呢?
其实就是集合的取出元素的方式。
如同抓娃娃游戏机中的夹子。
迭代器是取出方式,会直接访问集合中的元素。
所以将迭代器通过内部类的形式来进行描述。
通过容器的iterator()方法获取该内部类的对象。
@@List特有的方法:带角标操作的函数。……%……%……%……%……%……%……%……%
@@List集合判断元素是否相同,只依赖元素的equals方法。自定义对象最好对其进行复写。
@@其他的集合判断元素是否相同则不是只依据元素的equals方法。。
增-----------
void list.add(int index,E element)在指定位置添加元素
boolean list.addAll(index,Collection);index - 将指定 collection 的第一个元素所插入位置的索引(即在原集合中插入的位置)
删-----------
E list.remove(int index)删除index角标上的元素
remove(E e);//移除元素(底层调用了元素的equals方法)###
改-----------
E list.set(int index,E element) (特有)
查-----------
contains(e);(底层调用了元素的equals方法)###
E list.get(int index)返回指定位置的元素
List<E> list.subList(int fromIndex,int toIndex)
ListIterator<E> listIterator(int index)
int list.indexOf(e):获取指定元素的位置。(底层调用了元素的equals方法)###
在迭代时,不可以通过集合对象list的方法来操作集合中的元素。
因为会发生ConcurrentModificationException异常。
所以,在迭代器时,只能用迭代器的方法来操作元素,可是Iterator接口中的方法是有限的,
只能对元素进行判断,取出,删除的操作,
如果想要其他的操作如添加,修改等,就需要使用其子接口,ListIterator。
该接口只能通过List集合的listIterator方法获取。
@@ListIterator接口==List集合特有的迭代器<迭代器><迭代器><迭代器><迭代器><迭代器>
List集合特有的迭代器。ListIterator是Iterator的子接口。
======for(ListIterator it = al.listIterator(); it.hasNext() ; )//打印元素
{sop(it.next());}
void add(E e)
将指定的元素插入列表(可选操作)。
boolean hasNext()
以正向遍历列表时,如果列表迭代器有多个元素,则返回 true(换句话说,如果 next 返回一个元素而不是抛出异常,则返回 true)。
boolean hasPrevious()
如果以逆向遍历列表,列表迭代器有多个元素,则返回 true。
E next()
返回列表中的下一个元素。
int nextIndex()
返回对 next 的后续调用所返回元素的索引。
E previous()
返回列表中的前一个元素。
int previousIndex()
返回对 previous 的后续调用所返回元素的索引。
void remove()
从列表中移除由 next 或 previous 返回的最后一个元素(可选操作)。
void set(E e)
用指定元素替换 next 或 previous 返回的最后一个元素(可选操作)。
总结下:
ListIterator中有:
hasNext,Next,nextIndex
hasPrevious,previous,previousIndex
增add(E e新元素)
删remove()
改set(E e新元素)
for(ListIterator li = al.Listiterator(); li.hasNext() ; )//取出元素
{sop(li.next());}
@@Vector,JDK1.0的类,同步,容量10+%100... (JDK1.2开始Java Collections Framework,被ArrayList替代)
特有方法:(带element的都是,早期1.0的方法)
addElement(E obj)
...
@@枚举就是Vector特有的取出方式。
Enumeration<E> elements()
返回此向量的组件的枚举。
boolean hasMoreElements()
测试此枚举是否包含更多的元素。
E nextElement()
如果此枚举对象至少还有一个可提供的元素,则返回此枚举的下一个元素。
发现枚举和迭代器很像。
其实枚举和迭代是一样的。
因为枚举的名称以及方法的名称都过长。
所以被迭代器取代了。
枚举郁郁而终了。
@@LinkedList 特有方法
addFirst()
addLast()
getFirst()
getFirst()
返回元素
removeFirst() ==》 JDK1.6后 pollFirst()
removeLast() ==》 JDK1.6后 pollLast()
//集合中无元素则抛出异常NoSuchElementEception ==>集合中无元素返回null
返回删除的元素
@@Set(具有Collection接口的方法)元素无序,元素不可重复!只用迭代器操作元素。
@@在添加元素,判断和删除时,先看hashCode值,再equals比较是否同一个对象
HashSet要重写hashCode方法和equals方法
public int hashCode()******************************
{
return this.name.hashCode()+this.age*33;
}
public boolean equals(Object obj)******************
{
if(!(obj instanceof Person))
return false;
Person p = (Person)obj;//有泛型也得强转。
return this.name==p.name && this.age==p.age;
}
@@(day15TreeSet和泛型)**************************************************************************
|--Set:元素是无序(存入和取出的顺序不一定一致),元素不可以重复。、
|--HashSet:底层数据结构是哈希表。是线程不安全的。不同步。
HashSet是如何保证元素唯一性的呢?
是通过元素的两个方法,hashCode和equals来完成。
如果元素的HashCode值相同,才会判断equals是否为true。
如果元素的hashcode值不同,不会调用equals。
********复写public int hashCode()和public boolean equals(Object obj)
注意,对于判断元素是否存在,以及删除等操作,依赖的方法是元素的hashcode和equals方法。
|--TreeSet:可以对Set集合中的元素进行排序。
底层数据结构是二叉树。
保证元素唯一性的依据:
compareTo方法return 0.
******* TreeSet排序的第一种方式:让元素自身具备比较性。
元素implements Comparable接口,覆盖public int compareTo(Object obj)方法。
也种方式也成为元素的自然顺序,或者叫做默认顺序。
******* TreeSet的第二种排序方式。(有比较器时,以比较器为主)
当元素自身不具备比较性时,或者具备的比较性不是所需要的。
这时就需要让集合自身具备比较性。
在集合初始化时,就有了比较方式。
class MyCompare implements Comparator定义的比较器
public int compare(Object o1,Object o2)需要实现的方法
初始化时TreeSet ts = new TreeSet(new MyCompare());
class Student implements Comparable//(第一种TreeSet)该接口强制让学生(集合中的元素)具备比较性。
{
private String name;
private int age;
Student(String name,int age)
{
this.name = name;
this.age = age;
}
public int compareTo(Object obj)//******必须做***************
{
//return 0;表示两个元素相等
if(!(obj instanceof Student))
throw new RuntimeException("不是学生对象");
Student s = (Student)obj;
int num = this.getAge()-s.getAge();
if(num == 0)
return this.getName().compareTo(s.getName());
return num;
}
public String getName()
{
return name;
}
public int getAge()
{
return age;
}
}
class TreeSetDemo2
{
public static void main(String[] args)
{
TreeSet ts = new TreeSet();//第一种实现元素比较性的方式!
TreeSet ts = new TreeSet(new MyCompare());//第二种方式!用比较器的方法比较。
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<Student>//第二种实现元素比较性的方式=自定义的比较器。
{
public int compare(Object o1,Object o2)//********必须复写************
{
Student s1 = (Student)o1;//将元素向下转型!没泛型时必做!----------
Student s2 = (Student)o2;//
int num = s1.name.compareTo(s2.name);
if(num == 0)
return (s1.age-s2.age);
return num;
}
}
@@泛型Generic(JDK1.5后的)==》解决集合和迭代器的安全隐患。 是一个类型安全机制。
明确指定 集合 的元素类型为 <类型>
明确指定 迭代器 的元素类型为 <类型>
明确指定 Collection中一些接口的实现子类 的元素类型为 <类型>
明确指定 泛型类 的操作类型为 <类型>
明确指定 泛型方法 的操作类型为 <类型>
因为集合中的元素类型不同 可能会有安全隐患。
好处:
1,将运行时期出现问题ClassCastException(类型转换异常)转移到了编译时期。
2,避免了强制转换的麻烦。
class Student implements Comparable<Student>//(第一种TreeSet)该接口强制让学生(集合中的元素)具备比较性。
{
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.getAge()-s.getAge();
if(num == 0)
return this.getName().compareTo(s.getName());
return num;
}
public String getName()
{
return name;
}
public int getAge()
{
return age;
}
}
class TreeSetDemo2
{
public static void main(String[] args)
{
TreeSet<Student> ts = new TreeSet();//第一种实现元素比较性的方式!
TreeSet<Student> ts = new TreeSet(new MyCompare());//第二种方式!用比较器的方法比较。
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<Student>//第二种实现元素比较性的方式=自定义的比较器。
{
public int compare(Object o1,Object o2)//********必须复写************
{
//Student s1 = (Student)o1;//将元素向下转型!-----------------
//Student s2 = (Student)o2;//
int num = s1.name.compareTo(s2.name);
if(num == 0)
return (s1.age-s2.age);
return num;
}
}
@@泛型类
/*
什么时候定义泛型类?
当类中要操作的引用数据类型不确定的时候,
早期定义Object来完成扩展。
现在定义泛型来完成扩展。
*/
class Utils<QQ>
{
private QQ q;
public void setObject(QQ q)
{
this.q = q;
}
public QQ getObject()
{
return q;
}
}
@@泛型方法 泛型放返回类型的正前面
//泛型类上定义的泛型,在整个类中有效。如果该泛型被方法使用,-->
//那么泛型类的对象明确要操作的具体类型后,所有要操作的类型就已经固定了。
//为了让类中的不同方法可以操作不同类型,而且类型还不确定。
//那么可以将泛型定义类中在方法上。
/*
特殊之处:
1,静态方法不可以访问类上定义的泛型。
2,如果静态方法操作的应用数据类型不确定,可以将泛型定义在静态方法上。
*/
class demo
{
public <Q> void print(Q q)//泛型方法
{
System.out.println("print:"+q);
}
public static <W> void method(W t)//静态泛型方法
{
System.out.println("method:"+t);
}
}
class Demo<T>
{
public void show(T t)//和类上的泛型一致!
{
System.out.println("show:"+t);
}
public <Q> void print(Q q)//泛型方法
{
System.out.println("print:"+q);
}
public static <W> void method(W t)//静态泛型方法,不能访问类上的泛型<T>
{
System.out.println("method:"+t);
}
}
class GenericDemo4
{
public static void main(String[] args)
{
Demo <String> d = new Demo<String>();
d.show("haha");
//d.show(4);
d.print(5);
d.print("hehe");
Demo.method("hahahahha");
}
}
@@泛型接口
interface Inter<T>
{
void show(T t);
}
/*
class InterImpl implements Inter<String>
{
public void show(String t)
{
System.out.println("show:"+t);
}
}
*/
class InterImpl<T> implements Inter<T>
{
public void show(T t)
{
System.out.println("show:"+t);
}
}
class GenericDemo5
{
public static void main(String[] args)
{
InterImpl<Integer> i=new InterImpl<Integer>();
i.show(4);
//InterImpl i=new InterImpl();
//i.show("haha");
}
}
/*
@@泛型限定 进行泛型扩张用的!
? @@通配符。也可以理解为占位符。
? 任意类型:可以接受<?>任意类型
泛型的限定:一般在函数的形参上
? extends E: 可以接受E类型或E的子类型。 上限为E
? super E: 可以接受E类型或E的父类型。 下限为E
*/
public static void printColl(ArrayList<?> al)
{......}
public static void printColl(ArrayList<? extends Person> al)
{
Iterator <? extends Person> it=al.iterator();
......
}
TreeSet<E> ts = new TreeSet<E>();
TreeSet<E> ts = new TreeSet<Collection<? extends E> c>();
TreeSet<E> ts = new TreeSet<Comparator<? super E> comparator>();
TreeSet中想要比较的元素是Student,但是可以传递进去一个Student或其父类Person的比较器。