smile怎么读-brain什么意思
软件专业毕业论文外文文献中英文翻译
Object landscapes and lifetimes
Technically, OOP is just about abstract data
typing, inheritance, and polymorphism, but other
issues can be at least as important. The
remainder of this section will cover these issues.
One of the most important factors is the way
objects are created and destroyed. Where is the
data for an object and how is the lifetime of
the object controlled? There are different
philosophies
at work here. C++ takes the
approach that control of efficiency is the most
important issue, so it
gives the programmer a
choice. For maximum run-time speed, the storage
and lifetime can be
determined while the
program is being written, by placing the objects
on the stack (these are
sometimes called
automatic or scoped variables) or in the static
storage area. This places a priority
on the
speed of storage allocation and release, and
control of these can be very valuable in some
situations. However, you sacrifice flexibility
because you must know the exact quantity,
lifetime,
and type of objects while you're
writing the program. If you are trying to solve a
more general
problem such as computer-aided
design, warehouse management, or air-traffic
control, this is too
restrictive.
The
second approach is to create objects dynamically
in a pool of memory called the heap. In
this
approach, you don't know until run-time how many
objects you need, what their lifetime is, or
what their exact type is. Those are determined
at the spur of the moment while the program is
running. If you need a new object, you simply
make it on the heap at the point that you need it.
Because the storage is managed dynamically, at
run-time, the amount of time required to allocate
storage on the heap is significantly longer
than the time to create storage on the stack.
(Creating
storage on the stack is often a
single assembly instruction to move the stack
pointer down, and
another to move it back up.)
The dynamic approach makes the generally logical
assumption that
objects tend to be
complicated, so the extra overhead of finding
storage and releasing that storage
will not
have an important impact on the creation of an
object. In addition, the greater flexibility is
essential to solve the general programming
problem.
Java uses the second approach,
exclusively
]
. Every time you want to
create an object, you use
the new
keyword to build a dynamic instance of that
object.
There's another issue, however, and
that's the lifetime of an object. With languages
that allow
objects to be created on the stack,
the compiler determines how long the object lasts
and can
automatically destroy it. However, if
you create it on the heap the compiler has no
knowledge of
its lifetime. In a language like
C++, you must determine programmatically when to
destroy the
object, which can lead to memory
leaks if you don’t do it correctly (and this is a
common problem
in C++ programs). Java provides
a feature called a garbage collector that
automatically discovers
when an object is no
longer in use and destroys it. A garbage collector
is much more convenient
because it reduces the
number of issues that you must track and the code
you must write. More
important, the garbage
collector provides a much higher level of
insurance against the insidious
problem of
memory leaks (which has brought many a C++ project
to its knees).
The rest of this section looks
at additional factors concerning object lifetimes
and landscapes.
1. The singly rooted
hierarchy
One of the issues in OOP that has
become especially prominent since the introduction
of C++
is whether all classes should
ultimately be inherited from a single base class.
In Java (as with
virtually all other OOP
languages) the answer is “yes” and the name of
this ultimate base class is
simply Object. It
turns out that the benefits of the singly rooted
hierarchy are many.
All objects in a singly
rooted hierarchy have an interface in common, so
they are all
ultimately the same type. The
alternative (provided by C++) is that you don’t
know that
everything is the same fundamental
type. From a backward-compatibility standpoint
this fits the
model of C better and can be
thought of as less restrictive, but when you want
to do full-on
object-oriented programming you
must then build your own hierarchy to provide the
same
convenience that’s built into other OOP
languages. And in any new class library you
acquire, some
other incompatible interface
will be used. It requires effort (and possibly
multiple inheritance) to
work the new
interface into your design. Is the extra
“flexibility” of C++ worth it? If you need
it—if you have a large investment in C—it’s
quite valuable. If you’re starting from scratch,
other
alternatives such as Java can often be
more productive.
All objects in a singly
rooted hierarchy (such as Java provides) can be
guaranteed to have
certain functionality. You
know you can perform certain basic operations on
every object in your
system. A singly rooted
hierarchy, along with creating all objects on the
heap, greatly simplifies
argument
passing (one of the more complex topics in C++).
A singly rooted hierarchy makes it much easier
to implement a garbage collector (which is
conveniently built into Java). The necessary
support can be installed in the base class, and
the
garbage collector can thus send the
appropriate messages to every object in the
system. Without a
singly rooted hierarchy and
a system to manipulate an object via a reference,
it is difficult to
implement a garbage
collector.
Since run-time type information is
guaranteed to be in all objects, you’ll never end
up with an
object whose type you cannot
determine. This is especially important with
system level operations,
such as exception
handling, and to allow greater flexibility in
programming.
2 .Collection libraries and
support for easy collection use
Because a
container is a tool that you’ll use frequently, it
makes sense to have a library of
containers
that are built in a reusable fashion, so you can
take one off the shelf Because a
container is
a tool that you’ll use frequently, it makes sense
to have a library of containers that are
built
in a reusable fashion, so you can take one off the
shelf and plug it into your program. Java
provides such a library, which should satisfy
most needs.
Downcasting vs. templatesgenerics
To make these containers reusable, they hold
the one universal type in Java that was
previously mentioned: Object. The singly
rooted hierarchy means that everything is an
Object, so
a container that holds Objects can
hold anything. This makes containers easy to
reuse.
To use such a container, you simply
add object references to it, and later ask for
them back.
But, since the container holds only
Objects, when you add your object reference into
the container
it is upcast to Object, thus
losing its identity. When you fetch it back, you
get an Object reference,
and not a reference
to the type that you put in. So how do you turn it
back into something that has
the useful
interface of the object that you put into the
container?
Here, the cast is used again, but
this time you’re not casting up the inheritance
hierarchy to a
more general type, you cast
down the hierarchy to a more specific type. This
manner of casting is
called downcasting. With
upcasting, you know, for example, that a Circle is
a type of Shape so it’s
safe to upcast, but
you don’t know that an Object is necessarily a
Circle or a Shape so it’s hardly
safe
to downcast unless you know that’s what you’re
dealing with.
It’s not completely dangerous,
however, because if you downcast to the wrong
thing you’ll
get a run-time error called an
exception, which will be described shortly. When
you fetch object
references from a container,
though, you must have some way to remember exactly
what they are
so you can perform a proper
downcast.
Downcasting and the run-time checks
require extra time for the running program, and
extra
effort from the programmer. Wouldn’t it
make sense to somehow create the container so that
it
knows the types that it holds, eliminating
the need for the downcast and a possible mistake?
The
solution is parameterized types, which are
classes that the compiler can automatically
customize to
work with particular types. For
example, with a parameterized container, the
compiler could
customize that container so
that it would accept only Shapes and fetch only
Shapes.
Parameterized types are an important
part of C++, partly because C++ has no singly
rooted
hierarchy. In C++, the keyword that
implements parameterized types is “template.” Java
currently
has no parameterized types since it
is possible for it to get by—however
awkwardly—using the
singly rooted hierarchy.
However, a current proposal for parameterized
types uses a syntax that is
strikingly similar
to C++ templates.
对象的创建和存在时间
从技术角
度说,OOP(面向对象程序设计)只是涉及抽象的数据类型、继承以及多形性,
但另一些问题也可能显
得非常重要。本节将就这些问题进行探讨。
最重要的问题之一是对象的创建及破坏方式。对象需要的数
据位于哪儿,如何控制对象
的“存在时间”呢?针对这个问题,解决的方案是各异其趣的。C++认为程
序的执行效率是
最重要的一个问题,所以它允许程序员作出选择。为获得最快的运行速度,存储以及存在
时
间可在编写程序时决定,只需将对象放置在堆栈(有时也叫作自动或定域变量)或者静态存
储
区域即可。这样便为存储空间的分配和释放提供了一个优先级。某些情况下,这种优先级
的控制是非常有
价值的。然而,我们同时也牺牲了灵活性,因为在编写程序时,必须知道对
象的准确的数量、存在时间、
以及类型。如果要解决的是一个较常规的问题,如计算机辅助
设计、仓储管理或者空中交通控制,这一方
法就显得太局限了。
第二个方法是在一个内存池中动态创建对象,该内存池亦叫“堆”或者“内存堆”
。若
采用这种方式,除非进入运行期,否则根本不知道到底需要多少个对象,也不知道它们的存
在时间有多长,以及准确的类型是什么。这些参数都在程序正式运行时才决定的。若需一个
新对象,只需
在需要它的时候在内存堆里简单地创建它即可。由于存储空间的管理是运行期
间动态进行的,所以在内存
堆里分配存储空间的时间比在堆栈里创建的时间长得多(在堆栈
里创建存储空间一般只需要一个简单的指
令,将堆栈指针向下或向下移动即可)。由于动态
创建方法使对象本来就倾向于复杂,所以查找存储空间
以及释放它所需的额外开销不会为对
象的创建造成明显的影响。除此以外,更大的灵活性对于常规编程问
题的解决是至关重要的。
C++允许我们决定是在写程序时创建对象,还是在运行期间创建,这种控制
方法更加灵
活。大家或许认为既然它如此灵活,那么无论如何都应在内存堆里创建对象,而不是在堆栈<
br>中创建。
但还要考虑另外一个问题,亦即对象的“存在时间”或者“生存时间”(Lifeti
me)。
若在堆栈或者静态存储空间里创建一个对象,编译器会判断对象的持续时间有多长,到时会自动“破坏”或者“清除”它。程序员可用两种方法来破坏一个对象:用程序化的方式决定
何时破坏
对象,或者利用由运行环境提供的一种“垃圾收集器”特性,自动寻找那些不再使
用的对
象,并将其清除。当然,垃圾收集器显得方便得多,但要求所有应用程序都必须容忍
垃圾收集器的存在,
并能默许随垃圾收集带来的额外开销。但这并不符合C++语言的设计宗
旨,所以未能包括到C++里。
但Java确实提供了一个垃圾收集器(Smalltalk也有这样的设
计;尽管Delphi默认为
没有垃圾收集器,但可选择安装;而C++亦可使用一些由其他公司
开发的垃圾收集产品)。
本节剩下的部分将讨论操纵对象时要考虑的另一些因素。
1 单根结构
在面向对象
的程序设计中,由于C++的引入而显得尤为突出的一个问题是:所有类最终
是否都应从单独一个基础类
继承。在Java中(与其他几乎所有OOP语言一样),对这个问
题的答案都是肯定的,而且这个终级
基础类的名字很简单,就是一个“Object”。这种“单
根结构”具有许多方面的优点。
单根结构中的所有对象都有一个通用接口,所以它们最终都属于相同的类型。另一种方
案(就象C++那
样)是我们不能保证所有东西都属于相同的基本类型。从向后兼容的角度看,
这一方案可与C模型更好地
配合,而且可以认为它的限制更少一些。但假期我们想进行纯粹
的面向对象编程,那么必须构建自己的结
构,以期获得与内建到其他OOP语言里的同样的便
利。需添加我们要用到的各种新类库,还要使用另一
些不兼容的接口。理所当然地,这也需
要付出额外的精力使新接口与自己的设计方案配合(可能还需要多
重继承)。为得到C++额
外的“灵活性”,付出这样的代价值得吗?当然,如果真的需要——如果早已
是C专家,如
果对C有难舍的情结——那么就真的很值得。但假如你是一名新手,首次接触这类设计,象
Java那样的替换方案也许会更省事一些。
单根结构中的所有对象(比如所有Java对象
)都可以保证拥有一些特定的功能。在自
己的系统中,我们知道对每个对象都能进行一些基本操作。一个
单根结构,加上所有对象都
在内存堆中创建,可以极大简化参数的传递(这在C++里是一个复杂的概念
)。
利用单根结构,我们可以更方便地实现一个垃圾收集器。与此有关的必要支持可安装于
基
础类中,而垃圾收集器可将适当的消息发给系统内的任何对象。如果没有这种单根结构,
而且系统通过一
个句柄来操纵对象,那么实现垃圾收集器的途径会有很大的不同,而且会面
临许多障碍。
由于
运行期的类型信息肯定存在于所有对象中,所以永远不会遇到判断不出一个对象的
类型的情况。这对系统
级的操作来说显得特别重要,比如违例控制;而且也能在程序设计时
获得更大的灵活性。
2 集合库与方便使用集合
由于集合是我们经常都要用到的一种工具,所以一个集合库是十分
必要的,它应该可以
方便地重复使用。这样一来,我们就可以方便地取用各种集合,将其插入自己的程序
。Java
提供了这样的一个库,尽管它在Java 1.0和1.1中都显得非常有限(Java
1.2的集合库则
无疑是一个杰作)。
下溯造型与模板/通用性
为了使这些集合能
够重复使用,或者“再生”,Java提供了一种通用类型,以前曾把它
叫作“Object”。单根结
构意味着、所有东西归根结底都是一个对象”!所以容纳了Object
的一个集合实际可以容纳任何东
西。这使我们对它的重复使用变得非常简便。
为使用这样的一个集合,只需添加指向它的对象句柄即可
,以后可以通过句柄重新使用
对象。但由于集合只能容纳Object,所以在我们向集合里添加对象句
柄时,它会上溯造型
成Object,这样便丢失了它的身份或者标识信息。再次使用它的时候,会得到
一个Object
句柄,而非指向我们早先置入的那个类型的句柄。所以怎样才能归还它的本来面貌,调
用早
先置入集合的那个对象的有用接口呢?
在这里,我们再次用到了造型(Cast)。但这
一次不是在分级结构中上溯造型成一种更
“通用”的类型。而是下溯造型成一种更“特殊”的类型。这种
造型方法叫作“下溯造型”
(Downcasting)。举个例子来说,我们知道在上溯造型的时候,
Circle(圆)属于Shape
(几何形状)的一种类型,所以上溯造型是安全的。但我们不知道一
个Object到底是Circle
还是Shape,所以很难保证下溯造型的安全进行,除非确切地知
道自己要操作的是什么。
但这也不是绝对危险的,因为假如下溯造型成错误的东西,会得到我们称为“
违例”
(Exception)的一种运行期错误。我们稍后即会对此进行解释。但在从一个集合提取对
象
句柄时,必须用某种方式准确地记住它们是什么,以保证下溯造型的正确进行。
下溯造型和
运行期检查都要求花额外的时间来运行程序,而且程序员必须付出额外的精
力。既然如此,我们能不能创
建一个“智能”集合,令其知道自己容纳的类型呢?这样做可
消除下溯造型的必要以及潜在的错误。答案
是肯定的,我们可以采用“参数化类型”,它们
是编译器能自动定制的类,可与特定的类型配合。例如,
通过使用一个参数化集合,编译器
可对那个集合进行定制,使其只接受Shape,而且只提取Shap
e。
参数化类型是C++一个重要的组成部分,这部分是C++没有单根结构的缘故。
在C++中,
用于实现参数化类型的关键字是template(模板)。Java目前尚未提供参数化
类型,因为
由于使用的是单根结构,所以使用它显得有些笨拙。但这并不能保证以后的版本不会实现,<
br>因为“generic”这个词已被Java“保留到将来实现”(在Ada语言中,“generic”
被用
来实现它的模板)。Java采取的这种关键字保留机制其实经常让人摸不着头脑,很难断定
以后会发生什么事情。
腰包-根本的拼音
四级作文模板-conditioned
ticker-荡漾怎么读
惊天动地的意思-糟粕是什么意思
风止-七年级英语试卷分析
key复数-错颌畸形
学校英语怎么说-虾籽酱油
市场定位怎么写-银行资信证明怎么开
-
上一篇:精彩的英文怎么说?
下一篇:我们为什么要学英语,英语的重要性