Java's Access Specifiers

, , …,

In Java code, class and variable and method and constructor declarations can have “access specifiers”, that is one of: private, protected, public. (or none.)

The purpose of access specifiers is to declare which entity can not be accessed from where. Its effect is different when used on any of: {class, class variable, class method, class's constructor}.

Access Specifiers for Class Variables and Class Methods

Below is a table showing the effects of access specifiers for class members (i.e. class variable and class methods).

◆ = Can Access. ◇ = No Access.

Specifierclasssubclasspackageworld
private
protected
public
(none)

For example, if a variable is declared “protected”, then the class itself can access it, its subclass can access it, and any class in the same package can also access it, but otherwise a class cannot access it.

If a class memeber doesn't have any access specifier (the “(none)” row in above), its access level is sometimes known as “package”.

Here's a example.

class P {
    int x = 7;
}
public class A {
    public static void main(String[] args) {
        P p = new P();
        System.out.println(p.x);
    }
}

The code compiles and runs. But, if you add “private” in front of int x, then you'll get a compiler error: “x has private access in P”. This is because when a member variable is private, it can only be accessed within that class.

Access Specifiers for Constructors

Constructors can have the same access specifiers used for variables and methods. Their meaning is the same. For example, when a constructor has “private” declared, then, only the class itself can create a instance of it (kind of like self-reference). Other class in the same package can not create a instance of that class. Nor any subclass of that class. Nor any other class outside of this package.

(Note: constructors in Java are treated differently than methods. Class members are made of 2 things: ① class's variables. ② class's methods. Constructors are NOT considerd a class member.)

Here is a sample code.

class Q {
    public int x;
    private Q (int n) {
        x=n;
        System.out.println("i'm born!");
    }
}

public class A1 {
    public static void main(String[] args) {
        Q q = new Q(3);
        System.out.println(q.x);
    }
}

In the above code, it won't compile because Q's contructor is “private” but it is being created outside of itself. If you delete the “private” keyword in front of Q's constructor, then it compiles.

Constructors in Same Class Can Have Different Access Specifiers

Remember that a class can have more than one constructors, each with different parameters. Each constructor can have different access specifier.

In the following example, the class Q has two constructors, one takes a int argument, the other takes a double argument. One is declared private, while the other with no access specifier (default package level access).

class Q {
    Q (int n) {
        System.out.println("i'm born int!");
    }
    private Q (double d) {
        System.out.println("i'm born double!");
    }
}

public class A2 {
    public static void main(String[] args) {
        Q q1 = new Q(3);
        //Q q2 = new Q(3.3);
    }
}

The fact that there can be constructors with different access specifiers means that in Java, the ability to create a object also depends on which constructor is called to create the object.

Access Specifiers for Classes

For classes, only the “public” access specifier can be used on classes. Basically, Java has this “One Class Per File” paradigm. That is, in every java source code file, only one class in the file is public accessible, and that class must have the same name as the file. (For Example, if the file is xyz.java, then there must be a class named “xyz” in it, and that is the class that's public.) Optionally, the class can be declared with “public” keyword.

(Note: By convention, classes names should start with capital letter. So, a class named “xyz” really should be “Xyz”, with the file named “Xyz.java”.)

If you use any other access specifier on classes, or declare more than one class “public” in a file, the compiler will complain. For detail, see Packages in Java.

The Complexity of Access Specifiers in OOP

The rise of the elaborate access specifiers and their different consequences in Java entities is a complexity out of OOP and its machinery.

Note that the concept of access specifiers such as “private” is not at all related to issues of secrecy or the all-important aspect of cryptography in computing. Compiled Java code can relatively easily be decompiled by compiler specialists.

The concept of access specifiers is arisen out of the perceived need of good engineering practices. More specifically: to provide a way in the language of OOP paradigm to specify and control what items can not be accessed.

This concept and scheme, is not relevant to some 95% of programing in the real world. In writing Java code, you don't have to fret over them. Nothing's gonna happen if you declare everything public. Just about every other programing language are all “public”.

As we've seen above, these “access specifiers” has different meanings when used on different Java entities. When used on class variables or methods, they control where these variable/methods can not be used. When used on constructors, they control where a class can not be instantiated. And when applied to classes, they declare which class cannot be seen. How exactly did these complexities arise?

To find the answer, we realize that all these differences, including the concept of access specifiers, is a immediate consequence of OOP. As we've seen in the article What are OOP's Jargons & Complexities?, classes and methods are really just subroutines and inner-subroutines. And, a instance of a class (objects), are really just variables assigned with such super-subroutines as values. Naturally, when one deals with super-subroutines and execute commands by assigning them to variables and calling inner-subroutines thru these variables, complexity ensues.

Normally, the scoping of variables can be classified as one of dynamic or lexical, or that of global and local. Now with OOP ways, a variable in a class has a scope, while the same variable when the class is instantiated (a objet) is a different scoping issue. Also, the scope concept applicable to variables is now broadened to methods (inner-subroutines) and constructors (specialized inner-subroutines). All in all, the scoping complexities of OOP as applied to different OOP entities is manifested as access specifiers in Java.

blog comments powered by Disqus