Java 泛型(generics)是 JDK 5 中引入的一个新特性, 泛型提供了编译时类型安全检测机制,该机制允许程序员在编译时检测到非法的类型。
泛型的本质是参数化类型,即给类型指定一个参数,然后在使用时再指定此参数具体的值,那样这个类型就可以在使用时决定了。这种参数类型可以用在类、接口和方法中,分别被称为泛型类、泛型接口、泛型方法。
泛型类
语法:在类后面加< T >,字母不限。
public class Show<T> {//我们称Show<T>为泛型类,T为泛型
T t;//泛型作为类的属性,它可以是String,可以是Object,也可以是Double,默认情况下,如果你不指定,视为Object
public T getT() {
return t;
}
public void setT(T t) {
this.t = t;
}
}
泛型< T >作为类的属性,它可以是String,可以是Object,也可以是Double,默认情况下,如果你不指定,视为Object
这是一个泛型类的应用场景(以上面的Show类举例):
public class Test {
public static void main(String[] args) {
Show<String> show1 = new Show<>();
show1.setT("str");
System.out.println(show1.getT());
Show<Integer> show2 = new Show<>();
show2.setT(1);
System.out.println(show2.getT());
Show<Double> show3 = new Show<>();
show3.setT(1.312);
System.out.println(show3.getT());
}
}
这样的话,你每new一个Show类可以指定你想要的泛型,在接下来调用setT方法时,它会以你指定的泛型作为参数传递下去
复制一下体会一下吧!
泛型类的引出
public class Demo {
public String show(String s){
return s;
}
public Integer show(Integer integer){
return integer;
}
public Boolean show(Boolean b){
return b;
}
}
public class Test2 {
public static void main(String[] args) {
Demo demo = new Demo();
String s = demo.show("s");
System.out.println(s);
Integer integer = demo.show(1);
System.out.println(integer);
Boolean b= demo.show(true);
System.out.println(b);
}
}
你会发现,在Demo类里,它需要过多的重载去实现不同类型的参数的传递。为了避免这样重复的代码。泛型类的作用就体现出来了:
public class Demo<T> {
public T show(T t){
return t;
}
}
public class Test2 {
public static void main(String[] args) {
Demo<String> demo = new Demo<>();
String s = demo.show("mmm");
System.out.println(s);
Demo<Integer> demo1 = new Demo<>();
Integer show = demo1.show(21);
System.out.println(show);
Demo<Boolean> demo2 =new Demo<>();
Boolean b = demo2.show(true);
System.out.println(b);
}
}
但是同样有缺点那就是:
对象失去了共享性:原来的类被定义成泛型类之后,我们在创建对象的时候,需要指定泛型,就限制死了,只能传递该泛型的参数。
创建不同的对象,浪费更多的内存资源:原来的类使用了泛型类之后,我们原本只需要一个demo对象就可以完成的事情,居然要创建三个不同泛型类的对象!
因此这时泛型方法的作用就显现出来了!
泛型方法
泛型方法:只需要在修饰符public之后,或者返回类型前,加上<T>泛型即可,用来表示该方法是泛型的方法。
public class Demo {
public <T> T show(T t){
return t;
}
}
public class Test2 {
public static void main(String[] args) {
Demo demo = new Demo();
String s = demo.show("mmm");
System.out.println(s);
Integer integer = demo.show(1);
System.out.println(integer);
Boolean aBoolean = demo.show(true);
System.out.println(aBoolean);
Double aDouble = demo.show(312.13);
System.out.println(aDouble);
}
}
是不是解决了对象的共享性?使多个不同参数类型的方法被同一个对象所调用。
那么泛型类和泛型方法可以共存吗,答案是肯定的。如果你的对象指定了某个泛型类,你在传递其他泛型类的时候,只要是泛型方法,系统会自动帮你转换类型。例如这样:
public class Demo<T>{//使用了泛型类
public <T> T show(T t){//使用了泛型方法
return t;
}
}
public class Test2 {
public static void main(String[] args) {
Demo<Double> demo = new Demo();//即便对象指定了某个泛型
String s = demo.show("mmm");
System.out.println(s);
Integer integer = demo.show(1);//后续的对象并不会受到影响
System.out.println(integer);
Boolean aBoolean = demo.show(true);
System.out.println(aBoolean);
}
}
泛型接口
泛型通配符?
通配符的适用场景大多为一个不太确定泛型的泛型类,这种泛型类常常作为形参,而不能作为实参。
public class Test {
public static void printList(ArrayList<?> list){//?代表接收的泛型可以是任何引用类型
System.out.println(list);
}
public static void main(String[] args) {
ArrayList<Student> list = new ArrayList<>();
// ArrayList<String> list = new ArrayList<>();//泛型可以是String,也可以是parent
// ArrayList<parent> list = new ArrayList<>();
printList(list);
}
}
class parent{
}
class Student extends parent{
}
泛型通配符上下限
上限
本demo中上限为parent
public class Test {
public static void printList(ArrayList<? extends parent> list) {//? extends parent代表接收的泛型只能是parent本身或parent的子类
System.out.println(list);
}
public static void main(String[] args) {
ArrayList<Student> list = new ArrayList<>();//可以
// ArrayList<Object> list = new ArrayList<>();//不可以
printList(list);
}
}
class parent {
}
class Student extends parent {
}
下限
本demo中上限为Student
public class Test {
public static void printList(ArrayList<? super Student> list) {//? super Student代表接收的泛型只能是Student本身或Student的超类
System.out.println(list);
}
public static void main(String[] args) {
ArrayList<Student> list = new ArrayList<>();//可以
ArrayList<Object> list1 = new ArrayList<>();//可以
printList(list);
printList(list1);
}
}
class parent {
}
class Student extends parent {
}
总结
泛型
泛型的本质是参数化类型,即给类型指定一个参数,然后在使用时再指定此参数具体的值
泛型允许程序员在强类型程序设计语言中编写代码时使用一些以后才指定的类型
泛型的优点:
1.可重用性。
2.消除转换。
3.保证安全性。
4.避免了不必要的装箱和拆箱,强制转换,减少了系统开销,从而提升了性能。
泛型的缺点
Java 泛型的参数只可以代表类,不能代表个别对象。由于Java泛型的类型参数之实际类型在编译时会被消除,所以无法在运行时得知其类型参数的类型,而且无法直接使用基本值类型作为泛型类型参数。Java编译程序在编译泛型时会自动加入类型转换的编码,故运行速度不会因为使用泛型而加快。
泛型类
泛型类的特性:泛型类可以指定不同的泛型,从而实现了类的参数传递的多样性
它。
泛型方法
泛型方法的特性:随着我们的实例中的某个方法传入参数类型不同,他得到的类型也不同。泛型方法能使方法独立于类而产生变化。
泛型接口
泛型接口:泛型接口的实现类必须也声明成泛型类。
泛型通配符
泛型通配符?代表接收的泛型可以是任何引用类型。通配符上限和下限可以允许接收的泛型的范围。