学习目标
掌握泛型的产生意义。
掌握泛型的基本使用。
了解泛型的警告信息及泛型的擦除。
泛型是在JDK1.5之后增加的内容,泛型(Generic)
使用泛型的原因
题目分析:
首先要考虑到,必须建立一好一个表示坐标点的类——Point,此类中有两个属性分别用来表示x坐标和y坐标,但是x和y中所保存的整数类型会有三种(int、float、String),而要想使用一个类型可以同时接收这样的三种类型数据,现在只能使用Object,因为Object类可以接收任何类型的数据,都会自动发生向上转型操作,这样三种数据类型安装以下的方式进行转换:
数字(int) —> 自动装箱成Interger —> 向上转型使用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 ; } }; 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,之后自动拆箱 int y = (Integer)p.getY() ; // 取出数据先变为Integer,之后自动拆箱 System.out.println("整数表示,X坐标为:" + x) ; System.out.println("整数表示,Y坐标为:" + 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 GenericsDemo02{ public static void main(String args[]){ Point p = new Point() ; // 声明一个Point的对象 p.setX(10.5f) ; // 利用自动装箱操作:float --> Float --> Object p.setY(20.6f) ; // 利用自动装箱操作:float --> Float --> Object float x = (Float)p.getX() ; // 取出数据先变为Float,之后自动拆箱 float y = (Float)p.getY() ; // 取出数据先变为Float,之后自动拆箱 System.out.println("小数表示,X坐标为:" + x) ; System.out.println("小数表示,Y坐标为:" + 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 GenericsDemo03{ public static void main(String args[]){ Point p = new Point() ; // 声明一个Point的对象 p.setX("东经180度") ; // String --> Object p.setY("北纬210度") ; // String --> Object String x = (String)p.getX() ; // 取出数据先变为String,之后自动拆箱 String y = (String)p.getY() ; // 取出数据先变为String,之后自动拆箱 System.out.println("字符串表示,X坐标为:" + x) ; System.out.println("字符串表示,Y坐标为:" + 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 GenericsDemo04{ public static void main(String args[]){ Point p = new Point() ; // 声明一个Point的对象 p.setX(10) ; // 利用自动装箱操作:int --> Integer --> Object p.setY("北纬210度") ; // String --> Object int x = (Integer)p.getX() ; // 取出数据先变为Integer,之后自动拆箱 int y = (Integer)p.getY() ; // 取出数据先变为Integer,之后自动拆箱 System.out.println("整数表示,X坐标为:" + x) ; System.out.println("整数表示,Y坐标为:" + y) ; } };
传统的实现方法就有可能出现操作不当的情况,本程序就是数据类型不统一造成的。
认识泛型
泛型的使用
泛型可以解决数据类型的安全性问题,它主要的原理,是在类声明的时候通过一个标识表示类中某个属性的类型或者是某个方法的返回值以及参数类型。这样在类声明或实例化的时候只要指定好需要的类型即可。
泛型的定义格式如下:
[访问权限] class 类名称<泛型类型1,泛型类型2,......泛型类型3>{
[访问权限] 泛型类型标识 变量名称;
[访问权限] 泛型类型标识 方法名称(){ };
[访问权限] 返回值类型声明 方法名称(泛型类型标识 变量名称){};
}
泛型对象的定义
类名称<具体类型> 对象名称 = new 类名称<具体类型>();
按照此格式定义一个Point类。
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()) ; // 取得字符串的长度 } };
以上是将var变量设置成了String类型,当然也可以设置成Integer,如果设置的内容与指定的泛型类型不一致,则会在编译时就出现错误。
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 GenericsDemo07{ public static void main(String args[]){ Point<Integer> p = new Point<Integer>() ; // 里面的var类型为String类型 p.setVar("MLDN") ; // 设置字符串 } };
这样可以更好的去保护数据类型。
通过泛型就可以直接去修改之前的程序。
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(20) ; // 利用自动装箱操作:int --> Integer int x = p.getX() ; // 自动拆箱 int y = p.getY() ; // 自动拆箱 System.out.println("整数表示,X坐标为:" + x) ; System.out.println("整数表示,Y坐标为:" + y) ; } };
在这样程序里,减少类类型转换的操作代码,而且更加安全,如果设置的内容不是数字,则在编译的时候就会出现错误,如下所示:
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) ; } };
泛型也可以在构造方法中使用,一般有可能使用构造方法为类中的属性赋值。
构造方法中使用泛型
构造方法可以为类中的属性初始化,那么如果类中的属性通过泛型指定 而又需要通过构造设置属性内容的时候,那么构造方法的定义与之前并无不同,不需要像声明类那样指定泛型。
使用格式:
[访问权限] 构造方法 ([<泛型类型> 参数名称]){ }
例如:
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>("liuxun") ; // 里面的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(22) ; // 设置第二个内容 System.out.print("姓名;" + t.getKey()) ; // 取得信息 System.out.print(",年龄;" + t.getValue()) ; // 取得信息 } };
泛型的安全警告
在泛型应用中最好在声明类对象的时候指定好其内部的数据类型,例如"Info<String>" ,但也可以不指定类型。
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 GenericsDemo10{ public static void main(String args[]){ Info i = new Info() ; // 警告,没有指定泛型类型 i.setVar("MLDN") ; // 设置字符串 System.out.println("内容:" + i.getVar()) ; } };
在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()) ; } };
泛型的安全警告
在泛型应用中最好在声明类的时候指定其内部的数据类型,例如:"Info<String>",但也可以不指定类型,这样一来用户在使用这样的类的时候就会出现不安全的警告信息,如下图:
总结:
1、泛型的产生意义:为了保证数据的安全性。
2、泛型的基本使用,由外部指定的其具体操作类型。