15.1 java泛型(初体验)

15.1.1 什么是泛型?

泛型,即“参数化类型”。一提到参数,最熟悉的就是定义方法时有形参,然后调用此方法时传递实参。那么参数化类型怎么理解呢?顾名思义,就是将类型由原来的具体的类型参数化,类似于方法中的变量参数,此时类型也定义成参数形式(可以称之为类型形参),然后在使用/调用时传入具体的类型(类型实参)。

15.1.2 泛型的使用

腾讯课堂视频笔记:
1.概念:泛型就是参数化类型
  -适用于对多种数据类型执行相同功能的代码。
  -泛型中的类型在使用时指定。
  -泛型归根到底就是“模板”。

2.泛型主要适用在集合中。

3.任意化:Object是所有类的根类,但是具体类使用的时候,需要类型强制转换的
  - 多态:Object可以接受任意类型。
  - 缺点:
         需要类型转换;
         需要类型检查;
         需要处理转换错误异常。

4.泛型:使用泛型时,在实际使用之前类型就已经确定了,不需要强制转换。

5.泛型字母
  - 形式类型参数(formal type parameters)即泛型字母。
  - 命名:泛型字母可以随意指定(符合变量命名规则即可,包括中文),尽量使用单个的大写字母(有时候多个泛型类型时会加上数字,比如T1,T2)。
  - 常见字母(见名知意)
           T (Type) , K  V (Key  Value) , E (Element)
  - 当类被使用时,会使用具体的实际类型参数(actual type argument)代替。

6.泛型方法
  - 定义方法时:<字母>   
  - 注意: 泛型方法可以在非泛型类中
      public class Test{
          public static void main(String[] args){
            test("a");   //T--->String
          }
          //定义泛型方法
          public static <T> void test(T a){
            System.out.println(a);
          }
            //定义泛型方法 extends <=    
          public static <T extends Closeable> void test(T...a){
            for(T temp:a){
              try{
                  if(temp != null){
                      temp.close();
                  }
                  }catch(IOException e){
                      e.printStackTrace();
                  }
            }
          }
      }

7.泛型继承、实现
      public abstract class Father<T1,T2>{}  //父类
  (1)父类为泛型类,子类继承时:

        - (不保留父类泛型) 父类擦除|指定类型时,子类按需编写

        //父类擦除时,即父类泛型没有指定类型,默认为Object;这时子类可以不写泛型,也可以新增泛型
        public class Child extends Father{}
        public class Child<A,B> extends Father{}
        //父类指定具体类型时,子类可以不写泛型,也可以新增泛型
        public class Child extends Father<Integer,String>{}
        public class Child<A,B> extends Father<Integer,String>{}

        - (保留父类泛型)父类存在泛型,子类泛型参数个数必须 >= 父类保留泛型参数个数

        //部分保留父类泛型,则子类必须要写父类保留的泛型参数,也可以新增泛型
        public class Child<T1,A,B> extends Father<T1,String>{}
        //全部保留父类泛型,则子类必须要写所有父类的泛型,也可以新增
        public class Child<T1,T2,A> extends Father<T1,T2>{}

       - 属性类型:根据所在位置而定。父类中,随父类而定;子类中,随子类而定(需要扩充笔记)
       - 子类重写方法类型:随父类而定。

   (2)接口为泛型接口,子类实现时,
       - 与继承同理,重写方法随接口而定


8.泛型擦除
  - 定义:泛型擦除是指在继承(实现)或使用时没有指定具体的类型
  - 特点:一旦擦除之后按Object处理
         - 依然存在警告,加上Object可以去除,但是有些画蛇添足
         - 不完全等同于Object,编译不会类型检查
    public static void main(String[] args){
      //泛型擦除,但是存在警告
      Student stu= new Student();
      stu.setJavaScore("81");//以Object处理
      //消除警告,使用Object
      Student<Object> student= new Student<Object>();
      //不完全等同于Object,编译不会类型检查
      test(stu);//正确,擦除,编译通过,不会类型检查
      //test(student);//错误,Object编译检查
    }
    public static void test(Student<Integer> a){}

9.通配符?(Wildcards)
  - T、 K、 V、 E等泛型字母为有类型,类型参数赋予具体的值
  - ? 未知类型,类型参数赋予不确定值,任意类型
  - 只能用在声明类型、方法参数上,不能用在定义泛型类、泛型方法、泛型接口上,也不能用在创建对象。

  //此处T不能够换成?
  public class Student<T>{
    T Score;
    public static void main(String[] args){
      //通配符:用在声明类型,不能这样用new Student<?>();
      Student<?> stu = new Student<String>();
      test(new Student<Integer>());
    }
    //通配符:用在声明方法参数  接收信息
    public static void test(Student<?> stu){
      //获取信息
      System.out.print(stu.score);
    }
  }

10.上限extends:指定的类型必须是继承某个类,或实现某个接口,即<=(本类或子类)
   - ? extends Fruit
   - T extends List
   - 一般用于限制操作,不能使用在添加数据上面,一般都是读取操作,即不能添加信息
   - 规则:
         List<Fruit> 满足 List<? extends Fruit>
         List<Apple> 满足 List<? extends Fruit>
         List<? extends Apple> 满足 List<? extends Fruit>
         List<?> 等同 List<? extends Object> //不满足
   - 思考:public void test(List<? extends Fruit> list){
             list.add(new Fruit("f"));
             list.add(new Pear("p"));
             list.add(new Apple("a"));
           }  这段代码为什么无法通过编译呢???
    因为List<Fruit>、List<Apple>等都是List<? extends Fruit>的子类型。先假设传入的参数为List<Fruit>则以上代码的三个add操作都是可行的,可如果是List<Apple>,则只有第三个add可以执行,可见,为了保护其类型的一致性,也是不能往List添加任意对象的,不过却可以添加null。

11. 下限super:指定的类型不能小于操作的类,即 >= (本类或父类)
   - ? super Apple
   - T super Apple 
   - 不能添加父对象
   - 规则:
         List<Apple> 满足 List<? super Apple>
         List<Fruit> 满足 List<? super Apple>
         List<? super Fruit> 满足 List<? super Apple>
   - 思考:public void test(List<? super Apple> list){
             list.add(new Apple("apple"));
             list.add(new FujiApple("fuji"));
             list.add(new Fruit("fruit"));
             }    这段代码哪一行不能通过编译,为什么?
   同理,传入List<Apple>则第三行错误,不能list.add(new Fruit("fruit")),为了保护类型的一致性,因为“? super Apple”可以是Fruit,也可以是Object,因无法确定其类型,也就不能往List<? super Apple> 添加Apple的任意父类对象。

12.泛型嵌套
   - 稍微复杂一些,从外到内拆分
       public class Student<T>{
         T score;
       }
       public class Bjsxt<T>{
         T stu;
       }
       public class Main{
         public static void main(String[] args){
           //泛型的嵌套
           Bjsxt<Student<String>> room = new Bjsxt<>();
           //从外到内拆分
           room.stu = new Student<String>();
           Student<String> stu= room.stu;
           String score = stu.score;
           System.out.println(score);
         }
       }

13.其他
  - 泛型没有多态 //A<Fruit> f = new A<Apple>();编译出错
  - 没有泛型数组 //Student<String>[] stus = new Student<String>[10];编译出错
  - jdk1.7简化泛型(声明指定,创建可以省略):List<String> li = new ArrayList<>();

15.1.2.1 泛型运用在class中

   [访问修饰符]  class 类名<泛型1,泛型2,…>{
      [访问权限] 泛型类型标识  变量名称;
      [访问权限] 构造方法([<泛型类型>] 参数名称){ //内部代码}
      [访问权限] 返回值类型    方法名称(){    //内部代码        }
      [访问权限] 返回值类型声明    方法名称(泛型类型标识 变量名称){ //内部代码}
   }

例如:
/*
  此处声明了一个包含泛型T的泛型类,T代表所有可能的类型,而T
  的实际类型在 Test 类实例化时指定。 
*/
public class Test<T> {

   private T f;  //f为泛型成员。在类名后面声明泛型后,在类内部可以向普通类型一样使        
   public Test(){
    }
                                            //用泛型
   public Test(T f){
        this.f = f;
    }
   public void setF(T f) {//setF方法的参数类型为泛型T
        this.f = f;
   }
   public T getF() {//getF方法的返回类型为泛型T 
        return f;
   }
}

15.1.2.2 实例化泛型类

实例化泛型类时,必须制定泛型的具体类型。例如:

test test1 = new Test();//编译时默认指定为Object
Test<String> test1 = new Test<String>();
Test<String> test1 = new Test<>();//jdk1.7泛型的简化,后面可以不写

15.1.3 泛型运用在方法中(了解)

单独在方法中运用泛型:

public <T> T test(T t) {
    // 方法中的T 由 实际参数的类型决定.
    return t;
}

使用:
  对象引用名.<String>test("abc");//完整的写法
  对象引用名.test("abc");//jdk1.7之后,可以省略泛型的指定,而是根据传入的形参的类型自动而定

15.1.4 泛型中的 通配符 ? (了解)

通配符只能用在声明泛型类的引用,和定义泛型类返回值中:

Test<?> test=new Test<Object>();//该引用可以指向 new Test<任意类型>();
public Test<?> getTest(){//可以返回  new Test<任意类型>();
    return new Test<Object>();
}

15.1.5 泛型中使用 extends\super (了解)

  1. extends 可以用在设计泛型,也能用在声明泛型类的引用,和定义泛型类返回值中

  2. super 不能用在设计泛型,只能用在声明泛型类的引用,和定义泛型类返回值中

如:设计泛型类时

public class Test<K extends Student>{} //正确
public <T extends People> void text(T t) {//正
}
public class Test<K super Student>{} //错误
public <T super Student> void text(T t) {//错误
}

如:声明泛型类的引用,和定义泛型类返回值中

//声明泛型类的引用
Test<? extends People> test = new Test<Student>();
//定义泛型类返回值
public Test<? extends People> getTest(){
    return new Test<Student>();
}
//  正确
//声明泛型类的引用
Test<? super Student> test = new Test<People>();
//定义泛型类返回值
public Test<? super Student> getTest(){
    return new Test<People>();
}
//  正确

results matching ""

    No results matching ""