 |
 |
1) Introduction sur les « objets » |
|
 |
|
Texte original |
 |
Traducteur :
Jérome Quelin |
|
 |
|
 |
 |
 |
 |
 |
 |
|
 |
|
 |
 |
 |
Java uses the second approach,
exclusively[7]. Every
time you want to create an object, you use the new keyword to build a
dynamic instance of that object.
|
 |
Java utilise exclusivement la deuxième approche [7]. Le mot clef new est utilisé pour créer une instance dynamique d'un
objet à chaque fois qu'on en a besoin.
|
 |
 |
 |
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).
|
 |
Une autre particularité importante est la durée de vie d'un objet. Avec les
langages qui autorisent la création d'objets dans la pile, le compilateur détermine combien de
temps l'objet est amené à vivre et peut le détruire automatiquement. Mais si l'objet est créé dans
le segment, le compilateur n'a aucune idée de sa durée de vie. Dans un langage comme le C++, il
faut déterminer dans le programme quand détruire l'objet, ce qui peut mener à des fuites de mémoire
si cela n'est pas fait correctement (et c'est un problème courant en C++). Java propose une
fonctionnalité appelée ramasse-miettes (garbage collector) qui découvre automatiquement quand un
objet n'est plus utilisé et le détruit. Java propose donc un niveau plus élevé d'assurance contre
les fuites de mémoire. Disposer d'un ramasse-miettes est pratique car cela réduit le code à écrire
et, plus important, le nombre de problèmes liés à la gestion de la mémoire (qui ont mené à
l'abandon de plus d'un projet C++).
|
 |
 |
 |
The rest of this section looks at
additional factors concerning object lifetimes and
landscapes.
|
 |
Le reste de cette section s'attarde sur des facteurs additionnels
concernant l'environnement et la durée de vie des objets.
|
 |
 |
 |
Collections and iterators
|
 |
Collections et itérateurs
|
 |
 |
 |
If you don’t know how many objects
you’re going to need to solve a particular problem, or how long they will
last, you also don’t know how to store those objects. How can you know how
much space to create for those objects? You can’t, since that information
isn’t known until run-time.
|
 |
Si le nombre d'objets nécessaires à la résolution d'un problème est
inconnu, ou combien de temps on va en avoir besoin, on ne peut pas non plus savoir comment les
stocker. Comment déterminer l'espace nécessaire pour créer ces objets ? C'est impossible car
cette information n'est connue que lors de l'exécution.
|
 |
 |
 |
The solution to most problems in
object-oriented design seems flippant: you create another type of object. The
new type of object that solves this particular problem holds references to other
objects. Of course, you can do the same thing with an array, which is available
in most languages. But there’s more. This new object, generally called a
container (also called a collection, but the Java library uses
that term in a different sense so this book will use “container”),
will expand itself whenever necessary to accommodate everything you place inside
it. So you don’t need to know how many objects you’re going to hold
in a container. Just create a container object and let it take care of the
details.
|
 |
La solution à la plupart des problèmes en conception orientée objet est
simple : il suffit de créer un nouveau type d'objet. Le nouveau type d'objets qui résout ce
problème particulier contient des références aux autres objets. Bien sûr, un tableau ferait aussi
bien l'affaire. Mais il y a plus. Ce nouvel objet, appelé conteneur (ou
collection, mais la bibliothèque Java utilise ce terme dans un autre sens ; nous
utiliserons donc le terme « conteneur » dans la suite de ce livre), grandira
automatiquement pour accepter tout ce qu'on place dedans. Connaître le nombre d'objets qu'on désire
stocker dans un conteneur n'est donc plus nécessaire. Il suffit de créer un objet conteneur et le
laisser s'occuper des détails.
|
 |
 |
 |
Fortunately, a good OOP language comes
with a set of containers as part of the package. In C++, it’s part of the
Standard C++ Library and is sometimes called the Standard Template Library
(STL). Object Pascal has containers in its Visual Component Library (VCL).
Smalltalk has a very complete set of containers. Java also has containers in its
standard library. In some libraries, a generic container is considered good
enough for all needs, and in others (Java, for example) the library has
different types of containers for different needs: a vector (called an
ArrayList in Java) for consistent access to all elements, and a linked
list for consistent insertion at all elements, for example, so you can choose
the particular type that fits your needs. Container libraries may also include
sets, queues, hash tables, trees, stacks, etc.
|
 |
Heureusement, les langages orientés objet décents fournissent ces
conteneurs. En C++, ils font partie de la bibliothèque standard (STL, Standard Template Library).
Le Pascal Objet dispose des conteneurs dans sa Bibliothèque de Composants Visuels (VCL, Visual
Component Library). Smalltalk propose un ensemble vraiment complet de conteneurs. Java aussi
propose des conteneurs dans sa bibliothèque standard. Dans certaines bibliothèques, un conteneur
générique est jugé suffisant pour tous les besoins, et dans d'autres (Java par exemple), la
bibliothèque dispose de différents types de conteneurs suivant les besoins : des vecteurs
(appelé ArrayList en Java) pour un accès pratique à tous les éléments, des listes
chaînées pour faciliter l'insertion, par exemple, on peut donc choisir le type particulier qui
convient le mieux. Les bibliothèques de conteneurs peuvent aussi inclure les ensembles, les files,
les dictionnaires, les arbres, les piles, etc...
|
 |
 |
 |
All containers have some way to put
things in and get things out; there are usually functions to add elements to a
container, and others to fetch those elements back out. But fetching elements
can be more problematic, because a single-selection function is restrictive.
What if you want to manipulate or compare a set of elements in the container
instead of just one?
|
 |
Tous les conteneurs disposent de moyens pour y stocker des choses et les
récupérer ; ce sont habituellement des fonctions pour ajouter des éléments dans un conteneur
et d'autres pour les y retrouver. Mais retrouver des éléments peut être problématique, car une
fonction de sélection unique peut se révéler trop restrictive. Comment manipuler ou comparer un
ensemble d'éléments dans le conteneur ?
|
 |
 |
 |
The solution is an iterator, which is an
object whose job is to select the elements within a container and present them
to the user of the iterator. As a class, it also provides a level of
abstraction. This abstraction can be used to separate the details of the
container from the code that’s accessing that container. The container,
via the iterator, is abstracted to be simply a sequence. The iterator allows you
to traverse that sequence without worrying about the underlying
structure—that is, whether it’s an ArrayList, a
LinkedList, a Stack, or something else. This gives you the
flexibility to easily change the underlying data structure without disturbing
the code in your program. Java began (in version 1.0 and 1.1) with a standard
iterator, called Enumeration, for all of its container classes. Java 2
has added a much more complete container library that contains an iterator
called Iterator that does more than the older
Enumeration.
|
 |
La réponse à cette question prend la forme d'un itérateur, qui est un objet
dont le travail est de choisir les éléments d'un conteneur et de les présenter à l'utilisateur de
l'itérateur. En tant que classe, il fournit de plus un niveau d'abstraction supplémentaire. Cette
abstraction peut être utilisée pour séparer les détails du conteneur du code qui utilise ce
conteneur. Le conteneur, via l'itérateur, est perçu comme une séquence. L'itérateur permet de
parcourir cette séquence sans se préoccuper de sa structure sous-jacente - qu'il s'agisse d'une
ArrayList (vecteur), une LinkedList (liste chaînée), une
Stack (pile) ou autre. Cela permet de changer facilement la structure de données
sous-jacente sans perturber le code du programme. Java commença (dans les versions 1.0 et 1.1) avec
un itérateur standard, appelé Enumeration, pour toutes ses classes conteneurs.
Java 2 est accompagné d'une bibliothèque de conteneurs beaucoup plus complète qui contient entre
autres un itérateur appelé Iterator bien plus puissant que l'ancienne
Enumeration.
|
 |
 |
 |
From a design standpoint, all you really
want is a sequence that can be manipulated to solve your problem. If a single
type of sequence satisfied all of your needs, there’d be no reason to have
different kinds. There are two reasons that you need a choice of containers.
First, containers provide different types of interfaces and external behavior. A
stack has a different interface and behavior than that of a queue, which is
different from that of a set or a list. One of these might provide a more
flexible solution to your problem than the other. Second, different containers
have different efficiencies for certain operations. The best example is an
ArrayList and a LinkedList. Both are simple sequences that can
have identical interfaces and external behaviors. But certain operations can
have radically different costs. Randomly accessing elements in an
ArrayList is a constant-time operation; it takes the same amount of time
regardless of the element you select. However, in a LinkedList it is
expensive to move through the list to randomly select an element, and it takes
longer to find an element that is further down the list. On the other hand, if
you want to insert an element in the middle of a sequence, it’s much
cheaper in a LinkedList than in an ArrayList. These and other
operations have different efficiencies depending on the underlying structure of
the sequence. In the design phase, you might start with a LinkedList and,
when tuning for performance, change to an ArrayList. Because of the
abstraction via iterators, you can change from one to the other with minimal
impact on your code.
|
 |
Du point de vue du design, tout ce dont on a besoin est une séquence qui
peut être manipulée pour résoudre le problème. Si un seul type de séquence satisfaisait tous les
besoins, il n'y aurait pas de raison d'en avoir de types différents. Il y a deux raisons qui font
qu'on a besoin d'un choix de conteneurs. Tout d'abord, les conteneurs fournissent différents
types d'interfaces et de comportements. Une pile a une interface et un comportement différents de
ceux d'une file, qui sont différents de ceux fournis par un ensemble ou une liste. L'un de ces
conteneurs peut se révéler plus flexible qu'un autre pour la résolution du problème considéré.
Deuxièmement, les conteneurs ne sont pas d'une même efficacité pour les mêmes opérations. Prenons
le cas d'une ArrayList et d'une LinkedList. Les deux sont de
simples séquences qui peuvent avoir la même interface et comportement. Mais certaines opérations
ont des coûts radicalement différents. Accéder à des éléments au hasard dans une
ArrayList est une opération qui demande toujours le même temps, quel que soit
l'élément auquel on souhaite accéder. Mais dans une LinkedList, il est coûteux de
se déplacer dans la liste pour rechercher un élément, et cela prend plus de temps pour trouver un
élément qui se situe plus loin dans la liste. Par contre, si on souhaite insérer un élément au
milieu d'une séquence, c'est bien plus efficace dans une LinkedList que dans une
ArrayList. Ces opérations et d'autres ont des efficacités différentes suivant la
structure sous-jacente de la séquence. Dans la phase de conception, on peut débuter avec une
LinkedList et lorsqu'on se penche sur l'optimisation, changer pour une
ArrayList. Grâce à l'abstraction fournie par les itérateurs, on peut passer de
l'une à l'autre avec un impact minime sur le code.
|
 |
 |
 |
In the end, remember that a container is
only a storage cabinet to put objects in. If that cabinet solves all of your
needs, it doesn’t really matter how it is implemented (a basic concept
with most types of objects). If you’re working in a programming
environment that has built-in overhead due to other factors, then the cost
difference between an ArrayList and a LinkedList might not matter.
You might need only one type of sequence. You can even imagine the
“perfect” container abstraction, which can automatically change its
underlying implementation according to the way it is
used.
|
 |
En définitive, un conteneur n'est qu'un espace de stockage où placer des
objets. Si ce conteneur couvre tous nos besoins, son implémentation réelle n'a pas grande
importance (un concept de base pour la plupart des objets). Mais il arrive que la différence de
coûts entre une ArrayList et une LinkedList ne soit pas à
négliger, suivant l'environnement du problème et d'autres facteurs. On peut n'avoir besoin que d'un
seul type de séquence. On peut même imaginer le conteneur « parfait », qui changerait
automatiquement son implémentation selon la manière dont on l'utilise.
|
 |
 |
 |
The singly rooted hierarchy
|
 |
La hiérarchie de classes unique
|
 |
 |
 |
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.
|
 |
L'une des controverses en POO devenue proéminente depuis le C++ demande si
toutes les classes doivent être finalement dérivées d'une classe de base unique. En Java (et comme
dans pratiquement tous les autres langages OO) la réponse est « oui » et le nom de cette
classe de base ultime est tout simplement Object. Les bénéfices d'une hiérarchie
de classes unique sont multiples.
|
 |
 |
 |
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.
|
 |
Tous les objets dans une hiérarchie unique ont une interface commune, ils
sont donc tous du même type fondamental. L'alternative (proposée par le C++) est qu'on ne sait pas
que tout est du même type fondamental. Du point de vue de la compatibilité ascendante, cela épouse
plus le modèle du C et peut se révéler moins restrictif, mais lorsqu'on veut programmer en tout
objet il faut reconstruire sa propre hiérarchie de classes pour bénéficier des mêmes avantages
fournis par défaut par les autres langages OO. Et dans chaque nouvelle bibliothèque de classes
qu'on récupère, une interface différente et incompatible sera utilisée. Cela demande des efforts
(et éventuellement l'utilisation de l'héritage multiple) pour intégrer la nouvelle interface dans
la conception. Est-ce que la « flexibilité » que le C++ fournit en vaut réellement le
coup ? Si on en a besoin - par exemple si on dispose d'un gros investissement en C - alors
oui. Mais si on démarre de zéro, d'autres alternatives telles que Java se révèlent beaucoup plus
productives.
|
 |
 |
 |
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++).
|
 |
Tous les objets dans une hiérarchie de classes unique (comme celle que
propose Java) sont garantis d'avoir certaines fonctionnalités. Un certain nombre d'opérations
élémentaires peuvent être effectuées sur tous les objets du système. Une hiérarchie de classes
unique, accompagnée de la création des objets dans le segment, simplifie considérablement le
passage d'arguments (l'un des sujets les plus complexes en 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.
|
 |
Une hiérarchie de classes unique facilite aussi l'implémentation d'un
ramasse-miettes (qui est fourni en standard en Java). Le support nécessaire est implanté dans la
classe de base, et le ramasse-miettes peut donc envoyer le message idoine à tout objet du système.
Sans une hiérarchie de classe unique et un système permettant de manipuler un objet via une
référence, il est difficile d'implémenter un ramasse-miettes.
|
 |
 |
 |
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.
|
 |
Comme tout objet dispose en lui d'informations dynamiques, on ne peut se
retrouver avec un objet dont on ne peut déterminer le type. Ceci est particulièrement important
avec les opérations du niveau système, telles que le traitement des exceptions, et cela permet une
plus grande flexibilité dans la programmation.
|
 |
 |
 |
Collection libraries and support for easy collection use
|
 |
Bibliothèques de collections et support pour l'utilisation aisée des
collections
|
 |
 |
 |
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.
|
 |
Parce qu'un conteneur est un outil qu'on utilise fréquemment, il est
logique d'avoir une bibliothèque de conteneurs conçus de manière à être réutilisables, afin de
pouvoir en prendre un et l'insérer dans le programme. Java fournit une telle bibliothèque, qui
devrait satisfaire tous les besoins.
|
 |
 |
 |
Downcasting vs. templates/generics
|
 |
Transtypages descendants vs. patrons génériques
|
 |
 |
 |
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.
|
 |
Pour rendre ces conteneurs réutilisables, ils stockent le type universel en
Java précédemment mentionné : Object. La hiérarchie de classe unique implique que
tout est un Object, un conteneur stockant des Objects peut donc
stocker n'importe quoi. Cela rend les conteneurs aisément réutilisables.
|
 |
 |
 |
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?
|
 |
Pour utiliser ces conteneurs, il suffit d'y ajouter des références à des
objets, et les redemander plus tard. Mais comme le conteneur ne stocke que des
Objects, quand une référence à un objet est ajoutée dans le conteneur, il subit un
transtypage ascendant en Object, perdant alors son identité. Quand il est
recherché par la suite, on récupère une référence à un Object, et non une
référence au type qu'on a inséré. Comment le récupérer et retrouver l'interface de l'objet qu'on a
stocké dans le conteneur ?
|
 |
 |
 |
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.
|
 |
On assiste ici aussi à un transtypage, mais cette fois-ci il ne remonte pas
dans la hiérarchie de classe à un type plus général, mais descend dans la hiérarchie jusqu'à un
type plus spécifique, c'est un transtypage descendant ou spécialisation, ou soustypage. Avec la
généralisation, on sait par exemple qu'un Cercle est un type de
Forme, et que le transtypage est donc sans danger ; mais on ne sait pas qu'un
Object est aussi un Cercle ou une Forme, il est
donc rarement sur d'appliquer une spécialisation à moins de savoir exactement à quoi on a
affaire.
|
 |
 |
 |
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.
|
 |
Ce n'est pas trop dangereux cependant, car si une spécialisation est tentée
jusqu'à un type incompatible le système d'exécution générera une erreur appelée exception,
qui sera décrite plus loin. Quand une référence d'objet est rapatriée d'un conteneur, il faut donc
un moyen de se rappeler exactement son type afin de pouvoir le spécialiser correctement.
|
 |
 |
 |
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.
|
 |
La spécialisation et les contrôles à l'exécution génèrent un surcoût de
temps pour le programme, et des efforts supplémentaires de la part du programmeur. Il semblerait
plus logique de créer le conteneur de façon à ce qu'il connaisse le type de l'objet stocké,
éliminant du coup la spécialisation et la possibilité d'erreur. La solution est fournie par les
types paramétrés, qui sont des classes que le compilateur peut personnaliser pour les faire
fonctionner avec des types particuliers. Par exemple, avec un conteneur paramétré, le compilateur
peut personnaliser ce conteneur de façon à ce qu'il n'accepte que des Formes et ne
renvoie que des Formes.
|
 |
 |
 |
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.
|
 |
Les types paramétrés sont importants en C++, en particulier parce que le
C++ ne dispose pas d'une hiérarchie de classe unique. En C++, le mot clef qui implémente les types
paramétrés est « template ». Java ne propose pas actuellement de types paramétrés car
c'est possible de les simuler - bien que difficilement - via la hiérarchie de classes unique. Une
solution de types paramétrés basée sur la syntaxe des templates C++ est actuellement en cours de
proposition.
|
 |
 |
 |
The housekeeping dilemma: who should clean up?
|
 |
Le dilemme du nettoyage : qui en est responsable ?
|
 |
 |
 |
Each object requires resources in order
to exist, most notably memory. When an object is no longer needed it must be
cleaned up so that these resources are released for reuse. In simple programming
situations the question of how an object is cleaned up doesn’t seem too
challenging: you create the object, use it for as long as it’s needed, and
then it should be destroyed. It’s not hard, however, to encounter
situations in which the situation is more complex.
|
 |
Chaque objet requiert des ressources, en particulier de la mémoire. Quand
un objet n'est plus utilisé il doit être nettoyé afin de rendre ces ressources pour les réutiliser.
Dans la programmation de situations simples, la question de savoir comment un objet est libéré
n'est pas trop compliquée : il suffit de créer l'objet, l'utiliser aussi longtemps que désiré,
et ensuite le détruire. Il n'est pas rare par contre de se trouver dans des situations beaucoup
plus complexes.
|
 |
 |
 |
Suppose, for example, you are designing a
system to manage air traffic for an airport. (The same model might also work for
managing crates in a warehouse, or a video rental system, or a kennel for
boarding pets.) At first it seems simple: make a container to hold airplanes,
then create a new airplane and place it in the container for each airplane that
enters the air-traffic-control zone. For cleanup, simply delete the appropriate
airplane object when a plane leaves the zone.
|
 |
Supposons qu'on veuille concevoir un système pour gérer le trafic aérien
d'un aéroport (ou pour gérer des caisses dans un entrepôt, ou un système de location de cassettes,
ou un chenil pour animaux). Cela semble simple de prime abord : créer un conteneur pour
stocker les avions, puis créer un nouvel avion et le placer dans le conteneur pour chaque avion qui
entre dans la zone de contrôle du trafic aérien. Pour le nettoyage, il suffit de détruire l'objet
avion correspondant lorsqu'un avion quitte la zone.
|
 |
 |
 |
But perhaps you have some other system to
record data about the planes; perhaps data that doesn’t require such
immediate attention as the main controller function. Maybe it’s a record
of the flight plans of all the small planes that leave the airport. So you have
a second container of small planes, and whenever you create a plane object you
also put it in this second container if it’s a small plane. Then some
background process performs operations on the objects in this container during
idle moments.
|
 |
Mais supposons qu'une autre partie du système s'occupe d'enregistrer des
informations à propos des avions, ces données ne requérant pas autant d'attention que la fonction
principale de contrôle. Il s'agit peut-être d'enregistrer les plans de vol de tous les petits
avions quittant l'aéroport. On dispose donc d'un second conteneur des petits avions, et quand on
crée un objet avion on doit aussi le stocker dans le deuxième conteneur si c'est un petit avion.
Une tâche de fond s'occupe de traiter les objets de ce conteneur durant les moments d'inactivité du
système.
|
 |
 |
 |
Now the problem is more difficult: how
can you possibly know when to destroy the objects? When you’re done with
the object, some other part of the system might not be. This same problem can
arise in a number of other situations, and in programming systems (such as C++)
in which you must explicitly delete an object when you’re done with it
this can become quite complex.
|
 |
Le problème est maintenant plus compliqué : comment savoir quand détruire
les objets ? Quand on en a fini avec un objet, une autre partie du système peut ne pas en
avoir terminé avec. Ce genre de problème arrive dans un grand nombre de situations, et dans les
systèmes de programmation (comme le C++) où les objets doivent être explicitement détruits cela
peut devenir relativement complexe.
|
 |
 |
 |
With Java, the garbage collector is
designed to take care of the problem of releasing the memory (although this
doesn’t include other aspects of cleaning up an object). The garbage
collector “knows” when an object is no longer in use, and it then
automatically releases the memory for that object. This (combined with the fact
that all objects are inherited from the single root class Object and that
you can create objects only one way, on the heap) makes the process of
programming in Java much simpler than programming in C++. You have far fewer
decisions to make and hurdles to overcome.
|
 |
Avec Java, le ramasse-miettes est conçu pour s'occuper du problème de la
libération de la mémoire (bien que cela n'inclut pas les autres aspects du nettoyage de l'objet).
Le ramasse-miettes « sait » quand un objet n'est plus utilisé, et il libère
automatiquement la mémoire utilisée par cet objet. Ceci (associé avec le fait que tous les objets
sont dérivés de la classe de base fondamentale Object et que les objets sont créés
dans le segment) rend la programmation Java plus simple que la programmation C++. Il y a beaucoup
moins de décisions à prendre et d'obstacles à surmonter.
|
 |
 |
 |
Garbage collectors vs. efficiency and flexibility
|
 |
Ramasse-miettes vs. efficacité et flexibilité
|
 |
 |
 |
If all this is such a good idea, why
didn’t they do the same thing in C++? Well of course there’s a price
you pay for all this programming convenience, and that price is run-time
overhead. As mentioned before, in C++ you can create objects on the stack, and
in this case they’re automatically cleaned up (but you don’t have
the flexibility of creating as many as you want at run-time). Creating objects
on the stack is the most efficient way to allocate storage for objects and to
free that storage. Creating objects on the heap can be much more expensive.
Always inheriting from a base class and making all function calls polymorphic
also exacts a small toll. But the garbage collector is a particular problem
because you never quite know when it’s going to start up or how long it
will take. This means that there’s an inconsistency in the rate of
execution of a Java program, so you can’t use it in certain situations,
such as when the rate of execution of a program is uniformly critical. (These
are generally called real time programs, although not all real time programming
problems are this stringent.)
|
 |
Si cette idée est si bonne, pourquoi le C++ n'intègre-t-il pas ce
mécanisme ? Bien sûr car il y a un prix à payer pour cette facilité de programmation, et ce
surcoût se traduit par du temps système. Comme on l'a vu, en C++ on peut créer des objets dans la
pile et dans ce cas ils sont automatiquement nettoyés (mais dans ce cas on n'a pas la flexibilité
de créer autant d'objets que voulu lors de l'exécution). Créer des objets dans la pile est la façon
la plus efficace d'allouer de l'espace pour des objets et de libérer cet espace. Créer des objets
dans le segment est bien plus coûteux. Hériter de la même classe de base et rendre tous les appels
de fonctions polymorphes prélèvent aussi un tribut. Mais le ramasse-miettes est un problème à part
car on ne sait pas quand il va démarrer ou combien de temps il va prendre. Cela veut dire qu'il y a
une inconsistance dans le temps d'exécution de programmes Java ; on ne peut donc l'utiliser
dans certaines situations, comme celles où le temps d'exécution d'un programme est critique
(appelés programmes en temps réel, bien que tous les problèmes de programmation en temps réel ne
soient pas aussi astreignants).
|
 |
 |
 |
The designers of the C++ language, trying
to woo C programmers (and most successfully, at that), did not want to add any
features to the language that would impact the speed or the use of C++ in any
situation where programmers might otherwise choose C. This goal was realized,
but at the price of greater complexity when programming in C++. Java is simpler
than C++, but the trade-off is in efficiency and sometimes applicability. For a
significant portion of programming problems, however, Java is the superior
choice.
|
 |
Les concepteurs du langage C++, en voulant amadouer les programmeurs C, ne
voulurent pas ajouter de nouvelles fonctionnalités au langage qui puissent impacter la vitesse ou
défavoriser l'utilisation du C++ dans des situations où le C se serait révélé acceptable. Cet
objectif a été atteint, mais au prix d'une plus grande complexité lorsqu'on programme en C++. Java
est plus simple que le C++, mais la contrepartie en est l'efficacité et quelquefois son champ
d'applications. Pour un grand nombre de problèmes de programmation cependant, Java constitue le
meilleur choix.
|
 |
 |
 |
Exception handling: dealing with errors
|
 |
Traitement des exceptions : gérer les erreurs
|
 |
 |
 |
Ever since the beginning of programming
languages, error handling has been one of the most difficult issues. Because
it’s so hard to design a good error handling scheme, many languages simply
ignore the issue, passing the problem on to library designers who come up with
halfway measures that can work in many situations but can easily be
circumvented, generally by just ignoring them. A major problem with most error
handling schemes is that they rely on programmer vigilance in following an
agreed-upon convention that is not enforced by the language. If the programmer
is not vigilant—often the case if they are in a hurry—these schemes
can easily be forgotten.
|
 |
Depuis les débuts des langages de programmation, le traitement des erreurs
s'est révélé l'un des problèmes les plus ardus. Parce qu'il est difficile de concevoir un bon
mécanisme de gestion des erreurs, beaucoup de langages ignorent ce problème et le déléguent aux
concepteurs de bibliothèques qui fournissent des mécanismes qui fonctionnent dans beaucoup de
situations mais peuvent être facilement contournés, généralement en les ignorant. L'une des
faiblesses de la plupart des mécanismes d'erreur est qu'ils reposent sur la vigilance du
programmeur à suivre des conventions non imposées par le langage. Si le programmeur n'est pas assez
vigilant - ce qui est souvent le cas s'il est pressé - ces mécanismes peuvent facilement être
oubliés.
|
 |
 |
 |
Exception handling wires error handling
directly into the programming language and sometimes even the operating system.
An exception is an object that is “thrown” from the site of the
error and can be “caught” by an appropriate exception handler
designed to handle that particular type of error. It’s as if exception
handling is a different, parallel path of execution that can be taken when
things go wrong. And because it uses a separate execution path, it doesn’t
need to interfere with your normally executing code. This makes that code
simpler to write since you aren’t constantly forced to check for errors.
In addition, a thrown exception is unlike an error value that’s returned
from a function or a flag that’s set by a function in order to indicate an
error condition—these can be ignored. An exception cannot be ignored, so
it’s guaranteed to be dealt with at some point. Finally, exceptions
provide a way to reliably recover from a bad situation. Instead of just exiting
you are often able to set things right and restore the execution of a program,
which produces much more robust programs.
|
 |
Le système des exceptions pour gérer les erreurs se situe au niveau du
langage de programmation et parfois même au niveau du système d'exploitation. Une exception est un
objet qui est « émis » depuis l'endroit où l'erreur est apparue et peut être intercepté
par un gestionnaire d'exception conçu pour gérer ce type particulier d'erreur. C'est comme si la
gestion des exceptions était un chemin d'exécution parallèle à suivre quand les choses se gâtent.
Et parce qu'elle utilise un chemin d'exécution séparé, elle n'interfère pas avec le code
s'exécutant normalement. Cela rend le code plus simple à écrire car on n'a pas à vérifier
constamment si des erreurs sont survenues. De plus, une exception émise n'est pas comme une valeur
de retour d'une fonction signalant une erreur ou un drapeau positionné par une fonction pour
indiquer une erreur - ils peuvent être ignorés. Une exception ne peut pas être ignorée, on a donc
l'assurance qu'elle sera traitée quelque part. Enfin, les exceptions permettent de revenir d'une
mauvaise situation assez facilement. Plutôt que terminer un programme, il est souvent possible de
remettre les choses en place et de restaurer son exécution, ce qui produit des programmes plus
robustes.
|
 |
 |
 |
Java’s exception handling stands
out among programming languages, because in Java, exception handling was wired
in from the beginning and you’re forced to use it. If you don’t
write your code to properly handle exceptions, you’ll get a compile-time
error message. This guaranteed consistency makes error handling much
easier.
|
 |
Le traitement des exceptions de Java se distingue parmi les langages de
programmes, car en Java le traitement des exceptions a été intégré depuis le début et on est forcé
de l'utiliser. Si le code produit ne gère pas correctement les exceptions, le compilateur générera
des messages d'erreur. Cette consistance rend la gestion des erreurs bien plus aisée.
|
 |
 |
 |
It’s worth noting that exception
handling isn’t an object-oriented feature, although in object-oriented
languages the exception is normally represented with an object. Exception
handling existed before object-oriented
languages.
|
 |
Il est bon de noter que le traitement des exceptions n'est pas une
caractéristique orientée objet, bien que dans les langages OO une exception soit normalement
représentée par un objet. Le traitement des exceptions existait avant les langages orientés
objet.
|
 |
 |
 |
Multithreading
|
 |
Multithreading
|
 |
 |
 |
A fundamental concept in computer
programming is the idea of handling more than one task at a time. Many
programming problems require that the program be able to stop what it’s
doing, deal with some other problem, and then return to the main process. The
solution has been approached in many ways. Initially, programmers with low-level
knowledge of the machine wrote interrupt service routines and the suspension of
the main process was initiated through a hardware interrupt. Although this
worked well, it was difficult and nonportable, so it made moving a program to a
new type of machine slow and expensive.
|
 |
L'un des concepts fondamentaux dans la programmation des ordinateurs est
l'idée de traiter plus d'une tâche à la fois. Beaucoup de problèmes requièrent que le programme
soit capable de stopper ce qu'il est en train de faire, traite un autre problème puis retourne à sa
tâche principale. Le problème a été abordé de beaucoup de manières différentes. Au début, les
programmeurs ayant des connaissances sur le fonctionnement de bas niveau de la machine écrivaient
des routines d'interruption de service et l'interruption de la tâche principale était initiée par
une interruption matérielle. Bien que cela fonctionne correctement, c'était difficile et non
portable, et cela rendait le portage d'un programme sur un nouveau type de machine lent et
cher.
|
 |
 |
 |
Sometimes interrupts are necessary for
handling time-critical tasks, but there’s a large class of problems in
which you’re simply trying to partition the problem into separately
running pieces so that the whole program can be more responsive. Within a
program, these separately running pieces are called threads, and the general
concept is called multithreading. A common example of multithreading is
the user interface. By using threads, a user can press a button and get a quick
response rather than being forced to wait until the program finishes its current
task.
|
 |
Quelquefois les interruptions sont nécessaires pour gérer les tâches
critiques, mais il existe une large classe de problèmes dans lesquels on tente juste de
partitionner le problème en parties séparées et indépendantes afin que le programme soit plus
réactif. Dans un programme, ces parties séparées sont appelés threads et le concept général est
appelé multithreading. Un exemple classique de multithreading est l'interface utilisateur.
En utilisant les threads, un utilisateur peur appuyer sur un bouton et obtenir une réponse plus
rapide que s'il devait attendre que le programme termine sa tâche courante.
|
 |
 |
 |
Ordinarily, threads are just a way to
allocate the time of a single processor. But if the operating system supports
multiple processors, each thread can be assigned to a different processor and
they can truly run in parallel. One of the convenient features of multithreading
at the language level is that the programmer doesn’t need to worry about
whether there are many processors or just one. The program is logically divided
into threads and if the machine has more than one processor then the program
runs faster, without any special adjustments.
|
 |
Généralement, les threads sont juste une façon d'allouer le temps d'un seul
processeur. Mais si le système d'exploitation supporte les multi-processeurs, chaque thread peut
être assigné à un processeur différent et ils peuvent réellement s'exécuter en parallèle. L'une des
caractéristiques intéressantes du multithreading au niveau du langage est que le programmeur n'a
pas besoin de se préoccuper du nombre de processeurs. Le programme est divisé logiquement en
threads et si la machine dispose de plusieurs processeurs, le programme tourne plus vite, sans
aucun ajustement.
|
 |
 |
 |
All this makes threading sound pretty
simple. There is a catch: shared resources. If you have more than one thread
running that’s expecting to access the same resource you have a problem.
For example, two processes can’t simultaneously send information to a
printer. To solve the problem, resources that can be shared, such as the
printer, must be locked while they are being used. So a thread locks a resource,
completes its task, and then releases the lock so that someone else can use the
resource.
|
 |
Tout ceci pourrait faire croire que le multithreading est simple. Il y a
toutefois un point d'achoppement : les ressources partagées. Un problème se pose si plus d'un
thread s'exécutant veulent accéder à la même ressource. Par exemple, deux tâches ne peuvent envoyer
simultanément de l'information à une imprimante. Pour résoudre ce problème, les ressources pouvant
être partagées, comme l'imprimante, doivent être verrouillées avant d'être utilisées. Un thread
verrouille donc une ressource, accomplit ce qu'il a à faire, et ensuite relâche le verrou posé afin
que quelqu'un d'autre puisse utiliser cette ressource.
|
 |
 |
 |
 |
 |
 |
 |
 |
|
 |
 |
 |