本文共 6349 字,大约阅读时间需要 21 分钟。
Java高级开发之泛型
目录
泛型问题引出
泛型类的基本使用
泛型方法
通配符(重点)
泛型接口
类型擦除
泛型问题引出
假设需要你定义一个描述坐标的程序类Point,需要提供两个属性x、y。对于这两个属性的内容可能有如下选择:
1. x = 10、y = 20 ;
2. x = 10.1、y = 20.1 ;
3. x = 东经80度、y = 北纬20度
那么现在首先要解决的问题就是Point类中的x、y的属性类型问题,此时需要保存的有int、double、String,所以 在java中只有一种类型可以保存所有类型:Object型范例:定义Point类
class Point {private Object x ;private Object y ;public Object getX() {return x;}public void setX(Object x) {this.x = x;}public Object getY() {return y;}public void setY(Object y) {this.y = y;}}
范例:设置整型坐标
// 设置数据Point p = new Point() ;p.setX(10); // 自动装箱并且向上转型为Objectp.setY(20);// 取出数据int x = (Integer) p.getX() ; // 强制向下转型为Integer并且自动拆箱int y = (Integer) p.getY() ;System.out.println("x = " +x+",y = "+y);
范例:设置字符串
// 设置数据Point p = new Point() ;p.setX("东经80度");p.setY("北纬20度");// 取出数据String x = (String) p.getX() ;String y = (String) p.getY() ;System.out.println("x = " +x+",y = "+y);
观察问题:
// 设置数据Point p = new Point() ;p.setX(10.2);p.setY("北纬20度");// 取出数据String x = (String) p.getX() ;String y = (String) p.getY() ;System.out.println("x = " +x+",y = "+y);
这个时候由于设置方的错误,将坐标内容设置成了double与String,但是接收方不知道,于是在执行时就会出现
ClassCastException。 ClassCastException指的是两个没有关系的对象进行强转出现的异常。 这个时候语法不会对其做任何限制,但执行的时候出现了程序错误,所以得出结论:向下转型是不安全的操作,会 带来隐患。
泛型类的基本使用
范例:泛型类引入多个类型参数以及使用
class MyClass{ T value1; E value2;}public class Test { public static void main(String[] args) { MyClass myClass1 = new MyClass (); }}
注意:泛型只能接受类,所有的基本数据类型必须使用包装类!
范例:使用泛型定义Point类
class Point{ // T表示参数,是一个占位的标记;如果有多个泛型就继续在后面追加private T x ;private T y ;public T getX() {return x;}public void setX(T x) {this.x = x;}public T getY() {return y;}public void setY(T y) {this.y = y;}}public class TestDemo {public static void main(String[] args) {// 设置数据Point p = new Point () ; // JDK1.5的语法p.setX("东经80度");p.setY("北纬20度");// 取出数据String x = p.getX() ; // 避免了向下转型String y = p.getY() ;System.out.println("x = " +x+",y = "+y);}}
泛型方法
泛型方法定义
class MyClass{publicvoid testMethod(T t) {System.out.println(t);}}
使用类型参数做返回值的泛型方法
class MyClass{publicT testMethod(T t) {return t;}}
泛型方法与泛型类共存
class MyClass{public void testMethod1(T t) {System.out.println(t);}public T testMethod2(T t) {return t;}}public class Test {public static void main(String[] args) {class MyClass {public void testMethod1(T t) {System.out.println(t);}public T testMethod2(T t) {return t;}}public class Test {public static void main(String[] args) {
上面代码中,MyClass <T> 是泛型类,testMethod1 是泛型类中的普通方法,而 testMethod2 是一个泛型方法。
而泛型类中的类型参数与泛型方法中的类型参数是没有相应的联系的,泛型方法始终以自己定义的类型参数为准。 泛型类的实际类型参数是 String,而传递给泛型方法的类型参数是 Integer,两者不相干。 但是,为了避免混淆,如果在一个泛型类中存在泛型方法,那么两者的类型参数最好不要同名。比如,MyClass <T> 代码可以更改为这样:
class MyClass{public void testMethod1(T t) {System.out.println(t);}public E testMethod2(E e) {return e;}}
通配符(重点)
在程序类中追加了泛型的定义后,避免了ClassCastException的问题,但是又会产生新的情况:参数的统一问题。
使用通配符
class Message{private T message ;public T getMessage() {return message;}public void setMessage(T message) {this.message = message;}}public class TestDemo {public static void main(String[] args) {Message message = new Message() ;message.setMessage("比特科技欢迎您");fun(message);}public static void fun(Message temp){System.out.println(temp.getMessage());}}public class TestDemo {public static void main(String[] args) {Message message = new Message() ;message.setMessage(99);fun(message); // 出现错误,只能接收String}public static void fun(Message temp){System.out.println(temp.getMessage());}}
使用通配符
public class TestDemo {public static void main(String[] args) {Messagemessage = new Message() ;message.setMessage(55);fun(message);}// 此时使用通配符"?"描述的是它可以接收任意类型,但是由于不确定类型,所以无法修改public static void fun(Message temp){//temp.setMessage(100); 无法修改!System.out.println(temp.getMessage());}}
在"?"的基础上又产生了两个子通配符:
? extends 类:设置泛型上限: 例如:? extends Number,表示只能够设置Number或其子类,例如:Integer、Double等;? super 类:设置泛型下限: 例如:? super String,表示只能够设置String及其父类Object。观察泛型上限
class Message{ // 设置泛型上限private T message ;public T getMessage() {return message;}public void setMessage(T message) {this.message = message;}}public class TestDemo {public static void main(String[] args) {Message message = new Message() ;message.setMessage(55);fun(message);}// 此时使用通配符"?"描述的是它可以接收任意类型,但是由于不确定类型,所以无法修改public static void fun(Message temp){//temp.setMessage(100); 仍然无法修改!System.out.println(temp.getMessage());}}
设置泛型下限
class Message{private T message ;public T getMessage() {return message;}public void setMessage(T message) {this.message = message;}}public class TestDemo {public static void main(String[] args) {Message message = new Message() ;message.setMessage("Hello World");fun(message);}public static void fun(Message temp){// 此时可以修改!!temp.setMessage("bit!");System.out.println(temp.getMessage());}}
泛型接口
在子类定义时继续使用泛型
interface IMessage{ // 在接口上定义了泛型public void print(T t) ;}class MessageImpl implements IMessage {@Overridepublic void print(T t) {System.out.println(t);}}public class TestDemo {public static void main(String[] args) {IMessage msg = new MessageImpl() ;msg.print("Hello World");}}
在子类实现接口的时候明确给出具体类型
interface IMessage{ // 在接口上定义了泛型public void print(T t) ;}class MessageImpl implements IMessage {@Overridepublic void print(String t) {System.out.println(t);}}public class TestDemo {public static void main(String[] args) {IMessage msg = new MessageImpl() ;msg.print("Hello World");}}
类型擦除
观察类型擦除
class MyClass{private T message;private E text;public E getText() {return text;}public void setText(E text) {this.text = text;}public T getMessage() {return message;}public void setMessage(T message) {this.message = message;}public void testMethod1(T t) {System.out.println(t);}}public class Test {public static void main(String[] args) {MyClass myClass1 = new MyClass<>();Class cls = myClass1.getClass();Field[] fields = cls.getDeclaredFields();for (Field field : fields) {System.out.println(field.getType());}}}
在泛型类被类型擦除的时候,之前泛型类中的类型参数部分如果没有指定上限,如 <T> 则会被转译成普通的
Object 类型,如果指定了上限如 <T extends String> 则类型参数就被替换成类型上限。
转载地址:http://wmxrb.baihongyu.com/