Modifiers

You have already come across public modifier used for class definitions, methods and variables. In this lesson you will learn on the different types of access modifiers that are available in Java and their significance.

private

private modifier is the most restrictive of all the accessibility modifiers. private modifier is heavily used for declaring variables and methods. While private modifier cannot be used for a top level class, it can used for defining nested classes.

As the name suggests, anything declared private is only accessible by the class in which it is declared. Not even a sub class of that class can access a private member variable.

private variables

When you declare a variable private, the variable can be initialized or modified by only statements present in the same class. When you follow the principles of encapsulation, you declare all variables private. And the variables are given individual methods which will have public accessibility and hence can be used by other classes to set or modify the variable values.

Here is an example:

class Student{

    private String name;

    public String getFirstName(){
        return this.name;
    }

    public void setFirstName(String name){
        this.name= name;
    }
}

public class School{

    public static void main(String[] args){
        Student student = new Student();
        student.setFirstName("John");
    }
}

In the above example you see two classes; Student and School. Student class has a private variable name which is given a public accessor methods for setting and getting its values. In the School class's main method, Student object is instantiated and its name is set through the public access methods.

In the above example, if you remove the private modifier for the variable, then you can directly set the variable value in the main method instead of using its access methods.

class Student{

    String name;

    public String getFirstName(){
        return this.name;
    }

    public void setFirstName(String name){
        this.name= name;
    }
}

public class School{

    public static void main(String[] args){
        Student student = new Student();
        student.name("John");
    }
}

The above way of directly setting the value of the variable is not considered a good practice. The reason being, a program may set an invalid value to the variable and there is nothing you can do about it. For example, suppose the user sets his/her name with numbers for name, then it is not valid value for first name of any person. when you encounter an invalid value, you would like to tell the user to input the correct value. You can do so if you were setting the value through setter method. Here is the revised example with validation:

class School{

    public static void main(String[] args){
        Student student = new Student();
        student.setFirstName("123");
    }
}

class Student{

    private String name;

    public String getFirstName(){
        return this.name;
    }

    public void setFirstName(String name){

        try {  
            double d = Double.parseDouble(name);
            throw new IllegalArgumentException("firstname cannot be numeric");
          }  catch(NumberFormatException nfe)  {  
            this.name= name;
            System.out.println("firstname is valid");
          }  
    }
}

Notice that in the above code, if the given input is a valid string, then it falls into the exception block and then you set the name variable to the value that is given. If the given input is a numeric then you create and throw IllegalArgumentException.

Exercise: Change the value of name from '123' to some alpha character and see the output.

private methods

Just like private variables, private methods cannot be accessed by other classes including its own children. The method can be accessed only by other members of its own class.

class ChildClass extends SuperClass{

    public static void main(String[] args){
        ChildClass childClass = new ChildClass();
        childClass.displayTimeinMillis();
    }
}

class SuperClass{

    private void displayTimeinMillis(){
        System.out.println(System.currentTimeMillis());
    }

    private void anotherMethod(){
        this.displayTimeinMillis();
    }
}

You will get compilation error when you try to write the above code. Now remove the private keyword on the displayTimeInMillis method and see it work!

In a similar way you can declare a private nested class, in which case, the nested class can be accessed by members of the same class and not any other class. From now on member of a class means the non static variables, methods and even the nested classes declared within the class.

default - package

When no modifier is specified, then the members get default accessibility (a.k.a package access). In this case all the variables or methods which have default accessibility can be accessed by other classes of the same package and not by classes which belong to other packages.

package com.mbcc.b;
import com.mbcc.a.SuperClass;

public class ChildClass extends SuperClass{

    public static void main(String[] args){
        ChildClass childClass = new ChildClass();
        childClass.displayTimeinMillis();

        SuperClass superClass = new SuperClass();
        superClass.displayTimeinMillis();
    }
}

package com.mbcc.a;
class SuperClass{

     protected void displayTimeinMillis(){
        System.out.println(System.currentTimeMillis());
    }

}

package com.mbcc.a;

public class AnotherClass {

    public static void main(String[] args) {
        SuperClass superClass = new SuperClass();
        superClass.displayTimeinMillis();
    }

}

To see this working, create two packages 'com.mbcc.a' and 'com.mbcc.b' and create SuperClass, ChildClass, AnotherClass as shown in the code. You will see compilation errors in ChildClass when you try to access displayTimeinMillis method from either the ChildClas or the Superclass.

protected

When you declare a member protected in any class, then all classes in the package containing the class and all the subclasses of the class in any package can access the protected member.

To see this working, change the modifier to protected for displayTimeinMillis method in SuperClass in the above program. You will now see that ChildClass can access displayTimeinMillis method of the Superclass. However the SuperClass which is instantiated in the ChildClass is still unable to access this method. This is really interesting to note that the even though you are instantiating the SuperClass in the ChildClass, since you are directly accessing the protected member of the SuperClass's method in the ChildClass, it is not visible.

public

When you declare a member public then there is no restricted of any sort for any of the classes. Any class from any package, whether it is a subclass or not will be able to access public accessors. If you now change the accessor of displayTimeinMillis to public then all the compilation errors vanish.

static

So far you are mostly dealing with instance methods and variables except for the main method which was declared static. You add a prefix of static when you want to differentiate from instance members.

static variables

When you declare a variable static in a class, then you only have one copy of that variable in memory for any number of objects that might be created with that class. This is contrast to the instance variables, in which case, there is an individual copy of that variable for every single object that was created. Let us take an example:

class Student{

    static int numberOfStudents;

    private String name;

    public String getFirstName(){
        return this.name;
    }

    public void setFirstName(String name){
        this.name= name;
    }

    public int getNumberOfStudents(){
        return numberOfStudents;
    }

    public Student(){
        numberOfStudents++;
    }

    public static void main(String[] args) {
        Student student1 = new Student();
        student1.setFirstName("John");
        System.out.println(student1.getNumberOfStudents());
        Student student2 = new Student();
        student2.setFirstName("Jane");
        System.out.println(student2.getNumberOfStudents());
    }
}

In the above example, you see that the variable name is an instance variable as it does not contain static modifier. However variable numberOfStudents is not an instance variable as it contains the keyword static as its modifier. It also makes sense to make the firsName as an instance as every object (instance) has to keep its own value to distinguish individual students.

In this example you also see a no argument constructor for Student class, which increments the value of numberOfStudents. So what is going on here? When ever a Student object is instantiated with the new keyword, the value of the static variable, numberOfStudents is incremented by 1. While every instance should keep a separate value of its own to distinguish the value of name across instances, you do not need to keep a separate value for every instance when it comes to tracking the number of student objects created. You only need one value across all the instances. When you have scenarios of this sort, you declare a static variable. A static variable is also called a class variable as it belongs to the class and not to any instance although every instance can access the class variable.

Another Example

Now let us take another example of instance and static variables. The below picture depicts code in which two instances of Customer are created and the name of the Customer object is initialized with values "John" and "Jane". This class also has a static variable customerCount. Notice you have two copies of name variable; one each for each of the objects instantiated and you only have one copy of the static variable which belongs to the class. However both the object instances can access the static variable and make changes to its value. Even though the instances can access a static variable though the instance identifier, it is recommended to use the class name instead. Although in this example we are accessing the static variable using the instance to help understand the concept of static variables, it is recommended to access static variables though the class name and hence both customer1.customerCount++ and customer2.customerCount++ should be replace with Customer.customerCount++.

image alt text

static methods

Just like static variables, static methods also belong to the class. However there is no concept of having a separate copy of the method in case of methods though. When you declare a method static, you do not need to instantiate an object to access the static method of the class. You can directly invoke it using the class name. In the above example, method getNumberOfStudents can be declared static. The revised program would be:

class Student{

    static int numberOfStudents;

    private String name;

    public String getFirstName(){
        return this.name;
    }

    public void setFirstName(String name){
        this.name= name;
    }

    public static int getNumberOfStudents(){
        return numberOfStudents;
    }

    public Student(){
        numberOfStudents++;
    }

    public static void main(String[] args) {
        Student student1 = new Student();
        student1.setFirstName("John");
        System.out.println(Student.getNumberOfStudents());
        Student student2 = new Student();
        student2.setFirstName("Jane");
        System.out.println(Student.getNumberOfStudents());
    }
}

Notice that you do not need the instance reference to invoke getNumberOfStudents method in the System.out.println statements.

Points to remember!

  • You cannot invoke an instance member from a static member. If you think through, it makes perfect sense! A static member exists without an instance, hence referencing an instance member from static member becomes illegal.
  • A static method can invoke another static method
  • If you reference a static member from an instance reference, compiler shows you warning but you can still access it
  • Since static variables are kept in one single memory location, any instance can overwrite the static value set by another instance.

results matching ""

    No results matching ""