Learn Java from Scratch: Access modifiers in Java8 min read
Modifier Overview
We have learned about variables and data types in Java, I think now it’s a good time to introduce some concepts about modifier types in Java. Modifier types in Java play an important role that are used to change the meaning of a variable or method, or even class. Modifiers are Java keywords that give the compiler information about the nature of code, data, or classes. In Java, modifiers are categorized into two types:
- Access modifier
- Non-access modifier
In this article, we will first learn about access modifiers. non-access modifiers will be discussed in the next article.
Java Access modifier
Access modifiers in Java control which classes may use data, variables, nested classes, and constructors. There are 4 access modifiers in Java:
- public: the most generous modifier in Java, which is visible anywhere.
- protected: has scope within the package and all subclasses even in the different packages.
- default: has scope only inside the same package.
- private: the most restrictive modifier in Java, has only scope in the class it is declared but other classes can still access private code through the public getter method.
public
The most generous access modifier in Java is public. A class, method, constructor, interface, etc. declared public can be accessed anywhere. Any public method may be overridden by any subclass. An application declares its main() method to be public so that main() can be invoked from any Java runtime environment. For example:
#1: Classes in the same package
public class PublicClass {
public static int squared(int x){
return x * x;
}
}
class Main{
public static void main(String[] args){
System.out.println(PublicClass.squared(5)); // 25;
}
}
So in this example above, we have a class named PublicClass declared as public, which means it is visible and can be accessed anywhere. Then inside this class, we have a static method named squared
which takes one argument and returns its square number also marked as public. Then afterward, we want to test this method by creating a new class Main
, this class contains the main
method to execute this program, inside the main method, we call the square
method of the PublicClass
and give it an argument with a value of 5. Then again because this square
method is public then we can access this method in another class. The result after compiling is 25.
#2: Classes in different packages
Let’s define a public class named TestPublic
in the packageA
:
package packageA;
public class TestPublic {
public int num;
public TestPublic (int n){
num = n;
}
public int getNum(){
return num;
}
}
We simply define a public class, everything in this class also declared as public. Now let’s try to modify the data of this class in a different class of a different package. We create another package named packageB
and one class enclosed by this package called AnotherClass
. This AnotherClass
will modify create a new instance from TestPublic
class and also mutates TestPublic
class field(s):
package packageB;
import packageA.TestPublic;
public class AnotherClass {
public static void main(String[] args) {
TestPublic A = new TestPublic(50);
System.out.println(A.getNum());
A.num = 80;
System.out.println(A.getNum());
}
}
Inner the AnotherClass
we create a new instance of TestPublic
class and pass in to it a value of 50, then we access to the getNum
of this class and display the result. Later, we alter the value of the num
variable of object A
. Here is what we get if we run this code:
50
80
protected
The name protected I think it is a bit misleading. From its sound, you might reckon that protected access is extremely restrictive —perhaps the next closest thing to private access. In fact, protected features are even more accessible than default features–which we will learn right after this section.
Unlike public access modifier, which is applied to almost everything, from interfaces, classes, methods, to variables, etc…Only variables, methods, and constructors may be declared as protected. While declared as protected,
the code is accessible in the same package and subclasses (including the ones in other packages), protected variables and methods allow the class itself to access them, classes inside of the same package to access them, and subclasses of that class in a different package to access them. It’s quite ambiguous for now, let’s take an example to clarify this:
package Books;
public class Book {
public int page = 324;
public String description = "The unforgettable novel of a childhood in a sleepy Southern town and the crisis of conscience that rocked it.";
public double rating = 4.27;
protected void bookTitle() {
System.out.println("To Kill A Mockingbird");
}
}
class BookInfo extends Book {
public static void main(String[] args){
Book aBook = new Book();
aBook.bookTitle(); // works fine, access bookTitle method through inheritence
}
}
class AnotherClass {
public static void main(String[] args){
Book anotherBook = new Book();
anotherBook.bookTitle(); // works fine, because protected access modifier available anywhere within the same package, then we can directly call bookTitle() method through an instance.
}
}
So now pretend we create another package named anotherpackage
and import the Book class in the Books and we want to access the bookTitle()
method in the Book class:
package anotherpackage;
import Books.Book; // import class Book in the Books package.
package anotherpackage;
public class AnotherClass{
public void getTitle() {
Book aBook = new Book();
aBook.bookTitle(); // compiling error
}
}
This code segment above will throw an error because bookTitle()
method in the Book class which is located in Books package has protected access, which means another package cannot involve this method unless we declare a class that inherits the Book class, like this:
package anotherpackage;
import Books.Book;
public class AnotherClass extends Book{
public void getTitle() {
Book anotherBook = new Book();
anotherBook.bookTittle(); // no more error, works fine now!
}
}
As you can see, if you want to access the code with protected access in a different package, we need to inherit the class which contains protected code we want by using the extends
keyword followed by the parent class (we’ll cover more about inheritance and OOP concepts in some next articles.)
default
Default is the name of the access of classes, variables, and methods if you don’t specify an access modifier (it’s also called private-package modifier). This access modifier is special because it doesn’t have an associated keyword. And default access modifier is more restrictive than the protected modifier.
A variable or method declared without any access control modifier is available to any other class in the same package, anything outside that package will not be allowed to access it. For example:
package Aminal;
class Dog{
public void bark() {
System.out.println("Woof woof!");
}
}
And now we have another package, named Akita
and want to access to the Dog class in the Animal package:
package Akita;
import Animal.Dog;
public class Akita {
public void doSomething() {
Dog akita = new Dog(); // compiling error
}
}
Because of class Dog
has the default modifier, then classes in another package cannot access its code. However, it’s ok if the Akita
class in the same package with the Dog class:
package Animal;
public class Akita {
public void doSomething() {
Dog akita = new Dog(); // no problem, works just fine.
}
}
private
The most restrictive access modifier is private, it can be applied for members only. Top-level class or interface never can be declared as private (except the inner class or interface can be declared as private but we will leave it on some more advanced articles). When a member is marked as private, it is only accessible from within the enclosing class. Nothing outside the class can access a private member. Private access is the ideal way to encapsulate the object itself and hides data from the outside world. For example:
class Dog {
private int numOfTail = 1;
private int numOfLegs = 4;
private void bark() {
System.out.println("Woof woof!");
}
}
class Akita {
public void getDogProperties() {
Dog akita = new Dog();
akita.bark(); // compiling error!
}
}
We get a compiling error, even in the class Cat we use keyword extends
to inherit Dog class properties, again, because everything inside Dog class is marked as private, which are just visible in their enclosing brackets and nothing else:
class Dog {
private int numOfTail = 1;
public int numOfLegs = 4;
private void bark() {
System.out.println("Woof woof!");
}
}
class Akita extends Dog {
public void getDogProperties() {
Dog akita = new Dog();
akita.bark(); // still compiling error!
}
}
So we just can access the private variables, methods within their enclosing brackets, e.g the Dog class:
class Dog {
private int numOfTail = 1;
private int numOfLegs = 4;
private void bark() {
System.out.println("Woof woof!");
}
public static void main(String[] args){
Dog dog = new Dog();
System.out.println(dog.numOfLegs);
System.out.println(dog.numOfTail);
dog.bark();
}
}
Output:
4
1
Woof woof!
Summery
Finally, let’s recap the names of access modifiers:
- private — available only inside a class;
- default (also known as package-private) — available for all classes in the same package;
- protected — available for classes in the same package and for subclasses (even subclasses in another package)
- public — available for all classes everywhere.
Access Modifiers | Same Class | Same Package | Subclass | Other packages |
public | Y | Y | Y | Y |
protected | Y | Y | Y | N |
no access modifier (default) | Y | Y | N | N |
private | Y | N | N | N |