泛型学习笔记

泛型是 :把类型参数看作是使用参数化类型时指定的类型的一个占位符,就像方法的形式参数是运行时传递的值的占位符一样。

为什么需要泛型

没有泛型的情况的下,通过对类型Object的引用来实现参数的“任意化”,“任意化”带来的缺点是要做显式的强制类型转换,而这种转换是要求开发者对实际参数类型可以预知的情况下进行的。对于强制类型转换错误的情况,编译器可能不提示错误,在运行的时候才出现异常,这是一个安全隐患。
泛型的好处是在编译的时候检查类型安全,并且所有的强制转换都是自动和隐式的,以提高代码的重用率。
没有使用泛型

/**
 * 使用的时候,使用setter可以没有异常的给属性赋值,可以设置不同类型,但是取值的时候,就必须强转
 */
public class Main {
    public static void main(String[] args) {
        System.out.println("Hello World!");
        //使用objectPoint类很容易出现的问题
        ObjectPoint objectPoint = new ObjectPoint();
        //属性设置不同类的值,不会有异常
        objectPoint.setX(23);
        objectPoint.setY("234度");
        //读取属性的时候强转也不会有问题
        Integer x = (Integer) objectPoint.getX();
        Integer y = (Integer)objectPoint.getY();//这种向下强转编写代码并不会有任何错,只有编译时才会编译报错
        //运行的时候,就会报错,类型转换异常
        //拆箱的时候向下转型,此处体现了向下转型的不安全性
        System.out.println("x="+x+",y="+y);
    }
}
class ObjectPoint{
    private Object x;
    private Object y;
    //省略setter、getter
}

使用泛型

//T是占位符,可以是其他任何有效字符,如A,X,L,当使用的时候,申明的String,T就是String,申明为Integer,T就是Integer
class Type <T>{
    private T name;
    private T value;
    public T getName() {return name;}
    public void setName(T name) {this.name = name;}
    public T getValue() {return value;}
    public void setValue(T value) {this.value = value;}
}
public class GenericType {
    public static void main(String[] args) {
        Type<String> type = new Type<>();
        type.setName("泛型数据");
        //type.setValue(123);//设置整形数据编写代码的同时就提示了异常,注意和不使用泛型的区别
        String name = type.getName();//获取属性的时候也不需要向下转型
        String value = type.getName();
        System.out.println("name="+name+",value="+value);
    }
}

泛型接口

接口声明的时候用了泛型占位符的就是泛型接口,类似,方法使用了泛型占位符的方法就是泛型方法。
泛型接口的实现有两种:

/**
 * 定义了一个泛型接口,其实现有两种
 * @param <T>
 */
interface IMessage<T>{
    void log(T t);
}

/**
 * 实现方法1:接口指定类型,实现类中类型就得到限制,如方法参数类型
 */
class MessageIpm1 implements IMessage<String>{
    @Override
    public void log(String s) {
        System.out.println(s);
    }
}

/**
 * 实现方法2:不指定泛型类型,交由实现对象指明
 * @param <T>
 */
class MessageIpl2<T> implements IMessage<T>{
    @Override
    public void log(T t) {
        System.out.println(t);
    }
}

public class GenericInterface {
    public static void main(String[] args){
        IMessage<String> message1 = new MessageIpm1();//只需要在泛型类指明泛型类型
        message1.log("123");

        IMessage<String> message2 = new MessageIpl2<>();//需要添加泛型类型,两个地方:接口和实现类
        message2.log("messages2");
    }
}

泛型中的通配符

通配符能够限制使用的时候修改属性值

public class General {

    /**
     * 泛型通配符
     * @param args
     */
    public static void main(String[] args){
        Note<String> note = new Note<>();
        note.setNote("做笔记");
        func(note);
    }
    public static void func(Note<?> note){
        //note.set("做新笔记");//会报错,无法修改值,编译器提示不知道note的属性类型
        System.out.println(note.getNote());
    }
}
class Note<T>{
    private T note;
    public T getNote() {return note;}
    public void setNote(T note) {this.note = note;}
}

通配符和super、extends联合使用

?extends 设置泛型上限,如 ?extends Number,只能设置Number及其子类,如Integer、Double。用于方法参数和声明
?super 设置泛型下限,如?super String,表示只能设置String或其父类Object。用于方法参数。

public class General {

    /**
     * 泛型通配符
     * @param args
     */
    public static void main(String[] args){
        Note<String> note = new Note<>();//从这类开始代码就开始提示报错
        note.setNote("做笔记");
        func(note);
    }
}
class Note<T extends Number>{
    private T note;
    public T getNote() {return note;}
    public void setNote(T note) {this.note = note;}
}