您的位置:首页 > 职场人生

黑马程序员_java集合框架与泛型详解

2014-08-25 10:47 363 查看
-------android培训java培训、期待与您交流!
----------
 
一、java集合框架
1、集合类与容器
为什么出现集合类?
     面向对象语言对事物的体现都是以对象的形式,所以为了方便对多个对象的操作,就要对对象进行存储,集合就是存储对象最常用的一种方式。
数组和集合类同是容器,有何不同?
      数组元素既可以是基本数据类型的数据,也可以是引用数据类型的数据。而集合里只能存储引用数据类型。

      数组一旦定义后,长度不可变。而集合的长度会自动变化。

      数组定义成什么类型,就只能存储什么类型的数据。而集合可以存储不同类型的对象。
需要注意的是:无论是数组还是集合类容器,当其中存放的数据是引用类型数据时,那么其中存放的

只是对数据的引用(地址)而非数据本身。
集合类的特点
集合只用于存储对象,集合长度是可变的,集合可以存储不同类型的对象。
 
集合框架的构成及分类
 


 
两大接口体系
Java集合类主要由两个接口派生出来:
Collection
         Set          :不能存放重复对象;
         List         :可存放重复对象,有序;
         Queue     :队列;
         SortedSet       :可对集合数据排序;
Map
       SortedMap      :可对集合数据排序;
 

2、Collection体系介绍

1)、Collection接口

方法:
boolean add(Object o):该方法用于向集合里面添加一个元素,若集合对象被添加操作改变了,返回true.
boolean addAll(Collection c):把集合c里面的所有元素添加到指定集合里面去,如果集合对象被添加操作改变了返回true.
void clear():清除集合里面的所有元素,将集合长度变为0。
boolean contains(Object o):返回集合里是否包含指定的元素。
boolean containsAll(Collection c):返回集合里是否包含集合c内所有的元素。
boolean isEmpty():返回集合是否为空(长度是否为0)。
Iterator iterator():返回一个Iterator对象,用于遍历集合里的元素。
boolean remove(Object o):删除集合中指定元素o。
boolean removeAll(Collection c):从集合中删除集合c里面的元素。若删除一个或以上返回true。
boolean retainAll(Collection c):从集合中删除集合c里不包含的元素。
int size():得到集合元素的个数。
Object[] toArray():把集合转成一个数组,所有集合元素编程数组元素。
 
2)、Iterator接口
Iterator主要遍历Collection集合中的元素,也有称为迭代器或迭代精灵。
 boolean hasNext():若被迭代的集合元素还没有被遍历,返回true.
Object  next():返回集合的下一个元素.
void remove():删除集合上一次next()方法返回的元素。(若集合中有多个相同的元素,都可以删掉)
iterator对于集合才能用,for不同,只要是循环都可用。
 
迭代是取出集合中元素的一种方式。
因为Collection中有iterator方法,所以每一个子类集合对象都具备迭代器。
迭代器在Collcection接口中是通用的,它替代了Vector类中的Enumeration(枚举)。迭代器的next方法是自动向下取元素,要避免出现NoSuchElementException。
迭代器的next方法返回值类型是Object,所以要记得类型转换。(学到泛型就可以消除强转!)
Eg:
Iterator iter = l.iterator();
while(iter.hasNext()){
System.out.println(iter.next());
}

3)、List接口
Collection子接口;
List是有序的集合,集合中每个元素都有对应的顺序序列。List集合可使用重复元素,可以通过索引来访问指定位置的集合元素(顺序索引从0开始),List集合默认按元素的添加顺序设置元素的索引,比如第一个元素的索引就是0,好似数组。
List作为Collection子接口当然拥有其所有方法,同时也有自己的方法:
 
void add(int index,Object e):将元素e添加到List集合中的index处;
boolean addAll(int index,Collection c):将集合c所包含的所有元素都插入在List集合的index处;
Object get(int index):返回集合index索引处的元素;
int indexOf(Object o):返回对象o在List集合中第一次出现位置的索引;
int lastIndexOf(object o):返回对象o在List集合中最后一次出现的位置索引;
Object remove(int index):删除并返回index索引处的元素;
Object set(int index,Object e):把集合index处的元素替换为e对象,返回以前在指定位置的元素;
List subList(int fromIndex,int toIndex):返回从所有fromIndex(包括)到toIndex(不包括)处所有集合元素的子集合。
 4)、ListIterator
Iterator的子接口,专门用于操作List集合的输出;
List自己还有一个listIterator()方法,该方法返回ListIterator对象,ListIterator继承了Iterator接口,提供了专门操作List的方法。在Iterator上额外增加的方法:
int nextIndex();
int previousIndex();
void set(E e);
支持双向输出:
boolean hasPrevious():返回该迭代器关联集合是否还有上一个元素;
Object previous():返回该迭代器的上一个元素;
Eg:
package com.demo;
import java.util.ArrayList;
import java.util.List;
import java.util.ListIterator;
public class ListIteratorDemo {
public static void main(String[] args) {
List<Integer> l = new ArrayList<Integer>();
l.add(1);
l.add(2);
l.add(3);
l.add(2);
l.add(3);
System.out.println(l);
ListIterator<Integer> it = l.listIterator();
while(it.hasNext()){
System.out.println("正序:"+it.next());
}
System.out.println("==================================");
//使用向前迭代前必须将游标(指针)移动到后边!
while(it.hasPrevious()){
System.out.println("逆序:"+it.previous());
}
}
}

输出:
[1, 2, 3, 2, 3]
正序:1
正序:2
正序:3
正序:2
正序:3
==================================
逆序:3
逆序:2
逆序:3
逆序:2
逆序:1
 

5)、List接口中常用类
 Vector:线程安全,但速度慢,已被ArrayList替代。
ArrayList:线程不安全,查询速度快。
LinkedList:链表结构,增删速度快。取出List集合中元素的方式:
get(int  index):通过脚标获取元素。
iterator():通过迭代方法获取迭代器对象。
ArrayList和Vector类都是基于数组实现的List类,Vector比较古老,被ArrayList取代了;
ArrayList是线程不安全的,而Vector是线程安全的,但是即使这样,也不推荐使用Vector,因为Collections有方法可以得到线程安全的ArrayList对象;
Collections类: static  List synchronizedList(List list)返回指定列表支持的同步(线程安全的)列表。
 
Queue接口(作为补充)
 继承Collection接口
模拟队列:先进先出(FIFO);
void add(Object e):将e插入到队列尾部;
Object element():获取队列头部的元素;
boolean offer(Object e):将e插入到队列的尾部,当使用有容量限制的队列时,此方法比add(Object e)方法更好。
Object peek():获取队列头部的元素。如果此双端队列为空,则返回 null。
Object poll():获取并删除队列头部的元素。如果此双端队列为空,则返回 null。
Object remove():获取并删除队列头部的元素。 
Eg:练习:List的使用
设计Department 和 Employee 对象类(按照开发的样式没有写在一个文件里面)
//一个员工只可以有一个部门,所以按照普通的写法
//一个部门可以有许多员工,所以按照集合的写法;
//员工
package com.demo.Department;
public class Emp {
private Dept dept;//一个员工只可以有一个部门,所以按照普通的写法
private String name;
public Dept getDept() {
return dept;
}
public void setDept(Dept dept) {
this.dept = dept;
}
public Emp(String name) {
super();
this.name = name;
}
public String toString(){//覆写toString方法
return this.name+"";
}
}
//部门
package com.demo.Department;
import java.util.List;
public class Dept {
private String name;
private List emp;//一个部门可以有许多员工,所以按照集合的写法;部门里的属性,员工!
public Dept(String name) {
super();
this.name = name;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public List getEmp() {
return emp;
}
public void setEmp(List emp) {
this.emp = emp;
}
private Dept parent;//一个部门只有一个直接主管部门,所以普通写法
private List children;//但是一个部门可以管理很多部门,充当很多部门的直接主管部门,所以使用集合
public Dept getParent() {
return parent;
}
public void setParent(Dept parent) {
this.parent = parent;
}
public List getChildren() {
return children;
}
public void setChildren(List children) {
this.children = children;
}
public String toString(){
return this.name.toString();
}
}
//测试类,主方法!
package com.demo.Department;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
public class TestDemo {
public static void main(String[] args) {
Emp e1 = new Emp("zhangsan");
Emp e2 = new Emp("lisi");
Emp e3 = new Emp("wangwu");
Emp e4 = new Emp("zhaoliu");
Emp e5 = new Emp("liuer");
List list = new ArrayList();//把员工丢尽集合去
list.add(e1);
list.add(e2);
list.add(e3);
list.add(e4);
list.add(e5);
for (Object object : list) {//把员工给遍历出来,使用的是直接的foreach(四种方法之一)
System.out.println("----->"+object);
}
System.out.println("-------------------");
Dept d = new Dept("部门");//定义出一个部门来接收员工
d.setEmp(list);//把员工这个集合丢到部门去。
Dept d1 = new Dept("itcast");
Dept cditcast = new Dept("beijingheima");
Dept gzitcast = new Dept("shenzhenheima");
Dept d4 = new Dept("CSDN");
System.out.println(d4);
List children = new ArrayList();
children.add(cditcast);
children.add(gzitcast);
d1.setChildren(children);//定义直接被主管部门(集合)
d1.setParent(d4);//定义直接主管部门
Iterator it = children.iterator();//运用到了迭代遍历,四种之一!
while(it.hasNext()){
System.out.println(it.next());
}
}
}

6)、集合遍历输出方式
Iterator:迭代输出
一旦操作集合的遍历输出,首选Iterator接口;
ListIterator:Iterator子接口,专门输出List中的元素;
Enumeration:古老的输出方式,迭代Vector元素,被Iterator取代;
foreach:可输出数组和Iterable对象;
Eg:
package com.demo;
//遍历输出的四种方式
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
public class ListDemo {
public static void main(String[] args) {
List<String> l = new ArrayList();
l.add("1");
l.add("2");
l.add("3");
l.add("4");
System.out.println(l);
/**
* 遍历输出:四种方式
*/

// 1、推荐使用的Iterator对象,迭代输出!
Iterator it = l.iterator();
while (it.hasNext()) {
System.out.println("迭代输出:" + it.next());
}

// 2、对集合进行foreach循环!
for (String str : l) {
System.out.println("fore集合迭代输出:" + str);
}
// 3、for循环迭代,在for方法体内部实例化Iterator对象!
int i = 0;// for方法体内定义项不能出现多种不同类型
for (Iterator iter = l.iterator(); i < l.size(); i++) {
System.out.println("for循环迭代实例化输出:" + iter.next());
}
// 4、先将集合转换为数组,再利用数组的遍历输出;
Object[] o = l.toArray();
for (Object object : o) {
System.out.println("转换数组迭代输出:" + object);
}
}
}

 7)、Set接口(元素不可以重复)
Set是Collection子接口;
Set和Collection基本上一样,一点除外:
Set无法记住添加的顺序,不允许包含重复的元素。
当试图添加两个相同元素进Set集合,添加操作失败,add()方法返回false。
Set判断两个对象是否相等用equals,而不是使用==。
也就是说两个对象equals比较返回true,Set集合是不会接受这个两个对象的。
常用子类:
HashSet:散列存放
TreeSet:有序存放
 
hashCode方法对于HashSet的作用
HashSet类是Set接口最常用的实现类,采用hash算法存储数据,具有良好的存储和查找功能。
散列存储:不记录添加顺序;排列顺序时,顺序有可能发生变化;
线程不安全的,多个线程访问一个HashSet要使用同步代码;
HashSet集合元素值允许是null,但是最多只能有一个;//因为Set集合就不可以装重复的对象!
hash(翻译为哈希,或散列)算法的功能:
保证通过一个对象快速找到另一个对象;
其算法价值体现在速度,可以保证查询快速执行;
当从HashSet中访问元素时,HashSet先计算该元素的hashCode(也就是该对象的hashCode方法返回值),然后直接到该HashCode对应的位置取出该元素;
在这里对象的hashCode就好比是数组里的索引,但是不是索引;
 
HashSet元素添加
当向HashSet集合中存入一个元素时,HashSet会调用该对象的hashCode()方法来得到该对象的hashCode值,判断已经存储在集合中的对象的hashCode值是否与添加的对象的hashCode值一致:若不一致:直接添加进去;若一致,再进行equals方法比较,equals方法如果返回true,表明对象已经添加进去了,就不会再添加新的对象了,否则添加进去;
如果我们重写了equals方法,也要重写hashCode方法,反之亦然;。
HashSet集合判断两个元素相等的标准是两个对象通过equals方法比较相等,并且两个对象的hashCode方法返回值也相等。
如果需要某个类的对象保存到HashSet集合中,覆写该类的equals()和hashCode()方法,应该尽量保证两个对象通过equals比较返回true时,他们的hashCode返回也相等。
Eg:
package com.demo;
//hashset方法和equals方法判断输入的对象是否重复!
import java.util.HashSet;
import java.util.Set;
class Person{
private String name;
public Person(String name) {
super();
this.name = name;
}
@Override
public String toString() {
return "name= " + name ;
}
//没有覆写hashcode和equals方法前,显示三次(一样的)。覆写后,只剩下一个了!说明覆写后方法起作用了,重复的输入不进去!
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + ((name == null) ? 0 : name.hashCode());
return result;
}
@Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
PersonDemo other = (PersonDemo) obj;
if (name == null) {
if (other.name != null)
return false;
} else if (!name.equals(other.name))
return false;
return true;
}
}
public class HashSetDemo {
public static void main(String[] args) {
Set s = new HashSet();

s.add(new Person("zhangsan"));
s.add(new Person("zhangsan"));
s.add(new Person("zhangsan"));
System.out.println(s);
}
}
 

8)、TreeSet
TreeSet是SortedSet接口唯一的实现,与HashSet相比额外的方法有:
Comparator comparator():返回当前Set使用的Comparator,若返回null,表示以自然顺序排序。
Object first() 返回此 set 中当前第一个(最低)元素。
Object last() 返回此 set 中当前最后一个(最高)元素。
SortedSet subSet(Object  fromElement, E toElement)返回此 set 的部子集,其元素从 fromElement(包括)到 toElement(不包括)。
SortedSet headSet(Object  toElement)返回此 set的部分子集,其元素严格小于 toElement。
SortedSet tailSet(Object  fromElement)返回此 set 的部分子集,其元素大于等于 fromElement。
 
TreeSet的排序之自然排序
TreeSet会调用元素的compareTo(Object o)方法来比较元素之间的大小关系,然后将集合里的元素按升序排列.此时需要排序元素的类必须实现Compareble接口,并覆写其int compareTo(Object o)方法;
该方法用于比较对象,若:obj1,compareTo(obj2),返回0,表示两个对象相等,若返回一个正整数,表示obj1大于obj2,若返回一个负整数,表示obj1小于obj2;
对于TreeSet集合而言,判断两个对象相等的标准是:
compareTo()方法比较返回 0;
package com.demo;
//TreeSet可以自动进行排序!最简单的情况
import java.util.Set;
import java.util.TreeSet;
public class SetDemo {
public static void main(String[] args) {
Set<Integer> s = new TreeSet<Integer>();
s.add(1);
s.add(192);
s.add(123);
s.add(56);
s.add(13);
s.add(96);
System.out.println(s);//[1, 13, 56, 96, 123, 192]
}
}

package com.demo;
//TreeSet的自然排序,升序
import java.util.Set;
import java.util.TreeSet;
class Student implements Comparable{//必须实现接口
private Integer age;
public Student(Integer age) {
super();
this.age = age;
}
@Override
public int compareTo(Object o) {//比较的规则,运用泛型可以消除强转!
if(o instanceof Student){
Student s = (Student)o;
return this.age.compareTo(s.age);
}
return 0;
}
@Override
public String toString() {
return age+"" ;
}
}
public class TreeSetDemo {
public static void main(String[] args) {
Set<Student> s = new TreeSet();
s.add(new Student(140));
s.add(new Student(15));
s.add(new Student(11));
s.add(new Student(63));
s.add(new Student(96));
System.out.println(s);//[11, 15, 63, 96, 140]
}
}

TreeSet的排序之定制排序
TreeSet的自然排序是根据元素的大小进行升序排序的,若想自己定制排序,比如降序排序,就可以使用Comparator接口了:
该接口包含int compare(Object o1,Object o2)方法,用于比较两个对象的大小,比较结果和compareTo方法一致;
要实现定制排序,需要在创建TreeSet集合对象时,提供一个一个Comparator对象,该对象里负责集合元素的排序逻辑;
TreeSet(Comparator comparator)
Eg:
package com.demo;
//定制排序的话,必须在创建TreeSet集合对象的时候提供一个Comparator方法
import java.util.Comparator;
import java.util.Set;
import java.util.TreeSet;
class StudentInfo{
private Integer age;
public StudentInfo(Integer age) {
super();
this.age = age;
}
public Integer getAge() {
return age;
}
public void setAge(Integer age) {
this.age = age;
}
@Override
public String toString() {
return age + "";
}
}
class MyComparator implements Comparator{
@Override
public int compare(Object o1, Object o2) {
if(o1 instanceof StudentInfo & o2 instanceof StudentInfo){
StudentInfo s1 = (StudentInfo)o1;
StudentInfo s2 = (StudentInfo)o2;
if(s1.getAge() > s2.getAge()){
return -1;
}else if(s1.getAge() < s2.getAge()){
return 1;
}
}
return 0;
}
}
public class CompDemo {
public static void main(String[] args) {
Set<StudentInfo> s = new TreeSet(new MyComparator());
/*
要实现定制排序,需要在创建TreeSet集合对象时,提供一个一个Comparator对象,
该对象里负责集合元素的排序逻辑;
*/
s.add(new StudentInfo(19));
s.add(new StudentInfo(15));
s.add(new StudentInfo(16));
s.add(new StudentInfo(23));
s.add(new StudentInfo(18));
System.out.println(s);
}
}
 

 
2、Map体系介绍
映射关系,也有人称为字典,Map集合里存在两组值,一组是key,一组是value。Map里的key不允许重复。通过key总能找到唯一的value与之对应。
Map里的key集存储方式和对应的Set集合中的元素存储方式一致;
学生都有一个学号,我们能点学号就能找到某个学生,好比这个学号就是key,学生就是value。
Map.Entry是Map接口的内部接口,专门用来保存key-value内容:
 
Map常用方法
void clear():删除该Map对象中所有的key-value对。也就是清理该集合;
boolean containsKey(Object key):查询Map中是否包含指定的key;
boolean containsValue(Object  value):查询Map中是否包含至少一个value;
Set entrySet():返回Map所包含的key-value对所组成的Set集合,每个集合元素都是Map.Entry对象(Entry是Map内部类);
Object get(Object key):返回指定key所对应的value,若此Map中不包含该key,返回null;
boolean isEmpty():判断Map集合是否为空;
Set keySet():返回该Map中所有key所组成的Set集合;
Object put(Object key,Object value):添加一个key-value对,若Map中已有与key相等的key-value对,则新的key-value对覆盖原来的key-value对;
void putAll(Map m):将m中的key-value赋值到调用该方法的Map对象中;
Object remove(Object key):删除指定key所对应的key-value对,返回本删除key所关联的value,若key不存在,返回null;
int size():返回该Map里面key-value对的个数;
Collection values():返回Map里所有value组成的Collection。
Eg:package com.demo;
import java.util.Collection;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;
public class MapDemo {
public static void main(String[] args) {
Map m = new HashMap();
m.put(1, "zhangsan");
m.put(2, "lisi");
m.put(3, "wangwu");
System.out.println(m);//{1=zhangsan, 2=lisi, 3=wangwu}
Set s = m.entrySet();
System.out.println(s);//[1=zhangsan, 2=lisi, 3=wangwu]
s = m.keySet();
System.out.println(s);//[1, 2, 3]
for (Object key : s) {
System.out.println(key);//Key
System.out.println(m.get(key));//Value
}

Collection c = m.values();
System.out.println(c);
}
}
 

Map.Entry
Entry是Map接口里面的一个内部接口.
该接口用于封装key- value,有3个方法:
Object getKey();返回Entry里包含的key值
Object getValue();返回Entry里包含的value值
Object setValue(Object value):设置Entry里包含的value值,并返回新设置的value值;
Map集合的输出
按照最正统的做法,所有的Map集合的内容都要依靠Iterator输出,以上虽然是完成了输出,但是完成的不标准,Map集合本身并不能直接为Iterator实例化,如果此时非要使用Iterator输出Map集合中内容的话,则要采用如下的步骤:
方法一:
1.通过entrySet方法变成Set对象
2.调用Set的Iterator方法,此时每个Iterator对象是Map.Entry对象
3.对Map.Entry分离出 key - value
方法二:
1.通过keySet得到Map集合多有key的Set集合
2.调用Set的Iterator方法,此时每个Iterator对象是key值
3.通过Map的getValue(key)得到value值
Eg:
package com.demo;
//把Map中的元素取出来
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;
public class MapDemo2 {
public static void main(String[] args) {
Map<Integer, String> m = new HashMap<Integer, String>();
m.put(1, "zhangsan");
m.put(2, "lisi");
m.put(3, "wangwu");
//第一种方法
Set s = m.entrySet();
Iterator it = s.iterator();
while(it.hasNext()){
Map.Entry me = (Entry) it.next();
System.out.println(me.getKey()+"  "+me.getValue());
}
//第二种方法
s = m.keySet();//得到的是key的集合
it = s.iterator();//然后将key迭代出来
while(it.hasNext()){
int i = (int)it.next();
System.out.println(i+"   "+m.get(i));
}
}
}
 

3、Collections类
操作集合的工具类:
static void reverse(List list):反转指定List集合中的顺序;(和ListItertor的逆序排列一样!)
static void shuffle(List list):对集合元素随机排序
static void sort(List list):自然升序排序
static vois swap(List list,int i, int j):将指定的List集合i处元素和j处元素进行交换;
static void rotate(List list, int distance):
       若distance为正数,将list集合后的distance个元素移到前面;
       当distance为负数,将list集合前的distance个元素移到后面;
static  int binarySearch(List list, Object key)使用二分搜索法搜索指定列表,以获得指定对象。
调用之前必须调用 Collections.sort(List list)(完成自然排序);
 
static Object max(Collection coll)根据元素的自然顺序,返回给定 collection 的最大元素。  
static Object min(Collection coll)根据元素的自然顺序,返回给定 collection 的最小元素。     
static  void fill(List list, Object obj) 使用指定元素替换指定列表中的所有元素。
static int frequency(Collection c, Object o) 返回指定 collection 中等于指定对象的元素数。
static int indexOfSubList(Listsource, List target)返回指定源列表中第一次出现指定目标列表的起始位置;如果没有出现这样的列表,则返回 -1。
static int lastIndexOfSubList(List source, List target) 返回指定源列表中最后一次出现指定目标列表的起始位置;如果没有出现这样的列表,则返回 -1。
static boolean  replaceAll(List list, Object oldVal, Object newVal) 使用另一个值替换列表中出现的所有某一指定值。
同步集合
Eg:
import static java.util.Collections.binarySearch;
import static java.util.Collections.shuffle;
import static java.util.Collections.sort;
import java.util.ArrayList;
import java.util.List;
public class CollectionsDemo {
public static void main(String[] args) {
/*
static int binarySearch(List list, Object ele)使用二分搜索法搜索指定列表,以获得指定对象。

static void sort(List<T> list)根据元素的自然顺序对指定列表按升序进行排序。
*/
List list = new ArrayList();
list.add(1);
list.add(-3);
list.add(5);
list.add(-99);

System.out.println(list);
sort(list);
System.out.println(list);
int index = binarySearch(list, 0);
System.out.println(index);

/*
static void copy(List dest, List src)将所有元素从一个列表复制到另一个列表。

static void fill(List list, Object obj)使用指定元素替换指定列表中的所有元素。

static boolean replaceAll(List list, Object oldVal, Object newVal)
使用另一个值替换列表中出现的所有某一指定值。

static void shuffle(List list)使用默认随机源对指定列表进行置换。
*/
System.out.println("好的顺序" + list);
shuffle(list);
System.out.println("随机" + list);
/*
static void swap(List list, int i, int j)在指定列表的指定位置处交换元素。
*/
}
}

 4、Arrays
public static  List asList(Object... a)返回一个受指定数组支持的固定大小的列表(返回的是不可变的List(长度固定))。
(对返回列表的更改会“直接写”到数组。)此方法同 Collection.toArray()一起,充当了基于数组的 API 与基于 collection的 API 之间的桥梁。返回的列表是可序列化的,并且实现了 RandomAccess。
       此方法还提供了一个创建固定长度的列表的便捷方法,该列表被初始化为包含多个元素:
List<String> list= Arrays.asList("Larry", "Moe", "Curly");
list.add("Will");×
Eg:
import java.util.Arrays;
import java.util.List;
public class ArraysDemo {
public static void main(String[] args) {
/*
static  List  asList(Object... a)
返回一个固定长度的列表。
*/
List list = Arrays.asList("will","Lucy","小强");
System.out.println(list);
list.set(0, "你好");
//list.add("22");//错误,返回一个受指定数组支持的固定大小的列表。不可以再添加!
//list.remove(0);
System.out.println(list);
}
}

二、泛型(Generic)
1、泛型
泛型定义:
java5开始出现的一种对Java语言类型的一种拓展,以支持创建可以按类型进行参数化的类.可以把类型参数看作是使用参数类型时指定的类型占位符,就好比方法的形式参数是实际参数的占位符一样.
泛型能保证大型应用程序的类型安全和良好的维护性;
 使用泛型的优势:
类型安全,使编译器对泛型定义的类型做判断限制.如保证TreeSet里的元素类型必须一致;消除强制类型的转换,如,使用Comparable比较时每次都需要类型强转;
 2、泛型的使用
泛型类
在类声明时通过一个标识符表示类中某个字段的类型或者某个方法的返回值或参数的类型,这样在类声明或实例化的时候只要指定自己需要的类型就ok。
 声明带泛型的类:
class 类名<泛型类型1,泛型类型2……>{
       泛型类型 变量名;
       泛型类型 方法名(){}
       返回值类型方法名(泛型类型变量名){}
}
使用带泛型的类:
类名<具体类>对象名 = new 类名<具体类>();
 类型参数规范:推荐使用规范-常见的泛型,泛型只保存在源文件中,class文件中不存在;也就是说在编译阶段就会丢失,基本数据类型不能作为泛型类型;
K    键,比如映射的键  key的类型
V     值,比如Map的值 value类型
E     元素,比如Set<E>  Element表示元素,元素的类型
T    泛型,Type的意思
 
泛型使用例子
public class Point<Q> { //声明任意符号的标识符
private Q x;    //变量类型由外部组成
private Q y;
public Q getX() {
return x;
}
public void setX(Q x) { //类型由外部决定
this.x = x;
}
//..........................
}
.................main.........
{
Point<Double> p = new Point<Double>();   //定义具体类型
p.setX(1.1);
p.setY(2.2);
}

练习例子
需求:设计一个表示点的类Point,该类有两个字段,一个是横坐标x,一个纵坐标y,要求坐标有3种表达形式(Integer,Double,String):
 如果不使用泛型的话可以新建多个类,但是内部方法体只有参数类型不一样,所以用泛型的话更加简单,给定一个占位符,并不明确表示到底是什么类型,在实际运用的时候才确定类型!!
 很好的例子!
package generic;
class Point<T>{
private T t1;
private T t2;
public T getT1() {
return t1;
}
public void setT1(T t1) {
this.t1 = t1;
}
public T getT2() {
return t2;
}
public void setT2(T t2) {
this.t2 = t2;
}
}
public class GenericDemo {
public static void main(String[] args) {
//String类型的
Point<String> p = new Point<String>();
p.setT1("2");
p.setT2("3");
System.out.println(p.getT1());
System.out.println(p.getT2());
//Integer类型的
Point<Integer> p2 = new Point<Integer>();
p2.setT1(23);
p2.setT2(24);
System.out.println(p2.getT1());
System.out.println(p2.getT2());
//Double类型的
Point<Double> p3 = new Point<Double>();
p3.setT1(23.00);
p3.setT2(24.00);
System.out.println(p3.getT1());
System.out.println(p3.getT2());
//============================
Set<String> s = new HashSet<String>();//创建一个容器对象,应该在创建的时候就明确是装什么的
s.add("a");
//s.add(1);//此时就加不进去了,因为已经限制了容器内参数类型!
//此时就能保证集合里元素类型一致,
Set<Integer> treeSet = new  TreeSet<Integer>();
//规定key只能是String,value是Date
Map<String,Date> map = new HashMap<String,Date>();
// V put(K key, V value)
Date v = map.put("", new Date());//和上面定义的类型一样
//V get(Object key)
Date val = map.get("");
}
}

运行结果
2
3
23
24
23.0
24.0

这样的话借助泛型一个类就可以表达多个不同类型的参数!
要求
消除强制类型的转换,如使用Comparable比较时每次都需要类型强转;
1)、有加上泛型,最初的需要强制类型转换
package generic;
import java.util.Set;
import java.util.TreeSet;
class Person implements Comparable{//需要进行排序的类要实现Comparable
private Integer age;
public Person(Integer age) {
super();
this.age = age;
}
@Override
public int compareTo(Object o) {
Person p = (Person)o;//强制类型转换
return this.age.compareTo(p.age);
}
public String toString(){
return this.age.toString();
}
}
public class GenericDemo2 {
public static void main(String[] args) {
Set set = new TreeSet();
set.add(new Person(15));
set.add(new Person(12));
set.add(new Person(19));
set.add(new Person(53));
set.add(new Person(62));
System.out.println(set);
}
}
2)、加上泛型,不再需要强转(因为类型已经固定了)!
package generic;
import java.util.Set;
import java.util.TreeSet;
class Person implements Comparable<Person>{//
private Integer age;
public Person(Integer age) {
super();
this.age = age;
}
@Override
public int compareTo(Person o) {
return this.age.compareTo(o.age);//按照什么排序
}
public String toString(){
return this.age.toString();
}
}
public class GenericDemo2 {
public static void main(String[] args) {
Set<Person> set = new TreeSet<Person>();
set.add(new Person(15));
set.add(new Person(12));
set.add(new Person(19));
set.add(new Person(53));
set.add(new Person(62));
System.out.println(set);
}
}

3、声明多个泛型类型和通配符
若一个类中多个字段需要不同的泛型声明,则在声明类的时候指定多个泛型类型即可;
格式:
public interface IDAO<PK, T> {
       PK add(T t);
      void remove(PK id);
      void update(PK id, T t);
        T get(PK id);
}
 
在进行引用传递的时候泛型类型必须匹配才可以传递,否则编译不通过;
使用?,表示未知类型的泛型对象:
List<?> 表示未知元素的List集合;
这种带通配符的List仅表示各种泛型List的父类,并不能把元素添加入集合中;
List<?> list = new ArrayList<>(); list.add(1);//ERROR
public void show(List<?> list){}
//表示可接受任意类型的List集合
 
4、泛型的上限与下限
设置泛型对象的上限使用extends,表示参数类型只能是该类型或该类型的子类:
声明对象:类名<? extends类> 对象名
定义类:类名<泛型标签 extends类>{}
设置泛型对象的下限使用super,表示参数类型只能是该类型或该类型的父类:
声明对象:类名<? super类> 对象名称
定义类:类名<泛型标签 extends类>{}
 
public static void  show(List<? extends Number> l){
}
public static void  show(List<? super String> l){
}
public static void show(List<? extends Number> l){}
public static void show(List<? super String> l){}

泛型的上限
public static void main(String[] args) {
Person<Integer> p1 = new Person<>();
p1.setVal(99);
Person<Double> p2 = new Person<>();
p2.setVal(3.14);
Person<String> p3 = new Person<>();
p3.setVal("007");
show(p1);//√
show(p2);//√
show(p3);//×
}
public static void show(Person<? extends Number> p){//此处限定了Person的参数类型只能是Number或者是其子类,而String并不属于Number。
System.out.println(p.getVal());
}

泛型的下限
public static void main(String[] args) {
Person<Integer> p1 = new Person<>();
p1.setVal(99);//Integer
Person<Double> p2 = new Person<>();
p2.setVal(3.14);//Double

Person<String> p3 = new Person<>();
p3.setVal("007");//String
Person<Object> p4 = new Person<>();
p4.setVal(new Object());//Object

show(p1);//×
show(p2);//×
show(p3);//√
show(p4);//√
}
public static void show(Person<? super String> p){
System.out.println(p.getVal());
}

很好的例子!
package generic;
import java.util.ArrayList;
import java.util.List;
public class GenericDemo3 {
public static void main(String[] args) {
//因为show方法是用List<?>通配符接收的,所以可以是任意类型!
List<String> l1 = new ArrayList<>();//new ArrayList<String>()
show(l1);
List<Double> l2 = new ArrayList<>();
show(l2);
List<Number> l3 = new ArrayList<>();
show(l3);
List<Object> l4 = new ArrayList<>();
show(l4);
//使用up方法的话接收类型为Number或者其子类
//up(l1);//错误,因为up方法接收类型为Number或者其子类,l1(String)不符合!
up(l2);
up(l3);
//使用down方法的话接收类型为Number或者其父类
//down(l2);error
down(l3);
down(l4);
}
public static void down(List<? super Number> l){

for (Object object : l) {
System.out.println(object);
}
}
public static void up(List<? extends Number> l){

for (Object object : l) {
System.out.println(object);
}
}
public static void show(List<?> l){

for (Object object : l) {
System.out.println(object);
}
}
}

5、泛型接口和方法
java5后,可以声明泛型接口,声明方式和声明泛型类是一样的。
public interface IDAO<T>{}
泛型接口子类有两种方式:
直接在子类后申明泛型;
在子类实现的接口中给出具体的泛型类型
public class DaoImpl<T> implements IDAO<T>{}
public class DaoImpl implements IDAO<String>{}
 
泛型方法
方法中可定义泛型参数,形参的参数类型就是实参的类型。
格式:
<泛型标签>返回值类型方法名([泛型标签参数]...)
 
public static <T extends Number> List<T> show(T……t){
       return null;
}
.....main.....{
       //Show(new Object[]{});不可以,因为方法参数类型的限定
Show(new Number[]{});
Show(new Integer[]{});
}
 
6、泛型的嵌套(map例子)
 
package com.demo;
//泛型加Map的输出!
import java.util.Iterator;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;
import java.util.TreeMap;
public class GenericMapDemo {
public static void main(String[] args) {
Map<Integer, String> m = new TreeMap<Integer, String>();
m.put(1, "张三");
m.put(2, "李四");
m.put(3, "王五");
System.out.println(m);
//第一种方式,用到了entrySet方法
Set<Entry<Integer, String>> s = m.entrySet();
Iterator<Entry<Integer, String>> it = s.iterator();
while(it.hasNext()){
Entry<Integer, String> e = it.next();//用到了泛型,这里消除了强转!
System.out.println(e.getKey()+"  "+e.getValue());
}
//第二种方法,用到了keySet方法
Set<Integer> set = m.keySet();
Iterator<Integer> iter = set.iterator();
while(iter.hasNext()){
Integer i = iter.next();//直接写到输出语句,出错!
System.out.println(i+"  "+m.get(i));
}
}
}


 
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息