泛型
泛型在Java中还是比较容易的内容,所以学起来简单,在开发中如果能够将泛型使用好,那么对以后程序的扩展会有一个很好的基础。
问题:定义一个类来表示一个点的坐标
package com.sram.entity;
public class Point {
private Object pointX;
private Object pointY;
public Point() {
}
public Point(Object pointX,Object pointY){
this.pointX=pointX;
this.pointY=pointY;
}
public void setPointX(Object pointX) {
this.pointX = pointX;
}
public Object getPointX() {
return pointX;
}
public void setPointY(Object pointY) {
this.pointY = pointY;
}
public Object getPointY() {
return pointY;
}
@Override
public String toString() {
return "X坐标为"+this.pointX+",Y坐标为:"+this.pointY;
}
}
main方法
public static void main(String[] args) {
Point point=new Point(12,23);
System.out.println(point);
Point point2=new Point("北纬12度", "东经120度");
System.out.println(point2);
}
输出结果为:
X坐标为12,Y坐标为:23
X坐标为北纬12度,Y坐标为:东经120度
以上将坐标都定义成了Object类型的数据,这样做的目的是为了能够在调用方法进行属性赋值的时候通过面向对象的多态性来接收任何数据类型的坐标,看上去比较完美的解决了问题,但是其实里面还有很多的问题。
Point point3=new Point(12.5d,"东经120度");
System.out.println(point3);
输出结果为:
X坐标为12.5,Y坐标为:东经120度
执行了以上的代码发现最终的这个点的坐标是随时可能出问题的,所以上面的Point类的定义还是不完整的。因为一个点的横坐标和纵坐标的类型是一样的(必须保证)。其实要想解决上面的问题可以使用Java中的泛型。
泛型的定义
泛型可以解决数据类型的安全性问题,它主要的原理,是在类声明的时候通过一个标识表示类中某个属性的类型或者是某个方法的返回值及参数类型。这样在类声明或实例化的时候只要指定好需要的类型即可。
泛型具体的类型指定是在创建对象的时候指定。
型的使用要求
在泛型的指定中,是无法指定基本数据类型的,必须设置成一个类,这样在设置一个数字的时候就必须使用包装类
泛型的定义语法
[访问权限] class 类名称<泛型类型1,泛型类型2,…泛型类型3>{
[访问权限] 泛型类型标识 变量名称 ;
[访问权限] 泛型类型标识 方法名称(){} ;
[访问权限] 返回值类型声明 方法名称(泛型类型标识 变量名称){} ;}
通过泛型的定义的语法可以发现在定义类的时候就可以指定泛型了,而且泛型可以同时指定多个。
案例:
给坐标点使用泛型
package com.sram.entity;
public class Point<T>{
private T pointX;
private T pointY;
public Point() {
}
public Point(T pointX,T pointY){
this.pointX=pointX;
this.pointY=pointY;
}
public void setPointX(T pointX) {
this.pointX = pointX;
}
public T getPointX() {
return pointX;
}
public void setPointY(T pointY) {
this.pointY = pointY;
}
public T getPointY() {
return pointY;
}
@Override
public String toString() {
return "X坐标为"+this.pointX+",Y坐标为:"+this.pointY;
}
}
main方法
public static void main(String[] args) {
Point<Integer> point1=new Point<Integer>(23,34);
System.out.println(point1);
Point<Float> point2=new Point<Float>(23.3f,34.6f);
System.out.println(point2);
Point<String> point3=new Point<String>("北纬30度","东经120度");
System.out.println(point3);
}
输出结果为:
X坐标为23,Y坐标为:34
X坐标为23.3,Y坐标为:34.6
X坐标为北纬30度,Y坐标为:东经120度
通过上面的代码设置,就达到了咱们之前讨论的那两个要求:
- 能够接受任何数据类型
- 保证数据类型的统一性
泛型的安全警告(了解)
如果使用一个泛型类创建对象,必须指定泛型对应的具体的数据类型,如果不定义则会出现警告:
public static void main(String[] args) {
Point point1=new Point(23,34);
System.out.println(point1);
}
输出结果为:
X坐标为23,Y坐标为:34
此时出现警告这个警告在Java中就称为泛型的安全警告。
出现此警告的原因是没有指定泛型的具体数据类型,其实当一个泛型类在创建对象的时候没有指定泛型数据类型化就相当于直接使用Object类作为属性类型,这样话咱们设置泛型类就没有具体的意义。
在以后使用泛型类的时候尽量去指定泛型的数据类型。
通配符的使用
所谓的通配符其实就是使用一个符号来完成对应的多种数据类型的接收。在Java的泛型中有一个通配符”?”此通配符适合泛型类型的接收。
案例:
public static void main(String[] args) {
Point<Integer> point1=new Point<Integer>(23,34);
Point<Float> point2=new Point<Float>(23.3f,34.6f);
Point<String> point3=new Point<String>("北纬30度","东经120度");
show(point1);
show(point2);
show(point3);
}
public static void show(Point<?> point3){//使用通配符?来接受参数
System.out.println(point3);
}
输出结果为:
X坐标为23,Y坐标为:34
X坐标为23.3,Y坐标为:34.6
X坐标为北纬30度,Y坐标为:东经120度
受限泛型
在引用传递中,泛型操作中也可以设置一个泛型对象的范围上限和范围下限。范围上限使用extends关键字声明,表示参数化的类型可能是所指定的类型,或者是此类型的子类,而范围下限使用super进行声明,表示参数化的类型可能是所指定的类型,或者是此类型的父类型,直至Object类。
设置泛型的上限
在申明对象的时候使用:
设置的语法:类名称<? extends 类> 对象名称
案例:
public class Point<T extends Number>{//泛型的上线最大的为Number类
}
上面的代码代表此类在创建对象的时候只能执行泛型类型为Number及其子类。也就是此时能执行的泛型类型对象是AtomicInteger, AtomicLong, BigDecimal, BigInteger, Byte, Double, Float, Integer, Long, Short类及其子类,字符串无法使用了。
设置泛型的下限
在申明对象的时候使用:类名称<? super 类> 对象名称
案例:
public static void main(String[] args) {
Point<Integer> point1=new Point<Integer>(23,34);
Point<Number> point2=new Point<Number>(23.3f,34.6f);
Point<String> point3=new Point<String>("北纬30度","东经120度");
show(point1);
show(point2);
show(point3);
}
public static void show(Point<? super Integer> point3){//
System.out.println(point3);
}
此处设置了泛型的下限,设置了下限的话则只能输出当前类及其父类。
泛型接口
泛型接口的定义其实和泛型类的定义没有什么区别,只是定义类的时候使用class定义接口的时候使用interface定义。
案例:
public interface USB<T> {//泛型接口
}
泛型接口的实现
public interface USB<T> {//泛型接口
public abstract void show(T t);
}
public class Computer implements USB<String>{
@Override
public void show(String t) {
System.out.println(t);
}
}
public static void main(String[] args) {
Computer computer=new Computer();
computer.show("呵呵");
}
输出结果为:呵呵
方式二:在子类中也是用泛型
public interface USB<T> {//泛型接口
public abstract void show(T t);
}
public class Computer<T> implements USB<T>{
@Override
public void show(T t) {
System.out.println(t);
}
}
public static void main(String[] args) {
Computer<String> computer=new Computer<String>();
computer.show("呵呵");
}
输出结果为:呵呵
在开发过程中泛型接口也是会经常出现的,所以泛型接口的实现还需要加强练习。
多个泛型的设置
在Java中定义泛型接口或者泛型类的时候会遇到使用一种或者多种泛型的形式出现,那么怎么去定义多个泛型呢?
案例:
定义具有多个泛型的类
package com.sram.entity;
public class Person<T,K> {
private T name;
private K age;
private T sex;
public Person() {
}
public Person(T name,K age,T sex) {
this.age=age;
this.name=name;
this.sex=sex;
}
public void setAge(K age) {
this.age = age;
}
public K getAge() {
return age;
}
public void setName(T name) {
this.name = name;
}
public T getName() {
return name;
}
public void setSex(T sex) {
this.sex = sex;
}
public T getSex() {
return sex;
}
}
创建多个泛型类的对象:
public static void main(String[] args) {
Person<String,Integer> person=new Person<String, Integer>("张三", 23,"男");
System.out.println("姓名:"+person.getName()+",年龄:"+person.getAge()+",性别:"+person.getSex());
}
输出结果:
姓名:张三,年龄:23,性别:男