danilo.pianini@unibo.itgianluca.aguzzi@unibo.itangelo.filaseta@unibo.itCompiled on: 2025-12-05 — versione stampabile
staticstaticjava.lang.System.out: potete usarlo senza avere un oggetto System!
new System().out!Integer.MAX_VALUEInteger.parseInt(String s), Double.parseDouble(String s), etc.static
Classe.metodo(argomenti), e Classe.campo
main dentro una classeIl metodo main non richiede un oggetto per essere invocato
main in quella classemain come metodo statico di una classe (Java 25+)class EntryPoint {
static void main(String[] args) { // Main è un metodo statico della classe EntryPoint
System.out.println("Hello, World!");
}
}
In Java, anche se non obbligatorio, si adotta una convenzione di notazione per distinguere vari elementi del linguaggio
I nomi di classe iniziano in maiuscolo, e ogni parola “interna” al nome usa la maiuscola
PascalCase, no underscore _EnrolledStudent, System, Point3D, Integer, StringI nomi di campi istanza e metodi iniziano in minuscolo, e ogni parola “interna” al nome usa la maiuscola
camelCase, no underscore _firstName, lastName, getName(), parseInt()I nomi di campi static sono interamente in maiuscolo, e ogni parola “interna” al nome è separata da un underscore _
SCREAMING_SNAKE_CASEMAX_VALUE, MIN_GUESS, PIstatic)this si riferisce all’istanza della classe (l’oggetto) che riceve il messaggiostaticX, possono essere visti come metodi e campi dell’unico oggetto “classe X”java.lang.Math contiene solo campi e metodi statici per operazioni matematicheclass Point3D { // dichiarazione classe
double x; // 3 campi
double y;
double z;
void build(double a, double b, double c) {
this.x = a;
this.y = b;
this.z = c;
}
double getModule() {
return this.x * this.x + this.y * this.y + this.z * this.z;
}
static Point3D ZERO = new Point3D(); // 0,0,0
static Point3D max(Point3D[] ps) { // metodo statico
Point3D max = ZERO; // ricerca max
for (Point3D elem : ps) {
if (elem.getModule() > max.getModule()) {
max = elem;
}
}
return max;
}
}
class UsePoint3D {
public static void main(String[] s) {
// creo e inizializzo vari punti
Point3D p1 = new Point3D();
p1.build(10, 20, 30);
Point3D p2 = new Point3D();
p2.build(5, 6, 7);
Point3D p3 = new Point3D();
p3.build(100, 100, 100);
Point3D p4 = Point3D.ZERO; // questo è lo zero
// costruisco l'array
Point3D[] array = new Point3D[] { p1, p2, p3, p4 };
// calcolo il max
Point3D max = Point3D.max(array);
// stampo
System.out.println("Max: " + max.x + "," + max.y + "," + max.z);
}
}
main come metodo staticoNelle lezioni precedenti abbiamo usato la nuova sintassi (Java 25) che permette di scrivere direttamente un blocco main senza dichiarare esplicitamente la classe:
void main(String[] args) {
// codice
}
La sintassi canonica (classica) di Java richiede invece che main sia un metodo statico contenuto in una classe:
class EntryPoint {
static void main(String[] args) {
// codice
}
}
Punti chiave:
main è statico perché ha senso essere invocato senza creare un’istanza: la JVM lo chiama direttamente sulla classe.EntryPoint è solo un nome di esempio: la classe che contiene main può chiamarsi come si vuole, purché la JVM invii l’esecuzione a quel metodo.build è sempre chiamata su un oggetto, ossia su: new Point3D()zero e max sono chiamate sulla classe Point3Dmax è una funzionalità sui Point3D, quindi è naturale includerla nella classe Point3D, ma non è inquadrabile come funzionalità di un singolo oggetto (ognuno darebbe la stessa risposta)zero è trattato come “costante”, quindi non è proprietà di un oggettoPoint3DBis: inizializzazione con ritornoclass Point3DBis { // dichiarazione classe
double x; // 3 campi
double y;
double z;
Point3DBis build(double a, double b, double c) { // build con ritorno
this.x = a;
this.y = b;
this.z = c;
return this;
}
double getModule() {
return this.x * this.x + this.y * this.y + this.z * this.z;
}
static Point3DBis ZERO = new Point3DBis().build(0, 0, 0);
static Point3DBis max(Point3DBis[] ps) { // metodo statico
Point3DBis max = ZERO; // ricerca max
for (Point3DBis elem : ps) {
if (elem.getModule() > max.getModule()) {
max = elem;
}
}
return max;
}
}
Point3DBisclass UsePoint3DBis {
public static void main(String[] s) {
// creo vari punti
Point3DBis p1 = new Point3DBis().build(10, 20, 30);
Point3DBis p2 = new Point3DBis().build(5, 6, 7);
Point3DBis p3 = new Point3DBis().build(100, 100, 100);
Point3DBis p4 = Point3DBis.ZERO; // questo è lo zero
// costruisco l'array
Point3DBis[] array = new Point3DBis[] { p1, p2, p3, p4 };
// calcolo il max
Point3DBis max = Point3DBis.max(array);
// stampo
System.out.println("Max: " + max.x + "," + max.y + "," + max.z);
}
}
buildthisPoint3D// Classe Point3D con solo membri d'istanza (non-static)
class Point3D { // dichiarazione classe
double x; // 3 campi
double y;
double z;
Point3D build(double a, double b, double c) {
this.x = a;
this.y = b;
this.z = c;
return this;
}
double getModule() {
return this.x * this.x + this.y * this.y + this.z * this.z;
}
}
Pointsclass Points { // Modulo con funzionalità per punti
static Point3D zero = new Point3D().build(0, 0, 0);
static Point3D max(Point3D[] ps) { // metodo statico
Point3D max = zero; // ricerca max
for (Point3D elem : ps) {
if (elem.getModule() > max.getModule()) {
max = elem;
}
}
return max;
}
}
Point3D e Pointsclass UsePoint3D {
static void main(String[] s) {
// creo e inizializzo vari punti
Point3D p1 = new Point3D().build(10, 20, 30);
Point3D p2 = new Point3D().build(5, 6, 7);
Point3D p3 = new Point3D().build(100, 100, 100);
Point3D p4 = Points.zero; // questo è lo zero
// costruisco l'array
Point3D[] array = new Point3D[] { p1, p2, p3, p4 };
// calcolo il max
Point3D max = Points.max(array);
// stampo
System.out.println("Max: " + max.x + "," + max.y + "," + max.z);
}
}
newnew T crea un oggetto di tipo T inizializzando tutti i suoi campi al loro valore di default (p.e. $0$ per i numeri), e ne restituisce il riferimentoPoint3D p = new Point3D();
Point3D[] ps = new Point3D[2]; // [null, null] <- sintassi per creare array di oggetti
new si possono quindi passare dei valorinew Point3D()<NomeClasse>(<Tipo1> <arg1>, <Tipo2> <arg2>, ...) {
// codice di inizializzazione
}
public class Point3Dcons { // dichiarazione classe
double x;
double y;
double z;
// costruttore
Point3Dcons(double inx,double iny,double inz){ // nota: assenza di tipo di ritorno
this.x = inx; // metto l'argomento inx in this.x
this.y = iny; // ..
this.z = inz; // ..
}
public static void main(String[] args){
// creo l'oggetto usando il costruttore a tre argomenti
Point3Dcons p = new Point3Dcons(10.0, 20.0, 30.0);
// stampo
System.out.println("p: " + p.x + "," + p.y + "," + p.z);
// costruttore di "default" in questo caso non funziona!
// Point3D p2 = new Point3D(); NO!!
}
}
public class Point3Dcons { // dichiarazione classe
double x;
double y;
double z;
// costruttore
Point3Dcons(double inx,double iny,double inz){ // nota: assenza di tipo di ritorno
this.x = inx; // metto l'argomento inx in this.x
this.y = iny; // ..
this.z = inz; // ..
}
public static void main(String[] args){
// creo l'oggetto usando il costruttore a tre argomenti
Point3Dcons p = new Point3Dcons(10.0, 20.0, 30.0);
// stampo
System.out.println("p: " + p.x + "," + p.y + "," + p.z);
// costruttore di "default" in questo caso non funziona!
// Point3D p2 = new Point3D(); NO!!
}
}
È una prassi comune, ma non una regola (tutt’altro)
import java.util.Calendar;
public class Person { // dichiarazione classe
String name;
int birthYear;
boolean isMarried;
Person(String nome) {
this.name = nome;
this.birthYear = Person.currentYear;
this.isMarried = false;
}
Person(String nome, int annoNascita) {
this.name = nome;
this.birthYear = annoNascita;
this.isMarried = false;
}
Person(String nome, int annoNascita, boolean sposato) {
this.name = nome;
this.birthYear = annoNascita;
this.isMarried = sposato;
}
static int currentYear = Calendar.getInstance().get(Calendar.YEAR);
}
public class UsePerson {
public static void main(String[] s) {
// Person p1 = new Person(); NO!!
Person p2 = new Person("Mario Rossi");
Person p3 = new Person("Gino Bianchi", 1979);
Person p4 = new Person("Carlo Verdi", 1971, true);
Person[] persone = new Person[]{ p2, p3, p4 };
for(int i=0; i < persone.length; i++){
System.out.println(persone[i].name + ", nato/a nel " + persone[i].birthYear +
(persone[i].isMarried ? "" : ", non") + " è sposato/a.");
}
}
}
newthis punta all’oggetto creato)new restituisce il riferimento thisthis(..)import java.util.Calendar;
class Person2 { // dichiarazione classe
String name;
int birthYear;
boolean isMarried;
Person2(String nome, int yearOfBirth, boolean isMarried) { // costruttore completo
this.name = nome;
this.birthYear = yearOfBirth;
this.isMarried = isMarried;
}
Person2(String name, int birthYear) { // richiama costruttore a 3 arg..
this(name, birthYear, false);
}
Person2(String name) {
this(name, Person2.CURRENT_YEAR); // richiama costruttore a 2 arg..
}
static int CURRENT_YEAR = Calendar.getInstance().get(Calendar.YEAR);
}
+) e overloading costruttoriData una new, quale costruttore richiamerà? (JLS 15.12)
class ExampleOverloading {
static int m(double a, int b) { return 1; }
static int m(int a, double b) { return 2; }
static int m2(double a, double b) { return 1; }
static int m2(int a, int b) { return 2; }
public static void main(String[] s) {
// System.out.println(""+m(1, 1)); // ERROR: reference to m is AMBIGUOUS
// System.out.println(""+m(1.5, 1.5)); // ERROR: no suitable method found for m(Double,Double)
System.out.println("" + m(1.5, 1));
System.out.println("" + m((float)1, 1));
System.out.println("" + m(1, 1.5));
System.out.println("" + m2(1.5, 1.5)); // 1
System.out.println("" + m2(1, 1)); // 2
}
}
n1.n2....nj (p.e. java.lang).java siano organizzati in directory che rispecchiano la struttura del package
n1/n2/Foo.java per la classe Foo del package n1.n2.class
: su Linux, ; su Windows) in cui cercare i package-cp di javac e java o con la variabile d’ambiente CLASSPATH.).java) deve specificare il suo packagepackage pname;new o come tipo) specificando anche il package (p.e. new java.util.Date())import java.util.*; importa tutte le classi di java.utilimport java.util.Date; importa la sola java.util.Datejavac.javapublic e privatepublic – visibile da tutte le classipublicprivate – visibile solo nella classe correnteprivatepublic.javapublic/private può consentire di gestire a piacimento il concetto di information hiding
main classico di Java (Java 24 e precedenti)Il metodo main ha le seguenti caratteristiche:
staticpublicmain come metodo statico e pubblico di una classeclass EntryPoint {
public static void main(String[] args) { // Main è un metodo statico della classe EntryPoint
System.out.println("Hello, World!");
}
}
Se usate una versione di Java precedente alla 25, dovete sempre usare questa sintassi.
finalfinal = non modificabilepublic static final int CONST=10;public, si ha la garanzia che nessuno le modifichipublic class MagicExample {
// Put 100 into a constant and give it a name!!
private static final int SIZE = 100;
public static void main(String[] s) {
double[] array = new double[SIZE];
double sum = 0;
for (int i = 0; i < SIZE; i++) {
// Assegno un numero random
array[i] = Math.random();
sum = sum + array[i];
}
System.out.println("Somma " + sum);
}
}
GuessMyNumberApp: un esempio completoimport java.util.Random;
public class GuessMyNumberApp {
public static final int ATTEMPTS = 10;
public static final int MAX_GUESS = 100;
public static final int MIN_GUESS = 1;
public static void main(String[] args) {
int number = new Random().nextInt(MAX_GUESS - MIN_GUESS) + MIN_GUESS;
for (int i = 1; i <= ATTEMPTS; i++){
System.out.println("Attempt no. "+i);
System.out.println("Insert your guess.. ");
int guess = Integer.parseInt(System.console().readLine());
if (guess == number){
System.out.println("You won!!");
return;
} else if (guess > number){
System.out.println("Your guess is greater..");
} else {
System.out.println("Your guess is lower..");
}
}
System.out.println("Sorry, you lost!");
}
}
new Random().nextInt(MAX_GUESS - MIN_GUESS) + MIN_GUESSnextInt(n) genera numero tra 0 e n-1MIN_GUESS per ottenere l’intervallo desideratoSystem.console().readLine() legge una riga da consoleInteger.parseInt() converte la stringa in interonewmalloc del Cnew chiama il gestore della memoria, che alloca lo spazio necessariofree del C) senza che il programmatore debba occuparsenepublic class GC {
private static long size = 1000;
public static void main(String[] s) {
// Runtime dà info sull'esecuzione
Runtime r = Runtime.getRuntime();
// Creo oggetti all'infinito
for (long l = 0; true; l++) {
new Object();
// Stampo solo ogni tanto
if (l % size == 0) {
System.out.print("Objs (*10^6): " + l / 1000000);
System.out.println(" Freemem (MB):" + (r.freeMemory() >> 20));
}
// La memoria libera si vedrà calare lentamente
// e poi riprendersi di colpo, ciclicamente
}
}
}
GuessMyNumberGuessMyNumberGame: la classe principale che gestisce il flusso del gioco
play(): contiene il ciclo di giocoNumberPicker: una classe che contiene le logiche per generare numeri casuali
pickNumber(int min, int max): genera un numero casuale nell’intervallo specificatoIOManager: una classe che gestisce l’input e l’output
readIntInRange(int min, int max): legge il tentativo del giocatoreprintLine(String message): stampa un messaggio sulla consoleGameConfigQuesta classe non era necessaria, ma aiuta a raggruppare le costanti di configurazione del gioco.
public class GameConfig {
private final int attempts;
private final int minGuesses;
private final int maxGuesses;
public GameConfig(int attempts, int minGuesses, int maxGuesses) {
this.attempts = attempts;
this.minGuesses = minGuesses;
this.maxGuesses = maxGuesses;
}
public int getAttempts() {
return this.attempts;
}
public int getMinGuesses() {
return this.minGuesses;
}
public int getMaxGuesses() {
return this.maxGuesses;
}
}
NumberPickerpublic class NumberPicker {
private final Random random;
public NumberPicker() {
random = new Random();
}
public NumberPicker(int seed) {
random = new Random(seed);
}
public int pickNumber(int minInclusive, int maxExclusive) {
return random.nextInt((maxExclusive - minInclusive) + 1) + minInclusive;
}
}
IOManagerimport java.util.Scanner;
public class IOManager {
private final Scanner scanner;
public IOManager() {
this.scanner = new Scanner(System.in);
}
public void printLine(String text) {
System.out.println(text);
}
public int readIntInRange(int min, int max) {
while (true) {
String line = scanner.nextLine();
int value = Integer.parseInt(line.trim());
if (value < min || value > max) {
System.out.println("Please enter a number between " + min + " and " + max + ".");
} else {
return value;
}
}
}
}
GuessMyNumberGamepublic class GuessMyNumberGame {
private final GameConfig config;
private final NumberPicker numberPicker;
private final IOManager io;
public GuessMyNumberGame(GameConfig config, NumberPicker numberPicker, IOManager io) {
this.config = config;
this.numberPicker = numberPicker;
this.io = io;
}
public void play() {
int secret = numberPicker.pickNumber(config.getMinGuesses(), config.getMaxGuesses());
for (int attempt = 1; attempt <= config.getAttempts(); attempt++) {
io.printLine("Attempt no. " + attempt);
io.printLine("Insert your guess (" + config.getMinGuesses() + "–" + config.getMaxGuesses() + "):");
int guess = io.readIntInRange(config.getMinGuesses(), config.getMaxGuesses());
if (guess == secret) {
io.printLine("You won!!");
return;
}
if (guess > secret) {
io.printLine("Your guess is greater..");
} else {
io.printLine("Your guess is lower..");
}
}
io.printLine("Sorry, you lost!");
}
}
mainimport it.unibo.lifecycle.modeling.IOManager;
import it.unibo.lifecycle.modeling.GameConfig;
import it.unibo.lifecycle.modeling.NumberPicker;
void main() {
GameConfig config = new GameConfig(10, 1, 100);
NumberPicker numberPicker = new NumberPicker();
IOManager consoleManager = new IOManager();
GuessMyNumberGame game = new GuessMyNumberGame(config, numberPicker, consoleManager);
game.play();
}
IOManager va modificata.main: il main si limita a inizializzare e avviare il gioco, lasciando la logica nelle classi dedicate per un flusso principale chiaro e intuitivo.danilo.pianini@unibo.itgianluca.aguzzi@unibo.itangelo.filaseta@unibo.itCompiled on: 2025-12-05 — versione stampabile