泛型编程:写的代码可以处理任何的类型。(例如,当你要新建立一个数组时,但还不确定该数组的类型
可能后面要用的是整型数组,也可能要用的是字符串型数组,甚至栈类型数组。但因为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>