泛型编程

      泛型编程:写的代码可以处理任何的类型。(例如,当你要新建立一个数组时,但还不确定该数组的类型

可能后面要用的是整型数组,也可能要用的是字符串型数组,甚至栈类型数组。但因为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.输出时,需要手动进行类型的强制转换。

    3.效率低。(没有使用泛型时,系统先进行向上转型,在输出时,又进行向下转型:String->Object->String)

 

     所以在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>      

 

 注意:< >尖括号不是类型的一部分,它只是为了对泛型类型进行类型检查,只在编译阶段存在,运行阶段就没有了。

 

   泛型类型可用来定义三种:

       1.泛型类

     2.泛型方法  (在函数返回值前面加泛型类型列表)(可静态,可实例)

   3.泛型接口

   泛型类型要注意的问题:

     1,用泛型定义数组时,不可以A[] arr =new A[10];,应该A[] arr=(A[])new Object[];,因为在之前定义数组时有规定,定义的数组的类型必须明确。

     2,不能作为静态方法的传入参数类型,因为静态方法在类加载时加载,而泛型的类型只有在加载对象时才能确定。

          

          ♥当在用泛型类型定义的类中,使用compareTo()方法时,要将泛型类型的上界定义为Comparable,即为泛型类型继承Comparable。

(因为若不给定义上界则直接擦到Object类,而Object类中只有toString(),equals()等方法,没有compareTo()方法。)

  当继承了Comparable后,这时候T类型进行擦除机制时,只会擦到Comparable,而Comparable中正好有要用的CompareTo()方法。

 

           ♥当用泛型来定义静态方法时,运行时要用类调用,此时可在方法前加< >,来进行类型检查。如下,

       

 

 

        也可省略,因为jdk会根据你传进来的实参来推导。

         另外若要在该方法中使用compareTo()方法时,因为java有擦除机制,所以也要给类型参数定义上界为Comparable。

 

 

 

 

 

 

 

 

 

 

 

posted @ 2019-10-23 09:55  小L要努力吖  阅读(281)  评论(0编辑  收藏  举报