Introduzione a Java Jacopo Torrini Dipartimento di Sistemi e Informatica Laboratorio di Tecnologie del Software torrini@dsi.unifi.it
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: Blocks: Assegnazione Incremento e decremento (++, -- ) Invocazione metodi Espressioni di creazione oggetti (new) 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"); 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 draw(string s) {... public void draw(int i) {... public void draw(double f) {... public void 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); x); // print x to see if its value has changed System.out.println("After invoking passmethod, 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 circle, int deltax, int deltay) { // code to move origin of circle to x+deltax, y+deltay circle.setx(circle.getx() + deltax); circle.sety(circle.gety() + 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: Nel costruttore: public class Point { public int x = 0; public int y = 0; //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();