java 泛型
定义
- 泛型(Generic)就相当于标签
- 形式:<> ,
Collection<E>, List<E>, ArrayList<E>
这个<E>
就是类型参数,即泛型。
- 除了元素的类型不确定,其他的部分是确定的,例如关于这个元素如何保存,如何管理等是确定的,因此把元素的类型设计成一个参数,这个类型参数叫做泛型。
- 集合容器类在设计阶段/声明阶段不能确定这个容器到底实际存的是什么类型的对象,所以在JDK1.5之前只能把元素类型设计为Object,JDK1.5之 后使用泛型来解决。
- 如果不使用泛型的话,无论什么引用数据类型都可以存入集合,而一般我们在使用集合时为了便于管理基本上存入的都是相同类型的数据
import java.util.ArrayList;
public class Test1 {
public static void main(String[] args) {
ArrayList al = new ArrayList();
al.add(6);
al.add(8);
al.add(9);
al.add("abc");
//对集合遍历查看:
for (Object obj : al) {
System.out.println(obj);
}
//加入泛型的优点:在编译时期就会对类型进行检查,不是泛型对应的类型就不可以添加入这个集合。
ArrayList<Integer> ai = new ArrayList<Integer>();
ai.add(6);
ai.add(8);
ai.add(9);
/* ai.add("abc"); //Error:参数不匹配; java.lang.String无法转换为java.lang.Integer
ai.add(9.8); //Error:参数不匹配; double无法转换为java.lang.Integer*/
//对集合遍历查看:
for (Integer a : ai) {
System.out.println(a);
}
}
}
总结
- 出现于JDK1.5以后,泛型实际就是 一个
<>
引起来的 参数类型,这个参数类型具体在使用的时候才会确定具体的类型。 - 使用了泛型以后,可以确定集合中存放数据的类型,在编译时期就可以检查出来,并且使后续的遍历等操作简单。
- 泛型的类型:都是引用数据类型,不能是基本数据类型。基本数据类型都会自动装箱,(
short-->Short,int-->Integer,long-->Long,float-->Float,double-->Double,boolean-->Boolean,char-->Character
)故看起来像是能直接使用 -
ArrayList<Integer> ai = new ArrayList<Integer>();
在JDK1.7以后可以写为:ArrayList<Integer> ai = new ArrayList<>();
。<>
-->钻石运算符
使用
泛型类的定义和实例化:
Gene1是一个普通的类,而Gene1<E>
是一个泛型类,<>
里面就是一个参数类型,这个类型现在是不确定的,相当于一个占位,现在能确定的是这个类型一定是一个引用数据类型,而不是基本数据类型
public class Gene1<E> {
String name;
int age;
E sex;
public void a(E n){
}
public void b(E[] m){
}
}
class Test{
//这是main方法,程序的入口
public static void main(String[] args) {
//Gene1进行实例化:
//(1)实例化的时候不指定泛型:如果实例化的时候不明确的指定类的泛型,那么认为此泛型为Object类型
Gene1 gt1 = new Gene1();
gt1.a(6);
gt1.a(8.6);
gt1.b(new String[]{"a","b","c"});
//(2)实例化的时候指定泛型(推荐方式):
Gene1<String> gt2 = new Gene1<>(); //指定E为String
gt2.sex = "男";
gt2.a("abc");
//gt2.a(6);//Error:java: 不兼容的类型: int无法转换为java.lang.String
gt2.b(new String[]{"a","b","c"});
}
}
继承情况
父类指定泛型
指定父类泛型,那么子类就不需要再指定泛型了,可以直接使用
public class ChildGene1 extends Gene1<Boolean> { //指定Boolean泛型
}
class ChildTest {
public static void main(String[] args) {
ChildGene1 cgt = new ChildGene1();
cgt.name = "fyz";
cgt.sex = true;
cgt.a(6);//Error:java: 不兼容的类型: int无法转换为java.lang.Boolean
cgt.b(new Boolean[]{true, false});
}
}
父类不指定泛型
如果父类不指定泛型,子类也会变成一个泛型类,E的类型可以在创建子类对象的时候确定
public class ChildGene2 <E> extends Gene1<E>{
}
class CT2{
public static void main(String[] args) {
ChildGene2<String> cg2 = new ChildGene2<>();
cg2.age = 20;
cg2.a("fyz");
cg2.b(new String[]{"a","b","c"});
}
}
继承补充
A和B时子类父类的关系时,G与G不存在继承关系,是并列关系
Object o = new Object();
Integer i = 6;
o = i;// 父类 = 子类,多态的一种形式
Object[] objects = new Object[5];
String[] strings = new String[5];
objects = strings;// 父类 = 子类,多态的一种形式
List<Object> listo = new ArrayList<>();
List<String> lists = new ArrayList<>();
//listo = lists; //Error: java: 不兼容的类型:String无法转换为Object
//A和B时子类父类的关系时,G<A>与G<B>不存在继承关系,是并列关系
其他
- 泛型类可以定义多个参数类型
public class Generic<A, B, C> { //泛型类可以定义多个参数类型
A name;
B age;
C sex;
- 泛型类的构造器的写法
public Generic() {
}
/*public Generic<A, B, C>() { //非法,不可加<A, B, C>
}*/
public Generic(A name, B age, C sex) {
this.name = name;
this.age = age;
this.sex = sex;
}
- 不同的泛型的引用类型不可以相互赋值:
ArrayList<String> aL1 = null;
ArrayList<Integer> aL2 = null;
//Error:java: 不兼容的类型: java.util.ArrayList<java.lang.Integer>无法转换为java.util.ArrayList<java.lang.String>
//aL1 = aL2;//不同的泛型的引用类型不可以相互赋值
- 泛型如果不指定,那么就会被擦除,认为此泛型为Object类型
Gene1 gt1 = new Gene1();
gt1.a(6);
gt1.a(8.6);
gt1.b(new String[]{"a","b","c"});
- 泛型类中的静态方法不能使用类的泛型:静态方法优先于对象加载,此时尚未指定泛型对应类型
//Error: java: 无法从静态上下文中引用非静态 类型变量 A
public static void c(A name) { }
- 不能直接使用
E[]
的创建
//A[] i = new Object[5]; //Error: java: 不兼容的类型: java.lang.Object[]无法转换为A[]
A[] a = (A[]) new Object[5];
泛型方法
- 不是带泛型的方法就是泛型方法,泛型方法要求这个方法的泛型的参数类型要和当前的类的泛型无关。泛型方法对应的那个泛型参数类型和当前所在的这个类泛型是啥无关,甚至与其是否为泛型类都无关。
- 泛型方法定义的时候,要加上。如果不加的话,会把T当做一种数据类型,然而代码中没有T类型那么就会报错
- T的类型是在调用方法的时候确定的
- 泛型方法可以是静态方法
public class GeneMe<E> {
//不是泛型方法
public void a(E e) {
}
//是泛型方法
public static <T> void b(T t) {
}
}
class Test {
public static void main(String[] args) {
GeneMe<String> tg = new GeneMe<>();
tg.a("abc");
tg.b(19);
tg.b(true);
}
}
通配符
A 和 B是子类父类的关系,G和G不存在子类父类关系,是并列的加入通配符?
后,G<?>就变成了 G和G的父类
public class Genetp {
//方法的重复定义,不认为重载
/*public void a(List<Object> list){
}
public void a(List<String> list){
}
public void a(List<Integer> list){
}*/
public void a(List<?> list){
//1.遍历:内部遍历的时候用Object,不用通配符?
for(Object a:list){
System.out.println(a);
}
//2.数据的写入操作
//list.add("abc");//出错,不能随意的添加数据
list.add(null); //只能添加null
//3.数据的读取操作
Object s = list.get(0);
}
}
class Testtp{
public static void main(String[] args) {
Genetp gt = new Genetp();
gt.a(new ArrayList<Integer>());
gt.a(new ArrayList<String>());
gt.a(new ArrayList<Object>());
}
}
泛型受限
泛型上限
List<? extends Person>
就相当于List<? extends Person>
是List<Person>以及List<Person的子类>
的父类
泛型下限
List<? super Person>
相当于List<? super Person>
是List<Person>以及List<Person的父类>
的父类
class Person {
}
class Student extends Person {
}
public class Test {
//这是main方法,程序的入口
public static void main(String[] args) {
//a,b,c三个集合是并列的关系:
List<Object> a = new ArrayList<>();
List<Person> b = new ArrayList<>();
List<Student> c = new ArrayList<>();
//泛型上限
List<? extends Person> list1 = null;
// list1 = a;//Error: java: 不兼容的类型: List<java.lang.Object>无法转换为List<? extends Person>
list1 = b;
list1 = c;
//泛型下限
List<? super Person> list2 = null;
list2 = a;
list2 = b;
// list2 = c; //Error:java: 不兼容的类型: java.util.List<Student>无法转换为java.util.List<? Person>
}
}