泛型编程:写的代码可以处理任何的类型。(例如,当你要新建立一个数组时,但还不确定该数组的类型
可能后面要用的是整型数组,也可能要用的是字符串型数组,甚至栈类型数组。但因为Object类是所有类的
基类,所以此时只要将该数组定义成Object类型,这样其他的每个类型的数组都可以使用该Object类型的数
组,这就是泛型编程。)
在早期Java 5版本出现之前,人们要实现泛型编程,都是将类型定义成Object类型来实现的。
1 package L14; 2 import java.util.Arrays; 3 4 public class ObjectTest { 5 private Object[] array; //定义一个Object类数组 6 private int size; //存储数据元素个数 7 8 public ObjectTest(int size){ 9 this.array= new Object[size]; //给数组初始化 //一般新new的都是对象,而T只是个类型参数 10 this.size=0; 11 } 12 public ObjectTest(){ 13 this(10); 14 } 15 public void add(Object data){ //将添加的元素定义成Object类型 16 if(this.size==this.array.length){ //当数组满了,要进行扩容 17 this.array=Arrays.copyOf(this.array,this.array.length*2); 18 } 19 this.array[this.size++]=data; 20 } 21 public Object back() { 22 if(this.size==0){ //当数组内空了,return null 23 return null; //因为引用类型的默认初始值为null 24 } 25 return this.array[this.size-1]; //因为只返回,并不从栈中取出,所以进行size-1,而不是size-- 26 } 27 public static void main(String[] args) { 28 ObjectTest o=new ObjectTest(); //Object 类的构造函数会自动给O对象数组进行初始化 29 o.add(10); //因为Object类是所有类的基类,所以任何类型都可存到Object类的数组中 30 o.add(20); 31 o.add("30"); 32 String data1=(String) o.back(); 33 System.out.println(data1); 34 } 35 }
运行结果:
这是在使用者可以确保完全输入正确的情况下的,但是如果这次该用户想用Object类型的数组来
实现整型数组,但因为手误,而错输进一个字符串,这时编译是检测不到的。
只有在运行之后才会报错。(所以用Object类型来实现泛型编程存在好多弊端)
弊端: 1.无法检测传入的数据是否符合用户存储数据的正确类型
2.输出时,需要手动进行类型的强制转换。
所以在java5版本后,为了解决上述的两个问题,就出现了真正的泛型编程。
泛型编程的本质意义:1.检测传入的数据是否符合用户存储数据的正确类型
2.自动转换类型,无需用户手动进行类型的强制转换
1 public class GenericTest<T> { 2 private T[] array; //定义一个T类型的泛型数组 3 private int size; //存储数据元素个数 4 5 public GenericTest(int size){ 6 this.array=(T[]) new Object[size]; //将接收的Object类型强置转换为T类型 7 this.size=0; 8 } 9 public GenericTest(){ 10 this(10); 11 } 12 public void add(T data){ //添加一个T类型的数组 13 if(this.size==this.array.length){ 14 this.array=Arrays.copyOf(this.array,this.array.length*2); 15 } 16 this.array[this.size++]=data; 17 } 18 public T back(){ //返回一个T类型的数 19 if(this.size==0){ //当数组为空时,返回null。 20 return null; //因为null为引用变量的初始值 21 } 22 return array[this.size-1]; 23 } 24 25 public static void main(String[] args) { 26 GenericTest<String> text=new GenericTest(12); // 27 text.add("20"); 28 text.add("30"); 29 String str=text.back(); 30 System.out.println(str); 31 } 32 }
就是在开头类名后加一个尖括号<>,在尖括号内放入类型参数,(普通类类名+< 类型参数>),需要注意的是
该类型参数必须全为大写,如T,E,R等,然后在定义数组时,也将数组定义成T类型的,在构造函数中对数组初始化
时,将新new的Object类型也强置转换为T类型(因为一般new 对象时,要放具体的类型,而T只是类型参数,)。
然后在后面写成员方法时,将传入的值,或返回的值也要定义成T类型的。最后就是在main方法中新new对象时,
将你要定义的真正的类型写上,如要定义字符串数组,GenericTest<String> text=new GenericTest(12);
这样,当你输入的数据类型有错时,就会直接报错。也省略了手动对类型转换的过程。
需要注意,当确定一个泛型类型后,仍可以继续使用原始类型。但该类型还是会有之前的弊端(2个)。
此时相当于给T赋的是Object。
之所以还可以使用原始类型,是因为泛型在java5之后出现,若要强制必须给T赋类型的话,那么在5之前写的
那些代码(没有T类型)都会报错不能使用。
java泛型的类型擦除机制???
在编译阶段,Java编译器通过泛型类型进行类型检查和自动类型转换,处理完以后,就会把T类型一直往上
擦除(进行类型检查),直到上界(默认为Object类),所以在运行阶段都是以Object类型来运行。
所以在Java中认为 GenericTest <Interage> 这两个是同一类型的。(C语言中认为是两种)
GenericTest <String>