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泛型的主要内容,如果未能解决你的问题,请参考以下文章

Java泛型 VS C#泛型 (伪泛型 VS 真泛型)

java中啥叫泛型??

java中啥是泛型,怎么用泛型?

Java——泛型

java泛型的一些知识点:Java泛型--泛型应用--泛型接口泛型方法泛型数组泛型嵌套

Java 泛型泛型简介 ( 泛型类 | 泛型方法 | 静态方法的泛型 | 泛型类与泛型方法完整示例 )