DAIS Univ. Ca' Foscari Venezia Programmazione ad oggetti Samuel Rota Bulò
Classi astratte Le classi astratte sono un ibrido tra le classi concrete e le interfacce. Hanno le stesse caratteristiche di una classe concreta con 2 differenze principali: possono contenere metodi astratti, di cui si specifica solo la firma e saranno le sottoclassi che eventualmente forniranno un'implementazione non possono essere istanziati oggetti di una classe astratta direttamente Una classe astratta, sebbene non sia istanziabile, può avere costruttori invocabili dalle eventuali sue sottoclassi. public abstract class NomeClasse //campi //costruttori //metodi con implementazione //metodi astratti
Metodi astratti Un metodo viene dichiarato astratto aggiungendo la keyword abstract. public abstract nomemetodo(tipo nomeparam, tipo nomeparam, ); Un metodo astratto non fornisce l'implementazione del metodo. Una sottoclasse che estende una classe astratta può fare l'overriding di un metodo astratto per fornirne l'implementazione. Se non lo fa dovrà essere definita a sua volta classe astratta. Una classe astratta può non avere metodi astratti ma, essendo dichiarata astratta, non può comunque essere istanziata.
public abstract class AccountTransaction{ private BankAccount bacc; Esempio public AccountTransaction(BankAccount bacc){ this.bacc=bacc; public BankAccount getbankaccount(){ return bacc; public abstract void esegui(); //metodo astratto public class Prelievo extends AccountTransaction{ private double amount; public Prelievo(BankAccount bacc,double amount){ super(bacc); this.amount=amount; public void esegui(){ getbankaccount().withdraw(amount);
Metodi e classi final Aggiungendo ad un metodo la keyword final impediamo l'overriding del metodo in una sottoclasse. Se aggiungiamo la keyword final alla dichiarazione di classe questa non sarà estendibile da altre classi. Motivazioni: efficienza: metodi final hanno dispatch statico e quindi la virtual machine non ha l'overhead della ricerca del metodo da invocare a runtime. sicurezza: impediamo che qualcuno possa by-passare un check di controllo estendendo la classe.
Modalità di accesso Java ha 4 livelli di accesso agli elementi di una classe: public: accessibile dai metodi di qualunque classe private: accessibile dai metodi della stessa classe protected: accessibile dai metodi di una sottoclasse package (default): accessibile dai metodi di tutte le classi dello stesso package. public abstract class AccountTransaction{ private BankAccount bacc; protected AccountTransaction(BankAccount bacc){ this.bacc=bacc; protected BankAccount getbankaccount(){ return bacc; public abstract void esegui(); //metodo astratto
La classe Object Tutte le classe che non estendono esplicitamente una classe estendono la classe Object. La classe Object definisce alcuni metodi tra cui: String tostring() serve per descrivere l'oggetto con una stringa in Object ritorna il nome della classe + hashcode dell'oggetto boolean equals(object anotherobject) serve per confrontare due oggetti in Object ha la stessa semantica di == (confronto dei riferimenti) Object clone() effetua una copia fisica dell'oggetto Spesso questi metodi sono ridefiniti public class BankAccount{... public String tostring(){ return BankAccount[balance= +balance+ ] ;
equals public class Rectangle{ boolean equals(object anotherrectangle){ if(anotherrectangle!=null && anotherrectangle instanceof Rectangle) { Rectangle r=(rectangle) anotherrectangle; return width==r.width && height==r.height && x==r.x && y==r.y; return false;
clone Quando assegnamo riferimenti effettuiamo una copia dei riferimenti ma non degli oggetti Il metodo clone ritorna un nuovo oggetto i cui campi sono una copia dei campi dell'oggetto su cui clone è invocato. Attenzione: la clonazione non avviene ricorsivamente su eventuali campi riferimento ad oggetto. Se vogliamo creare una copia degli oggetti a cui dei campi riferiscono dobbiamo ridefinire il metodo clone. Il metodo clone è protected per proibirne l'invocazione se non è stato ridefinito esplicitamente. Il metodo clone di Object controlla che this implementi l'interfaccia Clonable. In caso contrario, lancia un'eccezione. Clone ritorna un Object che andrà opportunamente convertito previo casting.
Packages
Packages Insieme di classi e interfacce in relazione Le classi appartenenti ad un package hanno come prima istruzione la direttiva: package nomepackage; Può esserci una sola direttiva package per file sorgente. Classi che non dichiarano il package di appartenenza vengono incluse in un package anonimo. è buona norma assegnare tutte le classi ad un package, evitando il package anonimo.
Packages Package java.lang java.util java.io java.awt java.applet java.net java.sql java.swing Finalità Supporto al linguaggio Utilità Input/Output Interfacce utente AWT Applets Networking Database Interfaccia utente Swing......
Accesso ai package Per accedere alle classi di un package utilizziamo il nome qualificato java.util.scanner in = new java.util.scanner(system.in); con la direttiva import possiamo evitare l'uso verboso del nome qualificato: import java.util.scanner;... Scanner in = new Scanner(System.in); possiamo importare in un colpo tutte le classi di un package (ma non dei sottopackage) import java.util.*; possiamo importare anche costanti e metodi statici con la keyword import static import static java.lang.math.pi; import static java.lang.math.*;
Nomi di package Packages sono utili anche come namespaces per evitare conflitti di nomi (di classi/interfacce) per es: java.util.timer e javax.swing.timer I nomi dei package devono essere univoci convenzione: utlizzare i prefissi dei domini internet o degli indirizzi email (in ordine inverso) es: it.unive.dais Il nome di un package deve essere consistente con i path della directory che lo contiene it.unive.dais deve essere localizzato in <base dir>/it/unive/dais CLASSPATH: definisce le directory base o gli archivi JAR in cui localizzare i packages spesso sono usate due directory distinte per sorgenti e compilati
Classi annidate
Classi annidate Una classe può essere dichiarata all'interno di un'altra classe (classe annidata) Una classe annidata è riferibile da qualunque punto della classe in cui è dichiarata e in particolari casi anche esternamente Può essere dichiarata come private, public, protected static, non static Quando usarle: se è utile solo per la classe in cui è dichiarata per aumentare l'incapsulamento per rendere il codice più leggibile a manutenibile
Classi annidate class OuterClass{... class NestedClass{... Modalità di accesso: private: sono visibili solo per la classe in cui è dichiarata protected: visibili solo dalle sottoclassi della classe in cui è dichiarata public: visibili anche all'esterno package: visibile dalle classi nello stesso package della classe in cui è dichiarata
Classi annidate: statiche Classi annidate statiche: possono accedere ai metodi e campi statici della classe in cui sono dichiarate non possono accedere a metodi e variabili di istanza esternamente possiamo accedere alla classe statica annidata usando il nome della classe che la include: OuterClass.StaticNestedClass public class OuterClass{... public static class StaticNestedClass{... OuterClass.StaticNestedClass nestedobject=new OuterClass.StaticNestedClass();
Classi interne public class OuterClass{... public class InnerClass{... OuterClass outerobject=new OuterClass(); OuterClass.InnerClass innerobject=outerobject.new InnerClass(); Classi annidate non-statiche (o interne): ogni istanza della classe interna è legata ad un'istanza della classe che la include OuterClass.this: riferimento dell'istanza della classe esterna a cui l'istanza della classe interna è legata dai metodi della classe interna possiamo accedere a metodi e campi della classe in cui sono dichiarate (anche d'istanza)
Esempio public class IntList{ private int[] elements; private int size; public IntList(int maxsize){ elements=new int[maxsize]; public void add(int i){elements[size++]=i; public ListIterator iterator(){return new ListIterator(); public class ListIterator{ private int pos; public boolean hasnext(){ return pos<size; public int next(){ int i=elements[pos++]; return i;
Classi interne locali Una classe locale è una classe che viene dichiarata all'interno di un metodo Una classe locale può essere riferita solo nel corpo del metodo in cui è dichiarata Possiamo riferire a: campi e metodi della classe esterna variabili locali costanti (final) Se il metodo in cui è inserita è statico, allora potremo accedere solo a campi e metodi statici della classe esterna. Una classe locale non può avere metodi, o campi non costanti, statici. Può avere costanti statiche. Una classe locale non può essere: private, public, protected e static.
Classi locali anonime Consentono di creare una classe al volo per istanziare un singolo oggetto. Una classe anonima viene creata estendendo una classe già esistente o fornendo l'implementazione di un'interfaccia. A differenza delle dichiarazioni di classe viste finora, sono create all'interno di un'espressione. Quando usarle: la classe ha un corpo corto è necessaria solo un'istanza della classe la classe viene utilizzata immediatamente dopo la sua definizione il nome della classe non rende il codice più leggibile new classname(param1,...,paramn){ class-body oppure new interface-name(){class-body
Esempio public interface ListIterator{ boolean hasnext(); int next(); public class IntList{ private int[] elements; private int size; public IntList(int maxsize){ elements=new int[maxsize]; public void add(int i){elements[size++]=i; public ListIterator iterator(){ return new ListIterator(){ private int pos; public boolean hasnext(){ return pos<size; public int next(){ int i=elements[pos++]; return i;