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
关注公众号:
微信赞赏
支付宝赞赏