Skip to content
体验新版
项目
组织
正在加载...
登录
切换导航
打开侧边栏
OpenDocCN
cs61b-textbook-zh
提交
fb5a0009
C
cs61b-textbook-zh
项目概览
OpenDocCN
/
cs61b-textbook-zh
通知
3
Star
0
Fork
0
代码
文件
提交
分支
Tags
贡献者
分支图
Diff
Issue
0
列表
看板
标记
里程碑
合并请求
0
Wiki
0
Wiki
分析
仓库
DevOps
项目成员
Pages
C
cs61b-textbook-zh
项目概览
项目概览
详情
发布
仓库
仓库
文件
提交
分支
标签
贡献者
分支图
比较
Issue
0
Issue
0
列表
看板
标记
里程碑
合并请求
0
合并请求
0
Pages
分析
分析
仓库分析
DevOps
Wiki
0
Wiki
成员
成员
收起侧边栏
关闭侧边栏
动态
分支图
创建新Issue
提交
Issue看板
前往新版Gitcode,体验更适合开发者的 AI 搜索 >>
未验证
提交
fb5a0009
编写于
4月 26, 2019
作者:
飞
飞龙
提交者:
GitHub
4月 26, 2019
浏览文件
操作
浏览文件
下载
差异文件
Merge pull request #8 from renyuhuiharrison/master
第3章译文初版提交
上级
501a028f
cdfad52b
变更
1
隐藏空白更改
内联
并排
Showing
1 changed file
with
471 addition
and
0 deletion
+471
-0
zh/3.md
zh/3.md
+471
-0
未找到文件。
zh/3.md
0 → 100644
浏览文件 @
fb5a0009
# 第三章 满足规则
> 译者:[renyuhuiharrison](https://github.com/renyuhuiharrison)
在第二章中,我们看了并练习了许多抽象接口(abstract interfaces),从某种意义上来说它们是抽象的,这些接口是用来描述共同功能属性、方法签名(method signatures)、以及所有类型集。我们还没有讲到这些类型内部细节,也还没有讲实现这些接口的具体对象(concrete objects)是如何创建的。
在本章中,我们通过展示填空的方法,来进一步探讨这些接口的具体成员。从某种程度上来讲,它们并不是严格意义上的实现,它们将使用“原始简单”、相对低效的数据结构。不过,我们的目的是熟练面向对象编程的原理,以便你能随处表现自己的构想。
为了帮助编程人员引入我们之前提到的的抽象接口的全新实现,Java标准库提供一个对应类似的抽象类集,其中实现了一些方法。只要你编写出一些关键、未实现的方法,你会“毫无代价地”得到其余方法。在大部分普通程序中,这些部分实现的类不是直接拿来使用的,而仅仅是为类库开发者提供参考。这里给出了一张包含这些类的表格,它们其中一部分的接口是已实现的(都来自java.util包):
抽象类|接口
-|-
AbstractCollection|Collection
AbstractSet|Collection、 Set
AbstractList|Collection、 List
AbstractSequentialList|Collection、 List
AbstractMap|Map
这种调用部分实现的思路是一种叫做模板模式(Template Method)的设计模式。
*设计模式*
(design pattern)是用在面向对象的编程中,它是“一种在程序设计中用来解决特定问题的核心思路”。这个抽象类是给真正的实现来使用的。我们将这些形如
**Abstract...**
的类当做模板,用来作真正的实现。使用方法重载(method overriding),在方法中补全实现,在模板的其它每个地方将使用那些方法。
```
java
import
java.util.*
;
import
java.lang.reflect.Array
;
public
class
ArrayCollection
<
T
>
implements
Collection
<
T
>
{
private
T
[]
data
;
/** An empty Collection */
public
ArrayCollection
()
{
data
=
(
T
[])
new
Object
[
0
];
}
/** A Collection consisting of the elements of C */
public
ArrayCollection
(
Collection
<?
extends
T
>
C
)
{
data
=
C
.
toArray
((
T
[])
new
Object
[
C
.
size
()]);
}
/** A Collection consisting of a view of the elements of A. */
public
ArrayCollection
(
T
[]
A
)
{
data
=
T
;
}
public
int
size
()
{
return
data
.
length
;
}
public
Iterator
<
T
>
iterator
()
{
return
new
Iterator
<
T
>
()
{
private
int
k
=
0
;
public
boolean
hasNext
()
{
return
k
<
size
();
}
public
T
next
()
{
if
(!
hasNext
())
throw
new
NoSuchElementException
();
k
+=
1
;
return
data
[
k
-
1
];
}
public
void
remove
()
{
throw
new
UnsupportedOperationException
();
}
};
}
public
boolean
isEmpty
()
{
return
size
()
==
0
;
}
public
boolean
contains
(
Object
x
)
{
for
(
T
y
:
this
)
{
if
(
x
==
null
&&
y
==
null
||
x
!=
null
&&
x
.
equals
(
y
))
return
true
;
}
return
false
;
}
```
代码3.1: “从零开始”实现一种新的只读集合(Collection)
```
java
public
boolean
containsAll
(
Collection
<?>
c
)
{
for
(
Object
x
:
c
)
if
(!
contains
(
x
))
return
false
;
return
true
;
}
public
Object
[]
toArray
()
{
return
toArray
(
new
Object
[
size
()]);
}
public
<
E
>
E
[]
toArray
(
E
[]
anArray
)
{
if
(
anArray
.
length
<
size
())
{
Class
<?>
typeOfElement
=
anArray
.
getClass
().
getComponentType
();
anArray
=
(
E
[])
Array
.
newInstance
(
typeOfElement
,
size
());
}
System
.
arraycopy
(
anArray
,
0
,
data
,
0
,
size
());
return
anArray
;
}
private
boolean
UNSUPPORTED
()
{
throw
new
UnsupportedOperationException
();
}
public
boolean
add
(
T
x
)
{
return
UNSUPPORTED
();
}
public
boolean
addAll
(
Collection
<?
extends
T
>
c
)
{
return
UNSUPPORTED
();
}
public
void
clear
()
{
UNSUPPORTED
();
}
public
boolean
remove
(
Object
x
)
{
return
UNSUPPORTED
();
}
public
boolean
removeAll
(
Collection
<?>
c
)
{
return
UNSUPPORTED
();
}
public
boolean
retainAll
(
Collection
<?>
c
)
{
return
UNSUPPORTED
();
}
}
```
代码3.1续:由于这是只读集合,所有企图对集合的修改操作,都将会抛出UnsupportedOperationExceptio异常,这是一种提示不支持当前操作的常规做法。
在接下来的部分,我们将看到如何去使用这些类,以及它们内部是如何使用Java类库功能的。不过,我们首先得快速地看下可行的方法。
## 3.1 从零开始
为了作比较,我们可以假设,我们想引入一个简单的实现,这个实现允许我们以只读集合(Collection)的形式处理对象(Objects)数组。一个直接的方式正如代码3.1所示。接下来,解释下Collection,前两个构造函数,一个是用来生成一个空的collection(不是很有用,当然是因为你无法再添加它),另一个是通过给定的collection拷贝出一份。第三个构造函数是针对新的类,并提供一个Collection数组(array)视图,——也就是说,Collection中的每项成员对应着数组中的元素,也对应着Collection接口相应的操作。接下来是一些必要的方法。通过
**iterator**
返回得到的
**Iterator**
有一个匿名类型,调用
**ArrayCollection**
的用户无法直接创建这种类型的对象。由于这是只读的收集器,所以不允许使用optional方法(会修改收集器)。
**反射(Reflection)概览**
。 第二个
**toArray**
方法相当有意思,这个方法里使用了Java语言中一个特别的功能:
*反射*
。它是一种语言特性,允许调用者借助语言本身可以操控编程语言的构造。在英语中,当我们在说诸如“单词'hit'是一个动词”的时候,我们就在使用反射。
**toArray**
方法产生了一个数组,这个数组是由一组相同动态类型参数组成的。我们是这样做的,首先调用
**getClass**
,这个方法定义了所有的
**Objects**
,这样我们得到了内建类型
**java.lang.Class**
,它用来表示
**anArray**
参数的动态类型。
**Class**
类型其中的一个操作是
**getComponentType**
,这是一个数组类型,可以获取反射元素类型的
**Class**
。最后,newInstance方法(定义在java.lang.reflect.Array类中)创建了新的对象,需要我们给定它的大小以及表示component类型的
**类**
。
## 3.2 AbstractCollection类
AbstractCollection的实现中有个有意思的功能:
**isEmpty**
开始的几个方法中,都没有用到ArrayCollection的私有数据,而是依赖其它几个(公有)方法。因此
**Collection**
类中任何一个实现都可以调用他们。Java标准库中的AbstractCollection类利用了这种观察方式(如代码3.2所示)。这是一个已部分实现的抽象类,新的
**Collection**
可以得到扩展。至少来说,一个实现部分可以重写
**iterator**
和
**size**
的定义,以便得到一个只读方式收集的类。比如,在代码3.3中展示了一个更加简易的
**ArrayCollection**
重写形式。此外,如果开发者重写了
**add**
方法,那么
**ArrayCollection**
还将自动提供
**addAll**
。最后,如果
**iterator**
方法返回了一个支持
**remove**
方法的
**Iterator**
,那么
**AbstractCollection**
将自动提供
**clear**
、
**remove**
、
**removeAll**
以及
**retainAll**
等方法。
在程序中,使用
**AbstractCollection**
的仅仅是一个
**扩展**
项。那也就是说,它是一个简单的工具类,对实现部分中创建新的
**Collection**
带来方便。你不应该把它用来识别正式参数类型、局部变量或者作用域。在这里顺便提一下,在声明
**AbstractCollection**
时候应该设置为
**protected**
,这个关键字强调了只有
**AbstractClass**
的继承部分可以调用它。
在代码3.1中,你已经看到了展示
**AbstractClass**
是如何运行的五个例子:
**isEmpty**
、
**contains**
、
**containsAll**
方法以及两个
**toArray**
方法。你只要理解了这种常见的思路,就能相当轻松地写出类似的方法。在练习部分中,你将会写更多的方法。
## 3.3 实现List接口
AbstractList和AbstractSequentialList这两个抽象类是由AbstractCollection专门扩展的,AbstractCollection是由Java标准库提供的,它用来帮助开发者定义那些可以实现
**List**
接口的类。你选择哪种,取决于成员使用具体实现哪种list类型。
### 3.3.1 AbstractList类
在代码3.4中,给出了
**List**
、
**AbstractList**
的实现,为成员提供快速(通常是常数时间)
*随机访问*
各自元素的功能,即类成员提供了
**get**
和
**remove**
(如果有提供的话)的快速实现方式。代码3.5展示了
**listIterator**
的运行原理,作为演示的一部分。此外,这个类中还体现了很多有意思的技巧。
**Protected方法**
。
**removeRange**
方法不在public接口部分。由于它是声明了
**protected**
,所以只能在其它
**java.util**
包中进行调用,并且必须得在
**AbstractList**
扩展体范围之内。这样的方法是给本类及其扩展部分来使用的
*实现工具(implementation utilities)*
。在
**AbstractList**
标准实现中,
**removeRange**
用来实现
**clear**
(你只要还记得
**L.subList(k0,k1).clear()**
是一个删除
**List**
中任意元素,你就会觉得这个方法很重要)。
```
java
package
java.util
;
public
abstract
class
AbstractCollection
<
T
>
implements
Collection
<
T
>
{
/** The empty Collection. */
protected
AbstractCollection
<
T
>
()
{
}
/** Unimplemented methods that must be overridden in any
* non-abstract class that extends AbstractCollection */
/** The number of values in THIS. */
public
abstract
int
size
();
/** An iterator that yields all the elements of THIS, in some
* order. If the remove operation is supported on this iterator,
* then remove, removeAll, clear, and retainAll on THIS will work. */
public
abstract
Iterator
<
T
>
iterator
();
/** Override this default implementation to support adding */
public
boolean
add
(
T
x
)
{
throw
new
UnsupportedOperationException
();
}
Default
,
general
-
purpose
implementations
of
contains
(
Object
x
),
containsAll
(
Collection
c
),
isEmpty
(),
toArray
(),
toArray
(
Object
[]
A
),
addAll
(
Collection
c
),
clear
(),
remove
(
Object
x
),
removeAll
(
Collection
c
),
and
retainAll
(
Collection
c
)
/** A String representing THIS, consisting of a comma-separated
* list of the values in THIS, as returned by its iterator,
* surrounded by square brackets ([]). The elements are
* converted to Strings by String.valueOf (which returns "null"
* for the null pointer and otherwise calls the .toString() method). */
public
String
toString
()
{
...
}
}
```
代码3.2:这个抽象类java.util.AbstractCollection,可以用来帮助实现新的
**Collection**
。所有的方法都定义在
**Collection**
的规范说明中。实现部分必须完成对
**iterator**
和
**size**
的定义,并且还要重写其他方法,或者使用它们的默认实现部分(本例中没有给出)。
```
java
import
java.util.*
;
/** A read-only Collection whose elements are those of an array. */
public
class
ArrayCollection
<
T
>
extends
AbstractCollection
<
T
>
{
private
T
[]
data
;
/** An empty Collection */
public
ArrayCollection
()
{
data
=
(
T
[])
new
Object
[
0
];
}
/** A Collection consisting of the elements of C */
public
ArrayCollection
(
Collection
<?
extends
T
>
C
)
{
data
=
C
.
toArray
(
new
Object
[
C
.
size
()]);
}
/** A Collection consisting of a view of the elements of A. */
public
ArrayCollection
(
Object
[]
A
)
{
data
=
A
;
}
public
int
size
()
{
return
data
.
length
;
}
public
Iterator
<
T
>
iterator
()
{
return
new
Iterator
<
T
>
()
{
private
int
k
=
0
;
public
boolean
hasNext
()
{
return
k
<
size
();
}
public
T
next
()
{
if
(!
hasNext
())
throw
new
NoSuchElementException
();
k
+=
1
;
return
data
[
k
-
1
];
}
public
void
remove
()
{
throw
new
UnsupportedOperationException
();
}
};
}
```
代码3.3:重新实现ArrayCollection,使用
**java.util.AbstractCollection**
中的默认实现。
**removeRange**
的默认实现简单调重复地用了remove(k),所以这个运行速度不会很快。但如果一个特殊的
**List**
成员有更好的方法,那么程序员可以重写
**removeRange**
,使用
**clear**
可以有更好的性能(这就是为什么这个方法的默认实现没有在
**最后**
声明,即使
**List**
中的任何成员都可以使用)。
**检查有效性**
。 正如我们在2.2.3章节中讨论过的,
**List**
接口的
**iterator**
、
**listIterator**
和
**subList**
方法给我们产生了一种观点,即如果改变了list的结构那么它会
**变得无效**
。那些无视规则的程序员,不会知道
**List**
的实现做了些什么。使用一个无效的视图可能会导致不可预估的结果或异常。即便如此,
**AbstractList**
类在显式检查错误时候会遇到麻烦,并且会立即抛出一个特定的异常
**ConcurrentModificationException**
。
**modCount**
(声明为
**protected**
,以此代表它是用于
**AbstractList**
,而不是其它地方)会持续追踪
**AbstractList**
结构修改的数量。每次调用
**add**
或者
**remove**
(直接在List中或者通过视图)应该会增加它。个人视图可以持续记录最后一个值,它们在List的
**modCount**
成员变量中能
**监视**
这个值。如果这个值在这期间被改变了,那么会有异常抛出。我们将在代码3.5中看到这个范例。
**Helper类**
。
**AbstractList**
(至少是在Sun的实现中)的
**subList**
使用了一个非公有的工具类型
**java.util.SubList**
来得出它的结果。由于它是非公有的,所以
**java.util.SubList**
对
**java.util**
包来说是私有的,并且这不是由官方给出部分。然而,在同一个包中,你可以用它来访问非公有成员变量和
**removeRang**
的工具方法(
**removeRang**
)。
### 3.3.2 AbstractSequentialList类
第二个抽象
**List**
的实现,
**AbstractSequentialList**
(代码3.6),适用于随机访问相对较慢的成员,当时list迭代器的
**next**
操作的速度依然很快。
当你想对
**get**
和迭代器的
**next**
进行实现时,为这个例子设计一个有显著区别的类,这样的理由已经很充分了。如果我们假设有一个执行很快的
**get**
方法,那很容易实现一个带有
**next**
的迭代器,如代码3.5所示。如果
**get**
执行较慢,也就是说,如果查找list中的元素k,必须对在它前面的k项元素进行排序,那么要实现像范例代码中的
**next**
将会很糟糕。这个算法将花费O(n
<sup>
2
</sup>
)复杂度来迭代一个N个元素的list。所以,使用
**get**
来实现迭代并不一定是个好主意。
```
java
package
java.util
;
public
abstract
class
AbstractList
<
T
>
extends
AbstractCollection
<
T
>
implements
List
<
T
>
{
/** Construct an empty list. */
protected
AbstractList
()
{
modCount
=
0
;
}
abstract
T
get
(
int
index
);
abstract
int
size
();
T
set
(
int
k
,
T
x
)
{
return
UNSUPPORTED
();
}
void
add
(
int
k
,
T
x
)
{
UNSUPPORTED
();
}
T
remove
(
int
k
)
{
return
UNSUPPORTED
();
}
Default
,
general
-
purpose
implementations
of
add
(
x
),
addAll
,
clear
,
equals
,
hashCode
,
indexOf
,
iterator
,
lastIndexOf
,
listIterator
,
set
,
and
subList
/** The number of times THIS has had elements added or removed. */
protected
int
modCount
;
/** Remove from THIS all elements with indices in the
range K0 .. K1-1. */
protected
void
removeRange
(
int
k0
,
int
k1
)
{
ListIterator
<
T
>
i
=
listIterator
(
k0
);
for
(
int
k
=
k0
;
k
<
k1
&&
i
.
hasNext
();
k
+=
1
)
{
i
.
next
();
i
.
remove
();
}
}
private
Object
UNSUPPORTED
()
{
throw
new
UnsupportedOperationException
();
}
}
```
代码3.4:抽象类AbstractList,用作帮助编写能随机读取的
**List**
的实现。内部类
**ListIteratorImpl**
可详见代码3.5。
```
java
public
ListIterator
<
T
>
listIterator
(
int
k0
)
{
return
new
ListIteratorImpl
(
k0
);
}
private
class
ListIteratorImpl
<
T
>
implements
ListIterator
<
T
>
{
ListIteratorImpl
(
int
k0
)
{
lastMod
=
modCount
;
k
=
k0
;
lastIndex
=
-
1
;
}
public
boolean
hasNext
()
{
return
k
<
size
();
}
public
hasPrevious
()
{
return
k
>
0
;
}
public
T
next
()
{
check
(
0
,
size
());
lastIndex
=
k
;
k
+=
1
;
return
get
(
lastIndex
);
}
public
T
previous
()
{
check
(
1
,
size
()+
1
);
k
-=
1
;
lastIndex
=
k
;
return
get
(
k
);
}
public
int
nextIndex
()
{
return
k
;
}
public
int
previousIndex
()
{
return
k
-
1
;
}
public
void
add
(
T
x
)
{
check
();
lastIndex
=
-
1
;
k
+=
1
;
AbstractList
.
this
.
add
(
k
-
1
,
x
);
lastMod
=
modCount
;
}
public
void
remove
()
{
checkLast
();
AbstractList
.
this
.
remove
(
lastIndex
);
lastIndex
=
-
1
;
lastMod
=
modCount
;
}
public
void
set
(
T
x
)
{
checkLast
();
AbstractList
.
this
.
remove
(
lastIndex
,
x
);
lastIndex
=
-
1
;
lastMod
=
modCount
;
}
```
代码3.5:
**AbstractList**
一部分可能的实现,展示了内部类提供
**listIterator**
的值。
```
java
// Class AbstractList.ListIteratorImpl, continued.
/* Private definitions */
/** modCount value expected for underlying list. */
private
int
lastMod
;
/** Current position. */
private
int
k
;
/** Index of last result returned by next or previous. */
private
int
lastIndex
;
/** Check that there has been no concurrent modification. Throws
* appropriate exception if there has. */
private
void
check
()
{
if
(
modCount
!=
lastMod
)
throw
new
ConcurrentModificationException
();
}
/** Check that there has been no concurrent modification and that
* the current position, k, is in the range K0 <= k < K1. Throws
* appropriate exception if either test fails. */
private
void
check
(
int
k0
,
int
k1
)
{
check
();
if
(
k
<
k0
||
k
>=
k1
)
throw
new
NoSuchElementException
();
}
/** Check that there has been no concurrent modification and that
* there is a valid ‘‘last element returned by next or previous’’.
* Throws appropriate exception if either test fails. */
private
checkLast
()
{
check
();
if
(
lastIndex
==
-
1
)
throw
new
IllegalStateException
();
}
```
代码3.5续:
**ListIterator**
的私有成员
```
java
public
abstract
class
AbstractSequentialList
<
T
>
extends
AbstractList
<
T
>
{
/** An empty list */
protected
AbstractSequentialList
()
{
}
abstract
int
size
();
abstract
ListIterator
<
T
>
listIterator
(
int
k
);
Default
implementations
of
add
(
k
,
x
),
addAll
(
k
,
c
),
get
,
iterator
,
remove
(
k
),
set
From
AbstractList
,
inherited
implementations
of
add
(
x
),
clear
,
equals
,
hashCode
,
indexOf
,
lastIndexOf
,
listIterator
(),
removeRange
,
subList
From
AbstractCollection
,
inherited
implementations
of
addAll
(),
contains
,
containsAll
,
isEmpty
,
remove
(),
removeAll
,
retainAll
,
toArray
,
toString
}
```
代码3.6:
**AbstractSequentialList**
类
另一方面,如果我们总想通过迭代所有k项元素来实现
**get(k)**
(也就是说,使用
**Iterator**
的方法来实现
**get**
,而不是反转(reverse)),很显然,我们将不可能很快地来执行
**get**
。我们显然会失去快速获取的表示
## 3.4 AbstractMap类
如代码3.7所示,
**AbstractMap**
为
**Map**
接口提供了模板实现。重写了
**entrySet**
来提供一个只读的
**Set**
。另外,重写了
**put**
方法,给出了一个扩展的
**Map**
,并且实现了
**remove**
方法,
**entrySet().iterator()**
提供一个完全可修改的
**Map**
。
## 3.5 性能预测
在第二章的开始部分,我曾说过对于给定的接口有几种典型实现。在有几种可能的情况下会用到不止一种。首先,要么是因为有特殊的存储项目、关键字、或者需要特殊操作的值,要么是为了运行速度,或者是对这些特殊类型要做额外操作。其次,一些特定的
**Collections**
或是
**Maps**
可能需要一种特殊的实现,因为他们是其它的一部分,比如说
**subList**
或
**entrySet**
视图。再次,一种实现可能在某些情况下的性能好,但在其它情况下可能就不好。最后,在不同的实现之间可能有时间和空间的权衡,并且一些应用程序可能需要比较紧凑(节省空间)的成员结构。
```
java
package
java.util
;
public
abstract
class
AbstractMap
<
Key
,
Val
>
implements
Map
<
Key
,
Val
>
{
/** An empty map. */
protected
AbstractMap
()
{
}
/** A view of THIS as the set of all its (key,value) pairs.
* If the resulting Set’s iterator supports remove, then THIS
* map will support the remove and clear operations. */
public
abstract
Set
<
Entry
<
Key
,
Val
>>
entrySet
();
/** Cause get(KEY) to yield VAL, without disturbing other values. */
public
Val
put
(
Key
key
,
Val
val
)
{
throw
new
UnsupportedOperationException
();
}
Default
implementations
of
clear
,
containsKey
,
containsValue
,
equals
,
get
,
hashCode
,
isEmpty
,
keySet
,
putAll
,
remove
,
size
,
values
/** Print a String representation of THIS, in the form
* {KEY0=VALUE0, KEY1=VALUE1, ...}
* where keys and values are converted using String.valueOf(...). */
public
String
toString
()
{
...
}
}
```
代码3.7:
**AbstractMap**
类
我们不能对这里的
**Abstract...**
类成员有具体的性能要求,因为他们是模板而不是完整的实现。不过,我们可以把他们作为一个待开发者补充的函数来描述其性能。这里,让我们考虑两个例子:
**List**
接口的实现模板。
**AbstractList**
。 在AbstractList背后的策略是使用了
**size**
、
**get(k)**
、
**add(k,x)**
、
**set(k,x)**
以及
**remove(k)**
这些方法,它们是由扩展类型提供的,这些扩展类型还用来实现了其它部分。
**listIterator**
方法返回了一个
**listIterator**
,这个
**listIterator**
使用了
**get**
来实现
**next**
和
**previous**
,使用
**add**
(在AbstractList中的)实现了迭代器的
**add**
,使用
**remove**
(在AbstractList中的)实现了迭代器的
**remove**
。由增加或减少的整型变量构成迭代器实现了记账簿(bookkeeping)的功能,因此它的花费是一个较小的常数时间。这样看来,我们可以轻松地将迭代函数的耗费直接和那些方法(下表中所展示的)关联上。为了简化问题复杂度,对于个体而言的
**size**
和
**equals**
操作,我们将它们所耗费的时间看做是个常数。我们将"plugged-in"方法的数值以C
<sub>
α
</sub>
的形式给出;
**this**
(这里的
**List**
)的大小是N,其它收集器参数(表示为c,这里我们假设是相同类型的
**List**
,只是为了可以讲更多的内容)的大小是M。
```
math
```
**AbstractList**
实现的耗费
**AbstractSequentialList**
。 现在让我们比较一下AbstractList和AbstractSequentialList的实现,后者未使用低效的
**get**
操作,但它仍然使用了低效的迭代器。在这个例子中,
**get(k)**
操作是由新创建的
**AbstractSequentialList**
,同时由一个耗费
**k**
倍的时间性能
**next**
操作一起来实现的。让我们看下这张表格:
```
math
```
#练习
3.
1. 为
**AbstractCollection**
写出一个
**addAll**
的实现。在它做
**增加**
操作时,如果新增了收集器不支持的元素,则会抛出
**AbstractCollectio**
,如果支持的话,就新增一个元素。
3.
2. 为
**AbstractCollection**
写出一个
**removeAll**
的实现。如果支持当前移除操作,使用
**iterator**
来进行
**remove**
的操作。
3.
3. 为
**java.util.SubList**
写出一个实现。这个工具类实现了
**List**
,并且有这样的一个构造函数:
```
java
/** A view of items K0 throught K1-1 of THELIST. Subsequent
* modifications to THIS also modify THELIST. Any structural
* modification to THELIST other than through THIS and any
* iterators or sublists derived from it renders THIS invalid.
* Operations on an invalid SubList throw
* ConcurrentModificationException */
SubList
(
AbstractList
theList
,
int
k0
,
int
k1
)
{
...
}
```
3.
4. 为一个
**AbstractSequentialList**
类写出
**add(k,x)**
和
**get**
的实现。它在列表的任何一端或附近,都可以很快地获取一个元素。
3.
5. 扩展
**AbstractMap**
类,编写更多
**Map**
的实现。试着尽可能地不要依赖
**AbstractMap**
,仅仅实现需要的部分。比如说要写一个成员,写出
**Map.Entry**
的实现,要使用到Java库提供的现有的
**Set**
,即
**HashSet**
。把最终实现的类叫做
**SimpleMap**
。
3.
6. 在3.5章节,我们没有谈论到
**subList**
方法返回
**Lists**
操作的性能。请估算出
**AbstractMap**
和
**AbstractSequentialList**
的性能。对于
**AbstractSequentialList**
,
**get**
方法所需要的时间必须依赖
**subList**
(起点位置)取决于第一个参数。为什么是这样呢?在
**ListIterator**
定义中的哪些更改,不会让子列表上的
**get**
(和其他操作)的性能受到子列表的原始列表中的位置的影响?
\ No newline at end of file
编辑
预览
Markdown
is supported
0%
请重试
或
添加新附件
.
添加附件
取消
You are about to add
0
people
to the discussion. Proceed with caution.
先完成此消息的编辑!
取消
想要评论请
注册
或
登录