泛型学习笔记
泛型是 :把类型参数看作是使用参数化类型时指定的类型的一个占位符,就像方法的形式参数是运行时传递的值的占位符一样。
为什么需要泛型
没有泛型的情况的下,通过对类型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;}
}