Methods and encapsulation
Imagine that any passer-by could walk into your house and rearrange the furniture. Normally this does not happen: a guest rings the doorbell, and the owner decides what to hand over and what to allow. An object needs such a door too. Let's look at a bank account that does not have one yet:
public class Main {
public static void main(String[] args) {
Account acc = new Account();
acc.deposit(100);
System.out.println(acc.balance); // 100
}
}
class Account {
int balance;
void deposit(int amount) {
balance += amount;
}
}Let's go through the program step by step:
- The class
Accountdescribes an account with one field,balance. - The method
depositis declared withoutstatic. You call it through a dot on a particular account:acc.deposit(100). - Inside
deposit, the namebalancemeans the field of the account the method was called on. printlnprints100.
So far everything works. But the field balance is open, and anything can be written into it:
acc.balance = -500;
System.out.println(acc.balance); // -500The account shows minus 500, although nobody took money out of it. The method deposit could check the amount, but the outside code goes around it and writes straight into the field.
An object's methods
Until now, you have written only static methods, and main called them by name. A method without static belongs to the object: it is an action of a particular house, not of the blueprint. You have already called such methods on strings: word.length(). What matters about such a method:
- you call it through an object:
acc.deposit(100); - inside it there is
this, a reference to the object the method was called on; - a field name without
this.means a field of this object:balanceindepositisthis.balance; - two accounts have their own fields, so
a.deposit(100)does not change the accountb.
The word private
Let's close the field to other code. An access modifier is a word before a field or a method that decides which code may reach it. The modifier private opens a field only to the code inside its class: private int balance;. Now the line acc.balance = -500; in main does not compile:
error: balance has private access in AccountThe ban covers reading too: System.out.println(acc.balance) gives the same error. The boundary is the class, not the file: Main and Account sit in one file, Main.java, but Main is another class. The compiler catches the violation, so such a program never gets to run.
A getter and a check
If the field is closed, how do you find out the balance? The class itself opens what is needed, through its own methods:
class Account {
private int balance;
int getBalance() {
return balance;
}
void deposit(int amount) {
if (amount > 0) {
balance += amount;
}
}
}Let's see what changed:
private int balance;makes the field visible only insideAccount.getBalance()returns the value of the field. Such a method is called a getter, and by tradition its name starts withget.depositchecks the amount: a negative or zero deposit does not change the balance.- There is no method that would write any number into
balance, and that is on purpose.
A method that writes a new value into a field is called a setter, and its name starts with set: setOwner(String owner). But a setter that accepts anything in effect opens the field.
This approach is called encapsulation: the fields are closed, and from outside only operations that keep the object's rules are available. The account itself decides which deposit to accept, and it can never go below zero. Interviewers often ask you to explain encapsulation with an example. The account with deposit makes a good answer: the point is not a getter and a setter for every field, but that the object protects its data.
Here the door picture is not exact. Each house has its own door, but private closes a field to other classes, not to other objects. A method of the class Account can read the balance of another account if it gets a reference to it.
Four access levels
Java has four access levels, from the most closed to the most open:
private: only the code inside its own class;- no modifier: the classes of the same package, that is, the same group of classes. All classes of a program in one file sit in one package, which is why any of your code has seen such fields so far;
protected: the same as no modifier, plus subclasses in other packages;public: any code, as with the classMainand the methodmain.
A common interview question: what does a class member without a modifier mean? It is not public: only the classes of its package see it.
Common mistake
An object's method is called through the class name:
Account.deposit(100); // ✗error: non-static method deposit(int) cannot be referenced from a static contextThe program does not compile. deposit changes the balance of a particular account, and Account.deposit(100) does not say which one. Create an object first, then call the method on it: Account acc = new Account();, then acc.deposit(100);.
Key points
- A method without
staticbelongs to the object: you call it through the object, andbalanceinside it is that object's field. privatecloses a field to every other class, even in the same file:acc.balancefrommaindoes not compile.- Encapsulation means closed fields and open operations that keep the object's rules: a getter and a
depositwith a check. - The access levels from closed to open:
private, no modifier (package),protected,public.