泛型:是一种把类型明确的工作推迟创建对象或者调用方法时候才去明确的特殊的类型。参数化类型,把类型当作参数一样的传递
-
这么理解,泛型可以定义类,接口,方法,Collection等等的参数类型。
-
比如说在类上使用泛型,我们一个让这个类的数据不再单一化,可以让此类创建各种类型数据的对象。总之,泛型就相当于多样化的参数传递。
-
格式:
- <数据类型>
- 此处的数据类型只能是引用类型,各种基本数据的包装类和对象等等。
-
优势:
- 把运行时期的问题放到了编译时期
- 避免了强转
- 优化程序设计 解决黄色警告线
public class fanxingDome {
public static void main(String[] args)
{
//创建
ArrayList<String> arrayList = new ArrayList<String>();
将泛型使用在类上,此处说明ArrayList集合里只能存储String类型。
泛型用在集合上,限制了集合的数据,规范使用集合。
//添加
arrayList.add("赛文");
arrayList.add("艾斯");
arrayList.add(123); //123 不是String类型此处将在编译时期报错。
Iterator<String> iterator = arrayList.iterator();
while (iterator.hasNext())
{
String s = iterator.next();
System.out.println(s);
}
}
}
public class ObjectTool<T>{
private T obj;
public T getobj(){
retnurn obj;}
public void setobj(){
this.obj = obj;}
}
public class ObjectToolsTest
{
objectTool<String> ot = new objectTool<String>();
ot.setobj(new String("奥特曼"));
objectTool<Integer> ot1=new objectTool<Integer>();
ot1.setobj(new Integer(10));
}
public interface Inter<T>{
public abstract void show(T t);
}
public class InterImpl<T> implements Inter<T>{
//实现方法
public void show(T t){
---
}
public class Phone {
public <E> void show(E e){
System.out.println(e);
}
}
- 这是在方法上使用泛型。有一点需要说明的是,泛型参数,可以不止定义一个,可以定义多个。
public <E,V> void show(E e) //比如这样,我们可以随意的定义泛型个数但是还要注意具体数据分析
//不能因为泛型好用就盲目的使用。
泛型高级之 通配符
- ?:表示任意类型,如果没有明确那么就是Object以及任意的Java类了
- ? extends E :向下限定,表示E及其子类
- ? super E:向上限定 E及其父类
这个通配符怎么用,当需求分析我们不知道明确的类型操作时候,使用通配符?就是让我们告诉JVM(java虚拟机),我们也不清楚此时需要什么类型,所以先默认这个类,接口,方法,集合等等,可以接受所有类型。但是一般情况最好不要这么用,因为我们用泛型的初衷就是指定唯一类型,这与开始相互矛盾。
- 但是我们可以使用向上向下限定,来增加一点泛型规则,比如下面的代码
一个动物类,狗类继承动物类,猫类继承动物类,接下来:
Collection<?> c1 = new ArrayList<Object>();
Collection<?> c1 = new ArrayList<Animal>();
Collection<?> c1 = new ArrayList<Dog>();
Collection<?> c1 = new ArrayList<Cat>();
//?extends Animal 意思是说明这里可以接受Animal类以及它的子类。
Collection<? extends Animal > c1 = new ArrayList<Object>(); //报错 object是所有类的顶层父类 并不是
//Animal的子类
Collection<? extends Animal > c1 = new ArrayList<Animal>();
Collection<? extends Animal > c1 = new ArrayList<Dog>();
Collection<? extends Animal > c1 = new ArrayList<Cat>();
此时Object类就用不了了。
//?super Animal 意思是说明这里可以接受Animal类以及它的父类。
Collection<? super Animal > c1 = new ArrayList<Object>();
Collection<? super Animal > c1 = new ArrayList<Animal>();
Collection<? super Animal > c1 = new ArrayList<Dog>(); //报错
Collection<? super Animal > c1 = new ArrayList<Cat>(); //报错
此时Dog类 和 Cat类就用不了。
下面是使用泛型的一些注意事项
- 从泛型类派生的子类或者实现泛型接口时候,当使用这些接口和父类时不能包含类型形参
//定义类A继承Apple类 Apple类不能跟类型形参
public class A extends Apple<T>{...} //错误
public class A extends Apple<String> //正确
public class A extends Apple //正确
- 静态方法,静态初始化块,静态变量的声明和初始化不允许使用类型形参。
public class R<T>
{
//下面代码错误 不能在静态变量声明里使用类型形参
static T info;
T age;fan
public void foo(T msg){}
//下面代码错误 不能在静态方法里使用类型形参
public static void bar(T msg){}
}
泛型方法和类型通配符的区别
- 大多数使用泛型方法来代替类型通配符
//类型通配符
public interface Collection<E>{
boolean containsAll(Collection<?> c);
boolean addAll(Collection<? extends E> c);
...
}
//泛型方法
public interface Collection<E>
{
<T> boolean containsAll(Collection<T> c);
<T exteands E > boolean addAll(Collection<T> c);
}
- 上面两种方式中:在泛型方法里类型形参只使用了一次,类型形参T产生的唯一效果就是可以在不同的调用点传入不同的实际类型。对于这种情况应该使用通配符:通配符就是被设计用来支持灵活的子类化的。
- 泛型方法允许类型形参被用来表示方法的一个或多个参数之间的类型依赖关系,或者方法返回值与参数之间的类型依赖关系。如果没有这样的类型依赖关系,就不应该使用泛型方法。
- 类型通配符和泛型方法一个显著的区别:类型通配符既可以在方法签名中定义形参的类型,也可以用于定义变量的类型;但泛型方法中的类型形参必须在对应的方法中显示声明。