泛型

xiaoxiao2021-02-28  100

一、需要泛型的原因:  List list = new ArrayList();  list.add("shiyanlou");  list.add("admin");  list.add(100);   for (int i = 0; i < list.size(); i++) {       String name = (String) list.get(i); // 1       System.out.println("name:" + name);   } 在上述代码中,定义了一个List类型的集合,先向其中加入了两个字符串类型的值,随后加入一个Integer类型的值。这是完全允许的,因为此时list默认的类型为Object类型。在之后的循环中,由于忘记了之前在list中也加入了Integer类型的值或其他编码原因,很容易出现类似于//1中的错误。因为编译阶段正常,而运行时会出 现“java.lang.ClassCastException”异常。因此,导致此类错误编码过程中不易发现。 在如上的编码过程中,我们发现主要存在两个问题: 1.当我们将一个对象放入集合中,集合不会记住此对象的类型当再次从集合中取出此对象时,改对象的编译类型变成了Object类型,但其运行时类型任然为其本身类型 2.因此,//1处取出集合元素时需要人为的强制类型转化到具体的目标类型,且很容易出现“java.lang.ClassCastException”异常。 没有泛型操作集合的缺点:《1》因为 集合中存储都是以 Object 对象进行存储的 ,所以从集合取出对象时,需要执行类型转换操作。《2》由于没有类型检查,可以向集合添加任意对象,不便于我们对集合的管理,有时候甚至会导致严重的错误。  而泛型帮我们提供了类型参数,让我们提前规定好集合对象的类型。 二、泛型 1、泛型:即“参数化类型”,就是将类型由原来的具体的类型参数化,类似于方法中的变量参数,此时类型定义为参数形式(可以称之为 类型形参),然后在使用/调用时传入具体的类型(类型实参)。 2、 //注意:引入了泛型以后,List<Object>, List<String>是两种不同的类型 ArrayList<String> files = new ArrayList<String>(); /* *下面的代码是非法的 *List<Object> lo = files; */ 在集合的类型后面添加上一对<>,尖括号中填上我们需要规范的集合里对象的类型,我们可以指定一个或多个类型参数的名字,同时也可以对类型参数的取值范围进行限定,多个类型参数之间用,分隔。这样编辑器便会在编译时帮我们检查出不符合规范的元素添加。 3、泛型的规则: (1)泛型的类型参数只能是类类型(包括自定义类),不能是简单类型。 (2) 同一种泛型可以对应多个版本(因为参数类型是不确定的),不同版本的泛型类实例是不兼容的。 (3)泛型的类型参数可以有多个。 (4)泛型的参数类型可以使用 extends 语句。习惯上称为“有界类型”。 (5)泛型的参数类型还可以是通配符类型。例如 Class<?> classType = Class.forName("java.lang.String"); 4、定义带类型参数的类 package com.shiyanlou; /* 使用T代表类型,无论何时都没有比这更具体的类型来区分它。如果有多个类型参数,我们可能使用字母表中T的临近的字母,比如S。 */ class Test <T> {     private T ob;     /*     定义泛型成员变量,定义完类型参数后,可以在定义位置之后的方法的任意地方使用类型参数,就像使用普通的类型一样。     注意,父类定义的类型参数不能被子类继承。     */     //构造函数     public Test(T ob) {         this.ob = ob;     }     //getter 方法     public T getOb() {         return ob;     }     //setter 方法     public void setOb(T ob) {         this.ob = ob;     }     public void showType() {         System.out.println("T的实际类型是: " + ob.getClass().getName());     } } public class TestDemo {     public static void main(String[] args) {         // 定义泛型类 Test 的一个Integer版本         Test <Integer> intOb = new Test<Integer>(88);         intOb.showType();         int i = intOb.getOb();         System.out.println("value= " + i);         System.out.println("----------------------------------");         // 定义泛型类Test的一个String版本         Test<String> strOb = new Test<String>("Hello Gen!");         strOb.showType();         String s = strOb.getOb();         System.out.println("value= " + s);     } } 运行结果: 5、使用泛型方法 《1》 public class Animal {     public Animal(){         System.out.println("我是动物");     } } public class Dog extends Animal {     public Dog(){         System.out.println("我是狗");     } } public class Test { /* 注意:定义带类型参数的方法,其主要目的是为了表达多个参数以及返回值之间的关系。例如本例子中T和S的继承关系, 返回值的类型和第一个类型参数的值相同。 */     public <T, S extends T> T testDemo(T t, S s){         System.out.println("我是 T 类型,我的类型是" + t.getClass().getName());         System.out.println("我是 S 类型,我的类型是" + s.getClass().getName());         return t;     }     public static void main(String[] args) {         // TODO Auto-generated method stub         Test test = new Test();         Dog d = new Dog();         Animal a0 = new Animal();         Animal a1  = test.testDemo(a0, d);         System.out.println("我是整数 a,我的类型是" + a1.getClass().getName());     } } 运行结果: 《2》上面的例子中我们对类型参数赋予了具体的类型,当然我们有时候也无法确定类型参数的类型,这个时候我们便可以使用通配符。如果仅仅是想实现多态,请优先使用通配符解决。 import java.util.List; public class Test {     public void testDemo( List<?> s){         for(Object obj:s){             System.out.println("我的类型是" + obj.getClass().getName());         }     }     public static void main(String[] args) {         // TODO Auto-generated method stub         Test test = new Test();         Dog a0 = new Dog();         Animal a1 = new Animal();         List<Animal> s = new ArrayList<Animal>();         s.add(a0);         s.add(a1);         test.testDemo(s);     } } 运行结果: 参考: https://www.shiyanlou.com/courses/running http://www.cnblogs.com/lwbqqyumidi/p/3837629.html
转载请注明原文地址: https://www.6miu.com/read-62601.html

最新回复(0)