您的位置:首页 > 其它

集合框架之二 泛型-Map

2013-08-03 00:47 323 查看
-------android培训java培训、期待与您交流!
----------
泛型:jdk1.5版本,出现的技术。是一个安全机制。

泛型技术的由来:

集合中可以存储任意类型对象,但是在取出时,如果要使用具体对象的特有方法时,需要进行向下转型,

如果存储的对象类型不一致,在转型过程中就会出现ClassCastException异常。

这样就给程序带来了不安全性。

示例:

public static void methodDemo(){
ArrayList al = new ArrayList();
al.add("abc");
al.add("nba");
al.add("scdn");
al.add(6);//这样在编译时不会报错,在运行时会出现ClassCastException
Iterator it = coll.iterator();
while(it.hasNext()){
String str = (String)it.next();
System.out.println(str);
}
}

因为对象元素存入时都被提升为了Object,所以取出时要向下转型,转型就需要类型确定,而集合添加元素的时候类型不一致的话向下转型就不知道要转成什么类型,所以会出现异常。

在jdk1.5以后就有了解决方案。就是泛型技术。

解决方案就是,在存储元素时,就不允许存储不同类型的元素。

存储了就编译失败。

所以就需要在存储元素时,在容器上明确具体的元素类型。这其实和数组定义很像。

示例:

public static void methodDemo(){
ArrayList<String> al = new ArrayList();
al.add("abc");
al.add("nba");
al.add("scdn");
//	al.add(6);//这样在编译时就会报错,存不进去
Iterator<String> it = coll.iterator();
while(it.hasNext()){
System.out.println(it.next());//不需要向下转型
}
}


泛型的好处:

1,将运行时期的ClassCastException异常转移到了编译事情,进行检查,并以编译失败来体现。

这样有利于程序员尽早解决问题。

2,避免了向下转型(强转)的麻烦

什么时候写泛型呢?

先简单理解:只要在使用类或者接口时,该类或者接口在api文当描述时都带着<>就需要在使用时,定义泛型。

其实,泛型无非就是通过<>定义了一个形式参数。专门用于接收具体的引用类型。

在使用时,一定要传递对应的实际参数类型。

集合中泛型的应用特别多见。

泛型的擦除:

泛型技术是用于编译时期的技术,编译器会按照<>中的指定类型对元素进行检查,

检查不匹配,就编译失败,匹配,就编译通过,通过后,生产的class文件中是没有泛型的。这就成为泛型的擦除。

泛型的补偿:

运行时,可以根据具体的元素对象获取其具体的类型。并用该类型对元素进行自动转换。

如果要操作的类型不确定但是不一定和调用该方法的对象指定的类型一致。那么可以将泛型定义在方法上。

静态方法不能访问类上定义的泛型,如果需要泛型,该泛型只能定义在方法上。

比如:定义一个功能,只操作Person类型或者Person的子类型。

泛型演示:

public class GenericDemo3 {
public static void main(String[] args) {
Tool2<String> t = new Tool2<String>();
t.show("abc");
t.myprint("haha");
t.myprint(new Integer(4));
}
}
class Tool2<W>{
public void show(W w){
System.out.println("show:"+w.toString());
}
public <A> void myprint(A a){
System.out.println("myprint:"+a.toString());
}
public static <Y> void method(Y w){
System.out.println("method:"+w);
}
}

泛型通配符:?

当操作的不同容器中的类型都不确定时,而且使用的都是元素从Object类中继承的方法。

这时就要用通配符 ? 来表示即可。

泛型限定:明确具体类型代表哪一个类型,明确?代表哪一个类型。

将操作的类型限制在一个范围之内:? extends E :接收E类型或者E的子类型。这就是上限。

下限:? super E: 接收E类型或者E的父类型。

例如:

public static void print(Collection<? extends Person> coll){
Iterator<? extends Person> it = coll.iterator();
while(it.hasNext()){
System.out.println(it.next().getName());
}
}


什么时候使用上限呢?一般情况下,只要往容器中添加元素时,使用上限。 ? extends E

演示上限:

public static void extendsE(){
Collection<Student> coll = new ArrayList<Student>();
coll.add(new Student("lisi1",21));
coll.add(new Student("lisi0",25));
coll.add(new Student("lisi2",24));

TreeSet<Person> ts = new TreeSet<Person>(coll);//将coll中的元素存到TreeSet中
ts.add(new Person("zhangsan",23));

Iterator<Person> it = ts.iterator();
while(it.hasNext){
Person p = it.next ;
System.out.println(p.getName+":::"+p.getAge);
}
}

什么时候使用下限呢?一般情况下,只要从容器中取出元素时,使用下限。 ? super E

演示下限:

public static void superE(){
TreeSet<Student> ts1 = new TreeSet<Student>(new CompByName());
ts1.add(new Student("zhangsan2",20));
ts1.add(new Student("zhangsan0",25));
ts1.add(new Student("zhangsan3",22));
Iterator<Student> it1 = ts1.iterator();
while(it1.hasNext()){
Person p = it1.next();
System.out.println(p.getName()+":::student:::"+p.getAge());
}
TreeSet<Worker> ts2 = new TreeSet<Student>(new CompByName());
ts2.add(new Worker("zhangsan2",20));
ts2.add(new Worker("zhangsan0",25));
ts2.add(new Worker("zhangsan3",22));
Iterator<Worker> it2 = ts2.iterator();
while(it2.hasNext()){
Person p = it2.next();
System.out.println(p.getName()+":::student:::"+p.getAge());
}
}
class CompByName implements Comparator<Person>{
public int compare(Person o1, Person o2) {
int temp = o1.getName().compareTo(o2.getName());
return temp==0? o1.getAge()-o2.getAge():temp;
}
}


jdk1.5以后 出现的新方式。这种升级就是简化书写。

Collection有了一个父接口,Iterable

该接口封装了iterator方法,同时提供了一个新的语句。foreach语句(增强for循环)。

格式:

for(变量 : Collection集合or数组){

}

1,foreach循环简化了迭代器。迭代器还用吗?用,因为迭代过程中还可以remove().

一般只对基本遍历简化使用。

2,和传统for循环有什么区别呢?

foreach循环特点:必须明确被遍历的目标。没有目标没用。目的只能是数组或者Collection集合(Map集合不可以)。

如果要对数组的中的元素进行特定操作时,建议传统for循环,通过角标完成。

注意:foreach语句一般结合泛型使用。

Map:集合框架中的另一个顶层接口

Map:用于存储具备着对应关系的键和值。

而且要保证键的唯一性。

一次存储一对儿元素。

Collection一次存储一个元素,称之为单列集合。

Map集合一次存储一对儿元素,称之为双列集合。

Map常见方法:

1,添加。注意:在map集合中存储了相同的键,新值会替换就值。put方法会返回新值

v put(k,v):

void putAll(map);

2,删除。

void clear():清空集合。

v remove(key):通过键删除元素,并返回对应的值。

3,判断。

boolean containsKey(key);

boolean containsValue(value);

boolean isEmpty();

4,获取。

value get(key):根据键获取值。如果键不存在,返回null。可以用来判断一个集合中是否存在某一个键。

5,获取map中所有的元素(对应关系)。

Map是不具备迭代器的,获取原理就是将map集合先转成set集合。然后在使用迭代器。

Set<key> keySet();

Set<Map.Entry<key,value>> entrySet();

Map.Entry:其实entry就是Map接口中的一个内部接口而已

Colection<value> values();获取map集合中所有的值。

Map获取演示:

public static void mapMethodDemo2(Map<Integer,String> map){
map.put(4, "lisi");
map.put(1, "qianyi");
map.put(3, "zhangsan");
map.put(7, "zhouqi");
//通过keySet方法获取map集合中所有的键集
Set<Integer> keySet = map.keySet();
//通过Set集合的迭代器获取所有的键。
Iterator<Integer> it = keySet.iterator();
while(it.hasNext()){
Integer key = it.next();
//通过map集合的get方法可以获取键对应的值。
String value = map.get(key);
System.out.println(key+"::::"+value);
}
}
public static void mapMethodDemo3(Map<Integer,String> map){
map.put(4, "lisi");
map.put(1, "qianyi");
map.put(3, "zhangsan");
map.put(7, "zhouqi");
Set<Map.Entry<Integer, String>> entrySet = map.entrySet();
Iterator<Map.Entry<Integer, String>> it = entrySet.iterator();
while(it.hasNext()){
Map.Entry<Integer, String> me = it.next();
Integer key = me.getKey();
String value = me.getValue();
System.out.println(key+"----"+value);
}
}


Map体系:

|--Hashtable:底层是哈希表数据结构,是线程同步的,不允许null作为键,null作为值。

为了成功地在哈希表中存储和获取对象,用作键的对象必须实现 hashCode 方法和 equals 方法。

|--HashMap:底层是哈希表数据结构,不保证顺序,是线程不同步的,允许null作为键,null作为值。替代了
Hashtable。保证唯一性的依据是hashCode和equals

|--LinkedHashMap:有序。该顺序通常就是将键插入到映射中的顺序(插入顺序),也就是怎么存就怎么取。

|--TreeMap:可以对Map集合中的键进行指定顺序的排序,默认是使用键的自然顺序。当然也可以使用比较器。

存储自定义元素时必须实现Comparable接口,覆盖compareTo方法

LinkedHashMap演示:

public class LinkedHashMapDemo {
public static void main(String[] args) {
Map<Integer,String> map = new LinkedHashMap<Integer,String>();
mapMethodDemo(map);
}
public static void mapMethodDemo(Map<Integer,String> map){
map.put(3, "zhangsan");
map.put(2, "zhaoer");
map.put(5, "wangwu");
map.put(1, "qianyi");
map.put(4, "lisi");
Set<Map.Entry<Integer, String>> entrySet = map.entrySet();
Iterator<Map.Entry<Integer, String>> it = entrySet.iterator();
while(it.hasNext()){
Map.Entry<Integer, String> me = it.next();
Integer key = me.getKey();
String value = me.getValue();
System.out.println(key+"----"+value);
}
}
}


Collections:专门用于操作的集合的工具类。

该类中的方法都是静态的。

Collections 中可以将非同步的方法转成同步的。

Collections常用方法演示:

import java.util.ArrayList;
import java.util.Collections;
import java.util.Iterator;
import java.util.List;
import java.util.TreeSet;

public class CollectionsDemo {

/**
* @param args
*/
public static void main(String[] args) {
//		collectionsDemo1();
//		collectionsDemo2();
collectionsDemo3();

}
/**
* 逆向比较器:Collections.reverseOrder()
*/
public static void collectionsDemo3(){
TreeSet<String> ts = new TreeSet<String>(Collections.reverseOrder());
ts.add("abcde");
ts.add("cba");
ts.add("qq");
ts.add("ak47");
ts.add("zz");
System.out.println(ts);
}
/**
* 取最值:Collections.max(Collection<? extends T> coll)
*/
public static void collectionsDemo2(){
List<String> list = new ArrayList<String>();
list.add("abcde");
list.add("cba");
list.add("qq");
list.add("ak47");
list.add("zz");

//按自然顺序取最大值
String max = Collections.max(list);
System.out.println(max);
}
/**
* 排序:Collections.sort(List<T> list)
*/
public static void collectionsDemo1(){
List<String> list = new ArrayList<String>();
list.add("abcde");
list.add("cba");
list.add("qq");
list.add("ak47");
list.add("zz");
//按自然顺序排序
Collections.sort(list);
System.out.println(list);
}
}


Arrays:专门操作数组的工具类。

该类中的方法都是静态的。

将数组转成集合:asList(list);

注意:将数组转成集合后,不可以用集合的方法往里面添加或删除元素,因为数组的长度是固定的。

Arrays方法演示:

import java.util.Arrays;
import java.util.List;
public class ArraysDemo {
/**
* @param args
*/
public static void main(String[] args) {
//		method_1();
method_2();
}
/**
* 数组转集合
*/
public static void method_2() {
String [] str = {"abc","pptv","javaee","csdn","qq"};
List<String> list = Arrays.asList(str);
System.out.println(list);
}
}

集合转数组:

使用的是Collection接口中的toArray方法。

集合转数组的原因,限制对元素的操作,比如增删。

可变参数:

如果要传入多个参数,而且是同一类型,可以定义数组类型的参数。

但是传递时,必须先有数组对象。

JDK1.5后,为了简化书写,出现了可变参数,同样还是代表数组但是不需要再创建数组对象了

直接将数组中的元素作为参数传递即可。

它会自动的将这些参数封装到数组中。

可变参数的局限性:可变参数必须定义在参数列表的最后面。

如public static int add(int...arr,int a),这时错误写法

可变参数演示:

public class ParamDemo {
public static void main(String[] args) {
int sum = add(2,4,1,5);
System.out.println(sum);

int sum1 = add(1,3,2,5,4,7,6);
System.out.println(sum1);
}
public static int add(int...arr){
int sum = 0 ;
for(int x=0;x<arr.length;x++){
sum += arr[x];
}
return sum;
}
}


-------android培训java培训、期待与您交流!
----------
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: