Access, Encapsulation, & Scope
The public
Keyword
The public
and private
keywords are very important within Java. These keywords are defining what parts of our code have access to other parts of our code.
We can define the access of many different parts of our code including instance variables, methods, constructors, and even a class itself. If we choose to declare these as public
this means that any part of our code can interact with them - even if that code is in a different class!
The way we declare something to be public
is to use the public
keyword in the declaration statement. In the code block belowm, we have a public class, constructor, instance variables, and method. Notice the five different uses of public
:
1 2 3 4 5 6 7 8 9 10 11 12 13 |
|
Dog
is public, any other class can access anything about a Dog
. For example, let's say there was a DogSchool
class. Any method of the DogSchool
class could make a new Dog
using the public
Dog
constructor, directly access that Dog
's instance variables, and directly use that Dog
's methods:1 2 3 4 5 6 7 |
|
DogSchool
class and the makeADog()
method are also public. This means that if some other class created a DogSchool
, they would have access to these methods as well! We have public methods calling public methods! One final thing to note is that for the purposes of this lesson, we'll almost always make our classes and constructors public
. While you can set them to private
, it's fairly uncommon to do so. Instead, we'll focus on why you might make your instance variables and methods private
.
The private
Keyword and Encapsulation
When a Class' instance variable or method is marked as private
, that means that you can only access those structures from elsewhere inside that same class. Let's look back at our DogSchool
example:
1 2 3 4 5 6 7 8 |
|
makeADog
is trying to directly access Dog
's .age
variable. It's also trying to use the .speak()
method. If those are marked as private
in the Dog
class, the DogSchool
class won't be able to do that. Other methods within the Dog
class would be able to us .age
or .speak()
(for example, we could use cujo.age
within the Dog
class), but other classes won't have access. Accessor and Mutator Methods
When writing classes, we often make all of our instance variables private
. However, we still might want some other classes to have access to them, we just don't want those classes to know the exact variable name. To give other classes access to a private instance variable, we would write an accessor method (sometimes also known as a "getter" method).
1 2 3 4 5 6 7 8 9 |
|
name
is private
, other classes could call the public
method getName()
which returns the value of that instance variable. Accessor methods will always be public
, and will have a return type of the instance variable they're accessing. Similarly, private
instance variables often have mutator methods (sometimes known as "setters"). These methods allow other classes to reset the value stored in private
instance variables.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
|
void
methods - they don't return anything, they just reset the value of an existing variable. Similarly, they often have one parameter that is the same type as the variable they're trying to change. Scope: Local Variables
In addition to access modifiers like public
and private
, the scope of the variable also determines what parts of your code can access that variable.
The scope of a variable is determined by where the variable is declared. For example, because instance variables are declared inside a class but outside any methods or constructors, all methods and constructors are within the scope of that variable. For example, in the code block below, constructors and methods of the Dog
class are using the Dog
instance variables like name
and age
:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
|
public
or private
when declaring local variables. This idea of scope extends to conditionals and loops as well. If you declare a variable inside the body of a conditional or in a loop, that variable can only be used inside that structure. This also includes the variable you're using as your looping value. For example, consider the following block of code:
1 2 3 4 |
|
i
between the curly braces of the for loop. In general, whenever you see curly braces, be aware of the scope. If a variable is defined inside curly braces, and you try to use that variable outside those curly braces, you will likely see an error! Scope: The this
Keyword
Often times when creating classes, programmers will create local variables with the same name as instance variables. For example, consider the code block below:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
|
name
, but the method speakNewName
has a parameter named name
. So when the method tries to print name
, which variable will be printed? By default, Java refers to the local variable name
. So in this case, the value passed to the parameter will be printed and not the instance variable. If we wanted to access the instance variable and not the local variable, we could use the this
keyword.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 |
|
this
keyword is a reference to the current object. We used this.name
in our speakNewName()
method. This caused the method to print out the value stored in the instance variable name
of whatever Dog
Object called speakNewName()
. (Note that in this somewhat contrived example, the local variable name used as a parameter gets completely ignored). Oftentimes, you’ll see constructors have parameters with the same name as the instance variable. For example, you might see something like:
1 2 3 |
|
this
Dog
's instance variable name
equal to the variable passed into the constructor”. While this naming is a common convention, it can also be confusing. There’s nothing wrong with naming your parameters something else to be more clear. Sometimes you will see something like: 1 2 3 |
|
Dog
's instance variable name equal to the name
we give the constructor. Finally, mutator methods also usually follow this pattern:
1 2 3 |
|
Throughout the rest of this lesson, we’ll use this.
when referring to an instance variable. This isn't always explicitly necessary — if there's no local variable with the same name, Java will know to use the instance variable with that name. That being said, it is a good habit to use this.
when working with your instance variables to avoid potential confusion.
Using this
With Methods
We've seen how the this
works with variables, but we can also use the this
with methods.
Recall how we've been calling methods up to this point:
1 2 3 4 |
|
Dog
and using that Dog
to call the speak()
method. However, when defining methods, we can also use the this
keyword to call other methods. Consider the code block below: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
|
resetSettings()
method in particular. This method calls other methods from the class. But it needs an object to call those methods! Rather than create a new object (like we did with the Dog
named myDog
earlier), we use this
as the object. What this means is that the object that calls resetSettings()
will be used to call setBrightness(0)
and setVolume(0)
. 1 2 3 4 |
|
myComputer.resetSettings()
is as if we called myComputer.setBrightness(0)
and myComputer.setVolume(0)
. this
serves as a placeholder for whatever object was used to call the original method. Other Private Methods
Now that we've seen how methods can call other methods using this.
, let's look at a situation where you micht want to use private
methods. Oftentimes, private
methods are helper methods - that is to say that they're methods that other, bigger methods use.
For example, for our CheckingAccount
example, we might want a public method like getAccountInformation()
that prints information like the name of the account owner, the amount of money in the account, and the amount of interest the account will make in a month. That way, another class, like a Bank
, could call that public method to get all of that information quickly.
Well, in order to get that information, we might want to break that larger method into several helper methods. For example, inside getAccountInformation()
, we might want to call a function called calculateNextMonthInterest()
. That helper method should probably be private
. There's no need for a Bank
to call these smaller helper methods - instead, a Bank
can call one public
method, and rely on that method to do all of the complicated work by calling smaller rivate
methods.
Access, Encapsualtion, & Scope Review
-
The
public
andprivate
keywords are used to define what parts of code have access to other classes, methods, constructors, and instance variables. -
Encapsulation is a technique used to keep implementation details hidden from other classes. Its aim is to create small bundles of logic.
-
The
this
keyword can be used to designate the difference between instance variables and local variables. -
Local variables can only be used within the scope that they were defined in.
-
The
this
keyword can be used to call methods when writing classes.
Static Methods Refresher
In these notes, we're going to dive into how to create classes with our own static methods and static variables. To begin, let's brush up on static methods.
Static methods are methods that belong to an entire class, not a specific object of the class. Static methods are clled using the class name and the .
operator. We've seen a couple static methods already!
1 2 3 4 5 |
|
random()
is a static method that belongs to the Math
class. We didn't need to create a Math
object (like Math myMathObject = new Math()
) in order to use that method. We could just call it using the class name. Similarly, valueOf()
is a static method of the String
class. Given a String
as an input, this method will turn that String
into a double
. Again, we don't need to create a String
object in order to call this method - we use the class itself to call it.
Finally, notice that our main()
methods have been static
this whole time. When Java runs your program, it calls that main method of your class - YourClassName.main()
.
Static Variables
We'll begin writing our own static methods soon, but before we do, let's take a look at static variables. Much like static methods, you can think of static variables as belonging to the class itself instead of belonging to a particular object of the class.
Just like with static methods, we can access static variables by using the name of the class and the .
operator. Finally, we declare static variables by using the static
keyword during declaration. This keyword usually comes after the variable's access modifier (public
or private
).
When we put this all together, we might end up with a class that looks something like this:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
|
name
and age
, so those aren't static
. We could now access this static variable in a main()
function, like so: 1 2 3 4 5 6 7 |
|
1 2 3 4 5 6 7 8 |
|
Modifying Static Variables
Now that we've created a couple of static variables, let's start to edit them. The good news is that editing static variables is similar to editing any other variable. Whether you're writing code in a constructor, a non-static method, or a static method, you have access to static variables.
Often times, you'll see static variables used to keep track of information about all objects of a class. For example, our variable numATMs
is keep track of the total number of ATM
s in the system. Therefore, every time an ATM
is created (using the constructor), we should increase that variable by 1
. If we could somehow destroy the ATM
, the method that destroys it should decrease numATMs
static variable by 1
.
Similarly, we have a variable names totalMoney
. This variable is keeping track of all money across all ATMs. Whenever we remove money from an ATM using the non-static withdrawMoney()
method, we should modify the money
instance variable for that particular ATM as well as the totalMoney
variable. In doing so, all ATMs will know how much money is in the system.
Writing Your Own Static Methods
Now that we have seen how static variables work, let's look into how to write our own static methods.
Let's get the syntax out of the way first - just like with variables, to create a static method, use the static
keyword in the method's definition. Just like with variables, this keyword usually comes after public
or private
.
1 2 3 |
|
1 2 3 4 5 6 7 |
|
To wrap our mind's around this, let's consider why we use this
when working with non-static instance variables. Let's say we have a Dog
class with a non-static instance variable named age
. If we have a line of code like this.age = 5;
, that means we're setting the age
of a specific Dog
equal to 5
. However, if age
were static, that would mean that the variable belongs to the entire class, not just a specific object.
The this
keyword can't be used by a static method since static methods are associated with an entire class, not a specific object of that class. If you try to mix this
with a static method, you'll see the error message non-static variable this cannot be referenced from a static context
.
Static Variables Review
-
Static methods and variables are associated with the class as a whole, not objects of the class.
-
Static methods and variables are declared as static by using the
static
keyword upon declaration. -
Static methods cannot interact with non-static instance variables. This is due to static methods not having a
this
reference. -
Both static methods and non-static methods can interact with static variables.