java泛型基础详解

问题: 要求设计一个坐标类:(x,y), 可以同时满足三种类型的数据:
1. int型,x=10,y=100;
2. float型,x = 10.3, y = 50.2;
3. String型,x = "东经180度",y= "北纬210度";
分析:
这个类可以同时处理三种数据类型,为保证程序的正确性,最好采用Object类完成,因为Object可以接收任意的引用数据类型;
原理:
数字-----》自动装箱成为包装类----------》为object类接收;
String---》 Object类接收;
jdk1.5之前:如下实现:
package com.udast;
class Point
{
private Object x; // 用Object 去接收所有的数据类型
private Object y;
// 现实现int型:
public Point(Object x, Object y)
{
this.x = x; // 设置坐标
this.y = y;
}
public Object getX() // yong Object accept the return
{
return this.x;
}
public Object getY()
{
return this.y;
}
}
public class PointDemo
{
public static void main(String[] args)
{
int ix = 10;
int iy = 502;
Point point = new Point(ix, iy); // int--> Integer --> Object
// 这是jdk1.5前
int x = (Integer)point.getX(); // 存在不安全因素,因为Object的转型
int y = (Integer)point.getY(); // 可以是任意类型;
System.out.println("The point is: " + "(" + x + ", " + y + ")");
float fx = 10.3f;
float fy = 50.2f;
Point point1 = new Point(fx, fy);
float x1 = (Float)point1.getX();
float y1 = (Float)point1.getY();
System.out.println("The point is: " + "(" + x1 + ", " + y1 + ")");
String sx = "东经180度";
String sy = "北纬21度";
Point point2 = new Point(sx, sy);
String x2 = (String)point2.getX();
String y2 = (String)point2.getY();
System.out.println("The point is: " + "(" + x2 + ", " + y2 + ")");
}
}
------------------------jdk1.5后,出现了泛型;
package com.udast;
class Point<T> // T 是一个任意类型,在类实例化时才确定!
{
private T x; // 用T 去接收所有的数据类型
private T y;
// 现实现int型:
public Point(T x, T y)
{
this.x = x; // 设置坐标
this.y = y;
}
public T getX() // yong T accept the return
{
return this.x;
}
public T getY()
{
return this.y;
}
}
public class PointDemo
{
public static void main(String[] args)
{
int ix = 10;
int iy = 502; // 实例化时确定属性的类型,这样具有实时的类型安全性;
Point<Integer> point = new Point<Integer>(ix, iy); // T--> Integer
// 这是jdk1.5后
int x = point.getX(); // 不再用转型
int y = point.getY(); //
System.out.println("The point is: " + "(" + x + ", " + y + ")");
float fx = 10.3f;
float fy = 50.2f;
Point<Object> point1 = new Point<Object>(fx, fy); // 泛型擦除的无警告格式,T-->Object
float x1 = (Float)point1.getX(); // 和不用泛型一样,需要向下转型;
float y1 = (Float)point1.getY();
System.out.println("The point is: " + "(" + x1 + ", " + y1 + ")");
String sx = "东经180度";
String sy = "北纬21度";
Point<String> point2 = new Point<String>(sx, sy);
String x2 = point2.getX();
String y2 = point2.getY();
System.out.println("The point is: " + "(" + x2 + ", " + y2 + ")");
}
}
/*
class "className"<T> , T 是一个类类型; 也可以有任意多个T,
class "className"<T,A,B>,
泛型可以提供简洁,和安全性;
泛型可以在类的构造方法中使用;
泛型可以擦除:即实例化时不给出T的具体类型;系统将默认按T为Object处理,以确定程序无误!显式指出<Object>可以避免警告信息;但这不常用;
*/
------通配符:
------------泛型上限: ?extends 最大泛型类型,则实例化时使用的泛型必须是最大泛型类型或其子类型;
package com.udast;
class P<T extends Number> // 泛型上限:Number类型;
{
private T x;
private T y;
public P(T x, T y)
{
this.x = x;
this.y = y;
}
public void print()
{
System.out.println("X = " + this.x);
System.out.println("Y = " + this.y);
}
public T getX()
{
return this.x;
}
}
public class GenerDemo
{
public static void main(String[] args)
{
P<Integer> p = new P<Integer>(10, 200); // Ok, Integer is Child Class of Number
p.print();
P<Float> pf = new P<Float>(10.3f, 20.56f); // ok, Float is also ChildClass of Number
pf.print();
P<Number> pn = new P<Number>(10, 200); // use 泛型上限 <=> 泛型擦除, need convert below
pn.print();
int i = (Integer)pn.getX(); // Number --> Integer
System.out.println(i);
P pp = new P(20, 20); // 将得到警告:注意:./work/GenerDemo.java 使用了未经检查或不安全的操作。这是泛型擦除!
fun(p); // accept Integer
fun(pf); // accept Float
fun(pn); // accept Number
fun1(p); // 只接收Integer类
}
public static void fun(P<?> p) // ?是类型通配符,表示接收所有合法类型,这避免了使用Object或其他泛型上限时,不同泛型类型不支持相互传递
{
p.print();
}
public static void fun1(P<? extends Integer> p) // 将只能接收Integer类型或其 子类型;
{
System.out.println("对方法使用通配符和泛型上限限制:Integer!");
p.print();
}
}
/*
P<Object> p1 = new P<Object>(); // 好比整个商城的商品
P<Integer> p2 = new P<Integer>(); // 好比一个顾客购买的商品
p1 = p2; // 将是错误的,因为p1、p2不再是类类型,而是泛型类型,如上举例,显然不同!
那么:fun(P<Object> p); 将不能接收P<Integer> p2泛型;
而: fun(P<?> p); 包含 fun(P<Integer> p); 所有通配符解决了这个矛盾!
泛型上限:默认的上限是:Object,
显式声明格式: ? extends className, className表示泛型上限;
?super className , 下限;
*/
package com.udast;
class Str<T>
{
private T str;
public Str(T t)
{
this.str = t;
System.out.println("泛型下限:String!" + str);
}
}
public class GenDemo
{
public static void main(String[] args)
{
fun(new Str<String>("String类型可以!"));
fun(new Str<Object>("Object类型也可以!"));
}
public static void fun(Str <? super String> str) // 方法也可以使用泛型下限
{
System.out.println("接收泛型下限以上的类型:" + str);
}
}
/*
administrator@xu-desktop:~$ javac -d . ./work/GenDemo.java
administrator@xu-desktop:~$ java com.udast.GenDemo
泛型下限:String!String类型可以!
接收泛型下限以上的类型:com.udast.Str@3e25a5
泛型下限:String!Object类型也可以!
接收泛型下限以上的类型:com.udast.Str@19821f
*/
--------------泛型接口:和类的泛型语法相同;
package com.udast;
interface A<T> // 接口中使用泛型
{
public void fun(T param); // 抽象方法使用泛型;
}
class ClassInfo<T> implements A<T> // 第一种实现泛型接口的方法
{
public void fun(T param) // 这个T类型是在类实例化时确定的
{
System.out.println("要打印的类信息:" + param);
}
}
class Test implements A<Test> // 第二种实现方式:该泛型接口只对Test类的实例有效
{
public void fun(Test param)
{
System.out.println("只对本类有效的泛型接口实现:" + param);
}
}
public class GenDemo1
{
public static void main(String[] args)
{
ClassInfo<String> cinfo = new ClassInfo<String>(); // T --> String
A<String> a = cinfo;
cinfo.fun("String:字符串类型!");
a.fun("父类接口引用子类覆写的方法!");
A<Test> at = new Test(); // 第二种方式:对本类操作;
at.fun(new Test());
A<ClassInfo> ainfo = new ClassInfo<ClassInfo>(); // 与第二种方式效果同, 不过要确定T--->ClassInfo;
ainfo.fun(new ClassInfo());
}
}
/*
administrator@xu-desktop:~$ java com.udast.GenDemo1
要打印的类信息:String:字符串类型!
要打印的类信息:父类接口引用子类覆写的方法!
只对本类有效的泛型接口实现:com.udast.Test@addbf1
要打印的类信息:com.udast.ClassInfo@42e816
*/
--------------泛型方法:
在方法上使用泛型,不要求所在的类使用泛型,更灵活;
package com.udast;
class Demo
{
public <T> T print(T param) // 泛型方法:所在的类非泛型操作类
{
return param; // 返回值也是泛型
}
}
public class GenDemo2
{
public static void main(String[] args)
{
String str = new Demo().print("返回泛型!"); // T-->String
int i = new Demo().print(5); // T-->Integer
Demo demo = new Demo().print(new Demo()); // T-->Demo
Demo demo1 = new Demo();
System.out.println(str + "\n" + i + "\n" + demo + "\n" + demo1.print(demo1));
}
}
/*
administrator@xu-desktop:~$ javac -d . ./work/GenDemo2.java
administrator@xu-desktop:~$ java com.udast.GenDemo2
返回泛型!
5
com.udast.Demo@3e25a5
com.udast.Demo@19821f
*/
--------返回泛型数组的泛型方法:
package com.udast;
public class GenFun
{
public static void main(String[] args)
{
Integer i[] = fun(1, 2, 3, 4, 5); // 泛型为Integer
for (int x : i)
{
System.out.println(x);
}
}
public static <T> T[] fun(T ... param) // 该泛型方法接收可变参数
{
return param; // 接收的是可变参数,当然返回的是数组;
}
}
/*
administrator@xu-desktop:~$ javac -d . ./work/GenFun.java
administrator@xu-desktop:~$ java com.udast.GenFun
1
2
3
4
5
*/
---------------泛型嵌套:
用一个泛型类型设置泛型类型;
package com.udast;
class Info<T>
{
private T param; // 含有一个泛型的成员
public void setParam(T param) // 设置泛型成员
{
this.param = param;
}
public T getParam()
{
return this.param; // 获取泛型成员
}
}
class Person<T>
{
private T info; // 含有一个泛型的成员
public void setInfo(T info)
{
this.info = info; // 设置泛型成员
}
public T getInfo()
{
return this.info; // 返回泛型成员
}
}
public class MultiGen
{
public static void main(String[] args)
{
Person< Info<String> > per = new Person< Info<String> >(); // 泛型嵌套:T-->Info<T`>;T`-->String
per.setInfo(new Info<String>()); // 用一个空的Info的实例设置per的info成员
per.getInfo().setParam("泛型嵌套!"); // 设置Info实例的param成员
System.out.println(per.getInfo().getParam()); // 得到param成员
}
}
/*
administrator@xu-desktop:~$ javac -d . ./work/MultiGen.java
administrator@xu-desktop:~$ java com.udast.MultiGen
泛型嵌套!
*/
------------- 泛型应用:
/*
一个人的信息分为:基本信息,和联系方式;
实现一个类既能操作人的基本信息,又能操作联系方式;
*/
package com.udast;
interface Info // 表示人的各种信息
{
// 空实现的接口 称为 标识接口;
}
class Whois implements Info // 人的基本信息
{
private String name;
private int age;
public Whois()
{
super(); // 默认
}
public Whois(String name, int age)
{
super(); // 明确调用Object的默认构造
this.name = name;
this.age = age;
}
public String getName()
{
return this.name;
}
public void setName(String name)
{
this.name = name;
}
public int getAge()
{
return this.age;
}
public void setAge(int age)
{
this.age = age;
}
public String toString() // 覆写父类的方法
{
return "姓名:" + this.name + " 年龄:" + this.age;
}
}
class Contact implements Info // 表示联系方式
{
private String address;
private String zipCode;
public Contact()
{
super();
}
public Contact(String address, String zipCode)
{
this.address = address;
this.zipCode = zipCode;
}
public String getAddress()
{
return this.address;
}
public void setAddress(String address)
{
this.address = address;
}
public String getZipCode()
{
return this.zipCode;
}
public void setZipCode(String zipCode)
{
this.zipCode = zipCode;
}
public String toString() // 覆写父类方法
{
return "地址:" + this.address + " 区号:" + this.zipCode;
}
}
class Person<T extends Info> // 泛型上限为接口Info ,T只能是Info子类
{
private T info;
public Person(T info)
{
this.info = info;
}
public T getInfo()
{
return this.info;
}
public void setInfo(T info)
{
this.info = info;
}
}
public class GenPersonInfo
{
public static void main(String[] args)
{
String name = "张三";
int age = 30;
Person<Whois> perWhois = new Person<Whois>(new Whois()); // 一个空的实例 T-->Whois
perWhois.setInfo(new Whois(name, age)); // 给实例赋值
System.out.println(perWhois.getInfo());
String address = "北京", zipCode = "10000";
Person<Contact> perContact = new Person<Contact>(new Contact()); // T-->Contact
perContact.setInfo(new Contact(address, zipCode));
System.out.println(perContact.getInfo());
}
}
/*
administrator@xu-desktop:~$ javac -d . ./work/GenPersonInfo.java
administrator@xu-desktop:~$ java com.udast.GenPersonInfo
姓名:张三 年龄:30
地址:北京 区号:10000
*/
声明: 除非转自他站(如有侵权,请联系处理)外,本文采用 BY-NC-SA 协议进行授权 | 嗅谱网
转载请注明:转自《java泛型基础详解》
本文地址:http://www.xiupu.net/archives-4204.html
关注公众号:
微信赞赏
支付宝赞赏
