泛型的概念
泛型就是参数化类型。定义一个带参数的方法时有形参,调用这个方法的时候要传入实参。而所谓参数化类型就是这个形参的类型,将原来定义好的参数类型参数化,然后在使用的时候传入具体的类型。
泛型的作用
主要是限定参数类型,以防止后续调用出现错误,例如:
List不指定泛型时默认是object类,下面这个例子转化为Integer计算时就会报错。
public static void main(String [] args) throws Exception{
List list = new ArrayList();
list.add("lll");
list.add(123);
int a = (Integer) list.get(0) + (Integer) list.get(1);
System.out.print(a);
}
自定义泛型
有时我们需要对一些对象类型进行额外的逻辑操作,但是这些对象类型未定,这个时候使用自定义泛型是个不错的办法。
下面这个例子就是对Tag类中的data进行了额外的操作,data既可以是Integer,也可以是Boolean。
public static void main(String [] args) throws Exception{
Tag<Integer> integerTag = new Tag<Integer>(4,"数量是4");
System.out.println(integerTag.getDescription());
Tag<Boolean> booleanTag = new Tag<>(false,"这个标签目前是");
System.out.println(booleanTag.getDescription());
}
static class Tag<T>{
private T data;
private String description;
public Tag(){}
public Tag(T data,String description) {
this.description = description;
this.data = data;
}
public Tag(T data) {
this.data = data;
}
public T getData(){
return data;
}
public String getDescription(){
return description+data.toString();
}
}
这里要注意一点,就是Tag指定泛型后,仅仅只是限定了Tag内的数据类型,而对于Tag而言它的类型并没有什么变化,可以看下面的例子
public static void main(String[] args) {
Tag<String> name = new Tag<String>("corn");
Tag<Integer> age = new Tag<Integer>(712);
System.out.println("name class:" + name.getClass()); // com.xiaow.Tag
System.out.println("age class:" + age.getClass()); // com.xiaow.Tag
System.out.println(name.getClass() == age.getClass()); // true
}
现在我们已经知道了Tag<String>和Tag<Integer>是同一种类型,现在需要继续探讨一个问题,那么在逻辑上,类似于Tag<Number>和Tag<Integer>是否可以看成具有父子关系的泛型类型呢?看下面例子
public static void main(String [] args) throws Exception{
Tag<Integer> integerTag = new Tag<Integer>(4,"数量是4");
System.out.println(integerTag.getDescription());
Tag<Boolean> booleanTag = new Tag<>(false,"这个标签目前是");
System.out.println(booleanTag.getDescription());
Tag<Number> numberTag = new Tag<>(11);
printData(numberTag);//1
printData(integerTag);//2
}
public static void printData(Tag<Number> data) {
System.out.println(data.getData());
}
这里ide会告诉我们2处出现编译错误printData,错误提示为
(com.xiaow.learn.Annotion.Test.Tag<java.lang.Number>)
in Test cannot be applied
to
(com.xiaow.learn.Annotion.Test.Tag<java.lang.Integer>)
这表明了Tag<Number>和Tag<Integer>不能看做为具有父子关系的泛型类型。但是如果我们有需求是需要能使用父子关系的泛型呢?这里就需要使用类型通配符了,看下面例子:
首先我们可以使用类型通配符在printData方法里
public static void main(String [] args) throws Exception{
Tag<Integer> integerTag = new Tag<Integer>(4,"数量是4");
Tag<Number> numberTag = new Tag<>(11);
printData(numberTag);//1
printData(integerTag);//2
}
public static void printData(Tag<? extends Number> data) {
System.out.println(data.getData());
}
这样就不会出现编译错误了,如果我们要限定Tag内的data只能是某一类的对象呢,我们可以这样做,首先让这一类的对象都实现某个接口,然后定义Tag的泛型都要extends这个接口,如下例子
public static void main(String [] args) throws Exception{
Tag<Note> numberTag = new Tag<>(new Note("hh"));
Tag<Article> articleTag = new Tag<>(new Article(22));
}
static class Tag<T extends AppDo>{
private T data;
private String description;
public Tag(){}
public Tag(T data,String description) {
this.description = description;
this.data = data;
}
public Tag(T data) {
this.data = data;
}
public T getData(){
return data;
}
public String getDescription(){
return description+data.toString();
}
}
//接口
public interface AppDo extends Serializable {
}
//两个实现类
public class Article implements AppDo {
private Integer count;
public Integer getCount() {
return count;
}
public void setCount(Integer count) {
this.count = count;
}
public Article(Integer count) {
this.count = count;
}
public Article() {
}
}
public class Note implements AppDo {
private String name;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Note(String name) {
this.name = name;
}
public Note() {
}
}