目录
为什么要用泛型?
因为在定义集合的时候,没有明确存储的数据类型,当存了不同数据类型的元素时会出现错误,这样就有了安全隐患,为了解决这个安全隐患就提出了泛型
泛型格式:
通过<>来定义要操作的引用数据类型
示例:
//定义了一个ArrayList容器,容器中存的数据类型是String类型
ArrayList<String> a1 = new ArrayList<String>();
在使用java提供的对象时,什么时候写泛型?
通常在集合框架中很常见,只要见到<>就要定义泛型,其中<>是用来接收类型的,当使用集合时,将集合中要存储的数据类型作为参数传递到<>中即可
使用泛型的好处:
- 将运行时期出现问题ClassCastEcception,转移到了编译时期,方便于程序员解决问题,让运行事情问题减少,安全
- 避免了强制转换麻烦,而且安全了很多
好处一:
class GennericDemo
{
public static void main(String[] args)
{
ArrayList<String> a1=new ArrayList<String>();
a1.add("abc01");
a1.add("abc0991");
a1.add("abc0991");
a1.add(4); //会在编译时报错
Iterator<Stirng> it=a1.iterator();
while(it.hasNext())
{
String s =it.next();
System.out.println(s+":"s.length())
}
}
}
好处二:
//没有泛型时
class LenComparator implements Comparator
{
public int compare(Object o1,Object o2)
{
String s1=(Stirng)o1;
String s2=(Stirng)o2;
}
}
//有了泛型之后
class LenComparator implements Comparator<String>
{
public int compare(String o1,String o2)
{
}
}
泛型类
什么时候定义泛型类?
当类中要操作的引用数据类型不确定的时候,在其定义Object来完成扩展,现在定义泛型来完成扩展
//没有泛型时候定义工具类
class Worker
{
}
class Student
{
}
class Tool
{
private Object obj;
public void setObject(Object obj)
{
this.obj=obj;
}
public Object getObject()
{
return obj;
}
}
class GenericDemo
{
Tool t=new Tool();
//如果将new Student()换成new Worker(),不会在编译时期出错,会在运行时期出错,不具有安全性
t.setObject(new Student());
Worker w=(Worker)t.getObject();
}
//有泛型时候定义工具类
class Worker
{
}
class Student
{
}
class Utils<T>
{
private T t;
public void setObject(T t)
{
this.t=t;
}
public T getObject()
{
return t;
}
}
class GenericDemo
{
Utils<Worker> u=new Utils<Worker>();
//如果将new Worker换成new Student(),那将会在编译时期报错
u.setObject(new Worker());
//不需要强制转换
Worker w=u.getObject();
}
泛型类定义的泛型,在整个类中有效,如果被方法使用,那么泛型类的对象明确要操作的具体类型后,所要操作的类型就已经固定了
为了让不同方法可以操作不同类型,而且类型还不确定,那么可以将泛型定义在方法上
泛型方法
//普通类中的泛型方法
class Demo
{
public <T> void show(T t)
{
System.out.println("show:"+t);
}
public <Q> void print(Q q)
{
System.out.println("print:"+q);
}
}
class GenericDemo
{
public static void main(String[] args)
{
Demo d=new Demo();
d.show("haha");
d.show(new Integer(4));
}
}
//输出:
haha
4
//泛型类中的泛型方法
class Demo<T>
{
public void show(T t)
{
System.out.println("show:"+t);
}
public <Q> void print(Q q)
{
System.out.println("print:"+q);
}
}
class GenericDemo
{
public static void main(String[] args)
{
Demo<String> d=new Demo<String>();
//show方法中只能添加string类型,不能添加其他类型
d.show("haha");
d.print(5);
d.print("haha");
}
}
//输出:
haha
5
haha
静态方法:
静态方法不可以访问类上定义的泛型(因为静态方法创建的时候对象可能还没创建),如果静态方法操作的应用数据类型不确定,可以将泛型定义在方法上
错误实例
class Demo<T>
{
public void show(T t)
{
System.out.println("show:"+t);
}
public <Q> void print(Q q)
{
System.out.println("print:"+q);
}
//这样会报错
public static void method(T t)
{
System.out.println("method:"+t);
}
}
正确示例
class Demo<T>
{
public void show(T t)
{
System.out.println("show:"+t);
}
public <Q> void print(Q q)
{
System.out.println("print:"+q);
}
//这样会报错
public static <W> void method(W w)
{
System.out.println("method:"+w);
}
}
泛型接口
//在实现接口的时候规定数据类型
interface inter<T>
{
void show(T t);
}
class InterImp implements Inter<String>
{
public void show(String t)
{
System.out.println("show:"+t);
}
}
class GenericDemo
{
public static void main(String[] args)
{
InterImpl i =new InterImpl();
i.show("haha");
}
}
//在用类的时候指定类型
interface inter<T>
{
void show(T t);
}
class InterImp<T> implements Inter<T>
{
public void show(T t)
{
System.out.println("show:"+t);
}
}
class GenericDemo
{
public static void main(String[] args)
{
InterImpl<Integer> i =new InterImpl<Integer>();
i.show(4);
}
}
泛型的限定
?通配符,也可以理解为占位符
泛型的限定:
为什么会出现?
因为要简便的传入父子类
?extends E:可以接收E类型或者E的子类型,上限
?super E:可以接收E类型或者E的父类型,下限
?均表示接收的对象
上限:
接收,用上限
<? extend T>
collection<? extend T> colle 用来接收对象,这里接收的对象是未知对象。
理解:只要是T或者T的子类,,就可以接收
就可以使用这个方法,如:T是Person,那么他的子类Student\Worker都可以使用这个方法
?是待定类型,T是已知类型
下限:
取出,用下限
<? super T>
理解,只要是T或者T的父类,就可以取出
取集合的类型,用集合的父类型接收,保证所有元素全能接收到。
比如我们给Person写一个比较器
我们用comparator<? super T> comp接收对象(接收的对象是已经写好的比较器)
如果接收的对象是Student ,那么只要我们有Student或者Student父类的比较器,我们就可以取出里面的方法来使用
这样就能保证我们对Person写了比较器,对Person以及Person的子类同样适用
?是已知类型,T是待定类型,T就是我们就是我们将要传入的对象,一般为已知类型的子类