Java泛型
Posted 菜菜小谭
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Java泛型相关的知识,希望对你有一定的参考价值。
一.why 为什么有泛型
目的: 提高程序的健壮性和易用性
需求: 设计一个坐标类 Point
能满足以下三种需求
(1) 保存 int类型的坐标
int x = 10;
int y = 20;
Point point = new Point();
point.setX(10);//int--->Integer--->Object
point.setY(20);
int x = (Integer)point.getX();
int y = (Integer)point.getY();
System.out.println("x=" + x + ",y=" + y);
(2) 保存double类型的坐标
double x = 20.0
double y = 30.0
Point point = new Point();
point.setX(10.0);//int--->Double--->Object
point.setY(20.0);
double x = (Double)point.getX();
double y = (Double)point.getY();
System.out.println("x=" + x + ",y=" + y);
(3) 保存字符串类型的坐标
String x = "东经20度";
String y = "北纬30度";
初步考虑使用Object
public class Point{
private Object x;//经度
private Object y;//维度
}
把Point类的属性设计成Object 可以满足以上3种不同坐标的需求,头几天还是可以的
但是有一天,一个程序员不小心稍微改动了一下代码,问题发生了...
使用Object 虽然能满足需求,但是还是不安全的...但是这种错误在编译的时候发现不了,
只能在运行的时候才暴露出来... JDK5.0以前没有这种机制,为了让程序更加的安全,提高
程序的健壮性,出现了泛型
public class TestPoint {
public static void main(String[] args) {
Point point = new Point();
point.setX("东经20度");//int--->Double--->Object
point.setY(50);
String x = (String)point.getX();
String y = (String)point.getY();//ClassCassException Integer不能转换成String
System.out.println("x=" + x + ",y=" + y);
}
}
***************************二.什么是泛型*************************************
类型实参,定义类的时候 用一个占位符表示不知道使用的时候传入什么类型(形参),用的时候
传入实际的类型(实参)
类似方法的形参、实参的概念
public int sum(int x,int y){
}
***************************三.how泛型的使用***********************************
public class Point<T> {// 可以用任意一个字母 表示一个占位符 一般推荐用T Type
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;
}
}
测试代码:
import java.util.ArrayList;
public class TestPoint {
public static void main(String[] args) {
Point<Double> point = new Point<Double>();
point.setX(30.0);//int--->Double--->Object
point.setY(50.0);
double x = point.getX();
double y = point.getY();
System.out.println("x=" + x + ",y=" + y);
}
}
作用:
1. 编译的时候 可以帮我们检查 具体的类型 是不是正确 如果类型不一致 编译报错
提高了程序的健壮性
2. 不需要再向下转型了 就不会出现ClassCastException 编程更加简单了
***************************泛型的两点说明 **********************************
1.
加了泛型以后,使用泛型类的时候, 如果不为泛型指定类型,会出现警告
Point is a raw type. References to generic type Point<T> should be
parameterized
raw type 原始类型 就是没有加任何类型
如果使用的时候没有为泛型类 指定类型 相当于传入了Object类型 还是会出现错误的情况 还是需要向下转型
jdk5.0 没有要求必须加入泛型 目的是为了兼容以前的项目
2. JDK7.0开始 后面的泛型可以不加 可以只加前面的 ...
但是最好推荐 还是和以前一样 前后都要加
***************************通配符 ?**********************************
第一种解决方案:
使用重载.不可以.重载只看方法的参数,不看泛型
package com.chapter12.generic;
class Message<T> {
private T msg;
public T getMsg() {
return msg;
}
public void setMsg(T msg) {
this.msg = msg;
}
}
public class TestTongPeiFu {
// String 为了支持String test后面的参数 Message<String>
// Integer 方法后面的参数 Message<Integer>
// Double 方法后面的参数要改成Message<Double>
public static void main(String[] args) {
Message<Double> message = new Message<Double>();
message.setMsg(10.0);
TestTongPeiFu.test(message);
}
public static void test(Message<String> message) {
System.out.println(message.getMsg());
}
public static void test(Message<Integer> message) {
System.out.println(message.getMsg());
}
public static void test(Message<Double> message) {
System.out.println(message.getMsg());
}
}
第二种解决方案:
方法为了可以传任意类型的参数 例如 Message<String>、Message<Integer>、Message<Double>
可以把方法的形参 定义成Message 这样虽然能满足以上三种需求,但是还是有问题的.虽然能传任意类型了
但是把一个带泛型的引用传递给不带泛型的引用时,类型丢失了(都向上转型成Object),不安全.
package com.chapter12.generic;
class Message<T> {
private T msg;
public T getMsg() {
return msg;
}
public void setMsg(T msg) {
this.msg = msg;
}
}
public class TestTongPeiFu {
// String 为了支持String test后面的参数 Message<String>
// Integer 方法后面的参数 Message<Integer>
// Double 方法后面的参数要改成Message<Double>
public static void main(String[] args) {
Message<String> message = new Message<String>();
message.setMsg("hello");
TestTongPeiFu.test(message);
}
//泛型擦除后 原有的类型会向上转型成Object 类型会丢失
//转型成Object以后 又可以随意的修改 类型了 不安全
//类似 本来只能装 心脏病人的救心丸 现在又可以装 糖豆、甚至老鼠药 肯定是不可以的 不安全
//有没有一种机制 可以传任意类型 并且只能取出 不能修改
//? 通配符 表示可以传入任意类型 但是只能取 不能修改
public static void test(Message<?> message) {
System.out.println(message.getMsg());
}
}
****************************************泛型擦除************************************
把一个带泛型的引用 赋值给 不带泛型的引用 叫做泛型擦除
演示代码:
package com.chapter12.generic;
import java.util.ArrayList;
import java.util.List;
public class TestFanXingCaChu {
public static void main(String[] args) {
List<Integer> list = new ArrayList<Integer>();
list.add(10);
Integer integerA = list.get(0);
System.out.println(integerA);
List noTypeList = list;//把带泛型的元素 赋值给不带泛型的元素 编译器会丢失泛型类型 集合中的元素类型也会丢失 变成了Object
Object obj = noTypeList.get(0);
System.out.println(obj);
List<String> strList = noTypeList;
String str = strList.get(0);//ClassCastException 类转换异常
System.out.println(str);
}
}
****************************************泛型的上限和下限************************************
一.泛型上限
? extends 父类
例如:
? extends Number
可以传Number 或Number的子类 (Integer、Double、Byte)
演示代码:
package com.chapter12.generic.演示泛型上限和下限;
/**
* 公司:蓝桥软件学院
* 作者:zhangzy
* 时间:2017年7月20日 下午4:00:50
* 功能:演示泛型的上限和下限
*/
class Message<T extends Number> {
private T msg;
public T getMsg() {
return msg;
}
public void setMsg(T msg) {
this.msg = msg;
}
}
public class TestShangXianAndXiaXian {
public static void main(String[] args) {
Message<Integer> message = new Message<Integer>();
message.setMsg(10);
TestShangXianAndXiaXian.test(message);
}
public static void test(Message<? extends Number> message) {
System.out.println(message.getMsg());
}
}
二.泛型下限
? super 类
例如
? super String
可以传String 或 String 的父类
演示泛型下限:
package com.chapter12.generic.演示泛型上限和下限;
/**
* 公司:蓝桥软件学院
* 作者:zhangzy
* 时间:2017年7月20日 下午4:00:50
* 功能:演示泛型的上限和下限
*/
class Message<T> {
private T msg;
public T getMsg() {
return msg;
}
public void setMsg(T msg) {
this.msg = msg;
}
}
public class TestShangXianAndXiaXian {
public static void main(String[] args) {
Message<String> message = new Message<String>();
message.setMsg("Hello");
TestShangXianAndXiaXian.test(message);
}
public static void test(Message<? super String> message) {
System.out.println(message.getMsg());
}
}
***********************************泛型接口***************************************
//泛型接口
interface IMessage<T>{
public void print(T t);
}
泛型接口的实现类有两种实现方式:
1. 接口的实现类 也带泛型
package com.chapter12.generic;
class MessageImp<T> implements IMessage<T>{
@Override
public void print(T t) {
System.out.println(t);
}
}
public class 演示泛型接口 {
public static void main(String[] args) {
IMessage<String> message = new MessageImp<String>();
message.print("Hello 泛型接口");
}
}
2. 接口的实现类不带泛型(推荐)
class MessageImp implements IMessage<String>{
@Override
public void print(String t) {
System.out.println(t);
}
}
public class 演示泛型接口 {
public static void main(String[] args) {
IMessage<String> message = new MessageImp();
message.print("Hello 泛型接口");
}
}
***********************************泛型方法***************************************
package com.chapter12.generic;
class Message2{
//泛型方法
public <T> T test(T t){
return t;
}
}
public class 演示泛型方法 {
public static void main(String[] args) {
Message2 message = new Message2();
Integer str = message.test(new Integer(10));
System.out.println(str);
}
}
以上是关于Java泛型的主要内容,如果未能解决你的问题,请参考以下文章