🐨
type
status
date
slug
summary
tags
category
icon
password
Property
泛型是一种类似”模板代码“的技术,不同语言的泛型实现方式不一定相同。
Java语言的泛型实现方式是擦拭法(Type Erasure)。
所谓擦拭法是指,虚拟机对泛型其实一无所知,所有的工作都是编译器做的。
例如编写了一个泛型类
Pair<T>
,这是编译器看到的代码:而虚拟机根本不知道泛型。这是虚拟机执行的代码:
因此,Java使用擦拭法实现泛型,导致了:
- 编译器把类型
<T>
视为Object
;
- 编译器根据
<T>
实现安全的强制转型。
使用泛型的时候,我们编写的代码也是编译器看到的代码:
🐨
type
status
date
slug
summary
tags
category
icon
password
Property
Pair<Integer>
不是Pair<Number>
的子类。假设我们定义了
Pair<T>
:然后又针对
Pair<Number>
类型写了一个静态方法,它接收的参数类型是Pair<Number>
:上述代码是可以正常编译的。使用的时候,传入:
注意:传入的类型是
Pair<Number>
,实际参数类型是(Integer, Integer)
。既然实际参数是
Integer
类型,试试传入Pair<Integer>
:编译错误,原因很明显,因为
Pair<Integer>
不是Pair<Number>
的子类,因此,add(Pair<Number>)
不接受参数类型Pair<Integer>
。🐨
type
status
date
slug
summary
tags
category
icon
password
Property
泛型的继承关系:
Pair<Integer>
不是Pair<Number>
的子类考察下面的
set
方法:传入
Pair<Integer>
是允许的,但是传入Pair<Number>
是不允许的。和
extends
通配符相反,这次希望接受Pair<Integer>
类型,以及Pair<Number>
、Pair<Object>
,因为Number
和Object
是Integer
的父类,setFirst(Number)
和setFirst(Object)
实际上允许接受Integer
类型。使用
super
通配符来改写这个方法:注意到
Pair<? super Integer>
表示,方法参数接受所有泛型类型为Integer
或Integer
父类的Pair
类型。下面的代码可以被正常编译:
🐨
type
status
date
slug
summary
tags
category
icon
password
Property
Java的部分反射API也是泛型。例如:
Class<T>
就是泛型:调用
Class
的getSuperclass()
方法返回的Class
类型是Class<? super T>
:构造方法
Constructor<T>
也是泛型:可以声明带泛型的数组,但不能用
new
操作符创建带泛型的数组:必须通过强制转型实现带泛型的数组:
使用泛型数组要特别小心,因为数组实际上在运行期没有泛型,编译器可以强制检查变量
ps
,因为它的类型是泛型数组。但是,编译器不会检查变量arr
,因为它不是泛型数组。因为这两个变量实际上指向同一个数组,所以,操作arr
可能导致从ps
获取元素时报错,例如,以下代码演示了不安全地使用带泛型的数组:🐼
type
status
date
slug
summary
tags
category
icon
password
Property
在集合类中,
List
是最基础的一种集合:它是一种有序列表。List
的行为和数组几乎完全相同:List
内部按照放入元素的先后顺序存放,每个元素都可以通过索引确定自己的位置,List
的索引和数组一样,从0
开始。数组和
List
类似,也是有序结构,如果使用数组,在添加和删除元素的时候,会非常不方便。例如,从一个已有的数组{'A', 'B', 'C', 'D', 'E'}
中删除索引为2
的元素:这个“删除”操作实际上是把
'C'
后面的元素依次往前挪一个位置,而“添加”操作实际上是把指定位置以后的元素都依次向后挪一个位置,腾出来的位置给新加的元素。这两种操作,用数组实现非常麻烦。因此,在实际应用中,需要增删元素的有序列表,使用最多的是
ArrayList
。实际上,ArrayList
在内部使用了数组来存储所有元素。例如,一个ArrayList
拥有5个元素,实际数组大小为6
(即有一个空位):当添加一个元素并指定索引到
ArrayList
时,ArrayList
自动移动需要移动的元素:🦥
type
status
date
slug
summary
tags
category
icon
password
Property
InputStream
InputStream
就是Java标准库提供的最基本的输入流,位于java.io
这个包里。java.io
包提供了所有同步IO的功能。要特别注意的一点是,
InputStream
并不是一个接口,而是一个抽象类,它是所有输入流的超类。这个抽象类定义的一个最重要的方法就是int read()
,签名如下:这个方法会读取输入流的下一个字节,并返回字节表示的
int
值(0~255)。如果已读到末尾,返回-1
表示不能继续读取了。FileInputStream
是InputStream
的一个子类。顾名思义,FileInputStream
就是从文件流中读取数据。完整地读取一个
FileInputStream
的所有字节:在计算机中,类似文件、网络端口这些资源,都是由操作系统统一管理的。应用程序在运行的过程中,如果打开了一个文件进行读写,完成后要及时地关闭,以便让操作系统把资源释放掉,否则,应用程序占用的资源会越来越多,不但白白占用内存,还会影响其他应用程序的运行。
type
status
date
slug
summary
tags
category
icon
password
Property
目录
图像的读取和展示
MATLAB能够处理的数字图像分为三种:二值图像灰度图像彩色图像.
- 二值图像在MATLAB中以一个矩阵存储,矩阵中元素的取值为0(表示白)或1(表示黑).
- 灰度图像在MATLAB中以一个矩阵存储,矩阵中元素的取值介于0~255之间,表示灰度.
- 彩色图像在MATLAB中以三个矩阵存储,每个矩阵中元素的取值介于0~255之间,分别表示颜色R,G,B分量的浓度
读取和展示图像
使用
imread()
函数将图像读取到内存中,使用imshow()
函数展示图像,使用imwrite()
函数将内存中的图像写进硬盘.