Java泛型
从Java SE5开始有了泛型的概念,泛型实现了参数化类型的概念。泛型的核心概念就是告诉编译器想使用什么类型,一般可以认为泛型与其他类型差不多,只是带有一个类型参数罢了。泛型的类型参数可以有多个,以逗号分隔,同时也可以使用extends来限定类型,extends为边界符,与继承时使用的extends意义不同,多个边界使用&符号连接。
1、简单的泛型
public class ClassHolder{ public List getClassList(){ return new ArrayList (); } public static void main(String[] args) { //如下调用getClassList则会自动生成一个String的List List list = new ClassHolder ().getClassList(); } }
接口也可以使用泛型,方法和类的一样
public interface test{} public interface test {} public interface test extends E>{} public interface test extends E&K>{}
方法使用泛型,只需要将泛型参数列表置于返回值之前,即可;
publicvoid test(){}
2、类型参数推断
在进行赋值操作时,编译器可根据结果类型自动推断出泛型方法所需要的类型;
public class ClassHolder { public staticList getClassList(){ return new ArrayList (); } public static void main(String[] args) { //如下调用getClassList可不传类型参数,编译器可以根据stringList的类型,自动帮忙推断出getClassList()需要填充的类型是String List stringList = ClassHolder.getClassList(); //当然也可以如下这样显示的指出类型参数。不显示的指出虽然省了代码量,但有时候对代码的阅读难度提高了。 List stringList2 = ClassHolder. getClassList(); //如下这般非赋值操作的调用则不会进行类型推断,最终返回值的类型参数是Object ClassHolder.getClassList(); } }
3、通配符?的使用
主要在实例时的一些使用;
例:
public class StudyTest {} public class StudyTestChild1 extends StudyTest { } public class StudyTestChild2 extends StudyTest { } public class MainClass { public static void main(String[] args) { //1、边界通配符: <? extends T>,只允许单一边界,即只能extends一个类型 // 不允许创建 //Listlist = new ArrayList // 允许创建, list是具有任何从StudyTest继承类型的列表, 这样就将将两种类型建立了联系 List<? extends StudyTest> list = new ArrayList(); (); //不能向list里添加任何类型 // list.add(new StudyTestChild1()); // list.add(new StudyTest()); //但取出来的类型可以直接就是边界类型 StudyTest s = list.get(0); //2、超类型通配符 : <? super T> List<? super StudyTest> list1 = new ArrayList<>(); //可以add,这里好像可以直接使用StudyTest来限制list1的类型,加上? super StudyTest这样有什么区别。。 list1.add(new StudyTestChild1()); //3、无边界通配符:<?> ,即任意类型(但只能是一种类型),多数情况下似乎和Object的效果一样,只是使用了泛型而已。 //当处理多个泛型参数时,有时允许一个参数可以是任何类型,同时为其他参数确实某种特定类型。 Map map2 = new HashMap (); } }
4、擦除机制(重要)
1)在泛型代码内部,无法获取任何有关泛型参数类型的信息,如:List
2)因为泛型不是java一开始就有的,擦除机制也是因java语言的向前兼容造成的折中方案。
3)泛型类型只有在静态类型检查期间才会出现,在此之后,程序中的所有泛型类型都将被擦除,替换为它们的非泛型上界。诸如List
4)对于已擦除了类型信息的不能使用instanceof来比较两个类型是否相同(因为都是Object),但可以使用动态的isInstance()方法来判断。
5)想要实例一个传入参数类型的类,可使用Class的newInstance()来实现。直接实例不行,因为类型已经被擦除了。如不能使用new T()来实例,但可以使用new Class
5、其他
1)泛型也可以应用于内部类、匿名内部类;
2)泛型使用原则:只要能够使用,就应该尽量使用泛型;
3)static方法无法访问泛型类的类型参数
4)泛型的出现的原因
有许多原因促成了泛型的出现,最初最大的原动力就是为了创建容器类(List,Map,Set等)。
Java的泛型相对于其他实现了更纯粹泛型的语言(如C++)来说有许多限制。
如:(1)基本类型无法作为泛型的参数
(2)一个类不能同时实现同一个泛型接口的两种变体,因为擦除原因,这两个变体会被认为是相同的接口;
(3)使用带有泛型类型参数的转型,没有意义,使用instanceof也只会得到相同的结果
(4)不能使用泛型重载方法
如下是不行的:
public class ClassHolder
void get(T t){};
void get(E e){};
}
(5)自限定类型:class ClassHolder
(6)泛型与数组不能较好的使用,因为数组必须知道它所持有的确切类型。如 List