---------------------- ASP.Net+Android+IO开发S、.Net培训、期待与您交流! ----------------------
概述
为什么出现集合类?
面向对象语言对事物的体现都是以对象的形式,所以为了方便对多个对象的操作,就对对象进行存储,集合就是存储对象最常用的一种方式。
数组和集合同是容器,它们有何不同?
1、数组虽然也可以存储对象,但长度是固定的,集合长度是可变的。
2、数组可以存储基本数据类型,集合只能存储对象。
集合类的特点
1、集合只用于存储对象
2、集合长度是可变的
3、集合可以存储不同类型的对象。
为什么会出现这么多的容器?
因为每一个容器对数据的存储方式都有不同,这个存储方式称之为:数据结构。
![]()
Collection的共性方法
Collection的方法,请参看下图:![]()
示例代码如下:
import java.util.*; /* 1、add方法的参数类型是Object,以便接受任意类型对象。 2、集合中存储的都是对象的引用(地址)。 */ public class CollectionDemo{ public static void main(String[] args){ //创建一个集合容器,使用Collection接口的子类,ArrayList ArrayList a1=new ArrayList(); //1、添加元素。 a1.add("aaa"); a1.add("bbb"); a1.add("ccc"); a1.add("ddd"); a1.add("eee"); //打印集合 sop(a1); //3、删除元素 al.remove("aaa"); //a1.clear(); //清空集合 sop(a1); //4、判断元素 sop("ccc是否存在"+a1.contains("ccc")); sop("集合是否为空"+a1.isEmpty()); //2、获取个数,集合长度 sop("size:"+al.size()); } public static void sop(Object obj){ System.out.println(obj); } }
迭代器
迭代器,其实就是集合取出元素的方式。
把元素的取出方式定义在集合的内部,这样取出方式就可以直接访问集合内容的元素,如此一来取出方式就被定义成了内部类。
由于每一个容器的数据结构不同,所以取出的动作细节也不一样,但它们有共性的内容:判断和取出,所以可以将这些共性内容抽取。
这些内部类都符合一个规则,该规则就是Iterator。
如何获取集合的取出对象呢?
通过一个对外提供的方法,iterator()
示例代码如下:
import java.util.*; public class CollectionDemo{ public static void main(String[] args){ ArrayList a1=new ArrayList(); a1.add("aaa"); a1.add("bbb"); a1.add("ccc"); a1.add("ddd"); a1.add("eee"); for(Iterator it=a1.iterator();it.hasNext();){ sop(it.next()); } } public static void sop(Object obj){ System.out.println(obj); } }
List接口的共性方法
请参看下图
![]()
![]()
示例代码如下:
import java.util.*; public class CollectionDemo{ public static void main(String[] args){ ArrayList a1=new ArrayList(); a1.add("aaa"); a1.add("bbb"); a1.add("ccc"); a1.add("ddd"); a1.add("eee"); sop("原集合是:"+a1); //在指定位置上添加元素 a1.add(1,"zzz"); sop("新集合是:"+a1); //删除指定位置上的元素 a1.remove(2); //修改元素 a1.set(2,"abc"); //通过角标获取元素 sop("get(1):"+a1.get(1)); sop("index="+a1.indexOf("abc")); List sub=a1.subList(1,3); sop("sub="+sub); public static void sop(Object obj){ System.out.println(obj); } }
ListIterator接口
List集合特有的迭代器,ListIterator是Iterator的子接口。
在迭代时,不可以通过集合对象的方法操作集合中的元素,因为会发生并发修改异常。
所以,在迭代器时,只能用迭代器的方法操作元素,可是Iterator的方法是有限的,只能对元素进行判断、取出、删除的操作。如果想要其他的操作如添加、修改等,就需要用到其子接口,ListIterator。
该接口只能通过List集合的listIterator方法获取。
示例代码如下:
import java.util.*; public class CollectionDemo{ public static void main(String[] args){ ArrayList a1=new ArrayList(); a1.add("aaa"); a1.add("bbb"); a1.add("ccc"); sop(a1); ListIterator li=al.listIterator(); while(li.hasNext()){ Object obj=li.next(); if(obj.equals("bbb")) li.add("zzz"); } sop(a1); } public static void sop(Object obj){ System.out.println(obj); } }
枚举
查阅API,发现List中有一个名为Vector的子类,它里面没有迭代器,而是又一个enumeration的方法,这就是枚举。
枚举就是Vector特有的取出方式。
仔细查看后发现它和迭代器很像,其实枚举和迭代器是一样。只是因为枚举的名称以及方法的名称都过长,所以被迭代器取代了。
示例代码如下:
import java.util.*; public class CollectionDemo{ public static void main(String[] args){ Vector v=new Vector(); v.add("aaa"); v.add("bbb"); v.add("ccc"); Enumeration en=v.elements(); while(en.hasMoreElements()){ System.out.println(en.nextElement()); } } }
LinkedList中的特有方法
请看下图![]()
![]()
![]()
![]()
![]()
示例代码如下:
import java.util.*; public class CollectionDemo{ public static void main(String[] args){ LinkedList link=new LinkedList(); link.addFirst("aaa"); link.addFirst("bbb"); link.addLast("ccc"); link.addLast("ddd"); sop(link); sop(link.getFirst()); sop(link.getLast()); sop(link.removeFirst()); sop(link.removeLast()); } public static void sop(Object obj){ System.out.println(obj); } }
HashSet
Set是Collection的子接口,它的特点是存入的元素是无无序的,不可重复的。
在它之下,有两个常用接口,HashSet和TreeSet。
其中,HashSet的底层是哈希表数据结构,线程非同步;TreeSet的底层是二叉树数据结构,可以对set集合中的元素进行排序
Set接口的子类能保证元素的唯一性,HashSet是如何保证元素唯一性的呢?
是通过元素的两个方法,hashCode和equals来完成。hashCode方法返回元素的哈希值,如果哈希值不相同,则两个元素为不同的,不添加。如果哈希值相同,那么会接着运行equals方法,查看两个元素是否相同。相同则不添加,不相同才添加。
示例代码如下:class Person{ private String name; private int age; Person(String name.int age){ this.name=name; this.age=age; } public int hashCode(){ return name.hashCode()+age*21; } public boolean equals(Object obj){ if(!(obj instanceOf Person)) return false; Person p=(Person)obj; return this.name.equals(p.name)&&this.age==p.age; } public String toString(){ return name+"::"+age; } } public class Demo{ 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("a4",12)); hs.add(new Person("a4",14)); for(Iterator it=hs.iterator();it.hasNext();){ Person p=(Person)it.next(); sop(p); } } public static void sop(Object obj){ System.out.println(obj); } }
TreeSet
TreeSet也是Set的子类,能够保证元素的唯一性。它的底层是二叉树,能够是实现默认排序。
示例代码如下:
public class Demo{ public static void main(String[] args){ TreeSet ts=new TreeSet(); ts.add("cba"); ts.add("abcd"); ts.add("aaa"); ts.add("bca"); for(Iterator it=hs.iterator();it.hasNext();){ sop(it.next()); } } public static void sop(Object obj){ System.out.println(obj); } }
TreeSet集合实现元素唯一性的两种方式:
1、自然排序(元素具备比较性)
TreeSet的无参构造,要求对象所属的类实现Comparable接口,复写其中的compareTo方法。
2、比较器排序(集合具备比较性)
TreeSet的带参构造,要求构造方法接收一个实现了Comparator接口的对象。代码示例:让对象自己具备比较性
import java.util.*; 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; 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; } } public class Demo{ public static void main(String[] args){ TreeSet ts=new TreeSet(); ts.add(new Student("wangda",20)); ts.add(new Student("wanger",19)); ts.add(new Student("wangsan",25)); ts.add(new Student("wangsi",19)); for(Iterator it=ts.iterator();it.hasNext();){ Student stu=(Student)it.next(); System.out.println(stu.getName()+"..."+stu.getAge()); } } }
当对象的比较性不是我们想要的时,就可以自定义比较器,然后传给TreeSet。
示例代码如下:
import java.util.*; 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; 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 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 s1.getAge()-s2.getAge(); return num; } } public class Demo{ public static void main(String[] args){ TreeSet ts=new TreeSet(new MyCompare()); ts.add(new Student("wangda",20)); ts.add(new Student("wanger",19)); ts.add(new Student("wangsan",25)); ts.add(new Student("wangsi",19)); for(Iterator it=ts.iterator();it.hasNext();){ Student stu=(Student)it.next(); System.out.println(stu.getName()+"..."+stu.getAge()); } } }
泛型
JDK1.5版本后出现的新特性。用于解决安全问题,是一个安全机制。
泛型的好处
1、运行期间的classCastException转移到编译时期,方便程序员解决问题,让 运行期问题减少,较安全。
2、避免强制转换麻烦。
书写泛型的格式
通过< >来定义要操作的引用数据类型。其实< >就是来接收数据类型的。当使用集合时,将集合中要存储的数据类型作为参数传递到<>中即可。
如:ArrayList<String> al=new ArrayList<String>()
PS:自JDK7.0后,第二个<>中的内容也可不写
示例代码如下:
import java.util.*; public class Demo3{ public static void main(String[] args){ ArrayList<String>al=new ArrayList<>();//JDK7.0出现的新特色,第二个<>中不用传入类型。 al.add("aaa"); al.add("bbb"); al.add("ccc"); for(Iterator<String>it=al.iterator();it.hasNext();){ sop(it.next()); } } public static void sop(Object obj){ System.out.println(obj); } }
泛型类
什么时候定义泛型类?
当类中要操作的引用数据类型不确定的时候。早期定义Object 来完成扩展,现在定义泛型来完成扩展。
示例代码如下:
class Worker { } class Student { } class Utils<QQ> { private QQ q; public void setObject(QQ q){ this.q = q; } public QQ getObject(){ return q; } } class Demo3{ public static void main(String [] args){ Utils<Worker> u= new Utils<Worker>(); u.setObject(new Worker()); Worker w = u.getObject(); } }
泛型方法
泛型类定义的泛型,在整个类中有效。泛型类的对象明确要操作的具体类型后,所有要操做的类型就已经固定了。
为了让不同方法可以操作不同类型,而且类型还不确定,那么可以将泛型定义在方法上。
示例代码如下:
class Demo{ public <T> void show(T t){ System.out.println("show:"+t); } public <Q> void print(Q q){ System.out.println("print:"+t); } } class GenericDemo4{ public static void main(String [] args){ Demo d = new Demo(); d.show(new Integer(4)); d.print("hehe"); d.show("hahah"); } }
静态泛型方法
静态方法不可以访问类上定义的泛型,如果静态方法操作的应用数据类型不确定,可以将泛型定义在方法上
示例代码如下:
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){ System.out.println("method::"+t); } } public class GenericDemo5{ public static void main(String [] args){ Demo<String> d1 = new Demo<String>(); d1.print(5); d1.show("hahah"); Demo.method("hehehehe"); } }
泛型限定
示例代码如下:?:通配符,也可以理解为占位符。
?extends E:可以接受E类或者E的子类型 上限
?super E:可以接受E类型或者E的父类型 下限
import java.util.*; class Person{ private String name; Person(String name){ this.name = name; } public String getName(){ return name; } } class Student extends Person{ private String name; Student(String name){ super(name); } } class GenericTest{ public static void main(String[] args){ ArrayList<Person> al = new ArrayList<Person>(); al.add(new Person("abc1")); al.add(new Person("abc2")); al.add(new Person("abc3")); sop(al); ArrayList<Student> al1 = new ArrayList<Student>(); al1.add(new Student("abc--1")); al1.add(new Student("abc--2")); al1.add(new Student("abc--3")); sop(al1); } public static void sop(ArrayList<? extends Person> al){ Iterator<? extends Person> it = al.iterator(); while(it.hasNext()){ sop(it.next().getName()); } } public static void sop(Object obj){ System.out.println(obj); } }