一 为什么要引入泛型这个概念?
这里我用一个实例来简单说明。比如说:我们要设计一个表示二维坐标的类,但是因为关于坐标的表示有多种形式,比如:
(1)整数表示:x=10 y=20
(2)浮点型表示:x=10.5 y=20.8
(3)字符串表示:x=””东经 50度”” y=”北纬 79度”
因此,在我们设计的类中就不能单一的设置成int,float或String,而想要使用一个类型来接收这三种不同的数据类型,就只能使用Object。测试代码如下:
package javase.paradigm;
/**
* 二维坐标表示
* */
public class Point {
private Object X;
private Object Y;
public Object getX() {
return X;
}
public void setX(Object x) {
X = x;
}
public Object getY() {
return Y;
}
public void setY(Object y) {
Y = y;
}
public static void main(String[] args) {
Point point = new Point();
//1 整数表示坐标
point.setX(10); //int --> Integer --> Object
point.setY(20);
int x = (int) point.getX();
int y = (int) point.getY();
System.out.println("整数表示,X坐标是:" + x + ",Y坐标是:" + y);
System.out.println("******************我是华丽的分割线**********************");
//2 小数表示坐标
point.setX(10.5f); //float --> Float --> Object
point.setY(20.8f);
float x2 = (float) point.getX();
float y2 = (float) point.getY();
System.out.println("小数表示,X坐标是:" + x2 + ",Y坐标是:" + y2);
System.out.println("******************我是华丽的分割线**********************");
//3 字符串表示坐标
point.setX("东经 50度"); //String --> Object
point.setY("北纬 79度");
String x3 = (String) point.getX();
String y3 = (String) point.getY();
System.out.println("字符串表示,X坐标是:" + x3 + ",Y坐标是:" + y3);
}
}
输出:
整数表示,X坐标是:10,Y坐标是:20
******************我是华丽的分割线**********************
小数表示,X坐标是:10.5,Y坐标是:20.8
******************我是华丽的分割线**********************
字符串表示,X坐标是:东经 50度,Y坐标是:北纬 79度
通过上面设计的这个类貌似已经解决我们的需求了?但是真的是这样吗?这个类中将变量设置成Object类型,就意味着可以使用任意的Object子类来初始化,如果对变量初始化的类型和取出类型不一致,则程序在运行时会报错,出现类型转化异常。比如说这样:
point.setX(0);
point.setY("北纬179度");
int x4 = (int) point.getX();
int y4 = (int) point.getY(); //错误代码
System.out.println("错误案例,X坐标是:" + x4 + ",Y坐标是:" + y4);
这段代码编译没有问题,但是运行时报错,报错信息如下:
Exception in thread "main" java.lang.ClassCastException: java.lang.String cannot be cast to java.lang.Integer
at javase.paradigm.Point.main(Point.java:60)
错误信息已经很明显了,String类型不能转化成Integer类型。因此为了避免出现这种类型安全问题,我们就需要使用泛型
二 泛型的初步使用
(1)格式:
类名称<具体类> 对象名称 = new 类名称<具体类>()
如:Point2<Integer> point2_1 = new Point2<Integer>();
(2)完整测试案例代码如下:
package javase.paradigm;
public class Point2<T> {
private T var;
public T getVar() {
return var;
}
public void setVar(T var) {
this.var = var;
}
public static void main(String[] args) {
//1 整数
Point2<Integer> point2_1 = new Point2<Integer>();
point2_1.setVar(20);
System.out.println("整数测试:" + point2_1.getVar());
System.out.println("******************我是华丽的分割线**********************");
//字符串
Point2<String> point2_2 = new Point2<String>();
point2_2.setVar("zifangsky的个人博客");
System.out.println("字符串测试:" + point2_2.getVar());
}
}
输出:
整数测试:20
******************我是华丽的分割线**********************
字符串测试:zifangsky的个人博客
将第一个例子修改成泛型:
package javase.paradigm;
public class Point3<T> {
private T x;
private T y;
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 static void main(String[] args) {
//1 整数表示
Point3<Integer> point3_1 = new Point3<Integer>();
point3_1.setX(10);
point3_1.setY(20);
int x1 = point3_1.getX();
int y1 = point3_1.getY();
System.out.println("整数表示,X坐标是:" + x1 + ",Y坐标是:" + y1);
System.out.println("******************我是华丽的分割线**********************");
//2 字符串表示
Point3<String> point3_2 = new Point3<String>();
point3_2.setX("东经 50度");
point3_2.setY("北纬 79度");
String x2 = point3_2.getX();
String y2 = point3_2.getY();
System.out.println("字符串表示,X坐标是:" + x2 + ",Y坐标是:" + y2);
}
}<span style="font-family:'sans serif', tahoma, verdana, helvetica;font-size:16px;line-height:1.5;"></span>
三 一个类中定义多个泛型类型
package javase.paradigm;
public class Nodepad<K, V> {
private K key;
private V value;
public void setKey(K key) {
this.key = key;
}
public void setValue(V value) {
this.value = value;
}
public void print(){
System.out.println("键:" + key + ",值:" + value);
}
public static void main(String[] args) {
Nodepad<String, Integer> nodepad = new Nodepad<String, Integer>();
nodepad.setKey("zifangsky");
nodepad.setValue(100);
//测试
nodepad.print();
}
}
输出:
键:zifangsky,值:100
四 泛型方法的使用
(1)格式:
[访问权限]<泛型标志> 泛型标志 方法名称([泛型标志 参数名称])
(2)测试代码:
package javase.paradigm;
public class MethodDemo {
public <T> T getData(T t){
return t;
}
public void print(){
System.out.println("zifangsky");
}
public static void main(String[] args) {
MethodDemo methodDemo = new MethodDemo();
methodDemo.print();
int i = methodDemo.getData(10);
System.out.println("int: " + i);
String str = methodDemo.getData("hello world");
System.out.println("String: " + str);
}
}
输出:
zifangsky
int: 10
String: hello world
五 泛型接口的定义和两种实现方式
(1)泛型接口的定义:
package javase.paradigm;
public interface Info<T> {
public T getVar();
}
(2)接口的实现方式一:
在子类的定义上申明泛型类型:
package javase.paradigm;
public class InfoImpl_1<T> implements Info<T> {
private T var;
public InfoImpl_1(T var) {
this.var = var;
}
public T getVar() {
return this.var;
}
public void setVar(T var) {
this.var = var;
}
}
(3)接口的实现方式二:
直接在接口中指定具体类型:
package javase.paradigm;
public class InfoImpl_2 implements Info<String> {
private String var;
public InfoImpl_2(String var) {
this.var = var;
}
public String getVar() {
return this.var;
}
public void setVar(String var) {
this.var = var;
}
}
六 一个综合实例
(1)简单分析:
这里设计了Person这个类,但是一个人可能有多种信息展示形式,比如说:个人基本信息(姓名,性别,年龄。。。),联系方式(电话,地址,邮编。。。)。因此在Person中的信息类型就可以考虑申明为泛型。接着设计了一个空接口:Message和它的两个子类:Contact和Introduction,分别表示:联系方式和基本信息。
在对Person进行定义的时候用了:class Person<T extends Message> ,这里的意思是这个泛型T只能是Message这个接口的子类,也就是说只能是我们先前定义的Contact和Introduction,避免了传递进来我们所不需要的其他信息
(2)实例代码:
package javase.paradigm;
/**
* 定义标识接口
* */
interface Message{
}
/**
* 第一个子类,联系方式
* */
class Contact implements Message{
private String address;
private String telphone;
private String zipcode;
public Contact(String address, String telphone, String zipcode) {
this.address = address;
this.telphone = telphone;
this.zipcode = zipcode;
}
/**
* 重写toString方法
* */
public String toString(){
return "联系方式:\n" +
"\t|- 电话: " + telphone + "\n" +
"\t|- 地址: " + address + "\n" +
"\t|- 邮编: " + zipcode + "\n";
}
}
/**
* 第二个子类,个人信息
* */
class Introduction implements Message{
private String name;
private String sex;
private int age;
private String job;
public Introduction(String name, String sex, int age, String job) {
this.name = name;
this.sex = sex;
this.age = age;
this.job = job;
}
/**
* 重写toString方法
* */
public String toString(){
return "基本信息:\n" +
"\t|- 姓名: " + name + "\n" +
"\t|- 性别: " + sex + "\n" +
"\t|- 年龄: " + age + "\n" +
"\t|- 工作: " + job + "\n";
}
}
/**
* 定义泛型,并且T必须是Message这个接口的子类
* 避免了传递进来其他不需要的类型
* */
public class Person<T extends Message> {
private T message;
public Person(T message) {
this.message = message;
}
public String toString(){
return message.toString();
}
public static void main(String[] args) {
//1 将泛型实例化成Contact类型
Person<Contact> person_1 = new Person<Contact>(new Contact("http://www.zifangsky.cn", "10086", "1024"));
System.out.println(person_1);
System.out.println("******************我是华丽的分割线**********************");
//2 将泛型实例化成Introduction类型
Person<Introduction> person_2 = new Person<Introduction>(new Introduction("zifangsky", "男", 256, "程序猿"));
System.out.println(person_2);
}
}
输出:
联系方式:
|- 电话: 10086
|- 地址: http://www.zifangsky.cn
|- 邮编: 1024
******************我是华丽的分割线**********************
基本信息:
|- 姓名: zifangsky
|- 性别: 男
|- 年龄: 256
|- 工作: 程序猿
转载于:https://blog.51cto.com/983836259/1740102