Last modified: December 29, 2023
Some of the fields, methods, and classes we've used are declared with a public
keyword in front.
What does public
do? Why do we need it? Are there alternatives to public
?
By adding a public
keyword in front, we are declaring that a particular variable, method, or class can be accessed by any other class in any package.
By adding nothing in front, we are declaring that a particular variable, method, or class can be accessed by any other class within the same package.
This means if someone else is importing your code from another package, they cannot access the methods, fields and constructors declared with no access modifier.
When you are first learning to code, you will generally be writing classes that are all in the same package (the default package), so it might appear to you that package-private (no modifier) is the same as public, but when you start making classes in different packages, you will see that having no modifier is not the same as public.
A big disadvantage of putting classes in the default package is that they literally cannot be imported and therefore cannot be used in any other package. This is why you will eventually want to start using packages.
By adding a private
keyword in front, we are declaring that a particular variable, method, or class can only be accessed within the same class.
The protected access modifier indicates that a field or method can be accessed within the same class, within subclasses of the class or within classes in the same package, but cannot be accessed by any other classes. This keyword is typically used when you want subclasses to still be able to directly use or modify a method or field that is otherwise only supposed to be accessed internally or through getters and setters.
Right now, you will primarily use the private access modifier for instance variables because that allows you to control access to them through providing public getters (for read access) and public setters (for write access). By using the private access modifier, you can choose to:
Even if you want public read and write access, by making the access be through methods, you give yourself the option to add code in the setter that limits the values that can be set, performs other actions to update the state of the class in response to the changed value, or call listener methods so other objects can be informed of the change. For example, if you have a setter that changes the String that a Text class should display, it is important that the image representing the Text object be updated to reflect that change.
Examine these classes to see some examples of access modifiers in practice.
Let's say we have two files "Person.java" and "Driver.java", both in the default package (no package is declared):
public class Person {
String name;
public int age;
private String dna;
public Person(String name, int age) {
this.name = name;
this.age = age;
}
private void giveYouUp(){ ... }
private void letYouDown(){ ... }
public void changeDNA(String newDNA){
this.dna = newDNA;
}
}
public class Driver {
public static void main(String[] args){
Person rick = new Person("Rick", 56);
rick.name = "Rick Astley"; // ok because Driver is in the same package as Person
rick.age += 1; // ok because age is public
System.out.println(rick.DNA); // ERROR: you cannot directly read a private variable from another class!
rick.DNA = "abcdefghijklmnop"; // ERROR: you cannot directly modify a private variable from another class!
rick.giveYouUp(); // ERROR: you cannot use a private method from another class! Plus, rick never gives you up.
rick.letYouDown(); // ERROR: you cannot use a private method from another class! Plus, rick never lets you down.
rick.changeDNA("qwertyuiop");
// .changeDNA is ok because .changeDNA is a public method, even though internally it modifies a private variable.
}
}
Now, lets say we make another class Dog, in the k9 package:
package k9;
public class Dog {
public String name;
int age;
public Dog() {
name = "Dog";
age = 0;
}
// A getter for age
public int getAge() {
return age;
}
// A setter for age that only allows age >= 0
public void setAge(int newAge) {
if (newAge >= 0) {
age = newAge;
}
}
// a helper method accessible only in the same package
void doAFlip() { ... }
}
If we wanted to access the Dog class from the Driver class, we would need to import it. Since Dog is in the k9 package, the full name of the class is k9.Dog
.
import k9.Dog;
public class Driver {
public static void main(String[] args){ ... }
public static void testDog(){
Dog d = new Dog(); // create an instance of a Dog
System.out.println(d.name); // Legal because name is a public instance variable in Dog
d.name = "Fido"; // Legal because name is a public instance variable in Dog
System.out.println(d.age); // Illegal because age has no modifier so it is package-private and is only accessible to classes in the k9 package but Driver is not in k9 package
System.out.println(d.getAge()); // Legal because getAge() is public
d.age++; // Illegal because age has no modifier so it is package-private and is only accessible to classes in the k9 package but Driver is not in k9 package
d.doAFlip(); // Illegal because doAFlip() has no modifier so it is package-private and is only accessible to classes in the k9 package but Driver is not in k9 package
d.setAge(5); // Legal because setAge(int) is public
}
}