八、黑马程序员—集合框架(2)
第八篇 集合框架(2)
1、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) 在指定列表的指定位
置处交换元素。
*/
}
}
2、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);
}
}
3、泛型(Generic)
引入:我想使用 List 集合装公司的员工,却装了一条狗进来;
使用 TreeSet 的时候,只能存放同一种数据类型,可惜存了不同的数据类型,依然没有报错,可是
运行时出错.
泛型定义:
java5 开始出现的一种对 Java 语言类型的一种拓展,以支持创建可以按类型进行参数化
的类.可以把类型参数看作是使用参数类型时指定的类型占位符,就好比方法的形式参数是实
际参数的占位符一样.
泛型能保证大型应用程序的类型安全和良好的维护性;
使用泛型的优势:
类型安全,使编译器对泛型定义的类型做判断限制.如保证 TreeSet 里的元素类型必须一
致;消除强制类型的转换,如,使用 Comparable 比较时每次都需要类型强转;
4、泛型的使用
泛型类
在类声明时通过一个标识符表示类中某个字段的类型或者某个方法的返回值或参数的
类型,这样在类声明或实例化的时候只要指定自己需要的类型就 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);
}
}
第二步:加上泛型,不再需要强转(因为类型已经固定了)!
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);
}
}
5、声明多个泛型类型和通配符
若一个类中多个字段需要不同的泛型声明,则在声明类的时候指定多个泛型类型即可;
格式:
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 集合
6、泛型的上限与下限
设置泛型对象的上限使用 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);
}
}
}
7、泛型接口和方法
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[]{});
}
8、泛型的嵌套(map 例子)
package july7;
//泛型加Map的输出!
import java.util.Iterator;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;
import java.util.TreeMap;
public class Demo20 {
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));
}
}
}