为什么使用泛型
要求设计出一个可以表示坐标点的类,坐标由X和Y组成。
坐标表示方法:
整数:x=10,Y=20;
小数:X=10.5,Y=20.6
字符串:X="东经180度",Y=“北纬30度”
问,此类怎么设计。
题目分析
肯定要设计表示坐标点的类。类名称:Point。
但是坐标的X,Y保存的数据类型有三种(int,float,String),要想使用一个类可以同时接收这三种类型,则现在只能使用Object类,因为Object可以接受任何类型的
数据,都会自动发生向上转型。这样三种数据类型会发生以下转变:
数字(int)->自动装箱成(Integer)->向上转型Object接收 小数点(float)->自动装箱成(Float)->向上转型Object接收 字符串(String)->向上转型Object接收
Point类:
class Point{ private Object x ; // 表示X坐标 private Object y ; // 表示Y坐标 public void setX(Object x){ this.x = x ; } public void setY(Object y){ this.y = y ; } public Object getX(){ return this.x ; } public Object getY(){ return this.y ; } };
总体代码如下:需要注意向上转型和向下转型的自动装箱和自动拆箱操作。
class Point{ private Object x ; // 表示X坐标 private Object y ; // 表示Y坐标 public void setX(Object x){ this.x = x ; } public void setY(Object y){ this.y = y ; } public Object getX(){ return this.x ; } public Object getY(){ return this.y ; } }; public class GenericsDemo01{ public static void main(String args[]){ Point p = new Point() ; // 声明一个Point的对象 p.setX(10) ; // 利用自动装箱操作:int --> Integer --> Object p.setY(20) ; // 利用自动装箱操作:int --> Integer --> Object int x = (Integer)p.getX() ; // 取出数据先变为Integer,之后自动拆箱,Integer-->int int y = (Integer)p.getY() ; // 取出数据先变为Integer,之后自动拆箱 System.out.println("整数表示,X坐标为:" + x) ; System.out.println("整数表示,Y坐标为:" + y) ; } };
以上代码存在很大问题,加设里面的数据类型变换一下,则则自动拆箱操作处就要修改强制转型代码。
认识泛型
是在类声明的时候,通过一个标识表示类中某个属性的类型或者是某个方法的返回值及参数类型。这样在类声明和实例化的时候只要指定好要使用的类型即可。
泛型定义实例:
class Point<T>{ // 此处可以随便写标识符号,T是type的简称 private T var ; // var的类型由T指定,即:由外部指定 public T getVar(){ // 返回值的类型由外部决定 return var ; } public void setVar(T var){ // 设置的类型也由外部决定 this.var = var ; } };
结合上面完整的一个例子:
class Point<T>{ // 此处可以随便写标识符号,T是type的简称 private T var ; // var的类型由T指定,即:由外部指定 public T getVar(){ // 返回值的类型由外部决定 return var ; } public void setVar(T var){ // 设置的类型也由外部决定 this.var = var ; } }; public class GenericsDemo06{ public static void main(String args[]){ Point<String> p = new Point<String>() ; // 里面的var类型为String类型 p.setVar("MLDN") ; // 设置字符串 System.out.println(p.getVar().length()) ; // 取得字符串的长度 } };
可以更好的保护数据类型。
通过泛型就可以直接修改之前的程序。
修改结果如下:
class Point<T>{ private T x ; // 表示X坐标 private T y ; // 表示Y坐标 public void setX(T x){ this.x = x ; } public void setY(T y){ this.y = y ; } public T getX(){ return this.x ; } public T getY(){ return this.y ; } }; public class GenericsPoint{ public static void main(String args[]){ Point<Integer> p = new Point<Integer>() ; p.setX(10) ; // 利用自动装箱操作:int --> Integer p.setY("北纬210度") ; // 利用自动装箱操作:int --> Integer int x = p.getX() ; // 自动拆箱 int y = p.getY() ; // 自动拆箱 System.out.println("整数表示,X坐标为:" + x) ; System.out.println("整数表示,Y坐标为:" + y) ; } };
在这样的程序中,减少了类型转换的操作(不用用一个Object类在类中定义,不用向上转型,向下转型,拆箱,装箱)。
构造方法中使用泛型
泛型也可以在构造方法中使用,一般有可能为构造方法为类中属性赋值。
为构造方法属性赋值实例:
class Point<T>{ // 此处可以随便写标识符号,T是type的简称 private T var ; // var的类型由T指定,即:由外部指定 public Point(T var){ // 通过构造方法设置内容 this.var = var ; } public T getVar(){ // 返回值的类型由外部决定 return var ; } public void setVar(T var){ // 设置的类型也由外部决定 this.var = var ; } }; public class GenericsDemo08{ public static void main(String args[]){ Point<String> p = new Point<String>("MLDN") ; // 里面的var类型为String类型 System.out.println("内容:" + p.getVar()) ; } };
指定两个泛型类型,如下:
class Notepad<K,V>{ // 此处指定了两个泛型类型 private K key ; // 此变量的类型由外部决定 private V value ; // 此变量的类型由外部决定 public K getKey(){ return this.key ; } public V getValue(){ return this.value ; } public void setKey(K key){ this.key = key ; } public void setValue(V value){ this.value = value ; } }; public class GenericsDemo09{ public static void main(String args[]){ Notepad<String,Integer> t = null ; // 定义两个泛型类型的对象 t = new Notepad<String,Integer>() ; // 里面的key为String,value为Integer t.setKey("李兴华") ; // 设置第一个内容 t.setValue(30) ; // 设置第二个内容 System.out.print("姓名;" + t.getKey()) ; // 取得信息 System.out.print(",年龄;" + t.getValue()) ; // 取得信息 } };
泛型的安全警告
在泛型应用中最好在声明类对象的时候指定其内部的数据类型。例如:“Info<String>”,但是也可不指定类型。
package Thread1; class Info<T>{ private T var ; public T getVar(){ return this.var ; } public void setVar(T var){ this.var = var ; } public String toString(){ // 覆写Object类中的toString()方法 return this.var.toString() ; } }; public class demo1{ public static void main(String args[]){ Info i = new Info() ; // 警告,没有指定泛型类型 i.setVar("MLDN") ; // 设置字符串 System.out.println("内容:" + i.getVar()) ; } };
运行结果:
内容:MLDN
程序不会影响执行,但是在Info类中并没有指定泛型类型,则在java中为了保证程序依然可以运行,会将T自动设置成Object类型。这样一来就可以接受任意数据类型。
也就是说,此时的var类型就是Object,所有的泛型信息将被擦除。
以上程序相当于以下定义:
class Info<T>{ private T var ; public T getVar(){ return this.var ; } public void setVar(T var){ this.var = var ; } public String toString(){ // 覆写Object类中的toString()方法 return this.var.toString() ; } }; public class GenericsDemo11{ public static void main(String args[]){ Info<Object> i = new Info<Object>() ; // 指定Object为泛型类型 i.setVar("MLDN") ; // 设置字符串 System.out.println("内容:" + i.getVar()) ; } };