------- 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)
}
}
当类中要操作的引用数据类型不确定时,有早期的做法和使用泛型类的做法。
早期做法:定义对象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)
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)
? 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进行排序。
|----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删除这个键值对。
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():获取键值对个数。
int size():获取键值对个数。
Collection<V> values():返回映射中包含的值的Collection视图。
代码示例
//获取map集合中所有的值
Collection<String> coll = map.values();
System.out.println(coll);//输出[zhangsan1];
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);
}
}
}
通过名字可以知道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方法。