Introduzione a Java Jacopo Torrini Dipartimento di Sistemi e Informatica Laboratorio di Tecnologie del Software [email protected] Introduzione ● Il linguaggio Java è un linguaggio di alto livello con le seguenti caratteristiche: ● Semplice ● Object oriented ● Distribuito ● Multithread ● Dinamico (caricamento e linking) ● Architecture neutral (window system, processor) ● Portabile (byte code, standardizzazione tipi di dati) ● Alte performance (JIT compiler) ● Robusto (Strict compile-time and run-time check) ● Sicuro Compilatore ● Sorgente in file di testo .java ● Compilazione con javac e creazione di .class ● Il prodotto è bytecode eseguito da Java VM Esecuzione ● ● ll programma viene lanciato col comando java Lo stesso bytecode può essere eseguito su sistemi differenti Java Platform ● ● Con platform si intende un ambiente hardware o software nel quale un programma viene eseguito La Java platform è un ambiente software composto da 2 componenti: ● Java Virtual Machine (VM) ● Java Application Programming Interface (API) Java API Installazione ● ● ● Per l'esecuzione è necessaria soltanto una JRE (Java Runtime Environment) Per lo sviluppo è necessario scaricare la JDK (Java Development Kit) che contiene tra l'altro la JRE. www.oracle.com - Downloads - Java for Developers – Java Platform (JDK) Hello World ● Aprire un file di testo e scrivere il seguente codice: public class HelloWorld { public static void main( String [] args ) { System.out.println( "Hello world!" ); } } ● Salvare con nome HelloWorld.java ● Con una finestra di terminale digitare: ● ● javac HelloWorld.java Per eseguire digitare ● java HelloWorld Concetti di base ● Oggetto ● Classe ● Ereditarietà ● Interfaccia ● Package Oggetto ● ● Un oggetto nel mondo reale possiede due caratteristiche: ● Stato ● Comportamento Un oggetto software in modo simile: ● ● ● Campi (Memorizzano lo stato dell'oggetto) Metodi (Interazione con lo stato dell'oggetto e comunicazione tra oggetti) Incapsulamento Classe ● ● ● La classe rappresenta la definizione del tipo di dato L'oggetto è l'istanza di una classe. Normalmente vengono create diverse istanze della stessa classe. Ereditarietà ● ● ● Una classe può essere definita estendendo un'altra classe. La nuova classe eredita le proprietà e i metodi di quella estesa. La nuova classe può estendere / modificare il comportamento della classe estesa. Interfaccia ● ● ● ● ● L'interfaccia di un oggetto rappresenta i metodi che l'oggetto stesso espone verso il mondo esterno In Java si può definire un interfaccia tramite la keyword interface e la dichiarazione di un'insieme di metodi senza il body. Una classe che implementa un'interfaccia garantisce al mondo esterno di implementare i metodi definiti nell'interfaccia Classi differenti (di gerarchie differenti) possono implementare la stessa interfaccia (principio di sostituibilità) Una classe può implementare più interfacce Package ● ● ● ● È un namespace che permette di organizzare un set di classi e interfacce correlate È possibile creare classi con lo stesso nome su package differenti Permette un controllo maggiore sull'accesso ai metodi e i campi di un oggetto Il nome del package definisce la struttura delle cartelle dei file sorgente Concetti di base del linguaggio ● Variabili ● Operatori ● Expressions, statements e blocks ● Control flow statements Variabili int cadence = 0; int speed = 0; int gear = 1; ● Instance Variables (Non-Static Fields) ● Class Variables (Static Fields) ● Local Variables ● Parameters Operatori Expressions, statements e blocks ● Expressions: ● Statements: ● ● ● ● ● int cadence = 0; anArray[0] = 100; System.out.println("Element 1 at index 0: " + anArray[0]); int result = 1 + 2; // result is now 3 if(value1 == value2) System.out.println("value1 == value2"); Assegnazione Incremento e decremento (++, -- ) Invocazione metodi Espressioni di creazione oggetti (new) Blocks: class BlockDemo { public static void main(String[] args) { boolean condition = true; if (condition) { // begin block 1 System.out.println("Condition is true."); } // end block one else { // begin block 2 System.out.println("Condition is false."); } // end block 2 } } Control flow statements ● If-then ● If-then-else ● Switch ● While e do-while ● For ● Break ● Continue ● Return Classi public class Bicycle { // the Bicycle class has three fields private int cadence; private int gear; private int speed; // the Bicycle class has one constructor public Bicycle(int startCadence, int startSpeed, int startGear) { gear = startGear; cadence = startCadence; speed = startSpeed; } // the Bicycle class has four methods public void setCadence(int newValue) { cadence = newValue; } public void setGear(int newValue) { gear = newValue; } public void applyBrake(int decrement) { speed -= decrement; } public void speedUp(int increment) { speed += increment; } } Ereditarietà public class MountainBike extends Bicycle { // the MountainBike subclass has one field private int seatHeight; // the MountainBike subclass has one constructor public MountainBike(int startHeight, int startCadence, int startSpeed, int startGear) { super(startCadence, startSpeed, startGear); seatHeight = startHeight; } } // the MountainBike subclass has one method public void setHeight(int newValue) { seatHeight = newValue; } Dichiarazione classe class MyClass extends MySuperClass implements YourInterface1, YourInterface2 { //fields //constructors //method declarations } ● ● La classe deve essere dichiarata in un file col nome uguale a quello della classe (MyClass.java) Per costruttori, metodi e campi si specificano i modificatori di accesso: ● ● ● ● private protected private package (nessun modificatore) Campi (variabili membro) ● Campi (variabili membro) private int a; private String b; private double c = 0.5; ● La dichiarazione è composta da: ● Modificatore di accesso ● Il tipo del campo ● Il nome del campo ● Eventuale inizializzazione del campo Metodi public int doSomething( int par1, String par2 ) throws Exception { ... } ● È composto da: ● Modificatori di accesso ● Tipo del valore di ritorno ● Il nome del metodo (convenzioni) ● La lista dei parametri (eventuali) ● La lista delle eccezioni lanciate (eventuali) ● Il corpo del metodo Signature Questi metodi vengono chiamati instance methods Overloading dei metodi ● ● È possibile utilizzare lo stesso nome per più metodi a patto che abbiano signature differenti Metodi con signature identiche ma tipi di ritorno differenti non sono ammessi public void ... } public void ... } public void ... } public void ... } draw(String s) { draw(int i) { draw(double f) { draw(int i, double f) { Metodi e campi statici ● ● ● Un campo statico è condiviso da tutte le istanze della classe in cui è definito. Viene chiamato class variable. Un metodo statico può accedere alle variabili statiche. Viene chiamato class method. Il metodo o il campo si definiscono tramite la keyword static: ● ● ● static int a = 5; public static void doSomething() { … } Per accedere al metodo (o al campo) si usa la forma: ● NomeClasse.nomeMetodo(...); Passaggio parametri per valore public class PassPrimitiveByValue { public static void main(String[] args) { int x = 3; //invoke passMethod() with x as argument passMethod(x); // print x to see if its value has changed System.out.println("After invoking passMethod, x = " + x); } } ● // change parameter in passMethod() public static void passMethod(int p) { p = 10; } Dopo l'invocazione di passMethod x non varia Passaggio parametri per riferimento public void moveCircle(Circle // code to move origin of circle.setX(circle.getX() circle.setY(circle.getY() } ● circle, int deltaX, int deltaY) { circle to x+deltaX, y+deltaY + deltaX); + deltaY); //code to assign a new reference to circle circle = new Circle(0, 0); Nel metodo chiamante l'oggetto circle risulta modificato Restituzione di un valore public int getArea() { return width * height; } ● ● ● Il return deve contenere il valore del tipo specificato dal metodo. I metodi che non restituiscono valori (definiti come void) non hanno bisogno di alcun return. È possibile comunque utilizzarlo per uscire dal metodo senza bisogno di raggiungere la sua fine. È possibile restituire istanze di oggetti senza problemi Costruttori ● Il costruttore viene invocato alla creazione di un'istanza di una classe ● Nome identico alla classe ● Parametri differenziano più costruttori ● Nessun valore di ritorno ● Se la classe non dichiara alcun costruttore il compilatore ne crea uno senza argomenti (default constructor) public Bicycle() { gear = 1; cadence = 10; speed = 0; } public Bicycle(int startCadence, int startSpeed, int startGear) { gear = startGear; cadence = startCadence; speed = startSpeed; } Creazione istanza oggetto Bicycle yourBike = new Bicycle(); Bicycle myBike = new Bicycle(30, 0, 8); Garbage collector ● ● Java non prevede un esplicito intervento del programmatore per provvedere alla deallocazione degli oggetti. Tale compito è svolto automaticamente dalla JVM, attraverso il processo denominato garbage collection, che si occupa di ricercare nell'heap gli oggetti non più referenziati e deallocarli La keyword this ● Con una variabile: public class Point { public int x = 0; public int y = 0; } ● Nel costruttore: //constructor public Point(int x, int y) { this.x = x; this.y = y; } public class Rectangle { private int x, y; private int width, height; public Rectangle() { this(0, 0, 0, 0); } public Rectangle(int width, int height) { this(0, 0, width, height); } public Rectangle(int x, int y, int width, int height) { this.x = x; this.y = y; this.width = width; this.height = height; } ... Package package com.mycompany.myproject; class MyClass { } ● ● I package hanno una struttura gerarchica che definisce la struttura delle cartelle in cui sono presenti i file sorgente. I file compilati rispettano tale gerarchia Modificatori di accesso ● ● ● ● ● Si applicano alle classi, ai metodi e ai campi public: rende l'elemento accessibile da parte di tutte le classi dell'applicazione protected: rende l'elemento accessibile da parte delle classi del package e delle sottoclassi anche di altri package no modifiers (package): rende l'elemento accessibile da parte delle classi del package private: rende l'elemento accessibile solo alla classe stessa Interfacce public interface Resizable { public void setSize( int width, int height); public class Rectangle implements Resizable { … public void setSize( int width, int height ) { this.width = width; } this.height = height; } ● ● ● Definisce un tipo, come una classe, ma contiene solo la definizione di metodi (senza implementazione). Non possono essere istanziate, solo implementate o estese da altre interfacce. È ammessa l'ereditarietà multipla tra interfacce Ereditarietà ● Overriding dei metodi di istanza ● ● ● ● Un metodo di una classe può essere ridefinito (override) nella sottoclasse. In questo modo è possibile modificare il comportamento di una classe specializzando alcuni dei suoi metodi Il metodo ridefinito ha la stessa signature del metodo della superclasse. Al più può ridefinire il valore di ritorno con una sottoclasse del tipo della superclasse (covariant return type). Il modificatore di accesso devono essere pari o meno restrittivi del modificatore della superclasse Il metodo ridefinito deve (dovrebbe/è consigliato) avere l'annotazione @Override (si vedano le annotation) Ereditarietà ● Override di metodi di classe ● ● Il metodo ridefinito nella sottoclasse nasconde il metodo della superclasse Il metodo invocato dipende quindi dalla classe da cui si invoca: – – Subclass.aMethod(...) Superclass.aMethod(...) Polimorfismo ● ● ● Gli oggetti di una gerarchia di classi possono essere trattati come oggetti della classe di base Tramite l'override dei metodi ogni sottoclasse specializza alcuni comportamenti di ogni classe. I metodi definiti nella superclasse possono essere invocati indipendentemente su ogni istanza di oggetti della gerarchia, ottenendo risultati differenti a seconda del tipo. Esempio di polimorfismo public class Animale { public String getVerso() { return ""; } } public class Cane extends Animale { public String getVerso() { return "bau"; } } public class Gatto extends Animal { public String getVerso() { return "miao"; } } .... public static void main( String [] args ) { Animale [] animali = new Animale[2]; animali[0] = new Gatto(); animali[1] = new Cane(); } for( Aninale a : animali ) System.out.println( a.getVerso() ); La keyword super ● Accedere ai membri della superclasse ● ● super.aMethod(); Chiamare un costruttore esplicito della superclasse (altrimenti viene chiamato quello senza parametri) ● MyClass( int a, int b ) { super(a); this.b = b; } Classi e metodi astratti ● ● ● Un metodo può essere definito astratto se per esso non si vuole dare un'implementazione (come per le interfacce) Una classe con metodi astratti deve essere definita astratta. Una classe astratta non può essere istanziata. Object ● ● La classe Object è la superclasse di ogni oggetto (anche se non viene dichiarato con extends). Definisce un'insieme di metodi utili: ● ● ● ● ● ● ● clone: permette di creare copie dell'oggetto equals: compara due oggetti per valore e non per istanza. Questo metodo dovrebbe essere ridefinito nelle sottoclassi. hashCode: Restituisce la chiave hash associata all'oggetto. Dovrebbe essere ridefinito insieme a equals finalize: chiamato dal garbage collector quando l'oggetto viene finalizzato getClass: Riporta la runtime class dell'oggetto toString: Riporta una rappresentazione stringa dell'oggetto Altri metodi per la sincronizzazione Number e String ● ● Esistono delle classi che rappresentano l'implementazione oggetto dei tipi di dati primitivi (int, double ecc.) Queste classi (Integer, Double ecc) hanno il pregio di avere implementati un'insieme di metodi di utilità. ● Derivano da Number ● La classe String permette la gestione di stringhe di testo. ● È un value object ● Per la manipolazione di stringhe si utilizza StringBuilder Collections ● ● Le API Java contengono un vasto numero di implementazioni di classi per la gestione delle collezioni di valori (alberi binari, hash table, vettori, liste concatenate) Utilizzano i generics. Eccezioni ● ● Un'eccezione è un evento che occorre durante l'esecuzione di un programma e che interrome il normale flusso di esecuzione. Viene lanciata a seguito di un errore ed è rappresentata da un oggetto che contiene le informazioni dell'errore stesso Eccezioni ● ● ● Quando un'eccezione viene lanciata, il sistema di runtime cerca qualcosa che sia in grado di gestire questa eccezione. L'eccezione viene quindi passata a tutti i metodi del call stack. Questo meccanismo si arresta quando viene trovato il blocco di codice che gestisce l'eccezione, l'exception handler Exception propagation ● ● L'exception handler si dice che esegue il catch dell'eccezione. Se nessun metodo definisce l'handler, l'eccezione viene propagata fino al di fuori del main che provoca la terminazione del programma Tipi di eccezioni in Java ● Esistono due tipi di eccezioni: ● Checked exception ● Unchecked exception ● Le prime estendono la classe Exception ● Le seconde estendono la classe RuntimeException ● Per lanciare un'eccezione si utilizza la keyword throw ● ● Per catturare un'eccezione (exception handler) si utilizza il costrutto try – catch – finally Un metodo può dichiarare di lanciare un'eccezione tramite la keyword throws Checked exception ● ● ● Le eccezioni di questo tipo lanciate in un metodo hanno bisogno di un exception handler esplicito (try – catch - finally). In mancanza di esso, il metodo che le lancia deve dichiarare la classe dell'eccezione (throws). Se un metodo lancia una checked exception, a sua volta ha bisogno di un exception handler o deve dichiarare di lanciare l'eccezione Try-catch try { ... } catch( SomeException e ){ ... } finally{ ... } __________________________________________________ try { ... throw new SomeException( “An error occurred” ); ... } catch( SomeException e ) { e.printStackTrace(); } Metodo che lancia un'eccezione public void aMethod( int param ) throws SomeException { ... throw new SomeException(); ... } public void otherMethod() { try { aMethod( 4 ); } catch( SomeException e ) { e.printStackTrace(); } } Unchecked exception ● ● Si utilizzano come le checked exception, ma non è obbligatorio un exception handler o la dichiarazione throws del metodo. Servono per gestire errori di runtime non previsti, quali ● NullPointerException ● IllegalArgumentException ● ArrayIndexOutOfBoundsException Finally ● ● ● ● Il blocco finally deve essere messo in fondo ad un blocco try-catch o ad un blocco try Viene eseguito all'uscita di un metodo, sia che sia stata lanciata un'eccezione o meno. Serve per eseguire operazioni di finalizzazione quali chiusura di uno stream. Si può utilizzare finally senza catch a patto che il metodo dichiari di lanciare l'eccezione. Se sollevata, l'eccezione non viene gestita dal metodo ma viene propagata al suo esterno. Il blocco finally viene comunque regolarmente eseguito. Try-catch-finally. Esempio InputStream in = null; try { in = new FileInputStream (“/path/file”); ... } catch( IOException e ) { e.printStackTrace(); } finally { if( in != null ) in.close(); } Try-finally. Esempio public void aMethod throws IOException{ } InputStream in = null; try { in = new FileInputStream (“/path/file”); ... } finally { if( in != null ) in.close(); }