Free Java Tutorials >> Table of contents >> Oop Modifiers

1. Visibility Modifiers

Visibility ("Access") Modifiers

Visibility modifiers, also known as access modifiers control whether other classes can use a field or execute a method.

Visibility modifiers can be applied on an entire type (class, interface, abstract class, etc), or they can be individually applied to fields and methods. There are four modifiers: public, private, protected and no modifier. Having no modifier is sometimes called the "default modifier" or "package modifier". Top level types can only be public or default (not private or protected).

public class MyClass {  //"public" being applied to whole class
	int x; //no modifier applied to x, this is called the "default modifier"
	private int y; //private being applied to y
	protected int z; //protected
	public int a; //public
	
	public void example1() {  //public being applied to a method
	}
}

Note that Java allows only one public class per file, and the filename must be equal to the class

Permissions

When the public modifier is applied, then any code can use the class, method, or field. When private is applied, only code within the same class can reference the field or method. Here is a full table of how the modifier affects code that is within the same class, within the same package (folder), within a subclass, or anywhere ("world"):

Modifier Class Package Subclass World
public Y Y Y Y
protected Y Y Y N
no modifier Y Y N N
private Y N N N

Why use visibility modifiers?

Visibility modifiers are useful in organizing code, especially for others to use. When you create a class, you may want a set of fields to be only be modified through a series of methods. These methods could be made public such that other classes (potentially written by other programmers) can execute them. The set of publicly facing methods is often called a system's Application Programming Interface ("API"). However, it is important to note that marking a field as private does not guarantee it cannot be accessed to a determined user. Reflection and memory inspection can be used to inspect private fields, and so the visibility modifiers should not be relied upon for security purposes.

2. The static keyword

Static members belong to the class instead of a specific instance.

Static Fields

By default, fields in a class are instantiated for every instance of the class. For example:

class Thing {
	int x;
}

In the above example, if one created 5 "Thing" objects, then there would be 5 corresponding "x" variables in memory. Each of those x variables could have different values. In addition, x must be accessed through an instance of Thing. Thus, you would need to create a thing = new Thing() object, in order to access thing.x . In contrast, let's look at a static field:

class Thing {
	static int y;
}

A static field has only one instance no matter how many objects of the class are created. Unlike a regular field, a static field is accessed through the class name, not a particular variable. Thus rather than create a thing object, you could access Thing.y = 42 (with a capital T for the class).

Static methods

Like fields, methods can be made static. A static method can be invoked directly from the class name rather than via a particular object:

class Thing {
	static void myFunc() {
		System.out.println("hi!");
	}
}
//You can now execute Thing.myFunc(). 
//There is no need to perform new Thing() in order to run the function

However, since static methods are not associated with any object, they cannot access non-static methods without a reference. They also cannot call non-static methods without a reference:

class Thing {
	int var1;
	void func1(){}
	
	static int var2;
	static void func2(){}
	
	static void myFunc() {
		//Cannot access var1 or func1 without a Thing reference
		//But these are okay:
		var2 = 42;
		func2();
	}
}

The public static void main entrypoint

As you may have noticed, every Java application execution begins with the public static void main(String[] args) method. The Java Runtime Environment (JRE) searches for this method in order to execute an application. Although this main method needs to be within an enclosing class, Java doesn't need to instantiate the class since main is static.

Static nested ("inner") classes

Advanced material:. In rare cases, you may write a class definition within a class definition:

class A {
	int a;
	class B{
		int b;
		void function() {
			//we can access both the enclosing a field
			//in addition to the b field
		}
	}
}
class C{
	int c;
	static class D {
		int d;
		//Cannot access int c from here
	}
}

In the above example, every instance of class B is tied to an enclosing instance of class A. However, with the static inner class, class D cannot access field c without a reference to a C object. The only difference between a static inner class and a regular class written outside of the enclosing class ("C" in this case), is that static inner classes can call private enclosing methods.

3. Overloading

Java, unlike some dynamic languages like Javascript, allows multiple methods with the same name as long as they have a different arrangement of argument types:

public class MyProgram {
	public static void myFunc() {
		System.out.println("Ran first myfunc");
	}
	public static void myFunc(int x) {
		System.out.println("Ran second myfunc");
	}
	//public static void myFunc(int y) // <-- not allowed, even though y is a different name
	//The function argument *types* are what matter
    public static void main(String[] args) {
		myFunc();
		myFunc(5);
		myFunc();
    }
}

In the above example, the myFunc functions are different because one takes an argument of type int, while the other takes no inputs. Java can distinguish between the two when performing function calls, and it infers the function by the list of argument you pass. The function name and set of input arguments that allows Java to distinguish one overloaded method with another is called a function signature.

4. The this keyword

Within an instance (non static) method or a constructor, this refers to the current object. That is the object whose method or constructor is being called. You can then reference fields, methods, or constructors with the this keyword:

Using this with a field:

class Thing {
	int data; //field data
	Thing(int data) { //argument data
		//here, "data" refers to the argument data
		//so you must use "this.data" to refer to the field
		this.data = data;
	}
}

Using this with a Constructor

From within a constructor, you can also use the this keyword to call another constructor in the same class:

class Thing {
	int data; //field data
	Thing(int data) { //argument data
		//here, "data" refers to the argument data
		//so you must use "this.data" to refer to the field
		this.data = data;
	}
	Thing() {  //another constructor
		this(42);  //by default data is always set to 42
	}
}

Previous: Classes

Next: Enums