泛型

一、泛型入门
1、开发人员装入集合的数据类型不确定,所以它被设计成可以装入所有的Object。
2、装入集合的数据丢失原来的数据类型,都变为Object。这样取出来的时候就需要类型转换。并且类型转换如果出错,是运行时错误,装入一只狗,出来转成一只猫。我们尽量把错误提前,提前到编译期。
4、集合上加泛型,每次装入集合元素时,编译器会检查,是否和原来的规定一样。取出元素的时候就不需要转型了。
5、jdk1.7加入了类型自动推断,但要注意以下情况:
import java.util.ArrayList;
import java.util.LinkedList;
import java.util.List;

public class Driver {
    public static void main(String[] args) {
        List<Number> list = new ArrayList();
        Number number = list.get(0);

        List list1 = new LinkedList<Number>();
        Object o = list1.get(0);
    }
}
View Code

二、泛型类

1、泛型类在创建对象的时候确定泛型类型
import java.util.ArrayList;
import java.util.List;

public class Driver {
    public static void main(String[] args) {
        Animal<String> animal = new Animal<>();
        animal.setName("黄牛");
        String name = animal.getName();
        System.out.println(name); // 黄牛
    }
}
class Animal<N> {
    private N name;

    public N getName() {
        return name;
    }

    public void setName(N name) {
        this.name = name;
    }
}
View Code

2、子类不是泛型类,子类在继承泛型类时确定泛型类型

class Animal<N> {
   
}

class Dog extends Animal<String> {
    
}
View Code

3、子类也是泛型类,子类在继承泛型父类时保证子类的泛型标识包含父类的泛型标识

class Animal<N> {

}

class Dog<T> extends Animal<T> {

}

class Cat<T, K> extends Animal<T> {

}

// 这种报错
class Tiger<E> extends Animal<T> {

}
View Code

三、泛型方法

 1、泛型方法特指在方法返回值前使用 <T> 标识的方法

class Demo {
    public <T> List<T> demo(T t) {
        List<T> list = new LinkedList<>();
        list.add(t);
        return list;
    }
}
View Code

  2、调用泛型方法时确定泛型类型

import java.util.LinkedList;
import java.util.List;

public class Driver {
    public static void main(String[] args) {
        List<String> list = new Demo().demo("黄桃");
        String s = list.get(0);
        System.out.println(s);
    }
}

class Demo {
    public <T> List<T> demo(T t) {
        List<T> list = new LinkedList<>();
        list.add(t);
        return list;
    }
}
View Code

 3、泛型方法不传递参数就无法确定泛型类型;但泛型方法声明时可以没有形参,没有语法错误,此时泛型类型是Object。

import java.util.LinkedList;
import java.util.List;

public class Driver {
    public static void main(String[] args) {
        List<Object> demo = new Demo().demo();
    }
}

class Demo {
    public <T> List<T> demo() {
        List<T> list = new LinkedList<>();
        return list;
    }
}
View Code

 4、泛型类的成员方法不可以是静态的;泛型方法可以是静态的

class Demo<D> {
    private D d;
    // 报错
    public static void setD(D d) {
        this.d = d;
    }

    public static <T> void demo() {
        
    }
}
View Code

 四、泛型符号使用位置

1、<T>或<T extends Number>,声明泛型类和泛型方法的位置只能使用这两种写法

class Demo<T> {}

class Demo2<T extends Number> {}

class Demo3 {
    <D> void demo() {}

    <D extends Number> void demo2() {};
}

2、T,泛型类和泛型方法内部可以把泛型符号当做类型使用

class Demo<T> {
    private T t;

    public T getT() { return t; }

    public void setT(T t) { this.t = t; }
}

class Demo2 {
    <T> T demo(T t) {return null;}
}

3、List<?>、List<? extends Number>、List<? super Number>可以在泛型类外部使用,用来声明变量,有三种形式:声明全局或局部变量、声明方法形参、声明方法返回值。

import java.util.List;

class Demo {
    List<?> list;
    List<? extends Number> list2;
    List<? super Number> list3;

    void demo(){
        List<?> list;
        List<? extends Number> list2;
        List<? super Number> list3;
    }

    void demo1(List<?> list) {}
    void demo2(List<? extends Number> list) {}
    void demo3(List<? super Number> list) {}

    List<?> demo4() {return null;}
    List<? extends Number> demo5() {return null;}
    List<? super Number> demo6() {return null;}
}

4、List<? extends E>、List<? super E>,在一个泛型类或泛型方法内部,另一个泛型类外部使用,如下,这里的外部泛型类指的是List类。

import java.util.List;

class Demo<E> {
    List<? extends E> list;
    List<? super E> list2;
}

class Demo2 {
    <D> void demo() {
        List<? extends D> list;
        List<? super D> list2;
    }
}

五、实例化泛型 

1、泛型实例化错误示例

public class Demo<T> {
    // 表达式右边报错
    private T t = new T();
}

2、泛型实例化正确示例

class Demo<T> {
    T t;
    Demo(Class<T> clazz) throws InstantiationException, IllegalAccessException {
        t = clazz.newInstance();
    }
}

public class Dirver {
    public static void main(String[] args) throws InstantiationException, IllegalAccessException {
        Demo<String> demo = new Demo<>(String.class);
        String t = demo.t;
        System.out.println(t == null); // 输出 false
    }
}

3、泛型数组实例化错误示例

class Demo<T> {
    T[] t = new T[10];
}

4、泛型数组实例化正确示例

import java.lang.reflect.Array;
class Demo<T> {
    T[] t;
    Demo(Class<T> clzz, int length) {
        t = (T[]) Array.newInstance(clzz, length);
    }
}
public class Dirver {
    public static void main(String[] args) {
        Demo<String> demo = new Demo<>(String.class, 5);
        String[] t = demo.t;
        System.out.println(t.length); // 输出5
    }
}

5、泛型实例化的另外一个例子 

import java.lang.reflect.Array;
import java.util.ArrayList;
public class Dirver {
    public static void main(String[] args) {
        // 报错
        // ArrayList<String>[] listArr1 = new ArrayList<String>[5];
        // 运行时报错
        // ArrayList<String>[] listArr2 = new ArrayList<>[5];

        // 可以
        ArrayList<String>[] listArr3 = new ArrayList[5];
        listArr3[0] = new ArrayList<String>();
        listArr3[0].add("1");
        // 可以
        ArrayList<String>[] listArr4 = (ArrayList[])Array.newInstance(ArrayList.class, 5);
        listArr4[0] = new ArrayList<String>();
        listArr4[0].add("2");
        // 输出 1    2        
        System.out.println(listArr3[0].get(0) + '\t' + listArr4[0].get(0)); 
    }
}

、泛型一个问题

1、一个方法的形参是 List<Number>,传入一个List<Integer>类型的对象报错。

import java.util.LinkedList;
import java.util.List;

public class Demo {

    public static void main(String[] args) {
        demo(new LinkedList<Number>());
        // 以下报错
        //demo(new LinkedList<Integer>());
    }
    
    public static void demo(List<Number> list) {}
}
View Code

注意 1:一个List<Number>对象的add方法可以传入一个Integer类型的元素。add方法要求传入一个Number,传入Integer会有自动转型。

    public static void main(String[] args) {
        List<Number> list = new ArrayList();
        list.add(new Float(1.0));
        list.add(new Integer(100));
        list.add(new Double(99.9));
        list.stream().forEach( n -> System.out.println(n));
        // 输出
        // 1.0
        // 100
        // 99.9
        Number number = list.get(0);
    }
View Code

注意 2:List<List<Number>>对象不可以传入一个new ArrayList<Integer>(),可以传入new ArrayList<Number>()。

import java.util.ArrayList;
import java.util.List;

class Demo {
    void demo() {
        List<List<Number>> list = new ArrayList<>();
        list.add(new ArrayList<Number>());
        // 下面报错
        list.add(new ArrayList<Integer>());
    }
}
View Code

2、试图解决方案一

import java.util.LinkedList;
import java.util.List;

public class Demo {

    public static void main(String[] args) {
        // 以下两个都报错
        demo(new LinkedList<Number>());
        demo(new LinkedList<Integer>());
    }

    public static void demo(List<Object> list) {}
}
View Code

3、试图解决方案二

import java.util.List;

public class Demo {

    public static void main(String[] args) {

    }
    // 方法重载失败,报错
    public static void demo(List<Number> list) {}
    public static void demo(List<Integer> list) {}
}
View Code

4、原因分析

import java.util.ArrayList;

public class Demo {

    public static void main(String[] args) {

        ArrayList<Number> num1 = new ArrayList<>();
        ArrayList<Integer> num2 = new ArrayList<>();

        System.out.println(num1.getClass().getSimpleName()); // 输出ArrayList
        System.out.println(num2.getClass().getSimpleName()); // 输出ArrayList

        System.out.println(num1.getClass() == num2.getClass()); // 输出true

    }
}
View Code

 List<Number>和List<Integer>是同一种类型。

 List<Number>和List<integer>泛型不同。

当方法形参是List<Number>,传入实参是List<Integer>时,泛型不同,所以报错。

 5、解决办法一

import java.util.LinkedList;
import java.util.List;

public class Demo {

    public static void main(String[] args) {
        demo(new LinkedList<Number>());
        demo(new LinkedList<Integer>());
    }
    public static void demo(List<?> list) {}
}
View Code

 6、解决办法二 

import java.util.LinkedList;
import java.util.List;

public class Demo {

    public static void main(String[] args) {
        demo(new LinkedList<Number>());
        demo(new LinkedList<Integer>());
    }
    public static void demo(List<? extends Number> list) {}
}
View Code

 六、泛型的另一个问题

1、声明为List<? extends E>类型的变量无法添加元素

import java.util.ArrayList;
import java.util.List;

public class Demo {

    public static void main(String[] args) {
        List<? extends Object> list = new ArrayList<>();
        // 报错
        list.add(new Object());
    }
}
View Code

2、声明为List<? super Nuber>类型的变量,可以添加Number类型及其子类类型的元素

import java.util.ArrayList;
import java.util.List;

public class Demo {

    public static void main(String[] args) {
        List<? super Number> list = new ArrayList<>();
        list.add((Number)100);
        list.add((Integer)100);
        list.add(1.23);
        list.add(100F);
        list.add(new Byte("10"));
        Object object = list.get(0);
        // 报错
        list.add(Object);
    }
}
View Code

七、泛型擦除

1、

验证

import java.lang.reflect.Field;
class Eraser<T> {
    public T t;
}
public class Dirver {
    public static void main(String[] args) throws NoSuchFieldException {
        Eraser<String> eraser = new Eraser<>();
        Field field = eraser.getClass().getFields()[0];
        String name = field.getName();
        String typeName = field.getType().getSimpleName();
        // 输出 t    Object
        System.out.println(name + '\t' + typeName);
    }
}
View Code

 2、

 验证:

import java.lang.reflect.Field;
class Eraser<T extends Number> {
    public T t;
}
public class Dirver {
    public static void main(String[] args) throws NoSuchFieldException {
        Eraser<Integer> eraser = new Eraser<>();
        Field field = eraser.getClass().getFields()[0];
        String name = field.getName();
        String typeName = field.getType().getSimpleName();
        // 输出 t    Number
        System.out.println(name + '\t' + typeName);
    }
}
View Code

3、

4、

 八、泛型一个应用

import java.util.Arrays;
import java.util.Comparator;
import java.util.TreeSet;

/**
 *  TreeSet(Comparator<? super E> comparator)的应用
 */
class Person {
    String name;
}
class Student extends Person{
    Integer studentNo;
    Student(String name, Integer studentNo) {
        this.name = name;
        this.studentNo = studentNo;
    }
}
public class Dirver {
    public static void main(String[] args) {
        Comparator<Person> comparatorByName = (a, b) -> a.name.compareTo(b.name);
        Comparator<Student> comparatorByNo = (a, b) -> a.studentNo - b.studentNo;

        TreeSet<Student> setOrderByName = new TreeSet<Student>(comparatorByName);
        TreeSet<Student> setOrderByNo = new TreeSet<Student>(comparatorByNo);

        Student[] students = {new Student("Tom", 100), new Student("Jim", 300), new Student("Lucy", 200)};
        setOrderByName.addAll(Arrays.asList(students));
        setOrderByNo.addAll(Arrays.asList(students));

        setOrderByName.stream().forEach(student -> System.out.println(student.name + "-" +student.studentNo));
        setOrderByNo.stream().forEach(student -> System.out.println(student.name + "-" +student.studentNo));
    }
}
View Code

 

 

posted @ 2017-03-25 22:55  zhuangrunwei  阅读(178)  评论(0编辑  收藏  举报