以下是我学习java集合框架的笔记,内容主要是个人理解和网络视频、文章的摘录。
首先为了方便下面代码的理解,这里先提一下一些下面会用到的三个对象:Person、Student和Worker。
Person的属性只有String类型的name和int类型的age,其他就是一些基本的方法
Student和Worker都是完全继承Person类,都没有新的属性
下面开始正题
泛型,字面上理解是一个广泛的类型。
在jdk1.4版本之前,容器什么类型的对象都可以存储。但是在取出时,需要用到对象的持有内容时,需要做向下转型。但是对象的类型不一致,导致了向下转型发生了ClassCastException异常。为了避免这个问题,只能主观上控制,往集合中存储的对象类型保持一致。
jdk1.5以后解决了这个问题,在定义集合时,就直接明确集合中存储元素 的具体类型。这样,编译器在编译时,就可以对集合中存储的对象类型进行检查。一旦发现类型不匹配,就编译失败。这个技术就是泛型技术。
以下是一个例子
public static void main(String[] args) {
List<String> list=new ArrayList<String>();
list.add("haha");
list.add("abc");
for(Iterator<String> it=list.iterator();it.hasNext();){
String str=it.next();
System.out.println(str);
}
}
这里的<String>就是泛型的表示
注:这里额外提醒int的类型的要写Integer
所以泛型具有以下优点:
1:将运行时期的问题转移到了编译时期,可以更好的让程序员发现问题并解决问题
2:避免了向下转型的麻烦
总结:泛型就是应用在编译时期的一项安全机制
那么泛型是如何作用的呢?
泛型的擦除:编译器通过泛型对元素类型进行检查,只要检查通过,就会生成class文件,但在class文件中,就将泛型标识去掉了
泛型的表现:泛型技术在集合框架中应用的范围很大。什么时候需要写泛型呢?1:只要看到类,或者接口在描述的时候右边定义<>,就需要泛型。其实是,容器在不明确操作元素的类型的情况下,对外提供了一个参数<>。使用容器时,只要将具体的类型实参传递给该参数即可。简单来说,泛型就是,传递类型参数。
泛型类:jdk1.4时,类型向上抽取,当要操作的对象类型不确定的时候,为了扩展,可以使用Object类型来完成,但是这种方式有一种弊端,就是向下转型容易在运行时期发生ClassCastException。因此,jdk1.5以后,新的解决方案来了。就是类型不确定时,可以对外提供参数。有使用者通过传递参数的方式完成类型的确定。如下列例子,Util<w>就是一个泛型类
public class GenericDemo4 {
public static void main(String[] args) {
Util<Student> util=new Util<Student>();
util.setObj(new Student());//如果类型不匹配,直接编译失败
Student stu=util.getObj();//避免了向下转型
System.out.println(stu);
}
}
class Util<w>{
private w obj;
public final w getObj() {
return obj;
}
public final void setObj(w obj) {
this.obj = obj;
}
}
泛型方法:
public class GenericDemo5 {
public static void main(String[] args) {
// TODO Auto-generated method stub
Demo<String> d=new Demo<String>();
d.show("abc");
// d.show(6);这个调用的不是泛型方法,6不是String类型,所以不对
d.print("abc");
d.print(6);
d.staticShow(6);
d.staticShow("abc");
}
}
class Demo<W>{
public void show(W w){
System.out.println("show:"+w);
}
public static <A> void staticShow(A a){
//这里注意,静态方法是无法访问类型上定义的泛型的。
//如果静态方法需要定义泛型,泛型只能定义在方法上
System.out.println("staticShow:"+a);
}
public <Q> void print(Q w){//泛型方法
System.out.println("print:"+w);
}
}
public class GenericDemo6 {
public static void main(String[] args) {
// TODO Auto-generated method stub
SubDemo d=new SubDemo();
d.show("abc");
}
}
interface Inter<T>{//泛型接口
public void show(T t);
}
//这是第一种用到接口的类,明确了类型是String
class InterImpl1 implements Inter<String>{
@Override
public void show(String t) {
// TODO Auto-generated method stub
}
}
//这是第二种用到接口的类,没有明确类型,所以还是用的泛型。类型在他的子类SubDemo上定义
class InterImpl2<w> implements Inter<w>{
@Override
public void show(w t) {
// TODO Auto-generated method stub
System.out.println("show:"+t);
}
}
class SubDemo extends InterImpl2<String>{}
通配符:
在不明确具体类型的情况下,可以使用通配符“?”来表示
public class GenericDemo7 {
public static void main(String[] args) {
List<Student> list=new ArrayList<Student>();
list.add(new Student("abc1",21));
list.add(new Student("abc2",22));
list.add(new Student("abc3",23));
printCollection(list);
Set<String> set=new HashSet<String>();
set.add("haha");
set.add("xixi");
set.add("hoho");
printCollection(set);
}
private static void printCollection(Collection<?> coll) {//因为不确定是Person还是String类型,所以这里就使用了通配符
for(Iterator<?> it=coll.iterator();it.hasNext();){
Object obj=it.next();//这里注意使用了通配符,就要使用Object
System.out.println(obj);
}
}
}
限定
? extends E:接受E类型或者E的子类型,也就是限定了上限
? super E:接受E类型或者E类型的父类型,也就是限定了下限
(1)上限应用
public class GenericDemo9 {
public static void main(String[] args) {
// TODO Auto-generated method stub
Collection<Student> coll=new ArrayList<Student>();
coll.add(new Student("abc1",21));
coll.add(new Student("abc2",22));
coll.add(new Student("abc3",23));
coll.add(new Student("abc4",24));
TreeSet<Person> ts=new TreeSet<Person>(coll);
ts.add(new Student("abc5",25));
for(Iterator<Person> it=ts.iterator();it.hasNext();){
Person person=it.next();
System.out.println(person.getName());
}
}
}
class MyTreeSet<E>{
MyTreeSet(){}
MyTreeSet(Collection<? extends E> c){}
}
(2)下限应用
public class GenericDemo10 {
public static void main(String[] args) {
Comparator<Person> comp=new Comparator<Person>(){
@Override
public int compare(Person o1, Person o2) {
// TODO Auto-generated method stub
int temp=o1.getAge()-o2.getAge();
return temp==0?o1.getName().compareTo(o2.getName()):temp;
}
};
TreeSet<Student> ts=new TreeSet<Student>(comp);
ts.add(new Student("abc1",21));
ts.add(new Student("abc2",28));
ts.add(new Student("abc3",23));
ts.add(new Student("abc4",25));
TreeSet<Worker> ts2=new TreeSet<Worker>(comp);
ts2.add(new Worker("abc1",51));
ts2.add(new Worker("abc2",58));
ts2.add(new Worker("abc3",53));
ts2.add(new Worker("abc4",55));
for(Iterator<Student> it=ts.iterator();it.hasNext();){
Student student=it.next();
System.out.println(student);
}
for(Iterator<Worker> it=ts2.iterator();it.hasNext();){
Worker worker=it.next();
System.out.println(worker);
}
}
}
class YouTreeSet<E>{
YouTreeSet(Comparator<? super E> comparator){}
}
这里可以看出,无论是ts还是ts2,他们的父类都是Person,所以比较方法用Person为类型时,可以被他们使用
以上大多知识点摘自学习视频,如有侵权,请联系修改