------ android培训、java培训、java博客、java学习型技术博客、期待与您交流! -------
一、集合框架
1.0、集合类:
为什么出现集合类?面向对象语言对事物的体现都是以对象的形式,所以为了方便对多个对象的操作,就对对象进行存储,集合就是存储对象最常用的一种方式。
1.1、数组和集合类同是容器,有何不同?
数组虽然可以存储对象,但是长度是固定的;集合长度是可变的,数组可以存储基本数据类型,集合只能存储对象。
1.2集合类的特点:
集合只用于存储对象,集合长度是可变的,集合可以存储不同类型的对象。
Collection
|--List:元素是有序的,元素可以重复。因为该集合体系有索引。
|--ArrayList:底层的数据结构使用的是数组结构。特点:查询速度很快,但删除稍慢。线程不同步。
|--LinkedList:底层使用的是链表数据结构。特点:增删速度很快,查询稍慢。
|--Vector:底层是数组数据结构。线程同步(线程安全)。被ArrayList替代
|--Set :元素是无序,元素不可以重复。
|--HashSet:底层数据结构是哈希表。
|--TreeSet:
List:
特有方法,凡是可以操作角标的方法都是该体系特有的方法。
增
add(int index,Object element);//在指定位置添加元素
addAll(int index,Collection<? extends E> co);//将指定collection中的所有元素都插入到列表中的指定位置
删
E remove(int index);//删除指定位置的元素,将所有的后续元素向左移动(将其索引减1),返回从列表中移除的元素。
boolean remove(Object obj);//移除列表中出现的首个指定元素,如果列表不包含元素,则不更改列表。移除具体满足下面条件的最低索引i的元素:
(obj==null?get(i)==null:obj.equals(get(i)))r如果存在这样的元素。
改
set(int index,Object element)//修改指定位置元素,index-要替换的元素的索引。element-要在指定位置存储的元素。
查抛出:
UnsupportedOperationException-如果列表不支持 set 方法。
ClassCastException-如果指定元素的类不允许它添加到此列表。
NullPointerException-如果指定的元素为 null,并且此列表不支持 null 元素。
IllegalArgumentException-如果指定元素的某个方面不允许它添加到此列表。
IndexOutOfBoundsException-如果索引超出范围 (index < 0 || index >= size())。
E get(int index);//返回列表中指定位置元素,index-要返回的元素的索引
抛出:
IndexOutOfBoundsException-如果索引超出范围 (index < 0 || index >= size())。
List<E> subList(int from,int to);//包含头(from)不包含尾(to)取元素(如果from和to相等,则返回的列表为空)。
list.subList(from,to):此方法返回一个新的list集合。
List.subList(from,to).clear():此语句从列表中移除了元素的范围,原集合返回移除后剩下的所有元素
ListIterator<E>接口;此接口是Iterator的子接口,系列表迭代器,允许程序员按照任一方向遍历列表、迭代期间修改列表,并获得迭代器在列表中的当前位置。ListIterator没有当前元素;它的光标位置始终位于调用previous()所返回的元素和调用next()返回的元素之间。在长度为n的列表中,有n+1个有效的索引值,从0到n(包含0)
注意:remove()和set(Object)方法不是根据光标位置定义的;它们是根据对调用next()或previous()所返回的最后一个元素的操作定义的。
boolean hasPrevious(),如果反向遍历列表,列表迭代器有多个元素,则返回true。
E previous()返回列表中的前一个元素。可以重复调用此方法来迭代列表,或混合调用next来前后移动(注意交替调用next和previous将重复返回相同的元素)。
抛出:
NoSuchElementException-如果没有可迭代的上一个元素。
int indexOf(Object obj);//获取对象第一次出现的位置,如果对象不存在则返回-1;
List集合特有的迭代器。ListIterator是Iterator的子接口,在用Iterator迭代时
不可以通过集合对象的方法操作集合中的元素,因为会发生ConcurrentModificationException异常。
所以在迭代时,只能用迭代器的方法操作元素,可是Iterator方法是有限的。
只能对元素进行判断,取出,删除的操作,
如果想要其它的操作,如修改,添加。就需要使用其子接口,ListIterator。
该接口只能通过List集合的listIterator接口的方法获取。
一、
publicstaticvoiditerator(){
ArrayList al=new ArrayList();
al.add("java1");
al.add("java2");
al.add("java3");
al.add("java4");
Iterator it=al.iterator();
while(it.hasNext()){
Object obj=it.next();
if(obj.equals("java2"))
//al.remove(2);//集合对象操作会有异常
//it没有添加方法
it.remove();//把这个元素引用从集合中移除,但元素还在内存中
sop(obj);//元素还能被Object使用,所以全被打印了
}sop(al);//打印方法,打印出移除后的集合
}
二、
privatestaticvoid listIterator() {
ArrayList al=new ArrayList();
al.add("java1");
al.add("java2");
al.add("java3");
ListIterator li=al.listIterator();
while(li.hasNext()){
Object obj=li.next();
if(obj.equals("java2"))
//li.add("java9");//在java2的后面添加java9
li.set("hello");//将java2修改成hello
sop(obj);//此处输出的永远是原集合中元素
}
sop(al);//修改后的集合中元素
}
三、
privatestaticvoid listIterator() {
ArrayList al=new ArrayList();
al.add("java1");
al.add("java2");
al.add("java3");
ListIterator li=al.listIterator();
System.out.print(li.hasPrevious());//指针没有前一个元素返回false
while(li.hasNext()){//有下一个元素返回true,指针下移
Object obj=li.next();
System.out.print(obj);
}
sop(li.hasPrevious());//指针有前一个元素返回true
while(li.hasPrevious()){//逆向判断,有前一个元素就为true
System.out.print(li.previous());//逆序打印,previous()控制指针的跳跃个数,如果和要一个一个的打印,此处只能调用一次。
}
}
Vector:中的枚举
Enumeration<E> elements():返回此向量的组件枚举。返回的Enumeration对象将生成此向量中的所有项。生成的第一项为0处的项,然后是索引1处的项,依次类推。
枚举是Vector特有的取出方式。枚举和迭代器很像,其实一样,因为枚举的名称以及方法名称都过长,
所以被迭代器取代了。
publicstaticvoid vectorDemo(){
Vector v=new Vector();
v.add("java1");
v.add("java2");
v.add("java3");
Enumeration e=v.elements();//枚举Vector特有方法
while(e.hasMoreElements()){
sop(e.nextElement());
}
}
LinkedList:特有方法
addFirst(E o);//将给定元素o插入此列表的开头,添加后,取出打印结果是倒序
addLast(E o); //将给定元素追加到此列表的结尾
获取元素,但不删除元素,如果集合中没有元素,会出现NoSuchElementException
getFirst();//返回此列表的第一个元素-java1
getLast();//返回此列表的最后一个元素-java2
获取元素,但是元素被删除,如果集合中没有元素,会出现NoSuchElementException
removeFirst();//移除并返回此列表的第一个元素。
removeLast();//移除并返回此列表的最后一个元素。
在JDK1.6出现了替代方法。
boolean offerFirst(E e);//将指定元素此双端列队的开头。
boolean offerLast(E e);//将指定元素插入此双端列队的末尾
获取元素,但不删除元素,如果集合中没有元素,会返回null。
peekFirst();返回此双端列队的头部,如果此双端列队为空,则返回null
peekLast();
获取元素,但是元素被删除,如果集合中没有元素,会返回null。
pollFirst();
pollLast();
例:
publicstaticvoid linkedList(){
LinkedList li=new LinkedList();
li.addFirst("java1");
li.addFirst("java2");
li.addFirst("java3");
while(!li.isEmpty()){
sop(li.removeFirst());
}
}
使用LinkedList模拟一个堆栈或队列数据结构。
堆栈:先进后出,如图一个杯子;
队列:先进先出,如图一个水管;First in First out(FIFO)
import java.util.LinkedList;
class DuiLie{
private LinkedListlink;
DuiLie(){
link=new LinkedList();
}
publicvoid myAdd(Object obj){
link.addFirst(obj);
}
public Object myGet(){
returnlink.removeLast();
}
publicboolean isNull(){
returnlink.isEmpty();
}
}
publicclass LinkedListTest {
publicstaticvoid main(String[] args) {
DuiLie dl=new DuiLie();
dl.myAdd("java01");
dl.myAdd("java02");
dl.myAdd("java03");
while(!dl.isNull()){
System.out.println(dl.myGet());
}
}
}
|--Set :元素是无序,元素不可以重复。
|--HashSet:底层数据结构是哈希表。线程不同步
HashSet是如何保证元素唯一性的呢?
是通过元素的两个方法,hashCode和equals来完成。
如果元素的HashCode值相同,才会判断equals是否为true。
如果元素的hashCode值不同,才会调用equals。
注意:对于判断元素是否存在(contains),以及删除(remove)等操作,依赖的方法是元素的
hashCode和equals方法。
ArrayList依赖的只有equals方法。
哈希表特点:我们想删除元素或想判断元素时,都必须的先判断哈希值。
例:往HashSet集合中存入自定义对象
姓名和年龄相同为同一个人,重复元素。
import java.util.HashSet;
import java.util.Iterator;
class People{
private Stringname;
privateintage;
People(String name,int age){
this.name=name;
this.age=age;
}
publicint hashCode(){//两个相同的对象,比较哈希值是否相等,若相等再比较内容
returnname.hashCode()+age*27;//此处乘以27解决有可能导致两个不同对象的哈希值相同,还的再去判断
//equals,导致程序效率降低问题;
}
publicboolean equals(Object obj){//内容也相等则,不能存进去
if(!(obj instanceof People))
returnfalse;
People p=(People)obj;
System.out.println("hashCode值判断通过(相同)进入equals判断是否为true,为true即为相同元
素不能插入HashSet集合");
returnthis.name.equals(p.name)&&this.age==p.age;//姓名年龄都相等返回true
}
public String getName(){
returnname;
}
publicint getAge(){
returnage;
}
}
publicclass HashSet{
publicstaticvoid main(String[] args) {
HashSet hs=new HashSet();
hs.add(new People("a1",11));
hs.add(new People("a2",12));
hs.add(new People("a3",13));
hs.add(new People("a2",12));
Iterator it=hs.iterator();
while(it.hasNext()){
People p=(People)it.next();
System.out.println(p.getName()+".."+p.getAge());
}
}
}
Day_15
|--Set :元素是无序,元素不可以重复。
|--HashSet:底层数据结构是哈希表。线程不同步
|--TreeSet:可以对Set集合中的元素进行排序。
底层数据结构是二叉树。
保证元素唯一性的依据:
compareTo方法return 0.
int compareTo(T o)
比较此对象与指定对象的顺序。如果该对象小于、等于或大于指定对象,则分别返回负整数、零或正整数。
Set详解:存入set的每个元素必须是唯一的,这也是与List不同的,因为Set不保存重复元素。加入Set的Object必须定义equals()方法以确保对象的唯一性。Set与Collection有完全一样的接口。Set接口不保证维护元素的次序。
HashSet:HashSet能快速定位一个元素,存入HashSet的对象必须定义hashCode().
TreeSet:保持次序的Set,底层为二叉树结构。使用它可以从Set中提取有序的序列。
LinkedHashSet:具有HashSet的查询速度,且内部使用列表结构维护元素的顺序(插入的次序)。于是在使用迭代器遍历Set时,结果会按照元素的插入次序显示。
需要注意的是,生成自己的类时,Set需要维护元素的存储顺序,因此要实现Comparable接口定义compareTo方法。
TreeSet排序的第一种方式:让元素自身具备比较性。元素需要实现Comparable接口,覆盖compareTo方法。这种方式也称为元素的自然顺序,或者叫默认顺序。
TreeSet的第二种排序方式:当元素自身不具备比较性时,或者具备的比较性不是所需要的。这时就需要让集合自身具备比较性。
强制让对象具备比较性:
import java.util.Iterator;
import java.util.TreeSet;
publicclass TreeSetDemo {
publicstaticvoid main(String[] args) {
TreeSet ts=new TreeSet();
ts.add(new Student("a2",22));
ts.add(new Student("a3",24));
ts.add(new Student("a4",19));
ts.add(new Student("a1",22));
Iterator it=ts.iterator();
while(it.hasNext()){
Student s=(Student)it.next();
System.out.println(s.getName()+"::"+s.getAge());
}
}
}
class Studentimplements Comparable{//强制让学生具备比较性
private Stringname;
privateintage;
Student(String name,int age){
this.name=name;
this.age=age;
}
publicint compareTo(Object o) {
if(!(oinstanceof Student))
thrownew RuntimeException("不是学生对象");
Student stu=(Student)o;
if(this.age>stu.age)//当前元素>传入的元素
return 1;
if(this.age==stu.age){//主要条件
returnthis.name.compareTo(stu.name);//次要条件
}
return -1;
}
public String getName(){
returnname;
}
publicint getAge(){
returnage;
}
}
TreeSet的第二种排序方式:当元素自身不具备比较性时,或者具备的比较性不是所需要的。这时就需要让集合自身具备比较性。如果元素自身具备比较性,则以比较器为主
比较器:
class MyCompareimplementsComparator{
publicint compare(Object o1,Object o2){
if(o1 instanceof PeopleDemo || o2 instanceofPeopleDemo)
throw new RuntimeException(“不是同一种对象”);
PeopleDemo s1=(PeopleDemo)o1;
PeopleDemo s2=(PeopleDemo)o2;
int num= s1.getName().compareTo(s2.getName());//对象比较用compareTo
if(num==0){
//简化方式,对象封装,调用compareTo()
returnnew 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;
}
}
修改集合,为其添加比较器:
TreeSet ts=new TreeSet(new MyCompare());
--------------------------------
TreeSet练习:按照字符串长度进行排序。
class MyStrCompareimplementsComparator{
publicint compare(Object o1,Object o2){
String s1=(String)o1;
String s2=(String)o2;
int num=new Integer(s1.length()).compareTo(new Integer(s2.length()));
if(num==0)//长度相等后
return s1.compareTo(s2);//比较内容是否相同
return num;
}
}
总结:比较器如果作用于二叉树(TreeSet)排序结构,则直接在集合类参数中传入自定义比较器对象即可;
如果作用在底层数组结构(ArrayList)或列表结构(LinkedList)的集合类中时用法:
第一步:先对集合进行排序,a1代表集合引用
Collections.sort(al,new MyComparator());
第二步:根据迭代,最后输出结果
自定义比较器不能作用在HashSet(底层哈希表结构)中,因为内存中不能存在相同对象,哈希值唯一。
二、泛型:JDK1.5版本以后出现的新特性。用于解决安全问题,是一个类型安全机制。
好处:
1.将运行时期出现的问题ClassCastException,转移到了编译时期。方便程序员解决问题,让运行事情问题减少,安全。
2.避免了强制转换麻烦。
泛型格式:通过<>来定义要操作的引用数据类型。
在使用java提供的对象时,什么时候写泛型呢?
通常在集合框架中很常见,只要见到<>就要定义泛型。其实<>就是用来接收泛型的。当使用集合时,将集合中要存储的数据类型,作为参数传递到<>中即可。
什么时候定义泛型类呢?
当类中要操作的引用数据类型不确定的时候;
早期是通过定义Object来完成扩展。
现在定义泛型来完成扩展。
例如:
class Tools<PP>
{
privatePP p;
public void setObject(PPp){
this.p=p;
}
public PP getObject(){
return p;
}
}
1、泛型类定义的泛型,在整个类中有效,如果被方法使用,那么泛型类的对象明确要操作的具体类型后,所有要操作的类型就已经固定了。
2、为了让不同方法可以操作不同类型,而且类型还不确定,那么可以将泛型定义在方法上。
3、特殊之处:
静态方法不可以访问类上定义的泛型。
如果静态方法操作的应用数据类型不确定,可以将泛型定义在方法上。
class Demo<T>{
public void print(T t){
System.out,print(t);
}
public <Q> void print(Q q){
System.out,print(q);
}
public static <W> void method(W w){//此处注意泛型的位置
System.out.print(w);
}
}
泛型定义在接口上:
interface Inter<T>{
publicvoid show(T t);
}
class Outer<T>implements Inter<T>{
publicvoid show(T t){
System.out.println(t);
}
}
泛型的限定:
?通配符,也可以理解为占位符。
? extends E:可以接收E类型或者E的子类型------上限。
? super E:可以接收E类型或者E的父类型-------下限。
上限例子:
publicstaticvoid pringCollection(ArrayList<?extends Persons> al)
{ //存储Persons及Persons的子类--上限
Iterator<?extends Persons> it= al.iterator();
while(it.hasNext()){
System.out.println(it.next().getName());
}
}
占位符例子:
public static void pringCollection(ArrayList<?>al)//?是占位符
{
Iterator<?> it= al.iterator();
while(it.hasNext()){
System.out.println(it.next());
}
}
----- android培训、java培训、java博客、java学习型技术博客、期待与您交流! ------
如有疑问:http://edu.csdn.net/