Visibilità

Package

In Java si possono manipolare class diverse ma con lo stesso nome usando il meccanismo di package. Per esempio, si può avere una prima implementazione dei punti sviluppata da microsoft:
package microsoft;
class Point {
  Point(int x, int y) {
    ...
  }
  ....
}
e un'altra della sun:
package sun;
class Point {
  Point(int x, int y) {
    ...
  }
  ....
}
Adesso si possono usare i due tipi di Point nello stesso programma:
microsoft.Point pt1 = new microsoft.Point(3,4);
sun.Point pt2 = new sun.Point(4,5);
I package possono essere più strutturati usando i .
package microsoft.geometry;
class Point {
  Point(int x, int y) {
    ...
  }
  ....
}
package sun.geometry;
class Point {
  Point(int x, int y) {
    ...
  }
  ....
}
e adesso abbiamo:
microsoft.geometry.Point pt1 = new microsoft.geometry.Point(3,4);
sun.geometry.Point pt2 = new sun.geometry.Point(4,5);
sun e sun.geometry sono due package diversi. In particolare, un oggetto definito nel package sun.geometry non appartiene al package sun.

una class senza package appartiene al package anonimo.

Import

Utilizzare una class di un package può essere ripetitivo:
class Line {
  sun.geometry.Point pt1,pt2;
  Line (sun.geometry.Point p, sun.geometry.Point q) {
    pt1=p;
    pt2=q;
  }
}
La parola chiave import permette di usarlo di maniera trasparente:
import sun.geometry.Point;
class Line {
  Point pt1,pt2;
  Line (Point p, Point q) {
    pt1=p;
    pt2=q;
  }

}
Si può usare la notazione * per importare tutte le class di un package:
import sun.geometry.*;
class Line {
  Point pt1,pt2;
  Line (Point p, Point q) {
    pt1=p;
    pt2=q;
  }

}

non si può fare import sun.*.*;

Class pubblica

Il comportamento per default è che una class è visibile solo dentro il suo package. Per rendere una class accessibile da tutti bisogna utilizzare la parola chiave public:
package foo;

class A {
  ...
}
public class B {
  ...
}
La class B è pubblica, dunque questo è valido:
package bar;
import foo.*;

class C {
  B x;
}
La class A non è pubblica, dunque questo non è valido:
package bar;
import foo.*;

class C {
  A x;
}
Java di Sun richiede che dentro un'unità di compilazione (un file) ci sia solo una class pubblica.

Campi e metodi

Comportamento per default

Il comportamento per default è che i campi e i metodi sono visibili solo a tutte le class dello stesso package.
package foo;
public class A {
  int x;
}
Questo è valido:
package foo;

class B extends A {
  B(int x) {
    this.x = x;
  }
}
Questo non lo è:
package bar;
import foo.*;

class B extends A {
  B(int x) {
    this.x = x;
  }
}

Public

Per rendere un campo o un metodo accessibile a tutti quelli che possono accedere alla class si usa la parola chiave public. Con:
package foo;

public class A {
  public int x;
}
Adesso, questo va bene:
package bar;
import foo.*;

class B extends A {
  B(int x) {
    this.x = x;
  }
}

Private

Si può rendere un campo visibile solo per la class con la parola chiave private:
package foo;
public class A {
  private int x;
  A(int x) {
    this.x = x;
  }
}
Adesso questo non è valido:
package foo;
public class B extends A {
  B(int x) {
    this.x = x;
  }
}
Questo va bene:
package foo;

class A {
  private int x;
  int method(A a) {
    return a.x;
  }
}

Protected

Si può rendere un campo visibile solo per le class del package e le subclass negli altri package con la parola chiave protected

Con

package foo;

public class A {
  protected int x;
}
Questo va bene:
package bar;
import foo.*;

class B extends A {
  B(int x) {
    this.x = x;
  }
}
Ma questo non va bene:
package bar;
import foo.*;

class B {
  int method(A a) {
    return a.x;
  }
}
Ma questo va bene:
package bar;
import foo.*;

class B extends A {
  B(int x) {
    this.x = x;
  }
  int method (B a) {
    return a.x;
  }
}
Questo non va bene:
package foo;
import bar.*;

class A {
  int method (B a) {
    return a.x;
  }
}
package bar;
import foo.*;

class B extends A {
  protected int x;
}

Subclass

Cosí abbiamo quattro modicatori: private,niente,protected, public. Sono nell'ordine dal più restrittivo al meno restrittivo. Quando si fa un overriding si può anche allargare la visibilità ma non ridurla.

Con:

class A {
  protected int method() {
    return 1;
  }
}
Questo è valido:
class B extends A {
  public int method() {
    return 2;
  }
}
Questo non lo è:
class B extends A {
  private int method() {
    return 2;
  }
}

Subclass e campi

Questo è valido in Java:
class A {
  int x;
}
class B extends A {
  int x;
}
Un oggetto di tipo B risulterà con due campi diversi this.x e ((A)this).x.

Per questo è sempre meglio dichiarare i campi privati e creare metodi per accedervi:

class A {
  private int x;
  void setX(int x) {
    this.x = x ;
  }
  int getX() {
    return x ;
  }
}

Esercizio

E1. Riscrivere Tree, Node, Leaf nel package util in modo tale che solo la class Tree sia visibile.

E2*. Riscrivere List, Cons, Nil dall'esercizio D6 in tale mode che queste classi appartengo al package util e che di fuori del package si possono creare solamente liste ordinate, i.e. liste costruite usando solamente i metodi makeEmpty e add.


Laurent Théry
Last modified: Sun Jun 1 19:53:57 MEST 2003