Nimien käytettävyydestä eli ns. näkyvyydestä (scope) erilaisissa ohjelmanosissa on ollut puhetta jo monessa yhteydessä. Tässä luvussa kerrataan ja kerätään yhteen Javan tapa hallita nimien näkyvyyttä. (Tässä luvussa ei puututa sisäluokkien näkyvyyskysymyksiin.)
Javan näkyvyydensäätelymääreillä (access control modifiers) säädellään luokkien, kenttien, konstruktoreiden ja metodeiden näkyvyyttä:
Huom: Java-kääntäjä käyttää hyväksi nimen käyttöyhteyttä nimen merkityksen ymmärtämiseen.
Kielessä on mielestäni sallittu liian laaja nimien kuormittaminen:
Perverssi esimerkki teoksesta
Arnold, Gosling: The Java Programming Language, Addison-Wesley,
1996:
class Reuse {
Reuse Reuse(Reuse Reuse) {
Reuse:
for (;;) {
if (Reuse.Reuse(Reuse) == Reuse)
break Reuse;
}
return Reuse;
}
}
Kääntäjälle tuo kelpaa, mutta minä en suostu edes yrittämään
ymmärtää! Tuohon tyyliin nimiä käyttämällä voi varmistaa itselleen
vaikeuksia niin kokeessa kuin elämässäkin!
[Seuraavassa puhutaan vain metodeista vaikka tarkoitetaan sekä metodeita, että konstruktoreita!]
Metodin paikallisten nimien - muuttujien ja muodollisten parametrien - on oltava yksikäsitteisiä. Mutta paikallisten muuttujien käyttöaluetta metodissa voi rajoittaa alilohkoihin, for-lauseeseen ja lohkojen loppuosiin:
void m(int p) { int i=4; // p ja i ovat käytettävissä koko metodissa i += p; { int j=67; // j on käytettävissä vain alilohkossa j -= i; } i += p; for (int a=1; a<7; ++a) { ... // a on käytettävissä vain for-lausessa } int b=77; ... // b on käytettävissä vain metodin loppuosassa }Siis myös alilohkossa määritellyn muutujan nimen on erottava metodin kaikista muista paikallisista nimistä! Toisin sanoen metodin paikallisia nimiä ei voi metodin alilohkoissa peittää. (Katso kuitenkin Lohkot ja muuttujien määrittelylauseet kappaleessa 3.4.)
Paikallisen nimistön lisäksi metodissa voivat olla käytettävissä kaikki metodin oman luokan nimet. Metodi voi paikallisilla nimillään peittää näkyvistä luokan nimiä, mutta tällöinkin luokan nimiin pääsee käsiksi:
class Koe1 { int x, y; // x ja x() ovat eri nimiä! void x() {} static int z; void m(){ int x, z=5; x = this.x; Koe1.z = z; x(); } } class Koe2 { static int x, y; static void x() {} static void m(){ int x,z; x = Koe2.x; x(); } }
Ilmentymämuuttujien alustuslausekkeissa voidaan viitata sekä edeltäviin ilmentymämuuttujiin että kaikkiin luokkamuuttujiin. Kaikkia arvon palauttavia ilmentymämetodeita ja luokkametodeita voidaan kutsua ilmentymämuuttujien alustuslausekkeissa.
Lapsilta kielletty esimerkki (tätä ei tarvitse ymmärtää):
class Alustus {
int x = arvo();
int y = 7;
int arvo() {return y;}
}
class Akoe {
public static void main(String[] args) {
Alustus a = new Alustus();
System.out.println(a.x+" "+a.y);
}
}
Ohjelma tulostaa:
0 7
Luokkamuuttujien (static) alustuslausekkeissa ja staattisissa alustuslohkoissa voidaan viitata edeltäviin luokkamuuttujiin sekä kaikkiin luokkametodeihin, alustuslausekkeissa tietenkin vain arvon palauttaviin luokkametodeihin.
Toinen lapsilta kielletty esimerkki (tätäkään ei tarvitse ymmärtää):
class StaAlustus {
static int x = arvo();
static int y = 7;
static int arvo() {return y;}
public static void main(String[] args) {
System.out.println(x+" "+y);
}
}
Tämäkin ohjelma tulostaa:
0 7
Luokan ja sen piirteiden näkyvyyttä säädellään näkyvyydensäätelymääreillä:
public class Luokka { // tarjolla kaikelle maailmalle private int a; // luokan omaan käyttöön int b; // oman pakkauksen käyttöön protected int c; // pakkauksen ja aliluokkien käyttöön public int d; // koko maailman käyttöön public Luokka() {...} // tällä kaikki saavat konstruoida // ilmentymän luokasta private Luokka(int x) { // tällä vain luokka itse saa ... // konstruoida ilmentymän itsestään } // Metodien näkyvyyttä säädellään samalla tavalla. }Luokasta pääsee käsiksi yliluokan korvattuun tai peitettyyn metodiin tai kenttään ilmauksella super, yliluokan konstruktorin voi oman konstruktorin ensimmäisenä lauseena käynnistää ilmauksella super(...)