------Java培训、Android培训、iOS培训、.Net培训、期待与您交流! -------
七、泛型
泛型概述
泛型是JDK1.5以后出现的新特性,用于解决安全问题,是一个安全机制
泛型的好处
1、将运行时期的问题ClassCastException问题转换成了编译失败,体现在编译时期,程序员就可以解决问题
2、避免了强制转换的麻烦
泛型的格式
通过< >来定义操作的引用类型,当使用集合时,将集合中要存储的数据类型作为参数传递到<>里。
在使用java提供的对象时什么时候使用泛型呢
通常在集合框架中很常见,只要见到<>就写泛型
什么时候定义泛型
当类中要操作的引用数据类型不确定的时候
当操作数据类型不确定的时候,可以将泛型定义在类上
public <W> void method(W w)
{
System.out.println("method:"+w);
}
静态方法上的泛型
静态方法上的泛型:静态方法无法访问类上定义的泛型。如果静态方法数据类型不确定的时候必须要将泛型定义在方法上。
public static <Q> void function(Q t)
{
System.out.println("function:"+t);
}
泛型接口
interface Inter<T>
{
void show<T t>;
}
class InterImpl<R> implements Inter<R>
{
public void show(R r)
{
System.out.println("show:"+r);
}
}
泛型通配符
可以解决当具体类型不确定的时候,这个通配符就是?;当操作类型时,不需要使用类型的具体功能时,只使用Object类中的功能。那么可以用?通配符来表示未知类型。
也可以理解为占位符
泛型限定
上限:?extends E:可以接收E类型或者E的子类型对象
下限:? super E:可以接收E类型或者E的父类型对象
局限性:不可以引用数据类型的特有方法
泛型的细节
1、泛型到底是什么类型取决于调用者传入的类型,如果没传,默认是Object类型
2、使用泛型创建对象时,等式两边指定的泛型必须一致
原因:编译器检查对象调用方法时只看变量,然而程序运行期间调用方法时就要考虑对象具体类型了;
3、等式两边可以在任意一边使用泛型,在另一边不使用。(考虑向后兼容)
示例:
import java.util.*;
class GenericDemo
{
public static void main(String[] args)
{
ArrayList<Person> al = new ArrayList<Person>();
al.add(new Person("abc1"));
al.add(new Person("abc2"));
al.add(new Person("abc3"));
ArrayList<Student> al1 = new ArrayList<Student>();
al1.add(new Student("abc--1"));
al1.add(new Student("abc--2"));
al1.add(new Student("abc--3"));
printColl(al1);
}
//定义一个上限的泛型方法
public static void printColl(Collection<? extends Person> al)
{
Iterator<? extends Person> it = al.iterator();
while(it.hasNext())
{
System.out.println(it.next().getName());
}
}
}
class Person//定义父类
{
private String name;
Person(String name)
{
this.name = name;
}
public String getName()
{
return name;
}
}
class Student extends Person//子类学生继承父类
{
Student(String name)
{
super(name);
}
}
八、Map集合
概述
Map集合容器存储的是键Key和Value值的对应关系,即存储键值对。而且要保证键Key的唯一性。
|--Hashtable:底层是哈希表数据结构,是线程同步的。不可以储存null键,null值。
|--HashMap:底层是哈希表数据结构,是线程不同步的。可以存储null键,null值。替代了Hashtable。
|--TreeMap:底层是二叉树结构,可以对map集合中的键进行指定顺序的排序。
Map和Collection的区别
Map一次添加一对元素,Collection一次添加一个元素。Map也称为双列集合,Collection集合称为单列集合。
Map中存储的键和值是对应关系(映射)关系。
特点:要保证map集合中键的唯一性。
方法
1、添加
put(key,value);//当存储的键相同时新的值会替换老的值,并将老的值返回。如果键没有重复返回null.
void putAll(Map);
2、删除
void clear();清空
value remove(key);删除指定键
3、判断
boolean isEmpty();
boolean containsKey(key);是否包含value
boolean containsValue(value):是否包含value
4、取出
int size();返回长度
value get(key);通过指定键获取对应的值。如果返回null,可以判断该键不存在。当然有特殊情况,就是在hashmap集合中,是可以存储null键null值的。
Collection values();获取map集合中所有的值。
如何获取map中所有的元素
map中没有迭代器,Collection具备迭代器,只要将map集合转成Set集合,就可以使用迭代器了
之所以转成Set,是因为map集合具备着键的唯一性,其实set集合来自于map,set集合底层其实使用的就是map方法
Map集合的两种取出方式
keySet:将Map中所有的键存入到Set集合,因为Set具备迭代器。所以可以通过迭代方式取出所有的键,在根据get方法,获取每一个键对应的值。
Set entrySet:将map集合中的映射关系存入到了Set集合中,而这个关系的数据类型是:Map.Entry。(其实Entry也是一个接口,它是Map接口中的一个内部接口)
取出map集合中所有元素的方式
keySet方法
Set keySet = map.keySet();//取出map集合中所有的键
Iterator it = keySet.iterator();//对set集合进行迭代
while(it.hasNext()) {
Object key = it.next();
Object value = map.get(key);//通过get方法对获取键进行值的获取
System.out.println(key+":"+value);
}
entrySet方法
Set entrySet = map.entrySet();//将map映射关系取出存到集合
Iterator it = entrySet.iterator();
while(it.hasNext()) {
Map.Entry me = (Map.Entry)it.next();
System.out.println(me.getKey()+"::::"+me.getValue());//通过getKey和getValue分别获得键和值
}
map方式取出元素练习
代码如下
/*需求
1.描述一个学生
2.定义map容器,将学生作为键,地址作为值,存入。
3.获取map集合中的元素。
*/
import java.util.*;
class MapTest {
public static void main(String[] args) {
HashMap<Student,String> hm=new HashMap<Student,String>();
//Map集合添加元素方法是put,而不是add
hm.put(new Student("lisi01",21),"beijing");
hm.put(new Student("lisi03",23),"guangdong");
hm.put(new Student("lisi02",22),"shanghai");
//keySet取出方式,先取键
Set<Student> keySet=hm.keySet();
Iterator<Student> it=keySet.iterator();//对Set集合进行迭代
while(it.hasNext())
{
Student stu=it.next();
String addr=hm.get(stu);//通过get方法对获取的键进行值的获取
System.out.println("Student:"+stu+"...addr:"+addr);
}
//entrySet取出方式,取出映射关系
Set<Map.Entry<Student,String>> entrySet=hm.entrySet();
Iterator<Map.Entry<Student,String>> it2=entrySet.iterator();
while(it2.hasNext()) {
Map.Entry<Student,String> me=it2.next();
Student stu=me.getKey();
String addr=me.getValue();
System.out.println("Student:"+stu+"_ _ _addr:"+addr);
}
}
}
class Student {
private String name;
private int age;
Student(String name,int age) {
this.name=name;
this.age=age;
}
public String getName() {
return name;
}
public int getAge() {
return age;
}
public String toString() {
return name+":"+age;
}
//自定义对象需要覆写hashCode方法和equals方法
public int hashCode() {
return name.hashCode()+age*39;
}
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;
}
}
"ak+abAf1c,dCkaAbc-defa"获取该字符串中的字母出现的次数。
希望打印结果:a(1)c(2).....
import java.util.*;
class MapTest {
public static void main(String[] args) {
String s= charCount("ak+abAf1c,dCkaAbc-defa");
System.out.println(s);
}
public static String charCount(String str) {
char[] chs = str.toCharArray();
TreeMap<Character,Integer> tm = new TreeMap<Character,Integer>();
int count = 0;
for(int x=0; x<chs.length; x++) {
//每一个字母作为键查map集合
if(!(chs[x]>='a' && chs[x]<='z' || chs[x]>='A' && chs[x]<='Z'))//排除不是字母的元素
//不是字母继续循环
continue;
Integer value = tm.get(chs[x]);//通过get方法获取键所对应的值
if(value!=null)
count = value;
count++;
tm.put(chs[x],count);//put直接往集合中存储字符和数字,为什么可以,因为自动装箱。
count = 0;
}
StringBuilder sb = new StringBuilder();
//将映射关系储存到set集合
Set<Map.Entry<Character,Integer>> entrySet = tm.entrySet();
//获取set集合的迭代器
Iterator<Map.Entry<Character,Integer>> it = entrySet.iterator();
//提取映射关系,获取键和值
while(it.hasNext()) {
Map.Entry<Character,Integer> me = it.next();
Character ch = me.getKey();
Integer value = me.getValue();
sb.append(ch+"("+value+")");
}
return sb.toString();
}
}