danilo.pianini@unibo.itgianluca.aguzzi@unibo.itangelo.filaseta@unibo.itCompiled on: 2025-12-05 — versione stampabile
instanceof)SE B è un sottotipo di A
ALLORA ogni oggetto di B può/“deve poter” essere utilizzabile dove ci si attende un oggetto di A
void m(A a) { /* ... */ }
B b = /* ... */;
A a = b; // OK
m(b); // OK
class B extends A { ... }
B eredita tutti i membri (campi, metodi) di A, e non può restringerne la visibilitàB rispondono a tutti i messaggi previsti dalla classe A (ed eventualmente a qualcuno in più)B può essere passato dove se ne aspetta uno di A, senza dare problemi (di “typing”)Cosa mi hai de
Poiché è possibile, corretto, ed utile, allora in Java si considera B come un sottotipo di A a tutti gli effetti!

D che usi una classe C…ci saranno punti in D in cui ci si attende oggetti della classe C
si potranno effettivamente passare oggetti della classe C, ma anche delle classi C1, C2,..,C5, o di ogni altra classe successivamente creata che estende, direttamente o indirettamente C
class C { public void foo() { /*...*/ } }
class D { // rappresenta un generico "contesto"
C c;
public void m(C c) { c.foo(); }
}
class C1 extends C { }
class C2 extends C { }
D d = new D();
d.c = new C1(); // OK
d.m(new C2()); // OK
CA tutti gli effetti, gli oggetti di C1, C2 … (sottoclassi di C) sono compatibili con gli oggetti della classe C
C (in generale, qualcuno in più)Diamo alcune informazioni generali e astratte. Ogni JVM potrebbe realizzare gli oggetti in modo un po’ diverso. Questi elementi sono tuttavia comuni.
Inizia con una intestazione ereditata da Object (16 byte circa), che include
ObjectVia via tutti i campi della classe, a partire da quelli delle superclassi
C è sottoclasse di A…Allora un oggetto di C è simile ad un oggetto di A: ha solo informazioni aggiuntive in fondo, e questo semplifica la sostituibilità!

Personpublic class Person {
private final String name;
private final int id;
public Person(final String name, final int id) {
super();
this.name = name;
this.id = id;
}
public String getName() {
return this.name;
}
public int getId() {
return this.id;
}
public String toString() {
return "P [name=" + this.name + ", id=" + this.id + "]";
}
}
Studentpublic class Student extends Person {
final private int matriculationYear;
public Student(final String name, final int id,
final int matriculationYear) {
super(name, id);
this.matriculationYear = matriculationYear;
}
public int getMatriculationYear() {
return matriculationYear;
}
public String toString() {
return "S [getName()=" + getName() +
", getId()=" + getId() +
", matriculationYear=" + matriculationYear + "]";
}
}
Teacherimport java.util.Arrays;
public class Teacher extends Person {
final private String[] courses;
public Teacher(final String name, final int id,
final String[] courses) {
super(name, id);
this.courses = Arrays.copyOf(courses, courses.length);
}
public String[] getCourses() {
// copia difensiva necessaria a preservare incapsulamento
return Arrays.copyOf(courses, courses.length);
}
public String toString() {
return "T [getName()=" + getName() +
", getId()=" + getId() +
", courses=" + Arrays.toString(courses) + "]";
}
}
UsePersonpublic class UsePerson {
public static void main(String[] args) {
final var people = new Person[]{
new Student("Marco Rossi",334612,2013),
new Student("Gino Bianchi",352001,2013),
new Student("Carlo Verdi",354100,2012),
new Teacher("Mirko Viroli",34121,new String[]{
"OOP","PPS","PC"
})
};
for (final var p: people){
System.out.println(p.getName()+": "+p);
}
}
}
D realizza una interfaccia I, ma non eredita da un’altra classe CCounter può assumere vi sia un metodo increment(); mentre una classe che eredita da LimitCounter può assumere che increment() sia soggetto a un limite di incrementi unitariclass C extends D1, D2, ... { ... }
D1 e D2 avessero proprietà comuni (cf. Triangle Problem e Diamond Problem)
I, piuttosto che renderla una specializzazione di una classe C
interface Counter { ... }
interface MultiCounter extends Counter { ... }
interface BiCounter extends Counter { ... }
interface BiAndMultiCounter extends MultiCounter, BiCounter { ... }
class CounterImpl implements Counter { ... }
class MultiCounterImpl extends CounterImpl implements MultiCounter{ ... }
class BiCounterImpl extends CounterImpl implements BiCounter { ... }
class BiAndMultiCounterImpl extends BiCounterImpl implements BiAndMultiCounter { ... }
BiAndMultiCounterImplBiCounterImpl, si delega via composizione ad un oggetto di MultiCounterImplObjectObject[]
new Object[]{ new SimpleLamp(), new Integer(10) }Object[]Object[]import java.util.Arrays;
/* Tutti gli oggetti possono formare un elenco Object[] */
public class AObject {
public static void main(String[] s) {
final Object[] os = new Object[5];
os[0] = new Object();
os[1] = "stringa";
os[2] = Integer.valueOf(10);
os[3] = new int[] { 10, 20, 30 };
os[4] = new java.util.Date();
printAll(os);
System.out.println(Arrays.toString(os));
System.out.println(Arrays.deepToString(os));
}
public static void printAll(final Object[] array) {
for (final Object o : array) {
System.out.println("Oggetto:" + o.toString());
}
}
}
printAll(), dentro al for public static void printAll(final Object[] array) {
for (final Object o : array) {
System.out.println("Oggetto:" + o.toString());
}
}
o è Objecto varia di volta in volta: Object, String, Integer, …instanceofinstanceof e conversione di tipo/* Everything is an Object, ma quale?? */
public class AObject2 {
public static void main(String[] s) {
final Object[] os = new Object[5];
os[0] = new Object();
os[1] = Integer.valueOf(10);
os[2] = Integer.valueOf(20);
os[3] = new int[] { 10, 20, 30 };
os[4] = Integer.valueOf(30);
printAllAndSum(os);
}
/* Voglio anche stampare la somma degli Integer presenti */
public static void printAllAndSum(final Object[] array) {
int sum = 0;
for (final Object o : array) {
System.out.println("Oggetto:" + o.toString());
if (o instanceof Integer) { // test a runtime
final Integer i = (Integer) o; // (down)cast
sum = sum + i.intValue();
}
}
System.out.println("Somme degli Integer: " + sum);
}
}
instanceof e conversione di tipoData una variabile (o espressione) del tipo statico C può essere necessario capire se sia della sottoclasse D, in tal caso, su tale oggetto si vuole richiamare un metodo specifico della classe D.
instanceof + conversioneinstanceof si verifica se effettivamente sia di tipo DDC x = new java.util.Random().nextInt() > 0 ? new D() : null;
if(x instanceof D d) { /* codice che usa d */ }
instanceof)ClassCastException/* Showing ClassCastException */
public class ShowCCE {
public static void main(String[] as) {
Object o = Integer.valueOf(10);
Integer i = (Integer) o; // OK
String s = (String) o; // ClassCastException
// int i = o.intValue(); // No, intValue() non def.
// String s = (String)i; // No, tipi inconvertibili
}
}
instanceof, conversioni e Personpublic class UsePerson2 {
public static void main(String[] args) {
final Person[] people = new Person[] {
new Student("Marco Rossi", 334612, 2013),
new Student("Gino Bianchi", 352001, 2013),
new Student("Carlo Verdi", 354100, 2012),
new Teacher("Mirko Viroli", 34121,
new String[] { "PO", "FINF-A", "ISAC" }) };
for (final Person p : people) {
if (p instanceof Student) {
final Student s = (Student) p; // Qui non fallisce
System.out.println(s.getName() + " " +
s.getMatriculationYear());
}
}
}
}
Integer i = new Integer(10); // Deprecated in Java 17 (for removal)
i = Integer.valueOf(10); // recommended
Double d = new Double(10.5); // Deprecated in Java 17 (for removal)
d = Double.valueOf(10.5); // recommended
..ossia, ogni valore primitivo può essere “impacchettato” (“boxed”) in un oggetto
Object[]/* Showcase dell'autoboxing */
public class Boxing {
public static void main(String[] s) {
final Object[] os = new Object[5];
os[0] = new Object();
os[1] = 5; // equivale a os[1]=new Integer(5);
os[2] = 10; // equivale a os[2]=new Integer(10);
os[3] = true; // equivale a os[3]=new Boolean(true);
os[4] = 20.5; // equivale a os[4]=new Double(20.5);
final Integer[] is = new Integer[] { 10, 20, 30, 40 };
final int i = is[0] + is[1] + is[2] + is[3];
// equivale a: is[0].intValue()+ is[1].intValue()+..
// non funzionerebbe se 'is' avesse tipo Object[]..
System.out.println("Somma: " + i); // 100
}
}
int i = sum(10, 20, 30, 40, 50, 60, 70);
printAll(10, 20, 3.5, new Object());
Type... argname”void m(int a, float b, Object... argname) { ... }
argname è trattato come un Type[]Typeinstanceof, …public class VarArgs {
// somma un numero variabile di Integer
public static int sum(final Integer... args) {
int sum = 0;
for (int i : args) {
sum = sum + i;
}
return sum;
}
// stampa il contenuto degli argomenti, se meno di 10
public static void printAll(final String start, final Object... args) {
System.out.println(start);
if (args.length < 10) {
for (final Object o : args) {
System.out.println(o);
}
}
}
public static void main(String[] s) {
System.out.println(sum(10, 20, 30, 40, 50, 60, 70, 80));
printAll("inizio", 1, 2, 3.2, true, new int[] { 10 }, new Object());
System.out.format("%d %d\n", 10, 20); // C-like printf
}
}
Familiarizzare con:
danilo.pianini@unibo.itgianluca.aguzzi@unibo.itangelo.filaseta@unibo.itCompiled on: 2025-12-05 — versione stampabile