java 泛型声明与 通配符的使用
一:泛型类
把泛型定义在类上:作用域是整个类的内部
格式:public class 类名<泛型类型1,…>
注意:泛型类型必须是引用类型
import java.util.Arrays; public class GenericClassDemo { public static void main(String[] args) { MyArrayList<String> list = new MyArrayList<String>(); list.add("javase"); list.add("javaee"); list.add("javame"); System.out.println(list.get(0));//javase System.out.println(list);//[javase, javaee, javame] } } /*泛型类 把泛型定义在类上:作用域是整个类的内部 格式:public class 类名<泛型类型1,…> 注意:泛型类型必须是引用类型 */ class MyArrayList<T>{ private Object[] elementData = new Object[10]; public boolean add(T e) { //遍历数组中的元素值,如果当前元素是null,就说明当前位置没有值,就可以往元素位置里面放值 for(int i=0; i<elementData.length; i++){ if(elementData[i]==null){ elementData[i] = e; return true; } } return false; } public T get(int index) { //判断索引是否正确 if(index<0 || index>elementData.length-1){ return null; } return (T) elementData[index]; } //[javase, javaee, javame] @Override public String toString() { StringBuilder sb = new StringBuilder(); sb.append("["); for(int i=0; i<elementData.length; i++){ //把不等于null的元素添加进sb中 Object value = elementData[i]; if(null!=value){ sb.append(value+","); } } //将最后一个元素最右边的","去除掉 String result = sb.toString().substring(0, sb.length()-1); return result+"]"; } }
输出结果:
javase
[javase,javaee,javame]
泛型方法
把泛型定义在方法上:作用域是整个方法
格式:public <泛型类型> 返回类型 方法名(泛型类型 .)
package cn.edu360; public class GenericMethodDemo { public static void main(String[] args) { Object obj = "哈哈"; //把obj强转成String //String s = (String)obj; String s = cast(obj); System.out.println(s);//哈哈 obj = 123;//把123自动装箱成Integer //把obj强转成Integer //Integer i = (Integer)obj; Integer i = cast(obj); System.out.println(i);//123 } /*泛型方法 把泛型定义在方法上:作用域是整个方法 格式:public <泛型类型> 返回类型 方法名(泛型类型 .) */ public static <T> T cast(Object obj){ return (T) obj;//你要的是什么类型,我就给你强转成什么类型 } }
输出结果:
哈哈
123
接口泛型可以一直传递下去,接口的子类除了可以继承泛型,还可以定义自己特有的泛型
泛型接口
把泛型定义在接口上
格式:public interface 接口名<泛型类型1…>
public interface InterTest<T> { void test(T t); }
public class GenericInterfaceDemo<E,T,T2> implements InterTest<E> { public static void main(String[] args) { } @Override public void test(E t) { // TODO Auto-generated method stub } }
二、? ,类型通配符
1.无限定通配符,<?>。
2.上限通配符,<? extends Number>。表示参数类型只能是Number的子类。
3.下限通配符,<? supper Number>。表示参数类型只能是Number的父类。
import java.util.ArrayList; import java.util.Collection; import java.util.Iterator; //泛型特点:泛型的左右类型必须保持一致且必须是引用类型 public class GenericDemo { public static void main(String[] args) { /*泛型通配符<?> 任意类型,如果没有明确,那么就是Object以及任意的Java类了*/ //test1(); /*? extends E 向下限定,E及其子类*/ //test2(); /*? super E 向上限定,E及其父类*/ test3(); } /*泛型通配符<?> 任意类型,如果没有明确,那么就是Object以及任意的Java类了*/ private static void test1() { Object obj = "哈哈"; // Collection<Object> c = new ArrayList<String>();//error Collection<Object> c = new ArrayList<Object>(); Collection<?> c2 = new ArrayList<Object>(); Collection<?> c3 = new ArrayList<Animal>(); Iterator<?> iterator = c3.iterator(); //不能往c3里面添加值,因为不知道c3接收的是什么泛型的集合 //可以取出值,用Object类型接收,因为不论任何类型的值都是Object的子类 obj = iterator.next(); } /*? extends E 向下限定,E及其子类*/ private static void test2() { Collection<? extends Animal> c = new ArrayList<Animal>(); Collection<? extends Animal> c2 = new ArrayList<Pig>(); Collection<? extends Animal> c3 = new ArrayList<Dog>(); //Collection<? extends Animal> c4 = new ArrayList<Object>(); //不能往c3里面添加值,因为不知c3接收的是什么泛型的集合 Iterator<? extends Animal> iterator = c3.iterator(); //取值的类型可以Animal来接收,因为集合中添加的值肯定是Animal自身或者子类的类型的值 Animal animal = iterator.next(); } /*? super E 向上限定,E及其父类*/ private static void test3() { //Collection<? super Animal> c = new ArrayList<Pig>(); Collection<? super Animal> c2 = new ArrayList<Animal>(); Collection<? super Animal> c3 = new ArrayList<Object>(); //可以添加值,因为泛型的类型至少是Animal本身或者Animal的父类泛型,根据多态的特点,至少可以添加Animal类型的值 c3.add(new Animal()); Iterator<? super Animal> iterator = c3.iterator(); //因为最大的父类确定不了,所以只能用obj类接收 Object obj = iterator.next(); } } class Animal{} class Dog extends Animal{} class Pig extends Animal{}
泛型的好处:
在定义泛型对象的使用方法时,还不知道T是什么类型,它可能是String类型,也可能是Integer类型。如果,把T定义成一个确定的泛型数据类型,参数就只能是这种数据类型。此时,就用到了通配符代替确定的泛型数据类型。
使用泛型、通配符提高了代码的复用性。
把一个对象分为声明、使用两部分的话。泛型侧重于类型的声明上代码复用,通配符则侧重于使用上的代码复用。泛型用于定义内部数据类型的不确定性,通配符则用于定义使用的对象类型不确定性。