泛型
JDK1.5当中的泛型是主要的,他能帮我们实现参数转换问题。
目录
泛型的问题引出
现在假设需要你定义一个描述坐标的程序类Point,而这个坐标类中需要提供两个属性,x,y 对于这两个属性的内容有如下几种选着。
x=10,y=20;
x=10.1,y=20.2;
x=东京70度 y=北纬20度;
现在要解决的问题是point中的x和y属性类型问题,那么此时需要保存的是int double String 在java里面只有一种类型可以保存所有的类型。
int自动装 箱为Integer Integer自动向上转为Object
double自动装箱为Double,Double自动向上转为Object
String自动装箱为Object
1 package cn.Tony.demo; 2 3 import cn.Tony.util.MyMath; 4 5 class Point{ 6 private Object x; 7 private Object y; 8 public Object getX() { 9 return x; 10 } 11 public void setX(Object x) { 12 this.x = x; 13 } 14 public Object getY() { 15 return y; 16 } 17 public void setY(Object y) { 18 this.y = y; 19 } 20 } 21 22 public class TestDemo { 23 public static void main(String[] args) { 24 //第一步:设置数据 25 Point p=new Point(); 26 p.setX(10.2); 27 p.setY("北纬10度"); 28 //第二步:取出数据 29 String x=(String)p.getX(); 30 String y=(String)p.getY(); 31 System.out.println("x="+x+",y="+y); 32 } 33 }
ClassCastException 是两个没有关系的对象进行强制转换带来异常,那么这个时候语法不会有限制,编译时才会有错误,得出一个结论:向下转型是不安全的操作,会带来隐患。
泛型的实现
泛型指的是在类定义的时候并不会设置类中的属性或方法中的参数的具体类型,而是在类使用的时候在进行定义,泛型的操作,要做一个类型的声明,或者一个类型的标记,
范例:
1 package cn.Tony.demo; 2 //在Point类定义的时候完全不知道X和Y属性是什么类型。而由我们的使用者来进行 3 class Point <T>{//T表示参数, 是一个占位的标记 4 private T x; 5 private T y; 6 public T getX() { 7 return x; 8 } 9 public void setX(T x) { 10 this.x = x; 11 } 12 public T getY() { 13 return y; 14 } 15 public void setY(T y) { 16 this.y = y; 17 } 18 } 19 20 public class TestDemo { 21 public static void main(String[] args) { 22 //第一步:设置数据 23 Point<String> p=new Point<String>(); 24 p.setX("东经10度");//设置坐标 25 p.setY("北纬10度"); 26 //第二步:取出数据 27 String x=p.getX();//避免了向下转型 28 String y=p.getY();//避免了向下转型 29 System.out.println("x="+x+",y="+y); 30 } 31 }
当开发的程序可以避免向下转型,也就意味着安全隐患被消除了。尽量不要使用向下转型
通配符
虽然程序类中有了泛型的定以后避免了ClassCastException的问题,但是又会产生新的情况:参数统一的问题。
范例:观察程序
1 package cn.Tony.demo; 2 class Message<T>{ 3 private T note; 4 public void setNote(T note) { 5 this.note = note; 6 } 7 public T getNote() { 8 return note; 9 } 10 } 11 12 public class TestDemo { 13 public static void main(String[] args) { 14 Message<String> msg=new Message<>(); 15 msg.setNote("天天帅气!"); 16 fun(msg); 17 } 18 public static void fun(Message<String> temp) { 19 System.out.println(temp.getNote()); 20 } 21 }
但是这样会带来一个新的问题,如果泛型的类型设置的不是String,而是Integer(泛型类型只允许设置类和接口而不能是基本数据类型)
范例:错误代码
1 public class TestDemo { 2 public static void main(String[] args) { 3 Message<Integer> msg=new Message<>(); 4 msg.setNote(10); 5 fun(msg); 6 } 7 public static void fun(Message<String> msg) { 8 System.out.println(msg.getNote()); 9 } 10 }
1 public class TestDemo { 2 public static void main(String[] args) { 3 Message<Integer> msg=new Message<>(); 4 msg.setNote(10); 5 fun(msg); 6 } 7 //如果没有设置泛型,那么默认就是Object 8 public static void fun(Message msg) { 9 msg.setNote("天"); 10 System.out.println(msg.getNote()); 11 } 12 }
所以:可以接受所有的泛型类型,不能让用户修改。那么就需要使用我们的通配符来实现,使用“?”来处理。
1 public class TestDemo { 2 public static void main(String[] args) { 3 Message<Integer> msg=new Message<>(); 4 msg.setNote(10); 5 fun(msg); 6 } 7 //此时使用的通配符“?”描述可以接收任意类型,但是由于不确定类型,所以无法修改 8 public static void fun(Message<?> msg) { 9 System.out.println(msg.getNote()); 10 } 11 }
而在“?”的基础上又产生了两个子通配符
?extends类:设置泛型上限:
例如:?extends Number ,表示只能够设置Number或其子类,例如:Integer,Double等;
?super类:设置泛型下限:
例如:?super Strinhg ,表示只能够设置String或其父类Object
范例:观察泛型上限
1 package cn.Tony.demo; 2 class Message<T extends Number>{ 3 private T note; 4 public void setNote(T note) { 5 this.note = note; 6 } 7 public T getNote() { 8 return note; 9 } 10 } 11 public class TestDemo { 12 public static void main(String[] args) { 13 Message<Integer> msg=new Message<>(); 14 msg.setNote(10); 15 fun(msg); 16 } 17 //此时使用的通配符“?”描述可以接收任意类型,但是由于不确定类型,所以无法修改 18 public static void fun(Message<? extends Number> msg) { 19 System.out.println(msg.getNote()); 20 } 21 }
范例:设置泛型下限
1 package cn.Tony.demo; 2 class Message<T>{ 3 private T note; 4 public void setNote(T note) { 5 this.note = note; 6 } 7 public T getNote() { 8 return note; 9 } 10 } 11 public class TestDemo { 12 public static void main(String[] args) { 13 Message<String> msg=new Message<>(); 14 msg.setNote("11"); 15 fun(msg); 16 } 17 //此时使用的通配符“?”描述可以接收任意类型,但是由于不确定类型,所以无法修改 18 public static void fun(Message<? super String> msg) { 19 System.out.println(msg.getNote()); 20 } 21 }
泛型接口
泛型除了在类中定义之外还可以定义在接口里面,这种情况称为泛型接口
泛型接口:
1 interface IMessage<T> { 2 public void print(T t) ; 3 }
但是对于这个接口实现有两种做法:
范例:在子类定义的时候继续使用泛型
1 package cn.Tony.demo; 2 interface IMessage<T> { 3 public void print(T t) ; 4 } 5 class MessageIplm<T> implements IMessage<T>{ 6 public void print(T t) { 7 System.out.println(t); 8 } 9 } 10 public class TestDemo { 11 public static void main(String[] args) { 12 IMessage<String> msg=new MessageIplm<String>(); 13 msg.print("Hello"); 14 } 15 }
范例:在子类实现接口的时候给出具体类型
1 package cn.Tony.demo; 2 interface IMessage<T> { 3 public void print(T t); 4 } 5 class MessageIplm implements IMessage<String>{ 6 public void print(String t) { 7 System.out.println(t); 8 } 9 } 10 public class TestDemo { 11 public static void main(String[] args) { 12 IMessage<String> msg=new MessageIplm(); 13 msg.print("Hello"); 14 } 15 }
泛型方法
在之前定义的类和方法中继续使用泛型,这种方法就称为泛型方法,但是泛型方法不一定非定义在类和接口里面,也可以单独定义。
范例:定义泛型方法
1 package cn.Tony.demo; 2 3 public class TestDemo { 4 public static void main(String[] args) { 5 Integer data[]=fun(1,2,3); 6 for(int temp:data) {//迭代和自动拆箱 7 System.out.println(temp); 8 } 9 } 10 public static <T> T[] fun(T...args) { 11 return args; 12 } 13 }