转载自:http://blog.csdn.net/wangjian223344/article/details/16846165
1.泛型的引入:
为什么要用泛型?
比如现在要设计一个坐标的方法
坐标有几种表示方法:
1.整数:x=20,y=20
2.小数:x=20.2,y=20.2
3.字符串:x=东京180,y="北纬210"
看到这里我们是不是在想,要建立一个point类是,里面定义一个方法,来接收这三种数据,但是数据有三种,那么就只有用Object来接收了。因为Object可以接收任何数据,发生向上转型。。。
实现的思路:
代码:
//字符转接收
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 PointTest {
public static void main(String[] args ) {
Point point= new Point();
//整数接收
point.setX( "东经120" );
point.setY( "北纬60" );
String x=(String)point.getX();
String y=(String)point.getY();
System. out .println("x坐标:" +x);
System. out .println("y坐标:" +y);
}
}
结果:
x坐标:东经120
y坐标:北纬60
好像这样是实现了我们想要的结果,那么来看看这段代码:
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 PointTest {
public static void main(String[] args) {
Point point= new Point();
//整数接收
point.setX(123);
point.setY( "北纬60" );//这里是用Object来接收的,所以可以接收任何类型
int x=(Integer)point.getX();
int y=(Integer)point.getY();
System. out .println("x坐标:" +x);
System. out .println("y坐标:" +y);
}
}
结果:
Exception in thread "main" java.lang.ClassCastException : java.lang.String cannot be cast to java.lang.Integer
at test.PointTest.main( PointTest.java:42 )
所以,这样为们才有了现在的泛型
泛型代码:
class Point1<T>{//声明一个泛型类
private T var; //声明一个泛型变量
private T Yar;
public T getVar() {
return var ;
}
public void setVar(T var) {
this .var = var;
}
public T getYar() {
return Yar ;
}
public void setYar(T yar) {
Yar = yar;
}
}
public class PointTest1 {
public static void main(String[] args) {
Point1<Object> point= new Point1<Object>();
point.setVar(20);
point.setYar( "北纬" );
System. out .println("x坐标" +point.getVar());
System. out .println("y坐标" +point.getYar());
}
}
结果:
x坐标20
y坐标北纬
2.泛型的构造方法
class Point1<T>{//声明一个泛型类
private T var; //声明一个泛型变量
private T Yar;
public T getVar() {
return var ;
}
public Point1(T var, T yar) {
this .var = var;
Yar = yar;
}
public void setVar(T var) {
this .var = var;
}
public T getYar() {
return Yar ;
}
public void setYar(T yar) {
Yar = yar;
}
}
public class PointTest1 {
public static void main(String[] args) {
Point1<Object> point= new Point1<Object>(20,"北纬" );
System. out .println("x坐标" +point.getVar());
System. out .println("y坐标" +point.getYar());
}
}
结果:
x坐标20
y坐标北纬
3.指定多个泛型
class Point1<T,K>{//声明一个泛型类
private T var; //声明一个泛型变量
private K Yar;
public T getVar() {
return var ;
}
public void setVar(T var) {
this .var = var;
}
public K getYar() {
return Yar ;
}
public void setYar(K yar) {
Yar = yar;
}
public Point1(T var, K yar) {
this .var = var;
Yar = yar;
}
}
public class PointTest1 {
public static void main(String[] args) {
Point1<Integer,String> point= new Point1<Integer,String>(20,"北纬" );
System. out .println("x坐标" +point.getVar());
System. out .println("y坐标" +point.getYar());
}
}
结果:
x坐标20
y坐标北纬
4.泛型的安全警告
class Point1<T,K>{//声明一个泛型类
private T var; //声明一个泛型变量
private K Yar;
public T getVar() {
return var ;
}
public void setVar(T var) {
this .var = var;
}
public K getYar() {
return Yar ;
}
public void setYar(K yar) {
Yar = yar;
}
public Point1(T var, K yar) {
this .var = var;
Yar = yar;
}
}
public class PointTest1 {
public static void main(String[] args) {
Point1 point= new Point1(20, "北纬" );//这里如果不指定泛型,那么系统就会擦除泛型,变为Object类型来接收
/**
警告消息:
Multiple markers at this line
- Point1 is a raw type. References to generic type Point1<T,K> should be parameterized
- Point1 is a raw type. References to generic type Point1<T,K> should be parameterized
- Type safety: The constructor Point1(Object, Object) belongs to the raw type Point1. References to generic type Point1<T,K>
should be parameterized
*/
//point.setVar(20);
// Point1<String> point1=new Point1<String>();
// point.setYar("北纬");
System. out .println("x坐标" +point.getVar());
System. out .println("y坐标" +point.getYar());
}
}
结果:
x坐标20
y坐标北纬
5.通配符
class Info<T>{
private T var;
public T getVar() {
return var ;
}
public void setVar(T var) {
this .var = var;
}
}
public class TypeTest {
public static void main(String[] args) {
Info<String>i= new Info<String>();
i.setVar( "like" );
fun(i); //这里出现错误,无法传递
}
public static void fun(Info<Object> temp){
System. out .println("内容" +temp);
}
}
这样肯定是不行的,如果把代码改为这样:
class Info<T>{
private T var;
public T getVar() {
return var ;
}
public void setVar(T var) {
this .var = var;
}
}
public class TypeTest {
public static void main(String[] args) {
Info<String>i= new Info<String>();
i.setVar( "like" );
fun(i);
}
public static void fun(Info temp){
System. out .println("内容" +temp.getVar());
}
}
结果:
内容like
但是这样有出现安全警告,那到底怎样才好喃?那就是要用泛型的通配符了
定义:表示可以使用任意的泛型对象
代码:
public class TypeTest {
public static void main(String[] args) {
Info<String>i= new Info<String>();
i.setVar( "like" );
fun(i);
}
public static void fun(Info<?> temp){//这里使用了统配符
System. out .println("内容" +temp.getVar());
}
}
结果:
内容like
6.受限泛型
受限泛型是指在泛型的操作过程中,可以指定一个泛型对象的范围上限和范围下限
格式:
上限:
声明对象: 类名称<? extends 类>对象名称
声明类:访问权限 类名称<泛型标识 extends 类>
下限:
声明对象: 类名称<? super 类>对象名称
代码:
声明泛型对象
public class TypeTest {
public static void main(String[] args) {
Info<String>i= new Info<String>();
i.setVar( "like" );
fun(i); //这里出现错误,无法传递
}
public static void fun(Info<? extends Number > temp){
System. out .println("内容" +temp.getVar());
}
}
上面出现错误,是因为,泛型只能接收数字类型
改下代码:
class Info<T>{
private T var;
public T getVar() {
return var ;
}
public void setVar(T var) {
this .var = var;
}
}
public class TypeTest {
public static void main(String[] args) {
Info< Integer>i= new Info< Integer>();
i.setVar(20);
fun(i);
}
public static void fun(Info<? extends Number> temp){
System. out .println("内容" +temp.getVar());
}
}
结果:
内容20
也可以接收其他类型的数字
看代码:
//接收Double
public class TypeTest {
public static void main(String[] args) {
Info<Double>i= new Info<Double>();
i.setVar(20.28);
fun(i); //这里出现错误,无法传递
}
public static void fun(Info<? extends Number> temp){
System. out .println("内容" +temp.getVar());
}
}
结果:
内容20.28
其他的数字类型就不一一例举了
声明受限泛型类:
代码:
class Info<T extends Number>{//这里声明了受限泛型类
private T var;
public T getVar() {
return var ;
}
public void setVar(T var) {
this .var = var;
}
}
public class TypeTest {
public static void main(String[] args) {
Info<Double>i= new Info<Double>();
i.setVar(20.28);
fun(i);
}
public static void fun(Info<? extends Number> temp){//这里声明受限泛型方法
System. out .println("内容" +temp.getVar());
}
}
结果:
内容20.28
泛型下限:
声明受限泛型下限对象:
public class TypeTest {
public static void main(String[] args) {
Info<Double>i= new Info<Double>();
i.setVar(20.28);
fun(i);
}
public static void fun(Info<? super Double> temp){//这里声明泛型下限对象
//这里就说明最低接收Double,还可以接收比Double 更高的 Number,Object
System. out .println("内容" +temp.getVar());
}
}
结果:
内容20.28
代码:
class Info<T extends Double >{//这里声明泛型上限
private T var;
public T getVar() {
return var ;
}
public void setVar(T var) {
this .var = var;
}
}
public class TypeTest {
public static void main(String[] args) {
Info<Double>i= new Info<Double>();
i.setVar(20.28);
fun(i);
}
public static void fun(Info<? super Double> temp){
System. out .println("内容" +temp.getVar());
}
}
结果:
内容20.28
这段代码就是说明 怎样声明上限和下限一起使用
7.泛型与子类继承的限制
子类作为参数的泛型和父类作为参数的泛型是不同的类型
一个类的子类可以通过对象多态性来实例化父类对象,但是在泛型类中,子类无法为父类实例化对象
代码:
public class TypeTest {
public static void main(String[] args) {
Info<Double>i= new Info<Double>();
Info<Object>j= new Info<Object>();
j= i; //这里会报错
i.setVar(20.28);
}
public static void fun(Info<? super Double> temp){
System. out .println("内容" +temp.getVar());
}
}
子类不能实例化父类
8.泛型接口
泛型接口和普通接口也差不多,下面看代码就明白了
interface Info<T>{
public T getVar();
}
实现泛型接口有两种方式
interface Info<T>{
public T getVar();
}
public class TypeTest<T> implements Info<T>{
private T var;
public T getVar() {
return var ;
}
public void setVar(T var) {
this .var = var;
}
public static void main(String[] args) {
TypeTest<String> test= new TypeTest<String>();
test.setVar( "like" );
System. out .println(test.getVar());
}
}
结果:
like
还有一种
interface Info<T>{
public T getVar();
}
public class TypeTest implements Info<String>{
private String var;
public String getVar() {
return var ;
}
public void setVar(String var) {
this .var = var;
}
public static void main(String[] args) {
TypeTest test= new TypeTest();
test.setVar( "like" );
System. out .println(test.getVar());
}
}
结果:
like
9.泛型数组
public class TypeTest {
public static void main(String[] args) {
//Integer i[]={1,2,3,4,5};//静态初始化数组
Integer i[]= fun1(1,2,3,4,5);
fun2(i);
}
public static <T> T[] fun1(T...arg){ //可变参数和泛型数组
return arg;
}
public static <T> void fun2(T param[]){
for (T t: param){
System. out .print(t+"," );
}
}
}
结果:
1,2,3,4,5,
附:
java中的<?><T><E>详解Jdk5.0新特性Generic Types (泛型)
interface Collection<E>{
public boolean containsAll(Collection<?> c);
public boolean addAll(Collection<? extends E> c);
}
使用泛型方法的形式为:
interface Collection<E>{
public <T> boolean containsAll(Collection<T> c);
public <T extends E> boolean addAll(Collection<T> c);
}
无论如何,在ContainAll和addAll中,类型参数T仅被使用一次。返回类型不依赖于类型参数,也不依赖方法中的任何参数。这告诉我 类型参数正被用于多态,它的影响仅仅是允许不同的实参在不同的调用点被使用。
泛型方法允许类型参数被用于表达在一个或更多参数之间或者方法中的参数、返回类型的依赖。如果没有如此依赖,泛型方法就不能被使用。可能一前一后来联合使用泛型和通配符,这里有个例子:
class Collections{
public static <T> void copy(List<T> dest,List<? extends T> src){
}
}
注意两个参数之间的依赖,任何从原list的对象复制,必须分配一个目标LIST元素的类型T,于是Src的元素类型可能是任何T的子类型。我们不必在意在COPY的表达中,表示依赖使用一个类型参数,但是是使用一个通配符。
下面我们不使用通配符来重写上面的方法:
class Collections{
public static <T,S extends T>
void copy(List<T> dest,List<S> src){
}
}
这非常好,但是第一个类型参数既在dst中使用,也在第二个类型参数中使用,S本身就被使用了一次。在类型src中,没有什么类型依赖它。这是一个标志我们可以用通配符来替换它。使用通配符比显示的声明类型参数更加清楚和精确。所以有可能推荐使用通配符。
通配符也有优势,可以在方法之外来使用,作为字段类型、局部变量和数组。
这里有一个例子。
返回到我们画图的例子,假设我们要保持一个画图请求的历史,我们可以在Shape类内部用一个静态变量来保持历史。用drawAll()存储它到来的参数到历史字段。
static List<List<? extends Shape>> history = new ArrayList<List<? extends Shape>>();
public void drawAll(List<? extends Shape> shapes){
history.addLast(shapes);
for (Shape s : shapes){
s.draw(this);
}
}