黑马程序员--Java基础--集合(二)

------- android培训java培训、期待与您交流! ----------


第六部分:泛型

1、泛型由来:泛型是JDK1.5版本以后出现的新特性,用于解决安全问题,是一个安全机制。
泛型出现的优点:
a、将运行时期出现的异常ClassCastException(类型转换异常),转移到了编译时期。方便程序员解决问题,让运行问题减少,更加安全。
b、避免了强制转换的麻烦。(重点)

2、泛型格式:通过<>符号来定义要操作的引用类型。
其实<>就是用来接收类型的,当使用集合时,将集合中要存储的数据类型作为参数传递到<>括号里。

3、再使用java提供的对象时,什么时候写泛型?
通常在集合的框架中很常见,只要见到<>就要定义泛型
代码示例:
ArrayList<String> al = new ArrayList<String>();//关键句
Iterator<String> it = al.iterator();//关键句
while(it.hasNext())
{
        String s = it.next();//不用强制转换了
        System.out.println(s.length()+"");
}

当使用比较器Comparator时,使用Comparator<类或者数据类型>,则在方法内就不用进行强制转换。
class LenComparator implements Comparator<String>//关键句,这样就不用在compare方法里强转
{
	public int compare(String o1,String o2)
	{
		int num = new Integer(o1.length()).compareTo(new Integer(o2.length()));
		if(num == 0)
			return o1.compareTo(o2);
		return num;
		//如果使用倒序时候:new Integer(o2.length()).compareTo(new Integer(o1.length()));
		//return o2.compareTo(o1)
	}
}

4、泛型类
当类中要操作的引用数据类型不确定时,有早期的做法和使用泛型类的做法。
早期做法:定义对象Object来完成扩展。例如定义工人类Worker和学生类Student,使用Tool对两个类今次那个操作。
代码示例
class Worker{}
class Student{}
//泛型前做法
class Tool
{
	private Object obj;//关键句
	public void setObject(Object obj)
	{
		this.obj = obj;
	}
	public Object getObject()
	{
		return obj;
	}
}

使用泛型类的做法:
//泛型类
class Utils<E>//也是工具类
{
	private E e;
	public void setObject(E e){this.e = e};
	public E getObject(){return e};
}
//主函数内
Utils<Worker> u = new Utils<Worker>();
Worker w = u.getObject();

5、泛型方法
前面提到的泛型类,使用泛型类定义了泛型后,如果泛型类的对象明确了要操作的具体类型后,所有的方法要操作的类型就固定了。
当有些方法要操作的类型不确定时,为了让不同方法可以操作不同的类型,可以使用泛型方法。
代码示例:
class Demo
{
	public <T> void show(T t)
	{
		System.out.println(""+t);
	}
	public <Q> void print(Q q)
	{
		System.out.println(""+q);
	}
}

注意:泛型可以同时定义在类上和方法上,但是使用静态方法是不能访问类上的泛型。
解决办法是,静态方法要使用的泛型应该定义在方法上。
代码示例:
public static <W> void method(W w)

6、泛型接口
interface Inter<T>
{
	void show(T t);
}
class InterImpl<T> implements Inter<T>
{
	public void show(T t)
	{
		sop(""+t);
	}
}
//主函数
InterImpl<Integer> i = new InterImpl<Integer>();
i.show(4);

7、泛型限定:
泛型的限定:
? extends E:可以接收E类型或者子类型,称为上限限定。<>可以接收E或者E的子类型。
? super E:可以接收E类型或者E的父类型,称为下限限定。即<>可以接收E或者E的父类型。例如TreeSet(Comparator<? super E> comparator)

?表示通配符,也表示占位符。 例如<T>可以写为<?>,这是一样的效果

第七部分:Map<Key,Value>集合容器

1、Map:Map集合容器存储的是键Key和Value值的对应关系,即存储键值对。而且要保证键Key的唯一性。
Map和Collection的区别:
Map一次添加一对元素,Collection一次添加一个元素。Map也称为双列集合,Collection集合称为单列集合。

Map结构图:
Map
|----Hashtable:底层是哈希表数据结构,不可以存入null键null值。该集合是线程同步的。JDK1.0。效率低
|--------Properties:用来存储键值对型的配置文件的信息,可以和IO技术相结合。
|----HashMap:底层是哈希表数据结构,允许使用null键null值。该集合是不同步的。JDK1.2。效率高
|----TreeMap:底层是二叉树数据结构。线程不同步。可以用于给map集合中的值Value进行排序。


2、Map<Key,Value>的共性方法

a、添加
value put(key,value):返回前一个和key关联的值,如果没有返回null。
代码示例
Map<String ,String> map = new HashMap<String ,String>();
map.put("01","zhangsan1");
P.S:添加元素,如果出现添加相同的键,那么后添加的值会覆盖原有键对应只。put方法会返回被覆盖的值

b、删除
void clear():清空map集合。
value remove(Object key):根据指定的key删除这个键值对。

System.out.println("remove:"+map.remove("01"));//返回zhangsan1
</pre></div><div><span style="font-size:14px">c、判断</span></div><div><span style="font-size:14px">boolean containsKey(key);</span></div><div><pre name="code" class="java">System.out.println("containsKey"+map.containsKey("02"));//返回false
boolean containsValue(value);
boolean isEmpty();

d、获取
value get(key):通过键获取值,如果没有该键返回null。当然可以通过返回null,来判断是否包含指定键。
int size():获取键值对个数。
Collection<V> values():返回映射中包含的值的Collection视图。
代码示例
//获取map集合中所有的值
		Collection<String> coll = map.values();
		System.out.println(coll);//输出[zhangsan1];

2、重点:Map集合的两种取出方式
a、通过Set<K> keySet()方法:将map中所有的键Key存入到Set集合,因为Set集合具备了迭代器,所以可以同过迭代器方式取出所有的键Key,再根据get方法,获取每一个键对应的值。
原理是:将Map集合转换成Set集合,通过迭代器取出。
代码示例:
class  
{
	public static void main(String[] args) 
	{
		Map<String ,String> map = new Map<String,String>();
		map.put("01","zhangsan1");
		map.put("02","zhangsan2");
		map.put("04","zhangsan4");
		map.put("03","zhangsan3");

		//先获取map集合的所有键的Set集合,keySet()
		Set<String> keySet = map.keySet();//<String>是键的类型
		//有了Set集合。就可以获取其迭代器
		Iterator<String> it = keySet.iterator();
		while(it.hasNext())
		{
			String key = i.next();
			//有了key就可以通过map集合的get方法获取其对应的value
			String value = map.get(key);
			sop(key+":"+value);
		}
	}
}

b、通过Set<Map.Entry<K,V>> entrySet()方法:将Map集合中的映射关系存入到set集合中,而这个关系的数据类型就是Map.Entry。
通过名字可以知道Entry也是一个接口,它是Map接口中的一个内部接口。
代码示例:
class  
{
	public static void main(String[] args) 
	{
		Map<String ,String> map = new Map<String,String>();
		map.put("01","zhangsan1");
		map.put("02","zhangsan2");
		map.put("04","zhangsan4");
		map.put("03","zhangsan3");

		//将map集合中的映射关系取出,存入到set集合中
		Set<Map.Entry<String,String>> entrySet = map.entrySet();

		Iterator<Map.Entry<String,String>> it = entrySet.iterator();

		while(it.hasNext())
		{
			Map.Entry<String,String> me = it.next();
			//getKey()方法获取键
			String key = me.getKey();
			//getValue()方法获取值
			String value = me.getValue(); 
		}
	}
}

c、使用HashMap存储对象时,因为要保证键Key的唯一性,所以自然和hashCode()方法与equals()方法相关。
如果存储的是自定义对象,例如学生类Student,将姓名和年龄相同的视为同一个人,则要覆写hashCode()方法和equals()方法
//和哈希表相关的集合,就必须要想到hashCode()和equals()方法
	public int hashCode()
	{
		return name.hashCode()+age*34;
	}
	public boolean equals(Object obj)//这里不能用泛型
	{
		if(!(obj instanceof Student))
			throw new ClassCastException("类型不匹配");//类型转换异常
		Student s = (Student)obj;
		return this.name.equals(s.name) && this.age==s.age;
	}

使用TreeSet作为存储容器时,若重新实现排序功能,同样需要实现自定义类对象实现Comparable接口并覆写compareTo方法
或者,重新定义一个比较器实现Comparator接口,然后覆写compare方法。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值