当前位置: 首页 > news >正文

数据结构初阶:Java泛型

1.什么是泛型

泛型:就是接受许多类型;通俗来说就是将类型参数化,你想传什么类型的值都行。

下面详细讲:

2.引出泛型

目标:实现一个类,类中有一个能存放任何数据类型的数组,并且成员方法可以返回对应下标的值。

数组是将相同类型的值聚在一起:int[] array = new int[5];  String[] str = new String[10];

这些数组类型都定死了,只要传其他类型的值就报错。

这时我们想到类都继承于Object,写一个Object类型的数组就可以接收所有类型的值,如:

看到这里,我们意识到一个问题。我不知道要用什么类型来向下转型呀!这确实可以接收各种类型,但是这也太杂了;一个数组里有各种基本类型、各种引用类型,我们能否指定类对象只能接收哪个(哪些)类呢?——》Java就设计了泛型这一概念!!!

3.语法

class 泛型类名称<类型形参列表> {
//这里可以使用类型参数
}class ClassName<>{}class 泛型类名称<类型形参列表> extends 继承类/*这里可以使用类型参数*/{
//这里可以使用类型参数
}class ClassName<T1,T2,...,Tn> extends ParentClass<T1>{}

上述图片代码改写如下:

class MyArray<T>{Object[] objects = new Object[10];public T getElement(int index) {return (T)objects[index];}public void setElement(int index,T val){objects[index]=val;} 
}

代码解释:

1. 类名后的 <T> 代表占位符,表示当前类是一个泛型类。(实际上可以使用任意大写字母)
了解: 【规范】类型形参常用的名称有:
              E 表示 Element
              K 表示 Key
              V 表示 Value
              N 表示 Number
              T 表示 Type
              S, U, V 等等 - 第二、第三、第四个类型

3.1泛型类的使用

  • 定义泛型类的引用:泛型类<类型实参>  变量名 ;
  • 实例化泛型类对象:new 泛型类<类型实参>(构造方法实参);      //这里的类型实参不写也行,因为系统会根据引用的类型实参进行推导。

示例:

MyArray<Integer> list = new MyArray<Integer>();

//泛型类型不能是基本类型!!!

3.2泛型类引用的类型

先看下面的实操了解代码:

Test2.main()中的myArray是什么类型的?

因为MyArray继承了Object类,所以我们在打印时,会调用父类的toString()方法;

该方法返回调用引用的类型;

结论:可以看出myArray的类型还是MyArray,不是MyArray<Integer>!!!

小结:

1. 泛型是将类型参数化,进行传递
2. 使用 <T> 表示当前类是一个泛型类。
3. 泛型目前为止的优点:数据类型参数化,编译时自动进行类型检查和转换

4.实操

既然对类对象指定了输入数据的类型,那是否还能输入其他类型的数据?

答案是不能!!

5.擦除机制

泛型到底是怎样进行编译的呢?

其实,泛型是编译时期的一种机制,在运行期间是没有泛型这一概念的。

下图就很直观:

在编译的过程当中,将所有的T替换为Object这种机制,我们称为:擦除机制

有同学就要问了:那泛型有什么用呢?

答:编译时自动进行类型检查和转换。

6.泛型的上界

在定义泛型类时,有时需要对传入的类型进行约束。

6.1语法

class 泛型类名称<类型形参 extends 类型边界> {
              ......
}

例:

public class ClassName<E extends Number> {//......
}

代码解读:只有类型是Number或者Number的子类才能作为E的类型形参。(最多只能是Number类,这就是泛型的上界)

例:

代码解读:String不是Number的子类,所以当将String作为泛型实参时就会报错!!

7.泛型进阶

  7.1通配符

? 用于在泛型的使用,即为通配符
一个例子让你明白通配符的作用:
class Message<T>{private T message ;public T getMessage() {return message;}public void setMessage(T message) {this.message = message;}
}public class TestDemo2 {public static void main(String[] args) {Message<String> message = new Message<>() ;message.setMessage("不上早八!");func(message);}public static void func(Message<String> temp){System.out.println(temp.getMessage());}
}

上面的代码问题在于func(),这个方法写死了,当我泛型类型不是String,而是其它就会出问题,图例:

所以我想func()什么泛型类型都能接受,就用到通配符(?)。代码改成如下:

public class TestDemo2 {public static void main(String[] args) {Message<String> message = new Message<>() ;message.setMessage("不上早八!");func(message);Message<Integer> message2 = new Message<>() ;message2.setMessage(123);func(message2); //不报错}public static void func(Message<?> temp){//什么泛型类型都能接受了System.out.println(temp.getMessage());}
}

7.1.1通配符和<E>的区别

通配符是可以在泛型类之外使用的,但E等大写字母,必须在泛型中使用。(<大写字母>是泛型标识)

7.2通配符的上界

语法:

<? extends 上界>
<? extends Number> //解读:只能接收Number或者是Number的子类类型

7.2.2实操

将用下面的关系做示例

示例1:

class Biology {
}
class Animal extends Biology {
}
class Dog extends Animal {
}
class Cat extends Animal {
}class Message<T> { // 设置泛型private T message ;public T getMessage() {//获取return message;}public void setMessage(T message) {//设置this.message = message;}
}
public class TestDemo {public static void main(String[] args) {Message<Dog> message = new Message<>() ;message.setMessage(new Dog());fun(message);Message<Cat> message2 = new Message<>() ;message2.setMessage(new Cat());fun(message2);}public static void fun(Message<? extends Animal> message){System.out.println(message.getMessage());message.getMessage();}
}

注意1:

通配符可不像<E>,你不能写成   ? element = get....(); 所以你不知道传入了什么泛型类型

注意2:

所以我们在传入时要停下来想想了。

总结:通配符的上界,不能进行写入数据,只能进行读取数据

7.3通配符的下界

语法:

<? super 下界> 

<? super Number> //解读:只接收Number或者Number的父类

示例·:

通配符的下界与上界截然相反:

public static void main(String[] args) {Message<Animal> message = new Message<>() ;message.setMessage(new Animal());fun(message);Message<Biology> message2 = new Message<>() ;message2.setMessage(new Biology());fun(message2);}public static void fun(Message<? super Animal> message){//只接受Animal或者它的父类System.out.println(message.getMessage());message.setMessage(new Dog());//此时可以修改(传入数据),因为Dog、Cat都是Animal子类message.setMessage(new Cat());}

这放随便放,但取就要小心了!!!

7.3总结

总结:通配符上界取随便取,放值要思考;通配符下界放随便放,但取就要注意。

http://www.dtcms.com/a/521730.html

相关文章:

  • 推荐个好看的网站自己做网站花钱么
  • 潍坊设计网站wordpress任务论坛
  • 计网第二章——物理层
  • 河北网站推广网站购物车建设
  • 企业营销策略有哪几种莱芜网站优化招聘网
  • 39某健康网旋转验证码---Js逆向分析
  • 网站如何推广开发公司名称起名大全
  • 适合30岁短期培训班泉州seo排名
  • 欧洲稀土产业链
  • wordpress 去除tag自己的网站怎么优化
  • 网站建设多少钱合适临漳手机网站建设
  • 网络编程--TCP通信程序
  • GPIO口输入
  • 学校网站怎么做推广方案网站建设作业百度云资源
  • 随州做网站公司情感营销案例
  • 科技网站新版网站上线怎么看网站使用什么做的
  • 网站制作英文版网站创建公司策划书
  • c++注意点(15)----中介者模式
  • 正规网站建设团队是什么怎么在自己的网站上传视频
  • vs2017手机网站开发一千元左右最好的手机
  • 整站优化seo公司哪家好弹幕网站开发代码
  • 大学英文网站建设方案搜索引擎营销广告
  • 中文网站什么意思广州公司注册一网通
  • 赣州找工作的网站私自做彩票网站销售犯法么
  • TDengine 数学函数 RAND 用户手册
  • windows 安装 TDengine
  • 网站制度建设存在的问题服务器重启 iis网站暂停
  • 蛋白表达原理与关键要素解析
  • 网站seo搜索引擎优化案例千牛怎么做免费推广引流
  • 为什么top和/proc/pid/statm、/proc/pid/statm 统计的内存结果不同