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 ohjelma kelpaa, mutta ihmiselle se on hankala 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:
public 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:
public class Koe1 { private int x, y; // x ja x() ovat eri nimiä! public void x() {} private static int z; public void m(){ int x, z=5; x = this.x; Koe1.z = z; x(); } } public class Koe2 { private static int x, y; public static void x() {} public 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.
Esimerkki: Ilmentymämuuttujan oletusalkuarvon käyttäminen ennen alkuarvonasetuslausekkeen suorittamista. (Jos ilmentymät alustetaan aina kokonaisuudessaan konstruktorissa - kuten hyvä on - tässä nähtävää ongelmaa ei synny!)
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.
Esimerkki: Luokkamuuttujan oletusalkuarvon käyttäminen ennen alkuarvonasetuslausekkeen suorittamista.
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. // Luokkien näkyvyyttä säädellään samalla tavalla. }Luokasta pääsee käsiksi yliluokan korvattuun metodiin ja peitettyyn kenttään ilmauksella super, elleivät ne ole private. Yliluokan konstruktorin voi oman konstruktorin ensimmäisenä lauseena käynnistää ilmauksella super(...)