目录
1、泛型问题引出
2、泛型的定义
3、 泛型通配符
4、泛型接口
5、泛型方法
泛型是JDK1.5之后加到java语言里面的,主要目的是为了解决ClassCastException问题,在进行对象向下转型时都有可能存在安全隐患。
举例
public 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; } }
public class JavaDemo { public static void main(String[] args) { Point point = new Point(); point.setX(10); point.setY("dsfdf"); int x = (Integer) point.getY(); int y = (Integer) point.getX(); System.out.println(x + "====" + y); } }
这种情况,看似没有问题,但是存在安全隐患,由于使用了Object,这里面的字符串类型是无法强制转换为Integer的,而且在编译时又不会报错,所以有安全隐患。为了避免这种隐患,我们引入泛型的概念,使用泛型可以将这种隐患直接暴露在编译过程中。
泛型的本质在于,类中的属性或方法的参数与返回值的类型可以由对象实例化的时候动态决定。
使用方法:在类定义的时候明确定义的占位符(泛型标记),举例如下:
public 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; } }
如上所示,使用泛型标记后,Point类中的x和y属性的数据类型并不明确,他是由外部来确定的。
public class JavaDemo { public static void main(String[] args) { Point<Integer> point = new Point(); point.setX(10); point.setY("dsdf");//编译时直接报错 int x = point.getY(); int y = point.getX(); System.out.println(x + "====" + y); } }
如上,在实例化Point类时,指定了下x和y的数据类型为Integer(提示:这里如果不指定的话,Point还是使用Object,这个是默认结果),若是使用了不正确的类型转换,直接在编译过程就会报错,避免了运行时的安全隐患。
泛型通配符的引入主要是防止,随意篡改方法参数的数据类型。如下案例所示:
public class Message<T> { private T content; public T getContent() { return content; } public void setContent(T content) { this.content = content; } }
public class JavaDemo { public static void main(String[] args) { Message<String> msg1 = new Message<>(); msg1.setContent("www.loong.cn"); fun(msg1); Message<Integer> msg2 = new Message<>(); msg2.setContent(234); fun(msg2); } public static void fun(Message temp){ System.out.println(temp.getContent()); } }
以上使用看似没啥问题,其实暗藏隐患,正如上文所提的篡改参数问题,我们能够在方法中重新定义Message的数据类型。如下:输出的结果完全不一样了,两个实例化对象全部打印“hahaha”
public class JavaDemo { public static void main(String[] args) { Message<String> msg1 = new Message<>(); msg1.setContent("www.loong.cn"); fun(msg1); Message<Integer> msg2 = new Message<>(); msg2.setContent(234); fun(msg2); } public static void fun(Message temp){ temp.setContent("hahaha"); System.out.println(temp.getContent()); } }
所以我们有了新的概念,泛型通配符,使用方法如下
使用了?以后,方法虽然能够接受所有类型的参数,但是参数不能再被修改,只允许获得。
public class JavaDemo { public static void main(String[] args) { Message<String> msg1 = new Message<>(); msg1.setContent("www.loong.cn"); fun(msg1); Message<Integer> msg2 = new Message<>(); msg2.setContent(234); fun(msg2); } public static void fun(Message<?> temp){ temp.setContent("hahaha");//这行编译直接报错 System.out.println(temp.getContent()); } }
其他两种泛型通配符:
3.1 ?extends类:设置泛型的上限
例如: ? extends Number :表示该泛型只允许设置Number或Number的子类。
举例:
public class JavaDemo { public static void main(String[] args) { Message<String> msg1 = new Message<>(); msg1.setContent("www.loong.cn"); fun(msg1);//编译时这行报错 Message<Integer> msg2 = new Message<>(); msg2.setContent(234); fun(msg2); } public static void fun(Message<? extends Number> temp){ System.out.println(temp.getContent()); } }
3.2 ?super类:设置泛型的下限
例如: ? super String :表示该泛型只允许设置String或String的父类
举例:
public class JavaDemo { public static void main(String[] args) { Message<String> msg1 = new Message<>(); msg1.setContent("www.loong.cn"); fun(msg1); Message<Integer> msg2 = new Message<>(); msg2.setContent(234); fun(msg2);//报错 } public static void fun(Message<? super String> temp){ System.out.println(temp.getContent()); } }
泛型除了可以在类上定义以外,还可以在接口上使用
public interface Imessage<T> { public String echo(T t); }
对于泛型接口的子类而言现在就有两种实现方式:
4.1 子类中继续设置泛型:
public class MessageImpl<S> implements Imessage<S> { @Override public String echo(S s) { return "你好: " + s; } }
public class JavaDemo { public static void main(String[] args) { Imessage<String> imessage1 = new MessageImpl<>(); System.out.println(imessage1.echo("龙哥")); } }
4.2子类实现父类接口时直接定义
public class MessageImpl implements Imessage<String> { @Override public String echo(String s) { return "你好: " + s; } }
public class JavaDemo { public static void main(String[] args) { Imessage<String> imessage1 = new MessageImpl(); System.out.println(imessage1.echo("龙哥")); } }
如果将泛型标记写在方法上,那么这样的方法就被称为泛型方法
public class JavaDemo { public static void main(String[] args) { Integer[] num = fun(1, 2, 3); for (int temp : num) { System.out.println(temp + "! "); } String[] strings = fun("a", "b", "c"); for (String temp : strings) { System.out.println(temp + "! "); } } public static <T> T[] fun(T... args) { return args; } }