Sommario
8
Ereditarietà ................................................................................................................................... 4
8.1
Un esempio per imparare ...................................................................................................... 4
8.2
Ereditarietà gerarchica ........................................................................................................... 5
Ereditarietà e regole di accessibilità............................................................................................. 6
Ereditarietà e inizializzazione degli oggetti ................................................................................. 7
8.3
Aggiungere un elemento alla gerarchia ................................................................................. 9
8.4
Vantaggi dell'ereditarietà ..................................................................................................... 10
8.5
Sottotipi ............................................................................................................................... 11
Sottotipi e assegnamenti............................................................................................................. 12
Sottotipi e passaggio dei parametri ............................................................................................ 13
Casting ....................................................................................................................................... 14
La classe Object................................................................................................................... 15
8.7
Autoboxing e classi wrapper ............................................................................................... 16
8.8
Per ripassare ........................................................................................................................ 17
9
8.6
Approfondimenti sull'ereditarietà .............................................................................................. 18
9.1
The problem: network’s display method ............................................................................. 18
9.2
Static type vs dynamic type ................................................................................................. 18
9.3
Overriding ........................................................................................................................... 20
9.4
Dynamic method lookup (late binding)............................................................................... 21
9.5
Super Call in methods ......................................................................................................... 21
9.6
Method polymorphism ........................................................................................................ 21
9.7
Object methods: toString ..................................................................................................... 21
9.8
Object equality: equals and hashCode................................................................................. 21
9.9
Java visibility modifiers ...................................................................................................... 22
Protected access ......................................................................................................................... 22
Controlling Access to Members of a Class ................................................................................ 22
9.10
Access Control and Inheritance: ...................................................................................... 23
9.11
The instanceof operator ................................................................................................... 24
9.12
Per ripassare ..................................................................................................................... 24
10
Classi astratte e interfacce .......................................................................................................... 24
11
Object as a Superclass ................................................................................................................ 25
11.1
Clonazione di oggetti ....................................................................................................... 26
Non tutti gli oggetti sono clonabili ............................................................................................ 26
The clone() Method .................................................................................................................... 26
Copia superficiale: un primo esempio ....................................................................................... 27
Clonazione superficiale in classi derivate .............................................................................. 27
Copia superficiale e profonda: differenze .................................................................................. 27
Esempio: Classe Segmento .................................................................................................... 28
Copia superficiale .................................................................................................................. 29
Copia profonda: significato .................................................................................................... 29
Copia profonda: realizzazione ............................................................................................... 30
11.2
Uguaglianza tra oggetti .................................................................................................... 31
Uguaglianza superficiale ............................................................................................................ 31
Uguaglianza profonda ................................................................................................................ 32
11.3
The finalize() Method ...................................................................................................... 32
11.4
The getClass() Method .................................................................................................... 33
11.5
The hashCode() Method .................................................................................................. 33
11.6
The toString() Method ..................................................................................................... 33
11.7
Confronto tra oggetti........................................................................................................ 34
L'interfaccia java.lang.Comparable ......................................................................... 34
Ordinamento di Array con java.util.Arrays.sort() ...................................................................... 37
Ordinamento di List con java.util.Collections ........................................................................... 38
Collections vs Collection ........................................................................................................... 39
Ordinamento mediante l'interfaccia java.util.Comparator ......................................................... 40
11.8
Classi Nested ................................................................................................................... 43
Osservazioni ........................................................................................................................... 43
Convertire un ArrayList in un Array ............................................................................... 48
11.10
Convertire ArrayList in Array ......................................................................................... 49
12
11.9
Interfacce Grafiche (GUI) .......................................................................................................... 49
12.1
Elementi di un'interfaccia grafica .................................................................................... 49
12.2
AWT e Swing .................................................................................................................. 50
12.3
La prima applicazione grafica ......................................................................................... 50
Aggiunta di menu ....................................................................................................................... 51
Gestione degli eventi .................................................................................................................. 52
Osservazione importante: meglio avere listeners distinti per oggetti distinti ........................ 54
Inner classes (rivisitate) ............................................................................................................. 54
Anonymous inner classes ........................................................................................................... 56
12.4
Un programma per la visualizzazione e modifica delle immagini: prima versione ........ 58
12.5
Layouts ............................................................................................................................ 62
BorderLayout ......................................................................................................................... 63
FlowLayout ............................................................................................................................ 63
GridLayout ............................................................................................................................. 64
BoxLayout .............................................................................................................................. 64
Nested Containers ...................................................................................................................... 65
12.6
Creazione di un'interfaccia grafica con NetBeans ........................................................... 66
Esercizio 1: Il “gioco del 15”. .................................................................................................... 67
Versione con numeri .............................................................................................................. 67
Versione con immagini “puzzlefy” ........................................................................................ 67
Esercizio 2: Emulare la calcolatrice standard di Windows ........................................................ 67
13
Gestione delle eccezioni (rivisitate) ........................................................................................... 69
Approfondimenti.............................................................................................................. 69
13.2
Logging delle eccezioni e di situazioni specifiche: java.util.logging package ................ 69
14
13.1
Gestione dei file in Java ............................................................................................................. 69
java.io.File ....................................................................................................................... 69
14.2
java.util.Formatter e java.util.Scanner; ............................................................................ 70
14.3
Scrivere su file di testo con PrintWriter e BufferedWriter una riga alla volta ................ 73
14.4
Leggere da file di testo una riga alla volta con BufferedReader ..................................... 74
14.5
Un esempio di lettura da file CSV ................................................................................... 74
14.6
Un esempio di scrittura su file CSV ................................................................................ 75
14.7
Un esempio di uso di PrintWriter e BufferedReader ....................................................... 76
14.8
Serializzazione di oggetti ................................................................................................. 77
14.9
Progetto di una rubrica di contatti ................................................................................... 78
15
14.1
Riferimenti per Java ................................................................................................................... 78
In queste note si seguirà l'approccio del testo Objects First with Java i cui esempi (utilizzati in queste
note) sono liberamente scaricabili al link http://www.bluej.org/objects-first/resources/projects.zip .
8 Ereditarietà
8.1 Un esempio per imparare
Apriamo il progetto network-v1: esploriamo il codice e poi proviamo a creare alcuni oggetti.
Esercizio: discutere il codice e trovare eventuali problemi di progettazione.
Il problema fondamentale è che le classi MessagePost e PhotoPost condividono molto codice comune.
E se la nostra applicazione chiedesse di fare anche un ActivityPost (qualcosa che ci aggiorna sui
nostri contatti...qualcosa del tipo “tizio è ora amico di...”
Per risolvere il problema della duplicazione del codice possiamo utilizzare il concetto di ereditarietà:
creiamo una classe Post che contiene gli attributi e i metodi comuni di tutti i post e poi deriviamo il
MessagePost e il PhotoPost come classi che estendono la classe Post.
“The purpose of using inheritance is now fairly obvious. Instances of class MessagePost will have
all fields defined in class MessagePost and in class Post. (MessagePost inherits the fields from
Post.) Instances of PhotoPost will have all fields defined in PhotoPost and in Post. Thus, we
achieve the same as before, but we need to define the fields username, timestamp, likes, and
comments only once, while being able to use them in two different places).
The same holds true for methods: instances of subclasses have all methods defined in both the
superclass and the subclass. In general, we can say: because a message post is a post, a message-post
object has everything that a post has, and more. And because a photo post is also a post, it has
everything that a post has, and more. Thus, inheritance allows us to create two classes that are quite
similar, while avoiding the need to write the identical part twice. Inheritance has a number of other
advantages, which we discuss below. First, however, we will take another, more general look at
inheritance hierarchies.
”
8.2 Ereditarietà gerarchica
The principle is simple: inheritance is an abstraction technique that lets us categorize classes of
objects under certain criteria and helps us specify the characteristics of these classes.
public class Post
{
private String username; // username of the post’s author
private long timestamp;
private int likes;
private ArrayList<String> comments;
}
// Constructors and methods omitted.
public class MessagePost extends Post
{
private String message;
}
// Constructors and methods omitted.
public class PhotoPost extends Post
{
private String filename;
private String caption;
}
// Constructors and methods omitted.
Ereditarietà e regole di accessibilità
Members defined as public in either the superclass or subclass portions will be accessible to objects
of other classes, but members defined as private will be inaccessible. In fact, the rule on privacy
also applies between a subclass and its superclass: a subclass cannot access private members of its
superclass. It follows that if a subclass method needed to access or change private fields in its
superclass, then the superclass would need to provide appropriate accessor and/or mutator methods.
However, an object of a subclass may call any public methods defined in its superclass as if they were
defined locally in the subclass—no variable is needed, because the methods are all part of the same
object.
Ereditarietà e inizializzazione degli oggetti
public class Post
{
private String username; // username of the post’s author
private
long timestamp;
private int likes;
private ArrayList<String> comments;
/**
* Constructor for objects of class Post.
*
* @param author
The username of the author of this post.
*/
}
public
Post(String author)
{
}
username = author;
timestamp = System.currentTimeMillis();
likes = 0;
comments = new ArrayList<String>();
// Methods omitted.
public class MessagePost extends Post
{
private String message; // an arbitrarily long, multi-line message
/**
* Constructor for objects of class MessagePost.
*
* @param author
* @param text
*/
The username of the author of this post.
The text of this post.
}
public
MessagePost(String author, String text)
{
super(author);
message = text;
}
// Methods omitted.
First, the class Post has a constructor, even though we do not intend to create an instance of class
Post directly.
This constructor receives the parameters needed to initialize the Post fields, and it contains the code
to do this initialization.
Second, the MessagePost constructor receives parameters needed to initialize both Post and
MessagePost fields. It then contains the following line of code:
super(author);
The keyword super is a call from the subclass constructor to the constructor of the superclass. Its
effect is that the Post constructor is executed as part of the MessagePost constructor’s execution.
When we create a message post, the MessagePost constructor is called, which, in turn, as its first
statement, calls the Post constructor. The Post constructor initializes the post’s fields, and then
returns to the MessagePost constructor, which initializes the remaining field defined in the
MessagePost class. For this to work, those parameters needed for the initialization of the post fields
are passed on to the superclass constructor as parameters to the super call.
In Java, a subclass constructor must always call the superclass constructor as its first statement. If
you do not write a call to a superclass constructor, the Java compiler will insert a superclass call
automatically, to ensure that the superclass fields get properly initialized. The inserted call is
equivalent to writing
super();
Inserting this call automatically works only if the superclass has a constructor without parameters
(because the compiler cannot guess what parameter values should be passed). Otherwise, an error
will be reported. In general, it is a good idea to always include explicit superclass calls in your
constructors, even if it is one that the compiler could generate automatically. We consider this good
style, because it avoids the possibility of misinterpretation and confusion in case a reader is not aware
of the automatic code generation.
8.3 Aggiungere un elemento alla gerarchia
Aggiungere la classe EventPost con il campo eventType di tipo enumerativo.
E se volessimo i commenti solo per i messaggi e le foto, ma non per gli eventi:
Il progetto BlueJ con le modifiche dell'esercizio 8.8 diventa network-v2-modified:
8.4 Vantaggi dell'ereditarietà
Avoiding code duplication The use of inheritance avoids the need to write identical or very similar
copies of code twice (or even more often).
Code reuse Existing code can be reused. If a class similar to the one we need already exists, we can
sometimes subclass the existing class and reuse some of the existing code rather than having to
implement everything again.
Easier maintenance Maintaining the application becomes easier, because the relationship between
the classes is clearly expressed. A change to a field or a method that is shared between different types
of subclasses needs to be made only once.
Extendibility Using inheritance, it becomes much easier to extend an existing application in certain
ways.
8.5 Sottotipi
Confrontiamo la classe NewsFeed del progetto network-v2 con la classe NewsFeed del progetto
network-v1. Nella versione con ereditarietà il codice è molto più semplice perché abbiamo solo il tipo
Post e possiamo scrivere metodi che aggiungono un post oppure mostrano il contenuto di un post,
senza specificare se si tratta di MessagePost o di PhotoPost.
public void addPost(Post post)
{
posts.add(post);
}
/**
* Show the news feed. Currently: print the news feed details
* to the terminal. (To do: replace this later with display
* in web browser.)
*/
public void show()
{
// display all posts
for(Post post : posts) {
post.display();
System.out.println();
// empty line between posts
}
}
In our first version, we had two methods to add posts to the news feed. They had the following headers:
public void addMessagePost(MessagePost message)
public void addPhotoPost(PhotoPost photo)
In our new version, we have a single method to serve the same purpose:
public void addPost(Post post)
So far, we have interpreted the requirement that parameter types must match as meaning “must be of
the same type”—for instance, that the type name of an actual parameter must be the same as the type
name of the corresponding formal parameter.
This is only part of the truth, in fact, because an object of a subclass can be used wherever its
superclass type is required.
Sottotipi e assegnamenti
Imagine that we have a class Vehicle with two subclasses, Car and Bicycle (Figure 8.9). In this case, the typing rule
admits that the following assignments are all legal:
Vehicle v1 = new Vehicle();
Vehicle v2 = new Car();
Vehicle v3 = new Bicycle();
Because a car is a vehicle, it is perfectly legal to store a car in a variable that is intended for
vehicles
This principle is known as substitution. In object-oriented languages, we can
substitute a subclass object where a superclass object is expected, because the
subclass object is a special case of the superclass. If, for example, someone asks us to give
them a pen, we can fulfill the request perfectly well by giving them a fountain pen or a ballpoint pen.
Both fountain pen and ballpoint pen are subclasses of pen, so supplying either where an object of
class
However, doing it the other way is not allowed:
Car c1 = new Vehicle(); // this is an error!
This statement attempts to store a Vehicle object in a Car and an error will be reported if you try to
compile this statement. A vehicle, on the other hand, may or may not be a car—we do not know.
Thus, the statement may be wrong and is not allowed.
Similarly:
Car c2 = new Bicycle(); // this is an error!
This is also an illegal statement. A bicycle is not a car
Sottotipi e passaggio dei parametri
public class NewsFeed
{
public void addPost(Post post)
{
. . .
}
}
We can now use this method to add message posts and photo posts to the feed:
NewsFeed feed = new NewsFeed();
MessagePost message = new MessagePost()
PhotoPost photo = new PhotoPost(...);
feed.addPost(message);
feed.addPost(photo);
Because of subtyping rules, we need only one method (with a parameter of type both MessagePost
and PhotoPost objects.
Casting
Sometimes the rule that we cannot assign from a supertype to a subtype is more restrictive than
necessary. If we know that the supertype variable holds a subtype object, the assignment could
actually be allowed. For example:
Vehicle v;
Car c = new Car();
v = c; // correct
c = v; // error
The above statements would not compile: we get a compiler error in the last line, because assigning
a Vehicle variable to a Car variable (supertype to subtype) is not allowed. However, if we execute
these statements in sequence, we know that we could actually allow this assignment. We can see that
the variable v actually contains an object of type Car, so the assignment to c would be okay. The
compiler is not that smart. It translates the code line by line, so it looks at the last line in isolation
without knowing what is currently stored in variable v. This is called type loss. The type of the object
in v is actually Car, but the compiler does not know this.
We can get around this problem by explicitly telling the type system that the variable v holds a Car
object. We do this using a cast operator:
c = (Car) v; // okay
The cast operator consists of the name of a type (here, Car) written in parentheses in front of a variable
or an expression. Doing this will cause the compiler to believe that the object is a Car, and it will not
report an error.
At runtime, however, the Java system will check that it really is a Car. If we were careful, and it is
truly is a Car, everything is fine. If the object in v is of another type, the runtime system will indicate
an error (called a ClassCastException), and the program will stop.
Now consider this code fragment, in which Bicycle is also a subclass of Vehicle:
Vehicle v;
Car c;
Bicycle b;
c = new Car();
v = c; // okay
b = (Bicycle) c; // compile time error!
b = (Bicycle) v; // runtime error!
The last two assignments will both fail. The attempt to assign c to b (even with the cast) will be a
compile-time error. The compiler notices that Car and Bicycle do not form a subtype/supertype
relationship, so c can never hold a Bicycle object—the assignment could never work. The attempt
to assign v to b (with the cast) will be accepted at compile time but will fail at runtime. Vehicle is a
superclass of Bicycle, and thus v can potentially hold a Bicycle object.
At runtime, however, it turns out that the object in v is not a Bicycle but a Car, and the program will
terminate prematurely.
Casting should be avoided wherever possible, because it can lead to runtime errors, and that is
clearly something we do not want. The compiler cannot help us to ensure correctness in this case. In
practice, casting is very rarely needed in a well-structured object-oriented program. In almost all
cases, when you use a cast in your code, you could restructure your code to avoid this cast and
end up with a better-designed program. This usually involves replacing the cast with a
polymorphic method call (more about this in the next chapter).
8.6 La classe Object
All classes have a superclass. So far, it has appeared as if most classes we have seen do not have a
superclass. In fact, while we can declare an explicit superclass for a class, all classes that have no
superclass declaration implicitly inherit from a class called Object.
Object is a class from the Java standard library that serves as a superclass for all objects.
Writing a class declaration such as
public class Person
{
...
}
is equivalent to writing
public class Person extends Object
{
...
}
The Java compiler automatically inserts the Object superclass for all classes without an explicit
extends declaration, so it is never necessary to do this for yourself. Every single class (with the sole
exception of the Object class itself) inherits from Object, either directly or indirectly.
The following figure shows some randomly chosen classes to illustrate this.
8.7 Autoboxing e classi wrapper
We have seen that, with suitable parameterization, the collection classes can store objects of any
object type. There remains one problem: Java has some types that are not object types. As we know,
the simple types—such as int, boolean, and char—are separate from object types. Their values are
not instances of classes, and they do not inherit from the Object class.
Because of this, they are not subtypes of Object, and it would not normally be possible to add them
into a collection.
This is unfortunate. There are situations in which we might want to create a list of int values or a set
of char values, for instance. What can we do? Java’s solution to this problem is wrapper classes.
Every primitive type in Java has a corresponding wrapper class that represents the same type but is a
real object type. The wrapper class for int, for example, is called Integer.
The following statement explicitly wraps the value of the primitive int variable ix in an Integer
object:
Integer iwrap = new Integer(ix);
And now iwrap could obviously easily be stored in an ArrayList<Integer> collection, for instance.
However, storing of primitive values into an object collection is made even easier through a compiler
feature known as autoboxing.
Whenever a value of a primitive type is used in a context that requires a wrapper type, the compiler
automatically wraps the primitive-type value in an appropriate wrapper object. This means that
primitive-type values can be added directly to a collection:
private ArrayList<Integer> markList;
...
public void storeMarkInList(int mark)
{
markList.add(mark);
}
The reverse operation—unboxing—is also performed automatically, so retrieval from a collection
might look like this:
int firstMark = markList.remove(0);
Autoboxing is also applied whenever a primitive-type value is passed as a parameter to a method that
expects a wrapper type and when a primitive-type value is stored in a wrapper-type variable. Similarly,
unboxing is applied when a wrapper-type value is passed as a parameter to a method that expects a
primitive-type value and when stored in a primitive-type variable.
It is worth noting that this almost makes it appear as if primitive types can be stored in collections.
However, the type of the collection must still be declared using the wrapper type (e.g.,
ArrayList<Integer>, not ArrayList<int>).
Esercizio:
8.8 Per ripassare
9 Approfondimenti sull'ereditarietà
9.1 The problem: network’s display method
Vedere il libro
9.2 Static type vs dynamic type
Prendiamo il progetto network-v2 e osserviamo il comportamento del metodo display
Cosa succede se Post non ha il metodo display e nella classe NewsFeed si richiama il metodo
/**
* Show the news feed. Currently: print the news feed details
* to the terminal. (To do: replace this later with display
* in web browser.)
*/
public void show()
{
// display all posts
for(Post post : posts) {
post.display();
System.out.println();
// empty line between posts
}
}
Quale metodo display è invocato nel ciclo for-each?
We know that every Post object in the collection is in fact a MessagePost or a PhotoPost object,
and both have display methods. This should mean that post.display() ought to work, because,
whatever it is— MessagePost or PhotoPost—we know that it does have a display method.
Consider the following statement:
Vehicle v1 = new Car();
What is the type of v1? That depends on what precisely we mean by “type of v1.” The type of the
variable v1 is Vehicle; the type of the object stored in v1 is Car. Through subtyping and substitution
rules, we now have situations where the type of the variable and the type of the object stored in it are
not exactly the same.
Let us introduce some terminology to make it easier to talk about this issue:
We call the declared type of the variable the static type, because it is declared in the source code—
the static representation of the program.
We call the type of the object stored in a variable the dynamic type, because it depends on assignments
at runtime—the dynamic behavior of the program.
Thus, looking at the explanations above, we can be more precise: the static type of v1 is Vehicle, the
dynamic type of v1 is Car. We can now also rephrase our discussion about the call to the post’s
display method in the NewsFeed class. At the time of the call
post.display();
the static type of post is Post, while the dynamic type is either MessagePost or PhotoPost. We
do not know which one of these it is, assuming that we have entered both
MessagePost and PhotoPost objects into the feed.
9.3 Overriding
Il progetto network-v3 fornisce un'implementazione delle classi secondo quanto descritto
nell'esercizio 9.2
The technique we are using here is called overriding (sometimes it is also referred to as redefinition).
Overriding is a situation where a method is defined in a superclass (method display in class Post in
this example), and a method with exactly the same signature is defined in the subclass.
In this situation, objects of the subclass have two methods with the same name and header: one
inherited from the superclass and one from the subclass. Which one will be executed when we call
this method?
9.4 Dynamic method lookup (late binding)
Vedere §9.4 del libro.
9.5 Super Call in methods
Vedere §9.5 del libro.
9.6 Method polymorphism
Vedere §9.6 del libro.
9.7 Object methods: toString
Vedere §9.7 del libro.
9.8 Object equality: equals and hashCode
Esercizio: Creare due oggetti
Track t1 = new Track(“artista”, “titolo canzone 1”, “file name 1”);
Track t2 = new Track(“artista”, “titolo canzone 1”, “file name 1”);
e verificare se il metodo equals restituisce vero o falso.
t1.equals(t2)
Ridefinire il metodo equals() nella classe Track in modo che verifichi se i campi (variabili
d'istanza) siano a loro volta uguali.
t1.equals(t2)
Richiamare il metodo hashCode sugli oggetti t1 e t2 e commentare il risultato ottenuto.
t1.hashCode()
Eseguire le istruzioni
System.out.println(t1);
System.out.println(t2);
commentare il risultato
Ridefinire il metodo toString della classe Track in modo che presenti una descrizione completa
di una traccia e rieseguire le istruzioni:
System.out.println(t1);
System.out.println(t2);
9.9 Java visibility modifiers
http://docs.oracle.com/javase/tutorial/java/javaOO/accesscontrol.html
http://www.tutorialspoint.com/java/java_access_modifiers.htm
Protected access
Vedere §9.9 del libro.
Controlling Access to Members of a Class
Access level modifiers determine whether other classes can use a particular field or invoke a
particular method. There are two levels of access control:
 At the top level—public, or package-private (no explicit modifier).
 At the member level—public, private, protected, or package-private (no explicit
modifier).
A class may be declared with the modifier public, in which case that class is visible to all classes
everywhere. If a class has no modifier (the default, also known as package-private), it is visible
only within its own package (packages are named groups of related classes — you will learn
about them in a later lesson.)
At the member level, you can also use the public modifier or no modifier (package-private) just
as with top-level classes, and with the same meaning. For members, there are two additional
access modifiers: private and protected. The private modifier specifies that the member can only
be accessed in its own class. The protected modifier specifies that the member can only be
accessed within its own package (as with package-private) and, in addition, by a subclass of its
class in another package.
The following table shows the access to members permitted by each modifier.
Access Levels
Modifier
Class Package Subclass World
public
Y
Y
Y
Y
protected Y
Y
Y
N
no modifier Y
Y
N
N
private
Y
N
N
N
The first data column indicates whether the class itself has access to the member defined by the
access level. As you can see, a class always has access to its own members. The second column
indicates whether classes in the same package as the class (regardless of their parentage) have
access to the member. The third column indicates whether subclasses of the class declared outside
this package have access to the member. The fourth column indicates whether all classes have
access to the member.
Access levels affect you in two ways. First, when you use classes that come from another source,
such as the classes in the Java platform, access levels determine which members of those classes
your own classes can use. Second, when you write a class, you need to decide what access level
every member variable and every method in your class should have.
Let's look at a collection of classes and see how access levels affect visibility. The following
figure shows the four classes in this example and how they are related.
Classes and Packages of the Example Used to Illustrate Access
Levels
The following table shows where the members of the Alpha class are visible for each of the access
modifiers that can be applied to them.
Visibility
Modifier
public
protected
no modifier
private
Alpha
Y
Y
Y
Y
Beta
Y
Y
Y
N
Alphasub
Y
Y
N
N
Gamma
Y
N
N
N
Tips on Choosing an Access Level:
If other programmers use your class, you want to ensure that errors from misuse cannot
happen. Access levels can help you do this.
 Use the most restrictive access level that makes sense for a particular member.
Use private unless you have a good reason not to.
 Avoid public fields except for constants. (Many of the examples in the tutorial
use public fields. This may help to illustrate some points concisely, but is not
recommended for production code.) Public fields tend to link you to a particular
implementation and limit your flexibility in changing your code.
9.10 Access Control and Inheritance:
http://www.tutorialspoint.com/java/java_access_modifiers.htm
The following rules for inherited methods are enforced:
Methods declared public in a superclass also must be public in all subclasses.

Methods declared protected in a superclass must either be protected or public in
subclasses; they cannot be private.

Methods declared without access control (no modifier was used) can be declared more
private in subclasses.

Methods declared private are not inherited at all, so there is no rule for them.
9.11 The instanceof operator
Vedere §9.10 del libro
Con riferimento al progetto network-v2 estendere la classe NewsFeed introducendo la classe
ElaboratedNewsFeed che introduce il metodo showMessage che stampa solo i MessagePost e
showPhoto che stampa solo i PhotoPost.
9.12 Per ripassare
10 Classi astratte e interfacce
1. Vedere le slide su classi astratte e interfacce
2. Vedere gli esempi tratti da “Java How to Program”
3. Svolgere il seguente esercizio:
Esercizio:
In riferimento al diagramma UML allegato costruire la seguente gerarchia di classi secondo la
descrizione seguente:
 La prima classe descrive un lavoratore generico (Lavoratore). Nello specifico il lavoratore
possiede la proprietà matricola, la proprietà cognome, la proprietà nome Inoltre, un lavoratore
per essere tale deve implementare un metodo per il calcolo dello stipendio mensile.
 La seconda classe descrive un lavoratore a progetto (Contrattista). Nello specifico il
lavoratore a progetto è un lavoratore, per cui possiede tutte le caratteristiche della classe
Lavoratore e possiede la proprietà oreMensili, che indica il numero di ore lavorate e la
proprietà euroOra, che indica la tariffa oraria del lavoratore a progetto. Inoltre, come richiesto
dalla superclasse Lavoratore, la classe Contrattista implementa il metodo per il calcolo dello
stipendio.
 La
terza
classe
descrive
un
lavoratore
a
tempo
indererminato
(LavoratoreTempoIndeterminato).Nello specifico lavoratore a tempo indeterminato è un

lavoratore, per cui possiede tutte le caratteristiche della classe Lavoratore e possiede la
proprietà mensilita, che indica il numero di mensilità del lavoratore a tempo indeterminato,e
la proprietà lordoAnnuo, che indica la cifra annua che il lavoratore a tempo indeterminato
riceve.
Inoltre,come
richiesto
dalla
superclasse
Lavoratore,
la
classe
LavoratoreTempoIndeterminato implementa il metodo per il calcolo dello stipendio.
La quarta classe descrive un direttore che si occupa dei pagamenti dei propri
lavoratori(Direttore). Un direttore è un lavoratore a tempo indeterminato che in più percepisce
un bonus mensile per il raggiungimento degli obiettivi aziendali. Dipendentemente dal tipo di
lavoratore, il direttore calcola lo stipendio
11 Object as a Superclass
Tratto da https://docs.oracle.com/javase/tutorial/java/IandI/objectclass.html
The Object class, in the java.lang package, sits at the top of the class hierarchy tree. Every class is a
descendant, direct or indirect, of the Object class. Every class you use or write inherits the instance methods
of Object. You need not use any of these methods, but, if you choose to do so, you may need to override them
with code that is specific to your class. The methods inherited from Object that are discussed in this section are:

protected Object clone() throws CloneNotSupportedException
Creates and returns a copy of this object.

public boolean equals(Object obj)
Indicates whether some other object is "equal to" this one.

protected void finalize() throws Throwable
Called by the garbage collector on an object when garbage
collection determines that there are no more references to the object

public final Class getClass()
Returns the runtime class of an object.

public int hashCode()
Returns a hash code value for the object.

public String toString()
Returns a string representation of the object.
11.1 Clonazione di oggetti
Clonare un oggetto vuol dire creare una “copia” di un oggetto
http://www.dis.uniroma1.it/~liberato/laboratorio/clone/clone.html
Non tutti gli oggetti sono clonabili
Non tutti gli oggetti sono clonabili:
String a, b;
a=new String("abcd");
b=(String) a.clone(); // errore
Le stringhe non si clonano in quanto sono oggetti immutabili. Per creare una stringa che sia la copia di
un'altra basta usare il copy constructor:
a=new String("abcd");
b=String(a); // crea una nuova istanza della stringa con gli stessi
caratteri di a
Per le stringhe si può fare la copia in modo più efficiente sfruttando il fatto che si tratta di oggetti immutabili:
a=new String("abcd");
String b = a;
In questo caso non c'è nessun problema a fare la copia passando il riferimento allo stesso oggetto dal momento
che una volta creata una stringa non può più essere modificata.
The clone() Method
If a class, or one of its superclasses, implements the Cloneable interface, you can use the clone() method to
create a copy from an existing object. To create a clone, you write:
aCloneableObject.clone();
Object's implementation of this method checks to see whether the object on which clone() was invoked
implements
the Cloneable interface.
If
the
object
does
not,
the
method
throws
a CloneNotSupportedException exception. Exception handling will be covered in a later lesson. For the
moment, you need to know that clone() must be declared as
protected Object clone() throws CloneNotSupportedException
or:
public Object clone() throws CloneNotSupportedException
if you are going to write a clone() method to override the one in Object.
If the object on which clone() was invoked does implement the Cloneable interface, Object's implementation
of the clone() method creates an object of the same class as the original object and initializes the new object's
member variables to have the same values as the original object's corresponding member variables.
The simplest way to make your class cloneable is to add implements Cloneable to your class's declaration.
Then your objects can invoke the clone() method.
For some classes, the default behavior of Object's clone() method works just fine. If, however, an object
contains a reference to an external object, say ObjExternal , you may need to override clone() to get correct
behavior. Otherwise, a change in ObjExternal made by one object will be visible in its clone also. This means
that the original object and its clone are not independent—to decouple them, you must override clone() so that it
clones the object and ObjExternal. Then the original object references ObjExternal and the clone references
a clone of ObjExternal, so that the object and its clone are truly independent.
Copia superficiale: un primo esempio
Clonazione usando clone di Object
class Studente implements Cloneable {
...
public Object clone() {
try {
return super.clone();
}
catch(CloneNotSupportedException e) {
return null;
}
}
}
la classe deve implementare Cloneable
dato che clone di Object ha throws CloneNotSupportedException, va catturata
Clonazione superficiale in classi derivate
Se Borsista estende Studente:
class Borsista extends Studente {
...
public Object clone() {
return super.clone();
}
}
Commenti:

Non serve implements Cloneable dato che Studente implementa l'interfaccia
Cloneable, anche Borsista la implementa automaticamente in modo indiretto
 Non serve catturare l'eccezione, poiché viene già fatto nel clone di Studente
Chi clona l'oggetto?
Quando si invoca clone di Borsista: viene invocato clone di Studente che invoca clone di
Object
È sempre clone di Object che fa la copia!
Copia superficiale e profonda: differenze
Se un oggetto contiene altri riferimenti a oggetti:


Copia superficiale: viene copiato solo l'oggetto
Copia profonda: viene copiato l'oggetto e tutti quelli collegati
Esempio: Classe Segmento
class Segmento {
Point i, f;
}
Clonazione superficiale:
Gli oggetti Point sono esattamente gli stessi.
Clonazione profonda:
Gli oggetti Point non sono gli stessi, ma hanno gli stessi valori dentro
Prima della copia:
Dopo la copia superficiale:
Copia superficiale
Clone di Object fa la copia del solo oggetto
class Segmento implements Cloneable {
Point i, f;
public Object clone() {
try {
return super.clone();
}
catch(CloneNotSupportedException e) {
return null;
}
}
}
Copia profonda: significato
Ha senso richiedere una copia anche dei due oggetti Point
Questo non viene fatto da clone di Object, ma va fatto manualmente:
Copia profonda: realizzazione
Occorre invocare clone su ognuno degli oggetti di cui voglio fare la copia
Notare che super.clone() ha tipo di ritorno Object
Per poter accedere alle componenti, devo fare il cast
Lo stesso vale per le componenti
class Segmento implements Cloneable{
Point i, f;
public Object clone() {
try {
Segmento s;
s=(Segmento) super.clone();
s.i=(Point) this.i.clone();
s.f=(Point) this.f.clone();
return s;
}
catch(CloneNotSupportedException e) {
return null;
}
}
}
Osservazioni:
https://docs.oracle.com/javase/8/docs/api/java/lang/Cloneable.html
https://docs.oracle.com/javase/8/docs/api/java/lang/Object.html#clone--
11.2 Uguaglianza tra oggetti
The equals() Method
The equals()
method compares two objects for equality and returns true
if they are equal. The
equals()method provided in the Object class uses the identity operator (==) to determine whether two objects
are equal. For primitive data types, this gives the correct result. For objects, however, it does not.
The equals() method provided by Object tests whether the object references are equal—that is, if the objects
compared are the exact same object.
To test whether two objects are equal in the sense of equivalency (containing the same information), you must
override the equals() method. Here is an example of a Book class that overrides equals():
public class Book {
...
public boolean equals(Object obj) {
if (obj instanceof Book)
return ISBN.equals((Book)obj.getISBN());
else
return false;
}
}
Consider this code that tests two instances of the Book class for equality:
// Swing Tutorial, 2nd edition
Book firstBook = new Book("0201914670");
Book secondBook = new Book("0201914670");
if (firstBook.equals(secondBook)) {
System.out.println("objects are equal");
} else {
System.out.println("objects are not equal");
}
This program displays objects are equal even though firstBook and secondBook reference two distinct
objects. They are considered equal because the objects compared contain the same ISBN number.
You should always override the equals() method if the identity operator is not appropriate for your class.
Note: If you override equals() , you must override hashCode() as well.
Uguaglianza superficiale
Si confrontano i riferimenti degli oggetti
Due oggetti Segmento sono “equals” se i loro campi sono esattamente uguali
(contengono riferimenti agli stessi identici oggetti)
class Segmento {
Point i, f;
// equals superficiale
public boolean equals(Object o) {
if(o==null)
return false;
if(this.getClass()!=o.getClass())
return false;
Segmento s=(Segmento) o;
return((this.i==s.i)&&(this.f==s.f));
}
}
Uguaglianza profonda
Gli oggetti vengono confrontati in base ai loro valori, non ai loro riferimenti:
class Segmento {
Point i, f;
public boolean equals(Object o) {
if(o==null)
return false;
if(this.getClass()!=o.getClass())
return false;
Segmento s=(Segmento) o;
if(this.i==null) {
if(s.i!=null)
return false;
}
else if(!this.i.equals(s.i))
return false;
if(this.f==null) {
if(s.f!=null)
return false;
}
else if(!this.f.equals(s.f))
return false;
return true;
}
}
11.3 The finalize() Method
The Object class provides a callback method, finalize(), that may be invoked on an object when it becomes
garbage. Object's implementation of finalize() does nothing—you can override finalize() to do cleanup,
such as freeing resources.
The finalize() method may be called automatically by the system, but when it is called, or even if it is called, is
uncertain. Therefore, you should not rely on this method to do your cleanup for you. For example, if you don't close
file descriptors in your code after performing I/O and you expect finalize() to close them for you, you may run
out of file descriptors.
11.4 The getClass() Method
You cannot override getClass .
The getClass() method returns a Class object, which has methods you can use to get information about the
class, such as its name (getSimpleName() ), its superclass (getSuperclass()), and the interfaces it
implements (getInterfaces() ). For example, the following method gets and displays the class name of an
object:
void printClassName(Object obj) {
System.out.println("The object's" + " class is " +
obj.getClass().getSimpleName());
}
11.5 The hashCode() Method
The value returned by hashCode() is the object's hash code, which is the object's memory address in
hexadecimal.
By definition, if two objects are equal, their hash code must also be equal. If you override the equals() method,
you change the way two objects are equated and Object 's implementation of hashCode() is no longer valid.
Therefore, if you override the equals() method, you must also override the hashCode() method as well.
https://docs.oracle.com/javase/8/docs/api/java/lang/Object.html#hashCode-http://tutorials.jenkov.com/java-collections/hashcode-equals.html
http://stackoverflow.com/questions/27581/what-issues-should-be-considered-when-overriding-equals-andhashcode-in-java
11.6 The toString() Method
You should always consider overriding the toString() method in your classes.
The Object's toString() method returns a String representation of the object, which is very useful for
debugging. The String representation for an object depends entirely on the object, which is why you need to
override toString() in your classes.
You can use toString() along with System.out.println() to display a text representation of an object,
such as an instance of Book:
System.out.println(firstBook.toString());
which would, for a properly overridden toString() method, print something useful, like this:
ISBN: 0201914670; The Swing Tutorial; A Guide to Constructing GUIs, 2nd Edition
11.7 Confronto tra oggetti
http://www.mkyong.com/java/java-object-sorting-example-comparable-and-comparator/
http://docs.oracle.com/javase/tutorial/collections/interfaces/order.html
Un approccio graduale...con l'uso delle interfacce
java.lang.Comparable https://docs.oracle.com/javase/8/docs/api/java/lang/Comparable.html per
confrontare oggetti in base a una proprietà
java.util.Comparator https://docs.oracle.com/javase/8/docs/api/java/util/Comparator.html per
confrontare oggetti in base a un operatore (si usa quando si vuole confrontare gli oggetti sulla base
di più proprietà)
L'interfaccia java.lang.Comparable
Supponiamo di avere la seguente classe:
public class Fruit{
private String fruitName;
private String fruitDesc;
private int quantity;
public Fruit(String fruitName, String fruitDesc, int quantity) {
super();
this.fruitName = fruitName;
this.fruitDesc = fruitDesc;
this.quantity = quantity;
}
public String getFruitName() {
return fruitName;
}
public void setFruitName(String fruitName) {
this.fruitName = fruitName;
}
public String getFruitDesc() {
return fruitDesc;
}
public void setFruitDesc(String fruitDesc) {
this.fruitDesc = fruitDesc;
}
public int getQuantity() {
return quantity;
}
public void setQuantity(int quantity) {
this.quantity = quantity;
}
}
Supponiamo di voler ordinare una collection di oggetti di tipo Fruit in base a una proprietà da
noi scelta, ad esempio la quantità. Come facciamo?
Occorre implementare l'interfaccia java.lang.Comparable e fare overriding del metodo
compareTo() come descritto nel seguente esempio:
public class Fruit implements Comparable<Fruit>{
private String fruitName;
private String fruitDesc;
private int quantity;
public Fruit(String fruitName, String fruitDesc, int quantity) {
super();
this.fruitName = fruitName;
this.fruitDesc = fruitDesc;
this.quantity = quantity;
}
public String getFruitName() {
return fruitName;
}
public void setFruitName(String fruitName) {
this.fruitName = fruitName;
}
public String getFruitDesc() {
return fruitDesc;
}
public void setFruitDesc(String fruitDesc) {
this.fruitDesc = fruitDesc;
}
public int getQuantity() {
return quantity;
}
public void setQuantity(int quantity) {
this.quantity = quantity;
}
@Override
public int compareTo(Fruit compareFruit) {
int compareQuantity = compareFruit.getQuantity();
//ascending order
return this.quantity - compareQuantity;
//descending order
//return compareQuantity - this.quantity;
}
}
Possiamo ora eseguire il seguente codice di esempio:
import java.util.Arrays;
public class SortFruitObject{
public static void main(String args[]){
Fruit[] fruits = new Fruit[4];
Fruit pineappale = new Fruit("Pineapple", "Pineapple description",70);
Fruit apple = new Fruit("Apple", "Apple description",100);
Fruit orange = new Fruit("Orange", "Orange description",80);
Fruit banana = new Fruit("Banana", "Banana description",90);
fruits[0]=pineappale;
fruits[1]=apple;
fruits[2]=orange;
fruits[3]=banana;
Arrays.sort(fruits);
int i=0;
for(Fruit temp: fruits){
System.out.println("fruits " + ++i + " : " + temp.getFruitName() +
", Quantity : " + temp.getQuantity());
}
}
}
Ordinamento di Array con java.util.Arrays.sort()
Nel precedente esempio si è fatto uso del metodo statico sort della classe java.util.Arrays
per ordinare un array http://docs.oracle.com/javase/7/docs/api/java/util/Arrays.html
public class Arrays
extends Object
This class contains various methods for manipulating arrays (such as sorting and searching). This class also contains a static factory
that allows arrays to be viewed as lists.
The methods in this class all throw a NullPointerException, if the specified array reference is null, except where noted.
Se l'array fruits fosse stato un array di int o di double non ci sarebbe stato alcun bisogno di
implementare l'interfaccia Comparable. Bastava applicare il metodo statico Arrays.sort().
int a[]={30,7,9,20};
Arrays.sort(a);
System.out.println(Arrays.toString(a));
Se l'array fruits fosse stato un array di String si poteva fare l'ordinamento alfabetico ascendente
usando ancora il metodo Arrays.sort()
String[] fruits = new String[] {"Pineapple","Apple", "Orange", "Banana"};
Arrays.sort(fruits);
int i=0;
for(String temp: fruits){
System.out.println("fruits " + ++i + " : " + temp);
}
Output
fruits 1 : Apple
fruits 2 : Banana
fruits 3 : Orange
fruits 4 : Pineapple
Domanda: e se si volesse un ordinamento discendente?
Opzione 1: ridefinire il metodo compareTo in modo da restituire l'opposto di quello che è stato
definito nell'esempio precedente.
Opzione 2: utilizzare la versione di Arrays.sort che ha come input l'array da ordinare e un
comparatore.
static sort(T[] a, Comparator<? super T> c)
Sorts the specified array of objects according to the order induced by the
specified comparator.
L'istruzione per ordinare l'array in modo decrescente è in questo caso:
<T> void
Arrays.sort(fruits, Collections.reverseOrder()); //occore importare
java.util.Collections
I dettagli saranno chiariti nei prossimi paragrafi.
Ordinamento di List con java.util.Collections
La classe java.util.Collections https://docs.oracle.com/javase/8/docs/api/java/util/Collections.html
This class consists exclusively of static methods that operate on or return collections. It contains
polymorphic algorithms that operate on collections, "wrappers", which return a new collection backed
by a specified collection, and a few other odds and ends.
The methods of this class all throw a NullPointerException if the collections or class objects
provided to them are null.
java.util.Collections contiene alcuni metodi per ordinare liste, come ad esempio gli ArrayList
static sort(List<T> list)
Sorts the specified list into ascending order,
according to the natural ordering of its elements.
static sort(List<T> list, Comparator<?
<T> void super T> c)
Sorts the specified list according to the order
induced by the specified comparator.
<T extends Comparable<? super T>>
void
static void
reverse(List<?> list)
Reverses the order of the elements in the
specified list.
Ad esempio
List<Double> testList=new ArrayList();
testList.add(0.5);
testList.add(0.2);
testList.add(0.9);
testList.add(0.1);
testList.add(0.1);
testList.add(0.54);
testList.add(0.71);
Si può ordinare in senso decrescente con le istruzioni:
Collections.sort(testList); //ordina in senso ascendente
Collections.reverse(testList); //inverte gli elementi
Un ArrayList di oggetti, ad esempio di Fruit, si può ordinare con il metodo Collection.sort
facendo in modo che la classe degli oggetti (Fruit) implementi l'interfaccia Comparable, come nel
precedente esempio. In tal caso si potrà avere un esempio come il seguente:
List<Fruit> fruits= new ArrayList<Fruit>();
Fruit fruit;
for(int i=0;i<100;i++)
{
fruit = new fruit();
fruit.setname(...);
fruits.add(fruit);
}
Per ordinare l'ArrayList basta ora fare
Collections.sort(fruitList);
Collections vs Collection
Attenzione! In Java esiste anche l’interfaccia java.util.Collection (senza la “s” finale) che è
completamente diversa da java.util.Collections. Infatti Collections è una classe contenente
esclusivamente metodi statici di utilità per la manipolazione di oggetti di tipo Collection (o derivati).
https://docs.oracle.com/javase/8/docs/api/java/util/Collections.html
https://docs.oracle.com/javase/8/docs/api/java/util/Collection.html
Ordinamento mediante l'interfaccia java.util.Comparator
Oltre a definire un metodo per effettuare l'ordinamento naturale rispetto a una proprietà con il metodo
compareTo è possibile definire dei comparatori personalizzati che definiscono un ordinamento
mediante condizioni complesse, come riportato nel seguente esempio:
http://java67.blogspot.it/2012/10/how-to-sort-object-in-java-comparator-comparable-example.html
package provacomparator;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
/**
*
* Java program to test Object sorting in Java. This Java program
* test Comparable and Comparator implementation provided by Order
* class by sorting list of Order object in ascending and descending order.
* Both in natural order using Comparable and custom Order using Comparator in Java
*
* @author http://java67.blogspot.com
*/
public class ObjectSortingExample {
public static void main(String args[]) {
//Creating Order object to demonstrate Sorting of Object in Java
Order ord1 = new Order(101,2000, "Sony");
Order ord2 = new Order(102,4000, "Hitachi");
Order ord3 = new Order(103,6000, "Philips");
//putting Objects into Collection to sort
List<Order> orders = new ArrayList<Order>();
orders.add(ord3);
orders.add(ord1);
orders.add(ord2);
//printing unsorted collection
System.out.println("Unsorted Collection : " + orders);
//Sorting Order Object on natural order – ascending
//in questo caso si usa il metodo compareTo ridefinito
Collections.sort(orders);
//printing sorted collection
System.out.println("List of Order object sorted in natural order : " + orders);
// Sorting object in descending order in Java
Collections.sort(orders, Collections.reverseOrder());
System.out.println("List of object sorted in descending order : " + orders);
//Sorting object using Comparator in Java
Collections.sort(orders, new Order.OrderByAmount());
System.out.println("List of Order object sorted using Comparator - amount : " +
orders);
// Comparator sorting Example - Sorting based on customer
Collections.sort(orders, new Order.OrderByCustomer());
System.out.println("Collection of Orders sorted using Comparator - by
customer : " + orders);
}
}
/*
* Order class is a domain object which implements
* Comparable interface to provide sorting on natural order.
* Order also provides couple of custom Comparators to
* sort object based upon amount and customer
*/
class Order implements Comparable<Order> {
private int orderId;
private int amount;
private String customer;
/*
* Comparator implementation to Sort Order object based on Amount
*/
public static class OrderByAmount implements Comparator<Order> {
@Override
public int compare(Order o1, Order o2) {
return o1.amount > o2.amount ? 1 : (o1.amount < o2.amount ? -1 : 0);
}
}
/*
* Anohter implementation or Comparator interface to sort list of Order object
* based upon customer name.
*/
public static class OrderByCustomer implements Comparator<Order> {
@Override
public int compare(Order o1, Order o2) {
return o1.customer.compareTo(o2.customer);
}
}
public Order(int orderId, int amount, String customer) {
this.orderId = orderId;
this.amount = amount;
this.customer = customer;
}
public int getAmount() {return amount; }
public void setAmount(int amount) {this.amount = amount;}
public String getCustomer() {return customer;}
public void setCustomer(String customer) {this.customer = customer;}
public int getOrderId() {return orderId;}
public void setOrderId(int orderId) {this.orderId = orderId;}
/*
* Sorting on orderId is natural sorting for Order.
*/
@Override
public int compareTo(Order o) {
return this.orderId > o.orderId ? 1 : (this.orderId < o.orderId ? -1 : 0);
}
/*
* implementing toString method to print orderId of Order
*/
@Override
public String toString(){
return String.valueOf(orderId);
}
}
11.8 Classi Nested
Nell'esempio precedente la classe Order ha al suo interno due static nested class,
OrderByCustomer e OrderByAmount, che rappresentano i comparatori.
In Java è possibile dichiarare una classe all'interno di un'altra classe per alcuni usi specifici (ad
esempio la creazione di comparatori)
http://docs.oracle.com/javase/tutorial/java/javaOO/nested.html
The Java programming language allows you to define a class within another class. Such a class is
called a nested class and is illustrated here:
class OuterClass {
...
class NestedClass {
...
}
}
Terminology: Nested classes are divided into two categories: static and non-static. Nested
classes that are declared static are called static nested classes. Non-static nested classes are
called inner classes.
class OuterClass {
...
static class StaticNestedClass {
...
}
class InnerClass {
...
}
}
A nested class is a member of its enclosing class. Non-static nested classes (inner classes) have access
to other members of the enclosing class, even if they are declared private. Static nested classes do not
have access to other members of the enclosing class. As a member of the OuterClass, a nested class
can be declared private, public, protected, or package private. (Recall that outer classes can only be
declared public or package private.)
Osservazioni
L'interfaccia Comparator è molto potente in quanto permette di definire diversi criteri di confronto
sulla stessa classe base. Questa interfaccia comprende due metodi astratti compare e equals:
http://docs.oracle.com/javase/7/docs/api/java/util/Comparator.html
Method Summary
Methods
Modifier and Type Method and Description
compare(T o1, T o2)
Compares its two arguments for order.
int
equals(Object obj)
Indicates whether some other object is "equal to" this comparator.
Si noti che una classe che implementa l'interfaccia Comparator deve implementare il metodo
compare, ma non è tenuta a implementare il metodo equals dal momento che ogni classe eredita il
metodo equals di Object e che, come riportato nella documentazione del metodo equals di
Comparator, “ it is always safe not to override Object.equals(Object). ”
boolean
L'interfaccia Comparator trova la sua migliore espressione come classe nested in un'altra classe dal
momento che in questo modo si mantiene la coesione del codice (cohesion): un comparatore ha senso
in quanto definisce una relazione d'ordine su una classe base. Oltre che con l'ausilio di classi statiche
nested, come mostrato nell'esempio della classe Order, è anche possibile utilizzare l'interfaccia
Comparator nel seguente modo:
http://www.mkyong.com/java/java-object-sorting-example-comparable-andcomparator/
import java.util.Comparator;
public class Fruit implements Comparable<Fruit>{
private String fruitName;
private String fruitDesc;
private int quantity;
public Fruit(String fruitName, String fruitDesc, int quantity) {
super();
this.fruitName = fruitName;
this.fruitDesc = fruitDesc;
this.quantity = quantity;
}
public String getFruitName() {
return fruitName;
}
public void setFruitName(String fruitName) {
this.fruitName = fruitName;
}
public String getFruitDesc() {
return fruitDesc;
}
public void setFruitDesc(String fruitDesc) {
this.fruitDesc = fruitDesc;
}
public int getQuantity() {
return quantity;
}
public void setQuantity(int quantity) {
this.quantity = quantity;
}
public int compareTo(Fruit compareFruit) {
int compareQuantity = ((Fruit) compareFruit).getQuantity();
//ascending order
return this.quantity - compareQuantity;
//descending order
//return compareQuantity - this.quantity;
}
public static Comparator<Fruit> FruitNameComparator
= new Comparator<Fruit>() {
public int compare(Fruit fruit1, Fruit fruit2) {
String fruitName1 = fruit1.getFruitName().toUpperCase();
String fruitName2 = fruit2.getFruitName().toUpperCase();
//ascending order
return fruitName1.compareTo(fruitName2);
//descending order
//return fruitName2.compareTo(fruitName1);
}
};
}
Nell'esempio precedente la classe Fruit, oltre a implementare l'interfaccia Comparable per definire
l'ordinamento naturale sugli oggetti della classe Fruit (tramite il metodo compareTo), introduce
anche un campo statico di tipo public static Comparator<Fruit> inizializzato con il riferimento a un
oggetto di una classe anonima che implementa l'interfaccia Comparator<Fruit>, infatti:
FruitNameComparator è inizializzato con il riferimento all'oggetto creato da new
Comparator<Fruit>(){//classe anonima che implementa Comarator<Fruit> e ridefinisce il metodo
compare}
Con la versione precedente della classe Fruit è possibile ordinare un array di Fruit nel seguente modo;
Arrays.sort(fruits, Fruit.FruitNameComparator);
Oppure un ArrayList di Fruit:
Collections.sort(listOfFruit, Fruit.FruitNameComparator);
É anche possibile implementare l'interfaccia Comparator in classi distinte dalla classe base, come
mostrato nel seguente esempio:
http://javahungry.blogspot.com/2013/08/difference-between-comparable-and.html
//Country.java
public class Country{
int countryId;
String countryName;
public Country(int countryId, String countryName) {
super();
this.countryId = countryId;
this.countryName = countryName;
}
public int getCountryId() {
return countryId;
}
public void setCountryId(int countryId) {
this.countryId = countryId;
}
public String getCountryName() {
return countryName;
}
public void setCountryName(String countryName) {
this.countryName = countryName;
}
}
//CountrySortbyIdComparator.java
import java.util.Comparator;
//If country1.getCountryId() < country2.getCountryId():then compare method will return
-1
//If country1.getCountryId() > country2.getCountryId():then compare method will return
1
//If country1.getCountryId()==country2.getCountryId():then compare method will return 0
public class CountrySortByIdComparator implements Comparator<Country>{
@Override
public int compare(Country country1, Country country2) {
return (country1.getCountryId() < country2.getCountryId() ) ? -1:
(country1.getCountryId() > country2.getCountryId() ) ? 1:0 ;
}
}
//ComparatorMain.java
import
import
import
import
java.util.ArrayList;
java.util.Collections;
java.util.Comparator;
java.util.List;
public class ComparatorMain {
public static void main(String[] args) {
Country indiaCountry=new Country(1, "India");
Country chinaCountry=new Country(3, "USA");
Country nepalCountry=new Country(4, "Russia");
Country bhutanCountry=new Country(2, "Japan");
List<Country> listOfCountries = new ArrayList<Country>();
listOfCountries.add(indiaCountry);
listOfCountries.add(usaCountry);
listOfCountries.add(russiaCountry);
listOfCountries.add(japanCountry);
System.out.println("Before Sort by id : ");
for (int i = 0; i < listOfCountries.size(); i++) {
Country country=(Country) listOfCountries.get(i);
System.out.println("Country Id: "+country.getCountryId()+"||"+"Country
name: "+country.getCountryName());
}
Collections.sort(listOfCountries,new CountrySortByIdComparator());
System.out.println("After Sort by id: ");
for (int i = 0; i < listOfCountries.size(); i++) {
Country country=(Country) listOfCountries.get(i);
System.out.println("Country Id: "+country.getCountryId()+"|| "+"Country
name: "+country.getCountryName());
}
//Sort by countryName – utilizzo di un oggetto di una classe anonima
Collections.sort(listOfCountries,new Comparator<Country>() {
@Override
public int compare(Country o1, Country o2) {
return o1.getCountryName().compareTo(o2.getCountryName());
}
});
System.out.println("After Sort by name: ");
for (int i = 0; i < listOfCountries.size(); i++) {
Country country=(Country) listOfCountries.get(i);
System.out.println("Country Id: "+country.getCountryId()+"|| "+"Country
name: "+country.getCountryName());
}
}
}
Talvolta è utile effettuare la conversione tra ArrayList e Array e viceversa
11.9 Convertire un ArrayList in un Array
ArrayList class has a method called toArray() that we are using in our example to convert it into
Arrays.
Following is simple code snippet that converts an array list of countries into string array.
List<String> list = new ArrayList<String>();
list.add("India");
list.add("Switzerland");
list.add("Italy");
list.add("France");
String [] countries = list.toArray(new String[list.size()]);
So to convert ArrayList of any class into array use following code. Convert T into the class whose arrays you want
to create.
List<T> list = new ArrayList<T>();
T [] countries = list.toArray(new T[list.size()]);
11.10 Convertire ArrayList in Array
Vediamo il seguente esempio:
http://viralpatel.net/blogs/convert-arraylist-to-arrays-in-java/
import java.util.ArrayList;
import java.util.List;
import java.util.Arrays;
String[] countries = {"India", "Switzerland", "Italy", "France"};
List list = Arrays.asList(countries);
System.out.println("ArrayList of Countries:" + list);
The above code will work great. But list object is immutable. Thus you will not be able to add new values to it. In
case you try to add new value to list, it will throw UnsupportedOperationException.
Related: Resolve UnsupportedOperationException exception
Thus simply create a new List from that object. See below:
String[] countries = {"India", "Switzerland", "Italy", "France"};
List list = new ArrayList(Arrays.asList(countries));
System.out.println("ArrayList of Countries:" + list);
12 Interfacce Grafiche (GUI)
12.1 Elementi di un'interfaccia grafica
Per gestire un'interfaccia grafica dobbiamo essere in grado di controllare tre elementi:
■ What kinds of elements can we show on screen?
■ How do we arrange those elements?
■ How do we react to user input?
Un'interfaccia grafica è composta di tre cose:
Components are the individual parts that a GUI is built from. They are things such as buttons, menus,
menu items, checkboxes, sliders, text fields, and so on.
Layout deals with the issue of how to arrange the components on screen.
Event handling refers to the technique we shall use to deal with user input.
12.2 AWT e Swing
Java has two GUI libraries. The older one is called AWT (Abstract Window Toolkit) and was
introduced as part of the original Java API. Later, a much-improved GUI library, called Swing, was
added to Java.
Swing makes use of some of the AWT classes, replaces some AWT classes with its own versions,
and adds many new classes (Figure 11.1).
Wherever there are equivalent classes in AWT and Swing, the Swing versions have been identified
by adding the letter J to the start of the class name. You will, for example, see classes named Button
and JButton, Frame and Jframe, Menu and JMenu, and so on. The classes starting with a J are the
Swing versions; these are the ones we shall use, and the two should not be mixed in an application.
12.3 La prima applicazione grafica
Consideriamo l'esempio imageviewer0-1
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
public class ImageViewer
{
private JFrame frame;
public ImageViewer()
{
makeFrame();
}
private void makeFrame()
{
frame = new JFrame("ImageViewer mio");
Container contentPane = frame.getContentPane();
//JLabel label = new JLabel("I am a label. I can display some text.");
JButton button1 = new JButton("premi qui!");
//JButton button2 = new JButton("premi li!");
//contentPane.add(label);
contentPane.add(button1);
//contentPane.add(button2);
frame.pack();
frame.setVisible(true);
}
}
In maniera alternativa si può definire ImageViewer come sottoclasse di Jframe
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
public class ImageViewer extends JFrame
{
public ImageViewer()
{
super("ImageViewer");
makeFrame();
setVisible(true);
}
private void makeFrame()
{
Container contentPane = getContentPane();
JLabel label = new JLabel("I am a label. I can display some text.");
contentPane.add(label);
pack();
}
}
Si noti che il punto di partenza per la costruzione di un oggetto grafico è un oggetto di tipo JFrame.
All'oggetto di tipo JFrame è poi collegato un oggetto di tipo Container mediante il metodo
getContentPane dell'oggetto JFrame. Sull'oggetto Container sono aggiunti altri elementi
grafici come JLabel e JButton mediante il metodo add dell'oggetto Container. La costruzione
della finestra è quindi terminata invocando il metodo pack che permette di definirne le dimensioni
in base al suo contenuto.
Aggiunta di menu
First, we create the menus. Three classes are involved:
JMenuBar
—An object of this class represents a menu bar that can be displayed below the title bar at the top of
a window. Every window has at most one JMenuBar.
JMenu
—Objects of this class represent a single menu (such as the common File, Edit, or Help menus).
Menus are often held in a menu bar. They could also appear as pop-up menus, but we shall not do
that now.
JMenuItem
—Objects of this class represent a single menu item inside a menu (such as Open or Save).
The class JFrame has a method called setJMenuBar. We can create a menu bar and use this method
to attach our menu bar to the frame:
JMenuBar menubar = new JMenuBar();
frame.setJMenuBar(menubar);
Now we are ready to create a menu and add it to the menu bar:
JMenu fileMenu = new JMenu("File");
menubar.add(fileMenu);
These two lines create a menu labeled File and insert it into our menu bar. Finally, we can add menu
items to the menu. The following lines add two items, labeled Open and Quit, to the File menu:
JMenuItem openItem = new JMenuItem("Open");
fileMenu.add(openItem);
JMenuItem quitItem = new JMenuItem("Quit");
fileMenu.add(quitItem);
Gestione degli eventi
Swing uses a very flexible model to deal with GUI input: an event-handling model with event listeners.
The Swing framework itself and some of its components raise events when something happens that
other objects may be interested in. There are different types of events caused by different types of
actions. When a button is clicked or a menu item is selected, the component raises an ActionEvent.
When a mouse is clicked or moved, a MouseEvent is raised. When a frame is closed or iconified, a
WindowEvent is generated. There are many other types of events. Any of our objects can become
an event listener for any of these events. When it is a listener, it will get notified about any of the
events it listens to. An object becomes an event listener by implementing one of several existing
listener interfaces. If it implements the right interface, it can register itself with a component it wants
to listen to.
Let us look at an example. A menu item (class JMenuItem) raises an ActionEvent when it is
activated by a user. Objects that want to listen to these events must implement the ActionListener
interface from the java.awt.event package.
Un esempio completo di menu e gestione degli eventi (con un solo listener)
//progetto: imageviewer0-2
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
public class ImageViewer
implements ActionListener
{
private JFrame frame;
public ImageViewer()
{
makeFrame();
}
/**
* Receive notification of an action.
* @param event Details of the action.
*/
public void actionPerformed(ActionEvent event)
{
System.out.println("Menu item: " + event.getActionCommand());
}
private void makeFrame()
{
frame = new JFrame("ImageViewer");
makeMenuBar(frame);
Container contentPane = frame.getContentPane();
JLabel label = new JLabel("I am a label. I can display some text.");
contentPane.add(label);
// building is done - arrange the components and show
frame.pack();
frame.setVisible(true);
}
/**
* Create the main frame's menu bar.
* @param frame
The frame that the menu bar should be added to.
*/
private void makeMenuBar(JFrame frame)
{
JMenuBar menubar = new JMenuBar();
frame.setJMenuBar(menubar);
// create the File menu
JMenu fileMenu = new JMenu("File");
menubar.add(fileMenu);
JMenuItem openItem = new JMenuItem("Open");
openItem.addActionListener(this); //registro l'oggetto corrente ImageViewer come
listener di openItem
fileMenu.add(openItem);
JMenuItem quitItem = new JMenuItem("Quit");
quitItem.addActionListener(this); //registro l'oggetto corrente ImageViewer come
listener di quitItem
fileMenu.add(quitItem);
}
}
Osservazione importante: meglio avere listeners distinti per oggetti distinti
Si noti che con questo approccio l'oggetto ImageViewer è listener sia di openItem che di
quitItem con un solo metodo actionPerformed. Se si volesse realizzare una funzionalità diversa
per openItem e per quitItem al click del mouse dovremmo distinguere il tipo di evento con
istruzioni del tipo:
if(event.getActionCommand().equals("Open")) ...
questo approccio ha diversi problemi:

se cambia il nome del componente da “Open” a “Apri” bisogna modificare il codice.

C'è un unico metodo centralizzato che ascolta tutti gli eventi - ogni volta che si aggiunge un
componente bisogna modificare il metodo actionPerformed di ImageViewer
La gestione degli eventi sulle interfacce grafiche risulta ottimizzata facendo ricorso al concetto di
inner class già visto quando si è utilizzata l'interfaccia Comparator (in quel caso si trattava di static
nested class).
Inner classes (rivisitate)
To solve the problems with centralized event dispatch mentioned above, we use a new construct that
we have not discussed before: inner classes. Inner classes are classes that are declared textually inside
another class:
class EnclosingClass
{
...
class InnerClass
{
...
}
}
Instances of the inner class are attached to instances of the enclosing class; they can only exist together
with an enclosing instance, and they exist conceptually inside the enclosing instance. One interesting
detail is that statements in methods of the inner class can see and access private fields and methods
of the enclosing class. There is obviously a very tight coupling between the two, therefore. The inner
class is considered to be a part of the enclosing class just as are any of the enclosing class’s methods.
We can now use this construct to make a separate action-listener class for every menu item we like
to listen to. As they are separate classes, they can each have a separate actionPerformed method
so that each of these methods handles only a single item’s activation. The structure is this:
class ImageViewer
{
...
class OpenActionListener implements ActionListener
{
public void actionPerformed(ActionEvent event)
{
// perform open action
}
}
class QuitActionListener implements ActionListener
{
public void actionPerformed(ActionEvent event)
{
// perform quit action
}
}
}
Once we have done this, we can now create instances of these inner classes in exactly the same way
as for those of any other class. Note also that ImageViewer does not implement ActionListener
anymore (we remove its actionPerformed method), but the two inner classes do. This now allows
us to use instances of the inner classes as action listeners for the menu items.
JMenuItem openItem = new JMenuItem("Open");
openItem.addActionListener(new OpenActionListener());
...
JMenuItem quitItem = new JMenuItem("Quit");
quitItem.addActionListener(new QuitActionListener());
In summary, instead of having the image-viewer object listen to all action events, we create separate
listener objects for each possible event, where each listener object listens to one single event type. As
every listener has its own actionPerformed method, we can now write specific handling code in
these methods. Also, because the listener classes are in the scope of the enclosing class (they can
access the enclosing class’s private fields and methods), they can make full use of the enclosing class
in the implementation of the actionPerformed methods.
Notice a couple of characteristics of these listener objects:
We don’t bother storing them in variables—so, in effect, they are anonymous objects. Only the menu
items have a reference to the listener objects, so that they can call their actionPerformed methods.
We only create a single object from each of the inner classes, because each is highly specialized for
a particular menu item.
These characteristics will lead us to explore a further feature of Java in the next section.
Anonymous inner classes
Il progetto image-viewer0-3 implementa il concetto di inner class anonime per la gestione degli
eventi generati dal click del mouse su un oggetto di tipo JMenuItem
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
public class ImageViewer
{
private JFrame frame;
public ImageViewer()
{
makeFrame();
}
// ---- implementation of menu functions ----
/**
* Open function: open a file chooser to select a new image file.
*/
private void openFile()
{
// this is some test output, until we do this properly
System.out.println("open file");
}
/**
* Quit function: quit the application.
*/
private void quit()
{
System.exit(0);
}
private void makeFrame()
{
frame = new JFrame("ImageViewer");
makeMenuBar(frame);
Container contentPane = frame.getContentPane();
JLabel label = new JLabel("I am a label. I can display some text.");
contentPane.add(label);
// building is done - arrange the components and show
frame.pack();
frame.setVisible(true);
}
/**
* Create the main frame's menu bar.
* @param frame
The frame that the menu bar should be added to.
*/
private void makeMenuBar(JFrame frame)
{
JMenuBar menubar = new JMenuBar();
frame.setJMenuBar(menubar);
// create the File menu
JMenu fileMenu = new JMenu("File");
menubar.add(fileMenu);
JMenuItem openItem = new JMenuItem("Open");
openItem.addActionListener(new
ActionListener()
{//qui
inizia
la
classe
anonima
public void actionPerformed(ActionEvent e) { openFile(); }
});
fileMenu.add(openItem);
JMenuItem quitItem = new JMenuItem("Quit");
quitItem.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) { quit(); }
});
fileMenu.add(quitItem);
}
}
When using an anonymous inner class, we create an inner class without naming it and immediately
create a single instance of the class. In the action-listener code above, this is done with the code
fragment
new ActionListener() {
public void actionPerformed(ActionEvent e) { openFile(); }
}
An anonymous inner class is created by naming a supertype (often an abstract class or an interface—
here ActionListener), followed by a block that contains an implementation for its abstract methods.
This looks unusual, because it is not otherwise permitted to create an instance of an abstract class or
interface directly. In this example, we create a new subtype of ActionListener that implements the
actionPerformed method. This new class does not receive a name. Instead, we precede it with the
new keyword to create a single instance of this class. In our example, this single instance is an actionlistener object (it is of a subtype of ActionListener). It can be passed to a menu item’s
addActionListener method and will invoke the openFile method of its enclosing class when
activated. Each subtype of ActionListener created in this way represents a unique anonymous class.
Just like named inner classes, anonymous inner classes are able to access the fields and methods of
their enclosing classes. In addition, because they are defined inside a method, they are able to access
the local variables and parameters of that method. However, an important rule is that local variables
accessed in this way must be declared as final variables.
12.4 Un programma per la visualizzazione e modifica delle immagini:
prima versione
Apriamo il progetto imageviewer0-4:

ImageFileManager is a helper class that provides static methods to read an image file (in
JPEG or PNG format) from disk and return it in OFImage format and then save the OFImage
back to disk.

ImagePanel is a custom Swing component to show the image in our GUI.

The OFImage class is our own custom format for representing an image in memory. You can
think of an OFImage as a two-dimensional array of pixels. Each of the pixels can have a color.
We use the standard class Color (from package java.awt) to represent each pixel’s color.
OFImage is implemented as a subclass of the Java standard class BufferedImage (from
package java.awt.image). BufferedImage gives us most of the functionality we want (it also
represents an image as a two-dimensional array), but it does not have methods to set or get a
pixel using a Color object (it uses different formats for this, which we do not want to use). So
we made our own subclass that adds these two methods.
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
public class ImageViewer
{
private JFrame frame;
private ImagePanel imagePanel;
/**
* Create an ImageViewer show it on screen.
*/
public ImageViewer()
{
makeFrame();
}
// ---- implementation of menu functions ----
/**
* Open function: open a file chooser to select a new image file.
*/
private void openFile()
{
//carico il file contenente l'immagine
OFImage image = ImageFileManager.getImage();
//imposto l'immagine sul image panel
imagePanel.setImage(image);
frame.pack();
}
/**
* Quit function: quit the application.
*/
private void quit()
{
System.exit(0);
}
// ---- swing stuff to build the frame and all its components ----
/**
* Create the Swing frame and its content.
*/
private void makeFrame()
{
//creo il frame
frame = new Jframe("ImageViewer");
//creo la menubar
makeMenuBar(frame);
//creo il container
Container contentPane = frame.getContentPane();
//creo un image panel
imagePanel = new ImagePanel();
//aggiungo l'image panel al container
contentPane.add(imagePanel);
// building is done - arrange the components and show
frame.pack();
frame.setVisible(true);
}
/**
* Create the main frame's menu bar.
* @param frame
The frame that the menu bar should be added to.
*/
private void makeMenuBar(JFrame frame)
{
final int SHORTCUT_MASK =
Toolkit.getDefaultToolkit().getMenuShortcutKeyMask();
JMenuBar menubar = new JMenuBar();
frame.setJMenuBar(menubar);
// create the File manu
JMenu fileMenu = new JMenu("File");
menubar.add(fileMenu);
JMenuItem openItem = new JMenuItem("Open");
openItem.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_O,
SHORTCUT_MASK));
openItem.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) { openFile(); }
});
fileMenu.add(openItem);
JMenuItem quitItem = new JMenuItem("Quit");
quitItem.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_Q,
SHORTCUT_MASK));
quitItem.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) { quit(); }
});
fileMenu.add(quitItem);
}
}
Nota: nell'esempio si fa uso di della classe KeyEvent e Toolkit per creare degli shortcut sui menù. In
questa fase iniziale si può trascurare questi dettagli o anche rimuovere il relativo codice dall'esempio
per non renderlo inutilmente pesante.
12.5 Layouts
Supponiamo di voler inserire una etichetta (label) per indicare il nome del file aperto sopra l'immagine
visualizzata e un'altra etichetta sotto per indicare alcune notifiche relative alle operazioni fatte
sull'immagine , nel progetto imageviewer0-4. Si potrebbe pensare (erroneamente) di aggiungere il
codice seguente al metodo makeFrame:
private void makeFrame()
{
frame = new JFrame("ImageViewer");
makeMenuBar(frame);
Container contentPane = frame.getContentPane();
imagePanel = new ImagePanel();
contentPane.add(imagePanel);
JLabel filenameLabel = new JLabel("Nome file aperto");
contentPane.add(filenameLabel);
JLabel statusLabel = new JLabel("Version 1.0");
contentPane.add(statusLabel);
// building is done - arrange the components and show
frame.pack();
frame.setVisible(true);
}
In questo caso il visualizzatore di immagini non mostra più l'immagine, ma soltanto l'etichetta
“Version 1.0”. Se si prova a cambiare l'ordine di inserimento degli oggetti nel Container si otterrà di
volta in volta un risultato diverso: l'applicazione visualizza sempre l'ultimo oggetto inserito. Il motivo
di ciò sta nel fatto che non abbiamo definito un layout, vale a dire una disposizione, per la
visualizzazione degli oggetti.
Swing uses layout managers to arrange the layout of components in a GUI. Each container that holds
components, such as the content pane, has an associated layout manager that takes care of arranging
the components within that container.
Swing provides several different layout managers to support different layout preferences. The most
important are: FlowLayout, BorderLayout, GridLayout, and BoxLayout. Each of those is
represented by a Java class in the Swing library, and each lays out in different ways the components
under its control. The key differences between them are the ways in which they position components
and how the available space is distributed between the components. You can find the examples
illustrated here in the layouts project.
Aprire il progetto layouts:
BorderLayout
private void makeFrame()
{
frame = new JFrame("BorderLayout Example");
Container contentPane = frame.getContentPane();
contentPane.setLayout(new BorderLayout());
contentPane.add(new JButton("north"), BorderLayout.NORTH);
contentPane.add(new JButton("south"), BorderLayout.SOUTH);
contentPane.add(new JButton("center"), BorderLayout.CENTER);
contentPane.add(new JButton("west"), BorderLayout.WEST);
contentPane.add(new JButton("east"), BorderLayout.EAST);
frame.pack();
frame.setVisible(true);
}
FlowLayout
private void makeFrame()
{
frame = new JFrame("FlowLayout Example");
Container contentPane = frame.getContentPane();
contentPane.setLayout(new FlowLayout());
contentPane.add(new JButton("first"));
contentPane.add(new JButton("second"));
contentPane.add(new JButton("the third string is very long"));
contentPane.add(new JButton("fourth"));
contentPane.add(new JButton("fifth"));
frame.pack();
frame.setVisible(true);
}
GridLayout
private void makeFrame()
{
frame = new JFrame("GridLayout Example");
Container contentPane = frame.getContentPane();
contentPane.setLayout(new GridLayout(3, 2));
contentPane.add(new JButton("first"));
contentPane.add(new JButton("second"));
contentPane.add(new JButton("the third string is very long"));
contentPane.add(new JButton("fourth"));
contentPane.add(new JButton("fifth"));
frame.pack();
frame.setVisible(true);
}
BoxLayout
private void makeFrame()
{
frame = new JFrame("BoxLayout Example");
Container contentPane = frame.getContentPane();
contentPane.setLayout(new BoxLayout(contentPane, BoxLayout.Y_AXIS));
contentPane.add(new JButton("first"));
contentPane.add(new JButton("second"));
contentPane.add(new JButton("the third string is very long"));
contentPane.add(new JButton("fourth"));
contentPane.add(new JButton("fifth"));
frame.pack();
frame.setVisible(true);
}
Nested Containers
Layouts can be nested. Many of the Swing components are containers. Containers appear to the
outside as a single component, but they can contain multiple other components. Each container has
its own layout manager attached. The most-used container is the class JPanel. A JPanel can be
inserted as a component into the frame’s content pane, and then more components can be laid out
inside the JPanel. fig., for example, shows an interface arrangement similar to that of the BlueJ main
window. The content pane of this frame uses a BorderLayout, where the EAST position is unused.
The NORTH area of this BorderLayout contains a Jpanel with a horizontal FlowLayout that
arranges its components (say toolbar buttons) in a row. The SOUTH area is similar: another Jpanel
with a FlowLayout.
The button group in the WEST area was first placed into a JPanel with a one-column GridLayout
to give all buttons the same width. This JPanel was then placed into another JPanel with a
FlowLayout so that the grid did not extend over the full height of the WEST area. The outer JPanel
is then inserted into the WEST area of the frame. Note how the container and the layout manager
cooperate in the layout of the components. The container holds the components, but the layout
manager decides their exact arrangement on screen. Every container has a layout manager. It will use
a default layout manager if we do not explicitly set one. The default is different for different containers:
the content pane of a JFrame, for example, has by default a BorderLayout, whereas JPanels use
fig.
1: Layout innestati
mediante Jpanel
a FlowLayout
by default.
12.6 Creazione di un'interfaccia grafica con NetBeans
Un esempio guida: creare un convertitore di temperatura con NetBeans:
http://docs.oracle.com/javase/tutorial/uiswing/learn/index.html
Si veda anche il tutorial:
https://netbeans.org/kb/docs/java/quickstart-gui.html
Molti esempi e tutorial sulla creazione di interfacce grafiche con NetBeans si trovano a partire da
questo link:
https://netbeans.org/kb/trails/matisse.html
in particolare:
https://netbeans.org/kb/docs/java/gui-functionality.html
https://netbeans.org/kb/docs/java/gui-filechooser.html
https://netbeans.org/kb/docs/java/gui-image-display.html
altri esempi qui: (swing tutorial):
http://docs.oracle.com/javase/tutorial/uiswing/index.html
Progetti da svolgere (riporgettare) con NetBeans (matisse):
Molto utili gli esempi riportati nei Java tutotial ufficiali di Oracle:
“Using Swing Components: Examples”
http://docs.oracle.com/javase/tutorial/uiswing/examples/components/index.html#IconDemo
Esercizio 1: Il “gioco del 15”.
Versione con numeri
Versione con immagini “puzzlefy”
Per quest'ultima versione si considerino i seguenti link:
http://docs.oracle.com/javase/7/docs/api/java/awt/image/BufferedImage.html
http://stackoverflow.com/questions/9417356/bufferedimage-resize
http://www.mkyong.com/java/how-to-resize-an-image-in-java/
http://stackoverflow.com/questions/5813900/how-to-get-sub-image-from-buffered-image
e il seguente esempio (IconDemoProject) tratto dai java tutorials:
http://docs.oracle.com/javase/tutorial/uiswing/components/icon.html
il cui codice si trova qui:
http://docs.oracle.com/javase/tutorial/uiswing/examples/zipfiles/componentsCustomIconDemoProject.zip
Esercizio 2: Emulare la calcolatrice standard di Windows
Partire dal progetto my-calculator fornisce una classe per una calcolatrice (CalcEngine) che effettua
solo le operazioni “+” e “-”. Creare un progetto NetBeans chiamato MyCalc con un form
(UserInterface) e la classe CalcEngine.
La classe CalcEngine ha il seguente diagramma UML:
//file: UserInterface.java
package mycalc;
public class UserInterface extends javax.swing.JFrame {
private CalcEngine calc;
public UserInterface(CalcEngine calc) {
this.calc = calc;
initComponents();
}
@SuppressWarnings("unchecked")
//qui il “genereted code” di NetBeans
}//fine del Jframe form
//--------------------------------------------------------------------------//file MyCalcStarter.java
package mycalc;
public class MyCalcStarter {
public static void main(String args[]) {
/* Set the Nimbus look and feel */
CalcEngine calculator = new CalcEngine();
/* Create and display the form
*/
java.awt.EventQueue.invokeLater(new Runnable() {
public void run() {
new UserInterface(calculator).setVisible(true);
}
});
}
}
A partire dal progetto MyCalc progettare l'interfaccia grafica della calcolatrice usando il tool
Matisse di NetBeans.
13 Gestione delle eccezioni (rivisitate)
Seguire il capitolo 11 del libro Java Haw to program – Exception Handling: a deeper look con gli
esempi presenti sul sito del libro.
13.1 Approfondimenti
http://howtodoinjava.com/2013/04/04/java-exception-handling-best-practices/
13.2 Logging delle eccezioni e di situazioni specifiche: java.util.logging
package
http://tutorials.jenkov.com/java-logging/index.html
14 Gestione dei file in Java
Seguire il capitolo 17 del libro Java Haw to program – Files, Streams and Object serialization con
gli esempi riportati sul sito del libro.
14.1 java.io.File
//gestione dei file e delle directory
boolean canRead() Returns true if a file is readable by the current application; false otherwise.
boolean canWrite() Returns true if a file is writable by the current application; false otherwise.
boolean exists() Returns true if the file or directory represented by the File object exists; false otherwise.
boolean isFile() Returns true if the name specified as the argument to the File constructor is a file; false otherwise.
boolean isDirectory() Returns true if the name specified as the argument to the File constructor is a directory; false
otherwise.
boolean isAbsolute() Returns true if the arguments specified to the File constructor indicate an absolute path to a file or
directory; false otherwise.
String getAbsolutePath() Returns a String with the absolute path of the file or directory.
String getName() Returns a String with the name of the file or directory.
String getPath() Returns a String with the path of the file or directory.
String getParent() Returns a String with the parent directory of the file or directory (i.e., the directory in which the file or
directory is located).
long length() Returns the length of the file, in bytes. If the File object represents a directory, an unspecified value is
returned.
long lastModified() Returns a platform-dependent representation of the time at which the file or directory was last
modified. The value returned is useful only for comparison with other values returned by this method.
String[] list() Returns an array of Strings representing a directory’s contents. Returns null if the File object does not
represent a directory.
Una panoramica sulle classi Java per la gestione dei file si trova qui:
http://docs.oracle.com/javase/tutorial/essential/io/index.html
e qui: http://tutorials.jenkov.com/java-io/index.html
Esempi sui file di testo qui:
http://www.javapractices.com/topic/TopicAction.do?Id=42
Esempi sui file binari qui:
http://www.javapractices.com/topic/TopicAction.do?Id=245
14.2 java.util.Formatter e java.util.Scanner;
Con Formatter il file di testo precedentemente creato (se esiste) è completamente sovrascritto.
Con Scanner il delimitatore di default è un qualunque whitespace.
import java.io.FileNotFoundException;
import java.lang.SecurityException;
import java.util.Formatter;
import java.util.FormatterClosedException;
import java.util.NoSuchElementException;
import java.util.Scanner;
public class CreateTextFile
{
private Formatter output; // object used to output text to file
// enable user to open file
public void openFile()
{
try
{
output = new Formatter( "clients.txt" ); // open the file
} // end try
catch ( SecurityException securityException )
{
System.err.println(
"You do not have write access to this file." );
System.exit( 1 ); // terminate the program
} // end catch
catch ( FileNotFoundException fileNotFoundException )
{
System.err.println( "Error opening or creating file." );
System.exit( 1 ); // terminate the program
} // end catch
} // end method openFile
// add records to file
public void addRecords()
{
// object to be written to file
AccountRecord record = new AccountRecord();
Scanner input = new Scanner( System.in );
System.out.printf( "%s\n%s\n%s\n%s\n\n",
"To terminate input, type the end-of-file indicator ",
"when you are prompted to enter input.",
"On UNIX/Linux/Mac OS X type <ctrl> d then press Enter",
"On Windows type <ctrl> z then press Enter" );
System.out.printf( "%s\n%s",
"Enter account number (> 0), first name, last name and balance.",
"? " );
//int contatore = 0;
//int limit = 2;
while ( input.hasNext() ) // loop until end-of-file indicator
{
try // output values to file
{
// retrieve data to be output
record.setAccount( input.nextInt() ); // read account number
record.setFirstName( input.next() ); // read first name
record.setLastName( input.next() ); // read last name
record.setBalance( input.nextDouble() ); // read balance
if ( record.getAccount() > 0 )
{
// write new record
output.format( "%d %s %s %.2f\n", record.getAccount(),
record.getFirstName(), record.getLastName(),
record.getBalance() );
} // end if
else
{
System.out.println(
"Account number must be greater than 0." );
} // end else
} // end try
catch ( FormatterClosedException formatterClosedException )
{
System.err.println( "Error writing to file." );
return;
} // end catch
catch ( NoSuchElementException elementException )
{
System.err.println( "Invalid input. Please try again." );
input.nextLine(); // discard input so user can try again
} // end catch
System.out.printf( "%s %s\n%s", "Enter account number (>0),",
"first name, last name and balance.", "? " );
//contatore++;
} // end while
} // end method addRecords
// close file
public void closeFile()
{
if ( output != null )
output.close();
} // end method closeFile
} // end class CreateTextFile
14.3 Scrivere su file di testo con PrintWriter e BufferedWriter una riga
alla volta
Per scrivere una riga alla volta su file di testo:
Classe java.io.PrintWriter
oppure
Classe java.io.BufferedWriter
Quali differenze tra PrintWriter e BurreredWriter?
http://stackoverflow.com/questions/1747040/difference-between-java-io-printwriter-and-java-iobufferedwriter
// A.class
File file = new File("blah.txt");
FileWriter fileWriter = new FileWriter(file);
PrintWriter printWriter = new PrintWriter(fileWriter);
// B.class
File file = new File("blah.txt");
FileWriter fileWriter = new FileWriter(file);
BufferedWriter bWriter = new BufferedWriter(fileWriter);
What is the difference between these two methods?
When should we use PrintWriter over BufferedWriter?
The main reason to use the PrintWriter is to get access to the printXXX methods (like println(int)).
You can essentially use a PrintWriter to write to a file just like you would use System.out to write
to the console.
A BufferedWriter is an efficient way to write to a file (or anything else) as it will buffer the
characters in Java memory before (probably, depending on the implementation) dropping to C to do
the writing to the file.
There is no such concept as a "PrintReader" the closest you will come is probably java.util.Scanner.
Nota: per aprire un file di testo in scrittura in modalità append conviene utilizzare la classe
FileWriter http://docs.oracle.com/javase/7/docs/api/java/io/FileWriter.html usando il costruttore:
FileWriter(File file, boolean append)
http://stackoverflow.com/questions/1625234/how-to-append-text-to-an-existing-file-in-java
PrintWriter out = null;
try {
out = new PrintWriter(new BufferedWriter(new FileWriter("writePath", true)));
out.println("the text");
}catch (IOException e) {
System.err.println(e);
}finally{
if(out != null){
out.close();
}
}
Also, as of Java 7, you can use a try-with-resources statement . No finally block is
required for closing the declared resource(s) because it is handled automatically, and
is also less verbose:
try(PrintWriter out = new PrintWriter(new BufferedWriter(new FileWriter("writePath",
true)))) {
out.println("the text");
}catch (IOException e) {
System.err.println(e);
}
14.4 Leggere da file di testo una riga alla volta con BufferedReader
Per leggere un file di testo conviene utilizzare le classi:
FileReader e BufferedReader nel seguente modo:
BufferedReader input =
new BufferedReader(new FileReader(aFile));
14.5 Un esempio di lettura da file CSV
http://www.mkyong.com/java/how-to-read-and-parse-csv-file-in-java/
package com.mkyong.util;
import java.io.BufferedReader;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;
public class ReadCVS {
public static void main(String[] args) {
ReadCVS obj = new ReadCVS();
obj.run();
}
public void run() {
String csvFile = "/Users/mkyong/Downloads/GeoIPCountryWhois.csv";
BufferedReader br = null;
String line = "";
String cvsSplitBy = ",";
try {
br = new BufferedReader(new FileReader(csvFile));
while ((line = br.readLine()) != null) {
// use comma as separator
String[] country = line.split(cvsSplitBy);
System.out.println("Country [code= " + country[4]
+ " , name=" + country[5] + "]");
}
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} finally {
if (br != null) {
try {
br.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
System.out.println("Done");
}
}
14.6 Un esempio di scrittura su file CSV
http://stackoverflow.com/questions/17010222/how-do-i-append-text-to-a-csv-txt-file-inprocessing
import java.io.File;
import java.io.BufferedWriter;
import java.io.FileWriter;
import java.io.PrintWriter;
import java.io.IOException;
/**
*
* @author Prof.G
*/
public class WriteToCSV {
String outFilename = "out.txt";
void setup(){
// Write some text to the file
for(int i=0; i<10; i++){
appendTextToFile(outFilename, "Text " + i);
}
}
/**
* Appends text to the end of a text file located in the data directory,
* creates the file if it does not exist.
* Can be used for big files with lots of rows,
* existing lines will not be rewritten
*/
void appendTextToFile(String filename, String text){
File f = new File(filename);
if(!f.exists()){
createFile(f);
}
try {
PrintWriter out = new PrintWriter(new BufferedWriter(new FileWriter(f, true)));
out.println(text);
out.close();
}catch (IOException e){
e.printStackTrace();
}
}
/**
* Creates a new file including all subfolders
*/
void createFile(File f){
File parentDir = f.getParentFile();
try{
parentDir.mkdirs();
f.createNewFile();
}catch(Exception e){
e.printStackTrace();
}
}
14.7 Un esempio di uso di PrintWriter e BufferedReader
http://docs.oracle.com/javase/tutorial/essential/io/charstreams.html
import java.io.FileReader;
import java.io.FileWriter;
import java.io.BufferedReader;
import java.io.PrintWriter;
import java.io.IOException;
public class CopyLines {
public static void main(String[] args) throws IOException {
BufferedReader inputStream = null;
PrintWriter outputStream = null;
try {
inputStream = new BufferedReader(new FileReader("xanadu.txt"));
outputStream = new PrintWriter(new FileWriter("characteroutput.txt"));
String l;
while ((l = inputStream.readLine()) != null) {
outputStream.println(l);
}
} finally {
if (inputStream != null) {
inputStream.close();
}
if (outputStream != null) {
outputStream.close();
}
}
}
}
14.8 Serializzazione di oggetti
Seguire il cap. 17 del libro “Java How to Program” e integrare con i link:
http://www.tutorialspoint.com/java/java_serialization.htm
http://www.vogella.com/tutorials/JavaSerialization/article.html
http://www.javapractices.com/topic/TopicAction.do?Id=45 (implementing serializable)
http://www.javapractices.com/topic/TopicAction.do?Id=57 (reading and writing serialized objects)
http://www.tutorialspoint.com/listtutorial/How-to-use-transient-variable-in-Java-withExample/3735 (using transient variables)
http://www.coderanch.com/t/277986/java-io/java/detect-file (end of file in serilized object files)
http://docs.oracle.com/javase/7/docs/platform/serialization/spec/serialTOC.html
14.9 Progetto di una rubrica di contatti
Per creare un'applicazione multi-tab seguire i tutorial seguenti:
http://docs.oracle.com/javase/tutorial/uiswing/components/tabbedpane.html
https://blogs.oracle.com/geertjan/entry/tabs_in_netbeans_ide
Per realizzare liste cliccabili seguire i seguenti tutorial:
http://stackoverflow.com/questions/14625091/create-a-list-of-entries-and-make-each-entryclickable
http://docs.oracle.com/javase/tutorial/uiswing/components/list.html
http://docs.oracle.com/javase/tutorial/uiswing/components/tree.html#create
15 Riferimenti per Java
Documentazione ufficiale Oracle - Learning the Java Language: Table of Contents:
http://docs.oracle.com/javase/tutorial/java/TOC.html
Guida rapida con esempi: Tutorialspoint.com
http://www.tutorialspoint.com/java/
La documentazione ufficiale delle API e dei tools Java:
http://docs.oracle.com/javase/7/docs/