目录
本章主要介绍一下java的泛型
一、泛型的来由
在对象重载的时候,当方法什么都相同,参数类型为引用类型(类、接口、数组)时,如果写起来代码会比较较长,阅读起来也累。
注:集合也属于引用类型,因为它不是接口就是类
如:我要打印出学校的教程类、学生类、后勤类信息,我在每个类都添加toString方法,那么我得写3个打印方法,代码如下:
private void print(Stu stu){
System.out.println(stu);
}
private void print(Teacher teacher){
System.out.println(teacher);
}
private void print(Logistics logistics){
System.out.println(logistics);
}
这样一下写几个感觉代码有点多,能不能把参数类型也抽象化,把类型变弄成一个变量,这样是不是更通用,比如我就用一个X可以代表int、float、double三种类型,那么可以写形如下面这样的:
private void print(X x){
System.out.println(x);
}
是不是省事很多,这就是泛型的概念,类型进一步抽象,弄成变量化。
二、泛型写法及泛型标记
2.1 泛型写法
一般写法:
[修饰符号]<泛型标记>[返回类型][方法名](<泛型标记>){代码..}
ps:这里的泛型标记也可以理解成,类型变量
2.2 泛型标记
常用的泛型标记有如下几种:
E - Element (在集合中使用,因为集合中存放的是元素)
T - Type(Java 类int要改为Integer类,float要改为Float类,double;要改为Double类等等)
K - Key(键)
V - Value(值)
N - Number(数值类型)
? - 表示不确定的java类型
S、U、V - 2nd、3rd、4th types
Object跟这些标记符代表的java类型有啥区别呢?
Object是所有类的根类,任何类的对象都可以设置给该Object引用变量,使用的时候可能需要类型强制转换,但是用使用了泛型T、E等这些标识符后,在实际用之前类型就已经确定了,不需要再进行类型强制转换。
2.3 例子
就以上一章学生类
public class Stu {
//学号
private String sid;
//学生名
private String name;
//语文,不推荐用yuWen这种方式
private float chinese;
//不建议直接用shuXue这种拼音方式
private float maths;
public String getSid() {
return sid;
}
public void setSid(String sid) {
this.sid = sid;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public float getChinese() {
return chinese;
}
public void setChinese(float chinese) {
this.chinese = chinese;
}
public float getMaths() {
return maths;
}
public void setMaths(float maths) {
this.maths = maths;
}
@Override
// toString() 是把对象转为字符串输出,看情况添加
public String toString() {
return "Stu{" +
"sid='" + sid + '\'' +
", name='" + name + '\'' +
", chinese=" + chinese +
", maths=" + maths +
'}';
}
}
为例子
/T为test的意思
public class T1 {
//<T>表示这个是type类型,类中一定要有 toString()方法
public <T> void pringObject(T object)
{
System.out.println(object);
}
//保存学生信息
private Stu saveStu(String sid,String name,float chinese,float maths)
{
Stu stu = new Stu();
stu.setSid(sid);
stu.setName(name);
stu.setChinese(chinese);
stu.setMaths(maths);
return stu;
}
public static void main(String[] args) {
T1 t1 =new T1();
//保存一个学生
Stu stu=t1.saveStu("003", "王五", 91f,98f );
//打印学生,同理可以打印所有的class
t1.pringObject(stu);
}
}
运行结果:
Stu{sid='003', name='王五', chinese=91.0, maths=98.0}
三、泛型的类型通配符使用
3.1 泛型通配符?
类型通配符一般是使用?代替具体的类型参数。例如 List<?> 在逻辑上是List<String>,List<Integer> 等所有List<具体类型实参>的父类。
类型通配符上限通过形如List来定义,如此定义就是通配符泛型值接受Number及其下层子类类型。如:
public static void getUperNumber(List<? extends Number> data) {
//代码
}
在idae过程中,查看某类型的上下继承关系可以用如选择该类型然后按ctrl+h,如下图
从上图可以看出Number下级只有一级。
类型通配符下限通过形如 List<? super Number>来定义,表示类型只能接受Number及其三层父类类型,如 Object 类型的实例。
public static void getDownNumber(List<? super Integer> data) {
System.out.println("data :" + data.get(0));
}
在idae过程中,查看某类型的上下继承关系可以用如选择该类型然后按ctrl+h,如下图:
从上图中可以看出,最顶顶为Object,所以它几乎支持所有
3.2 例子
import java.util.*;
//T为test的意思
public class T1 {
public static void main(String[] args) {
List<String> name = new ArrayList<String>();
List<Integer> age = new ArrayList<Integer>();
List<Number> number = new ArrayList<Number>();
name.add("icon");
age.add(18);
number.add(314);
//getUperNumber(name);//1
getUperNumber(age);//2
getUperNumber(number);//3
//getDownNumber(name)
getDownNumber(age);
getDownNumber(number);
}
public static void getData(List<?> data) {
System.out.println("data :" + data.get(0));
}
//通配符上限,<? extends Number> 的意思就是 Number及其子类都有效
public static void getUperNumber(List<? extends Number> data) {
System.out.println("上限data :" + data.get(0));
}
//通配符下限,<? extends Number> 的意思就是 Number及其子类都有效
public static void getDownNumber(List<? super Integer> data) {
System.out.println("下限data :" + data.get(0));
}
}
结果:
上限data :18
上限data :314
下限data :18
下限data :314