本章目标
掌握泛型的产生意义
掌握泛型的基本使用
了解泛型的警告信息及泛型的擦除
为什么要有泛型?
现在有以下的实例要求:
——现在要求设计一个可以表示出坐标点的类,坐标由X和Y组成,坐标的表示方法有以下三种:
————整数表示:x = 10、y = 20
————小数表示:x = 10.5、y = 20.6
————字符串表示:x = "东经180度"、y = "北纬210度"
问:此类该如何设计?
题目分析
一看到这样的要求,读者首先就要考虑到,必须建立好一个表示坐标点的类 —— Point,此类中有两个属性分别用来表示x坐标和y坐标,但是x和y中所保存的数据类型会有三种(int、float、String),而要想使用一个类型可以同时接收这样的三种类型数据,则现在只能使用Object,因为Object类可以接收任何类型的数据,都会自动发生向上转型操作,这样三种数据类型将按以下的方式进行转换:
——数字(int) —> 自动装箱成Integer —> 向上转型使用Object接收
——小数(float) —> 自动装箱成Float —> 向上转型使用Object接收
——字符串(String) —> 向上转型使用Object接收
设计Point类
public class Point {
private Object x;//表示 x 坐标
private Object y;//表示 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 GenericDemo01 {
public static void main(String[] args) {
Point p = new 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);
}
/* 结果:
* 整数表示,X坐标为:10
* 整数表示,Y坐标为:20
* */
}
public class GenericDemo02 {
public static void main(String[] args) {
Point p = new 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);
}
/* 结果:
* 整数表示,X坐标为:10.5
* 整数表示,Y坐标为:20.6
* */
}
public class GenericDemo03 {
public static void main(String[] args) {
Point p = new Point();
p.setX("东经 180 度");//String -->Object
p.setY("北纬 210 度");//String -->Object
String x = (String)p.getX();//取出数据
String y = (String)p.getY();//取出数据
System.out.println("整数表示,X坐标为:"+x);
System.out.println("整数表示,Y坐标为:"+y);
}
/* 结果:
* 整数表示,X坐标为:东经 180 度
* 整数表示,Y坐标为:北纬 210 度
* */
}
public class GenericDemo04 {
public static void main(String[] args) {
Point p = new Point();
p.setX(10);//利用自动装箱操作:int --> Integer -->Object
p.setY("北纬 210 度");//String -->Object
int x = (Integer)p.getX();//取出数据
int y = (Integer)p.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 J031001.GenericDemo04.main(GenericDemo04.java:9)
* */
}
泛型
泛型可以解决数据类型的安全性问题,它主要的原理,是在类声明的时候通过一个标识表示类中某个属性的类型或者是某个方法的返回值及参数类型。这样在类声明或实例化的时候只要指定好需要的类型即可。
泛型类定义格式:
——[访问权限] class 类名称<泛型类型1,泛型类型2,…泛型类型3>{
[访问权限] 泛型类型标识 变量名称 ;
[访问权限] 泛型类型标识 方法名称(){} ;
[访问权限] 返回值类型声明 方法名称(泛型类型标识 变量名称){} ;}
泛型对象定义
——类名称<具体类> 对象名称 = new 类名称<具体类>() ;
声明泛型
public class Point<T> {//此处可以是任意的标识符号,T 是 type 的简称
private T var;//此变量的类型由外部决定
public T getVar() {//返回值的类型由外部指定
return var;
}
public void setVar(T var) {//设置的类型由外部指定
this.var = var;
}
}
public class GenericDemo05 {
public static void main(String[] args) {
Point<Integer> p = new Point<Integer>();//里面的 var 类型为 Integer 类型
p.setVar(30);//设置数字,自动装箱
System.out.println(p.getVar()*2);//计算结果,按数字取出
}
/* 结果:
* 60
* */
}
public class GenericDemo06 {
public static void main(String[] args) {
Point<String> p = new Point<String>();//里面的 var 类型为 String 类型
p.setVar("chaoyi");//设置字符串
System.out.println(p.getVar().length());//取得字符串的长度
}
/* 结果:
* 6
* */
}
设置泛型的要求
在泛型的指定中,是无法指定基本数据类型的,必须设置成一个类,这样在设置一个数字的时候就必须使用包装类,而在JDK 1.5之后提供了自动装箱的操作,操作时也不会太复杂。
泛型应用中的构造方法
构造方法可以为类中的属性初始化,那么如果类中的属性通过泛型指定,而又需要通过构造设置属性内容的时候,那么构造方法的定义与之前并无不同,不需要像声明类那样指定泛型。
使用格式:
——[访问权限] 构造方法 ([<泛型类型> 参数名称]){}
public class Point<T> {//指定泛型类型
private T x;//表示 x 坐标,具体类型由外部指定
private T y;//表示 x 坐标,具体类型由外部指定
public T getX() {
return x;
}
public void setX(T x) {
this.x = x;
}
public T getY() {
return y;
}
public void setY(T y) {
this.y = y;
}
}
public class GenericPoint {
public static void main(String[] args) {
Point<Integer> p = new Point<Integer>();//定义Point对象,指定 Integer 为泛型类型
p.setX(10);//设置整数,自动装箱
p.setY(20);//设置整数,自动装箱
int x = p.getX();//自动拆箱
int y = p.getY();//自动拆箱
System.out.println("整数表示,X坐标为:"+x);//输出信息
System.out.println("整数表示,Y坐标为:"+y);//输出信息
}
/* 结果:
* 整数表示,X坐标为:10
* 整数表示,Y坐标为:20
* */
}
指定多个泛型类型
如果一个类中有多个属性需要使用不同的泛型声明,则可以在声明类的时候指定多个泛型类型。
class Point<T> {//此处可以是任意的标识符号,T 是 type 的简称
private T var;//此变量的类型由外部决定
public Point(T var){
this.var=var;
}
public T getVar() {//返回值的类型由外部指定
return var;
}
public void setVar(T var) {//设置的类型由外部指定
this.var = var;
}
}
public class GenericDemo08 {
public static void main(String[] args) {
Point<String> p = null;//定义泛型类对象
p = new Point<String>("chaoyi");//里面的 var 类型为 String 类型
System.out.println("内容:"+p.getVar());//取得字符串
}
/* 结果:
* 内容:chaoyi
* */
}
class Notepad<K,V>{//此处指定两个泛型类型
private K key;//此变量的类型由外部决定
private V value;//此变量的类型由外部决定
public K getKey() {//取得 key
return key;
}
public void setKey(K key) {//设置 key
this.key = key;
}
public V getValue() {//取得 value
return value;
}
public void setValue(V value) {//设置 value
this.value = value;
}
}
public class GenericDemo09 {
public static void main(String[] args) {
Notepad<String, Integer> t = null;//定义两个泛型类型的对象
t= new Notepad<String, Integer>();//里面的Key 为 String,Value 为 Integer
t.setKey("chaoyi");//设置第 1 个内容
t.setValue(30);//设置第 2 个内容
System.out.print("姓名:"+t.getKey());//取得信息
System.out.println(",年龄:"+t.getValue());//取得信息
}
/* 结果:
* 姓名:chaoyi,年龄:30
* */
}
泛型的安全警告
在泛型应用中最好在声明类的时候指定好其内部的数据类型,例如:“Info<String>”,但也可以不指定类型,这样一来用户在使用这样的类时,就会出现不安全的警告信息。