1、泛型类:
在写容器之前想要容器中要存什么?所以要先写好泛型
Eg:TreeSet<Person>ts=new TreeSet<Person>();
有了泛型后就不要强转
Eg:public class Person implementsComparator<Person>{}
对于下面覆盖的它的compare方法就不用强制转换了。
public int compare(Person p){}这里就不用在做强制转换了。
实现代码:
public static void main(String[] args){
Tool t=new Tool();
t.setObject(new Cat());
t.setObject(new Dog());这时编译会出现没问题,但是运行时会出现错误,因为发生了类型转换异常,dog不能转换成Cat。
Cat c=(Cat)t.getObject();
Tool<Cat> t=new Tool<Cat>();
t.setObject(new Cat());此时就不用强转了
t.setObject(new Dog()):此时编译就失败,把运行时的异常转到编译时候。
}
class Cat{}
class Dog{}
/*
class Tool{
private Object obj;
public void setObject(Object obj){
this.obj=obj;
}
public Object getObject(){
return obj;
}
}
*/
改进后
Class Tool<T>{
private T t;
public void setObject(T t){
this.t=t;
}
public T getObject(){
return t;
}
}
总结:这就是将泛型定义在类上,这个类称为泛型类,是一种替代Object类的一种技术,因为Object类有自动类型提升和转换,泛型已经替代它做了,编译时期更安全,省去了强转的麻烦。
什么时候使用泛型类?当类中要操作的引用数据类型不确定的时候,以前使用的是共性类型Object现在可以使用泛型来解决,比Object更为安全。
2、泛型方法:既然类中的方法操作类型不确定,其实可以将泛型定义在方法上。
实现代码:
Tool<String> t=new Tool2<String>();
t.show(newInteger(5));编译失败,因为类型不一致。
Tool2<Integer> t1=new Tool2<Integer>();这样便可以操作Integer类型的对象了。
t.show();
classTool2<T>{
显示对象的打印结构,可是对象不确定,所以使用Object,而现在可以使用泛型解决。
<W>void show(W obj){
System.out.println(obj);
}
当静态方法的时候,如果方法是静态的是无法访问类上定义的泛型的,如果该方法还需要泛型,必须将泛型定义在方法上,
static <Y> void static Method(Y t){}
泛型定义在方法上时只能放在返回值的前面和修饰符的后面
}
什么时候使用泛型方法?当方法操作的引用数据类型不确定的时候就使用。
3、泛型接口:
实现代码:
InterfaceInter<T>{
void show(T t);
}
class InterImpl implements Inter<String>{
public void show(String str){
Sop(str);
}
}
不明确的时候用上面这种,但是当我们明确了类型时候使用下面的这种情况
class InterImpl<W> implements Inter<w>{
public void show(W w){}
}
public staticvoid main(String[] args){
new InterImpl().show("haha");
}
4、泛型通配符:不带泛型也是可以的,因为新的可以兼容前面的,因为泛型擦除之后它还是Object注意区分T t代表某一种
实现代码:
public staticvoid main(String[] args){
ArrayList<Student> al=new ArrayList<Student>();
al.add(new Student("lisi",21));
al.add(new Student("lisi2",22));
al.add(new Student("lisi3",23));
ArrayList<Worker> al2=new ArrayList<Worker>();
al2.add(new Student("lisiw",23));
al2.add(new Student("lisiq",24));
al2.add(new Student("lisisdsdf",23));
ArrayList<String> al3=new ArrayList<String>();
printCollection(al);
printCollection(al2);
}
public staticvoid printCollection(Collection<? super Student> coll)
{
Iterator<? Super Student> it=coll.iterator();
While(it.hasNext()){
Student p=it.next();
System.out.println(p.getName()+p.getAge());
Object obj=it.next();
System.out.println(obj.toString());
}
}
对集合中的元素进行迭代的功能,因为打印集合中的元素类型是不确定的,无法明确,可以使用泛型中的通配符来完成,该通配符用?来标示,
如果要对操作的类型进行限定,只操作一部分类型时,可以使用泛型的高级功能,泛型的限定。
? extends E:可以接收E类型和E的子类型。
? super E:可以接收E类型或者E的父类型。
实现代码:
public staticvoid printCollection(Collection<? Extedns Person> coll){
Iterator<? extends Person> it = coll.iterator();
while(it.hasNext()){
Person p =it.next();
System.out.println(p.getName()+"-----"+p.getAge());
}
}
5、什么时候使用E extends?
一般在存储具体引用类型时使用这种情况,因为存储E类型或者E类型的子类,这时可以保证类型是安全的。
实现代码:
public static void main(String[] args) {
Collection<Person> coll = newArrayList<Person>();
coll.add(newPerson("abc1",21));
coll.add(newPerson("abc2",22));
Collection<Student> coll2 = newArrayList<Student>();
coll2.add(newStudent("lisi1",31));
coll2.add(newStudent("lisi2",32));
coll2.add(newStudent("lisi3",33));
Collection<Worker> coll3 = newArrayList<Worker>();
coll3.add(newWorker("lisi11",31));
coll3.add(newWorker("lisi22",32));
coll.addAll(coll2);
coll.addAll(coll3);
Iterator<Person> it =coll.iterator();
while(it.hasNext()){
Personstu = it.next();
System.out.println(stu.getName());
}
}
6、泛型下限:
下限什么时候用?
从集合中取出对象进行操作时,可以使用下限。比如:比较器。无论集合中的元素对象的类型是什么,只要比较器的指定的类型可以接受这些对象完成比较,就可以了。所以比较器的类型,可以是集合中当前元素的类型,也是可以该元素类型的父类型。
实现代码:
public staticvoid main(String[] args) {
TreeSet<Student>ts = new TreeSet<Student>(new ComparatorName());
ts.add(newStudent("lisi1",21));
ts.add(newStudent("lisi2",28));
ts.add(newStudent("lisi9",23));
ts.add(newStudent("lisi7",27));
TreeSet<Worker>ts2 = new TreeSet<Worker>(new ComparatorName());
ts2.add(newWorker("lisi11",41));
ts2.add(newWorker("lisi22",48));
ts2.add(newWorker("lisi99",43));
ts2.add(newWorker("lisi77",47));
printCollection(ts);
printCollection(ts2);
}
public static void printCollection(TreeSet<? extends Person> ts2) {
Iterator<?extends Person> it = ts2.iterator();
while(it.hasNext()){
Person p = it.next();
System.out.println(p.getName()+":"+p.getAge());
}
}
}
class ComparatorName implements Comparator<Person>{
@Override
public int compare(Person o1, Person o2){//Person o1 = new Student("lisi1",21)
int temp = o1.getName().compareTo(o2.getName());
return temp==0?o1.getAge()-o2.getAge():temp;
}
}
下限什么时候用?
从集合中取出对象进行操作时,可以使用下限。比如:比较器。
无论集合中的元素对象的类型是什么,只要比较器的指定的类型可以接受这些对象完成比较,就可以了。
所以比较器的类型,可以是集合中当前元素的类型,也是可以该元素类型的父类型。
7、Map集合:
特点:
1、它是集合框架中的顶层。
2、它一次存储一对元素,一个叫键,一个叫值,也就是键值对。
Collection一次存一个,称为单列集合。
Map一次存一对,称为双列集合。
3、map集合中必须保证键的唯一性。
4、如果存储键值对时,键出现重复,新值覆盖旧值,其实map集合存储的是映射关系。
8、Map常见的方法:
该集合存储的键值对,一对一对的往里存,而且要保证键的唯一性。
1、添加:
put(key,value);
putAll()
2、删除:
clear();
remove(key);根据键来删,因为键唯一。
3、判断:
containKey():
containVlaue();
isEmpty();
4、获取:
get(Object key);
size();获取长度。
values();获取所有的值。张三对的北京人,李四对应上海人。所以要把所有的值都获取,看。
entrySet();将map集合中的映射关系
map.Entry其实Entry也是一个接口,它是map接口中的一个内部接口。
Interface Map{
publicstatic interface Entry{
public abstract Object getKey();
public abstract Object getValue();
}
}
keySet();将map中所有的键都存入了set集合,因为set具备迭代器,所以可以迭代方式取出所有的键,在根据get方法获取每一个键对应的值。
Map集合的取出原理:将map集合转成set集合,在通过迭代器取出
2、Map
|--Hashtable:低层是哈希表数据结构,不可以存入null作为键和null作为值。该集合是线程同步的。JDK1.0
|--HashMap:低层是哈希表数据结构,该集合是不同步的,允许使用null键和null值。JDK1.2效率高
|--TreeMap:低层是二叉树数据结构,线程不同步,可以用于给Map集合中的键进行排序。
map集合被使用是因为具备映射关系。
4、collections:
1、里面的方法都是静态的。
2、没有构造函数是因为不用创建对象的。