Java泛型的那些事
1.泛型概述
1.1.为什么使用泛型
没有泛型,在编写代码时只能使用具体类型或Object类型,无法做到使用者想要使用什么类型就是类型。比如:创建一个方法,形参需要指定需要使用的数据类型,在创建方法之初就已经决定了该方法可以处理的数据类型,这大大限制了编程的灵活性。正因如此,才出现了在使用时才决定具体类型是什么的泛型编程。
1.2.泛型是什么
泛:广泛、普遍,非具体的东西,泛型就是定义之初用符号表示不具体的类型,在使用的时候才动态地指定具体的类型。更应该明白这种泛型编程设计思想,使用泛型带来的好处是代码更加简洁、更加灵活、使程序更加健壮(编译期没警告,运行期不会出现类强转异常--ClassCastException)。
2.泛型接口、类、方法
泛型允许在定义接口、类、方法时使用,将在声明变量、创建对象、调用方法时动态地指定。
2.1.泛型接口
定义泛型接口:比如集合中的List接口
// 定义接口时指定泛型:E,E类型在接口中就可以作为类型使用public interface List<E> extends Collection<E>{
……
boolean add(E e);
Iterator<E> iterator();
……
}
// 定义接口时指定泛型:K 和 V,K和V类型在接口中就可以作为类型使用
public interface Map<K,V>{
……
Set<K> keySet();
Collection<V> values();
Set<Map.Entry<K, V>> entrySet();
……
}
使用泛型接口:List接口的泛型类型E,在使用时指定为具体类型String
public static void main(String[] args) { List<String> list = new ArrayList<>();// 指定泛型类型E=String
list.add("我只认识字符串");//boolean add(E e); 等价于boolean add(String e);
Iterator<String> iterator = list.iterator();//Iterator<E> iterator();
while (iterator.hasNext()){
String next = iterator.next();//不需要强转为String
System.out.println(next);
}
}
关于泛型接口Map<K,V> 集合怎么用,就自行编写感受下。
2.2.泛型类
普通泛型类
定义泛型类
public class DemoFx<D> { private D dd;
public D getDd(){
return this.dd;
}
public void setDd(D dd){
this.dd = dd;
}
}
使用泛型类
public static void main(String[] args) { DemoFx<String> stringDemoFx = new DemoFx<>();
stringDemoFx.setDd("我是字符串类型");
System.out.println(stringDemoFx.getDd());
}
泛型类的继承与实现
定义泛型类:以ArrayList 类为例,继承泛型抽象类和实现泛型接口:
public class ArrayList<E> extends AbstractList<E> implements List<E>, RandomAccess, Cloneable, java.io.Serializable{
……
public E get(int index) {
rangeCheck(index);
return elementData(index);
}
……
}
使用泛型类
public static void main(String[] args) { List<String> list = new ArrayList<String>();// 指定泛型类型E=String
list.add("我只认识字符串");
String s = list.get(0);// 返回值为String
}
2.3.泛型方法
定义泛型方法:还是ArrayList案例
public class ArrayList<E> extends AbstractList<E> implements List<E>, RandomAccess, Cloneable, java.io.Serializable{
……
public <T> T[] toArray(T[] a) {
if (a.length < size)
// Make a new array of as runtime type, but my contents:
return (T[]) Arrays.copyOf(elementData, size, a.getClass());
System.arraycopy(elementData, 0, a, 0, size);
if (a.length > size)
a[size] = null;
return a;
}
……
}
使用泛型方法:public <T> T[] toArray(T[] a)
public static void main(String[] args) { List<String> list = new ArrayList<String>();
list.add("s1");
list.add("s2");
list.add("sn");
// public <T> T[] toArray(T[] a)
String[] strings = list.toArray(new String[list.size()]);
System.out.println(Arrays.asList(strings));
}
3.类型通配符
3.1.使用类型通配符
通配符表示符号是问号<?>,它是未知类型,可以匹配任何类型,也称为无界通配符。
对比”通配符“和”泛型“创建的方法
// 通配符定义public void foreach(List<?> list){
for (int i =0 ;i<list.size();i++) {
Object o = list.get(i);
System.out.println(o.toString());
}
}
// 泛型定义
public <T> void foreach2(List<T> list){
for(T t : list){
System.out.println(t.toString());
}
}
// 使用
public static void main(String[] args) {
List<String> list = new ArrayList<String>();
list.add("s1");
list.add("s2");
list.add("sn");
Demo demo = new Demo();
demo.foreach(list); // 通配符
demo.foreach2(list); // 泛型
}
通配符和泛型都可以实现相同的效果,并且泛型方法还可以使用本身定义的泛型类型,而通配符的”?“不可以当作数据类型来使用,所以通配符方法案例中只能用Object来接收list的元素,这也是通配符的缺点:无法确定未知类型是什么类型。
所以通配符的出现到底有什么用呢?
通配符为泛型的一种特例,无需定义既可在形参中使用的未知类型。
泛型和通配符的区别
Java编译器把泛型【T】推断成T类型,在代码块中允许出现 T类型变量;而把通配符【?】推断成未知类型,不存在 ?类型变量; 以上是 Java泛型的那些事 的全部内容, 来源链接: utcz.com/z/392447.html