Methods/EncapsulationJ8 Home « Methods/Encapsulation
Lets take a look at the points outlined at Oracle Java SE 8 Programmer I for this part of the certification.
- Working with Methods and Encapsulation
- Create methods with arguments and return values; including overloaded methods.
- Apply the static keyword to methods and field.
- Create and overload constructors; differentiate between default and user defined constructors.
- Apply access modifiers.
- Apply encapsulation principles to a class.
- Determine the effect upon object references and primitive values when they are passed into methods that change the values.
The table below breaks the above list down into topics with a link to the topic in question.
topic | Link |
---|---|
Create methods with arguments and return values; including overloaded methods. | Method Creation Overloading Methods |
Apply the static keyword to methods and field | Static Methods Static Variables |
Create and overload constructors | Constructors Overloaded Constructors |
Differentiate between default and user defined constructors | |
Apply access modifiers | |
Apply encapsulation principles to a class | |
Determine the effect upon object references and primitive values when they are passed into methods that change the values |
Method CreationTop
There are two types of methods available in Java, static and non-static methods. The general mechanics are the same but static methods apply to the class as a whole, whereas non-static methods generally apply to an instance of the class. We will discuss the vagaries of static methods in the Static Methods later in this lesson.Lets start by looking at the components of a method:
Method declarations can have up to six components but the only required elements are the method's return type, the method name, a pair of parenthesis ()
and a body between braces
{}
. Following is the order the components must appear in when used.
- Modifiers — such as
public
as used here are discussed in the Encapsulation lesson along with the other access modifiers andstatic
which we will discuss later in this section in the Static Members lesson. There are also other modifiers which we will learn about later. - The return type — which is the data type of the value returned by the method, or
void
if the method doesn't return any value. - The method name — which must be a valid identifier as discussed in the Java Variables section of the Primitive Variables lesson. By convention, method names should be a verb in lowercase or multiple words that begin with a verb in lowercase, followed by adjectives, nouns, etc. in camel case.
- The parameter list - A comma-delimited list of input parameters, preceded by their data types, enclosed by parentheses. If there are no parameters, you must use empty parentheses. The arguments passed when we call a method are received into the parameter list are within scope as discussed in the Defining A Scope section of the Method Scope lesson.
- An exception list — Which will be discussed when we get to look at exceptions.
- The method body - The method's code, statements, local variable declaration etc, goes in the body which is enclosed between braces.
Passing Arguments To A Method Top
Before we look at this lets clear up some terminology about arguments and parameters. Arguments are what we pass to a method whereas parameters are what we receive the arguments into. We have already seen with our use of the
main()
method how to pass an argument to a method and we also coded our own printBits
method in the Bitwise Operators lesson. Both these methods accept a single
argument into their parameter list, but Java has no restriction on the amount of parameters we can code into a method. Lets code a Tiger
class with a new method that accepts two parameters:
package info.java8;
/*
A Tiger Class
*/
public class Tiger {
String name, colour;
int age;
void tigerMannerisms(String action, int times) { // Our new method with 2 parameters
System.out.println("Our tiger " + action + " " + times + " times a day.");
}
}
Save and compile the file in directory c:\_ObjectsAndClasses in the usual way. Lets write a new test class for our Tiger
class.
package info.java8;
/*
Test Class for Tiger
*/
public class TigerTest {
public static void main (String[] args) {
Tiger tony = new Tiger(); // Create a Tiger instance
tony.tigerMannerisms("eats food", 4); // Pass values
String tiggerAction = "runs up trees";
int tiggerTimes = 2;
tony.tigerMannerisms(tiggerAction , tiggerTimes ); // Pass types
tony.tigerMannerisms(tony.name, tony.age ); // Pass instance variables
}
}
Save, compile and run the file in directory c:\_ObjectsAndClasses in the usual way.
The above screenshot shows the output of running our Tiger
class. We created a Tiger
instance and passed two arguments to the tigerMannerisms
method in various ways.
Returning Values From A Method Top
Up until now all our methods have been declared using the void
return type which denotes that the method doesn't return any value. We can declare methods with a return type and if we do we must return a value
compatible with that type or covariant thereof, using the return
keyword. Lets see this in action :
package info.java8;
/*
Test class for maths stuff
*/
public class MathsStuff {
public static void main (String[] args) {
int aSquare = squareNumber(5); // The return value will go into aSquare
System.out.println(aSquare);
}
/*
A method that squares and returns the passed integer
*/
static int squareNumber(int number) {
int square = number * number;
return square; // Here we use the return keyword to pass back a value
}
}
Save, compile and run the file in directory c:\_ObjectsAndClasses in the usual way.
The above screenshot shows the output of running our MathsStuff
class. The return value from the squareNumber()
method gets assigned to the aSquare
primitive.
Overloading MethodsTop
You can use the same method name more than once in a class or subclass and this is known as overloading. When using overloading each method must have different parameter lists so the compiler knows which method to call. Having the same parameter types is fine as long as the order differs.
Overloading Method Rules
When we overload a superclass method or a method in the same class there are rules to adhere to:
- A method overload must have a different argument list to any like named methods in the same class.
- A method overload must have a different argument list to any like named methods in a superclass or you end up with a method override and all the rules that apply when using overrides as listed in the section above.
- A method overload has no constraints on return types.
- A method overload has no constraints on accessibility.
- A method overload has no constraints on checked exceptions.
/*
Some code showing method override rules
*/
public class A {
void methodA(int i) { }
final void methodB() {}
protected void methodC(String s) {}
void methodD(String s, int i) {}
String methodE(String s, int i) { return s; }
void methodF() { }
}
import java.io.*; // Import IO exception classes
public class B extends A {
void methodA(int i) { } // OK, same parameter list as superclass so an override
void methodA(String s, int i) { } // OK, this is an overloaded method of superclass
final void methodB(int i) {} // OK, parameter list differs from superclass method
// marked as final, so valid overload
void methodC(int i) {} // OK, no constraints on subclass overload accessibility
protected void methodD(int i, String s) {} // OK, this is an overloaded subclass method
void methodD(String s, int i) { } // OK, valid override
int methodE(int i, String s) { return i; } // OK, no constraints on subclass overload return types
void methodF(int i) throws IOException { } // OK, no constraints on subclass overload
// checked exceptions
void methodG() {}
void methodG(String s) {} // OK, overloaded in same class
}
Static Methods Top
Static methods run without any instance of a class being involved, as static they belong to the class as a whole, and are accessed using the name of the class in the same way as static variables. Lets think about it,
the main()
method we have used since the start of these lessons to test our classes, runs before any instances of a class exist. In fact you cannot access the instance variables of a class from a static method
within the class or the compiler gets upset. This makes sense as how would a static method know which instance variable to use, there is no reference. Its the same thing when you try to call a non-static method from a static
method, the compiler doesn't like it. The static method has no way of knowing how to use any instance variables associated with the non-static method and has no way to reference which instance they belong to. Even if the
method has no instance variables the compiler still won't allow it because in the future you may amend the method to include an instance variable. Lets look at these rules with some code:
package info.java8;
/*
Test class for static calls
*/
public class StatCalls {
public static void main (String[] args) {
int aSquare = squareNumber(5); // Calling non-static method
System.out.println(aSquare);
}
/*
A method that squares and returns the passed integer
*/
int squareNumber(int number) {
int square = number * number;
return square; // Here we use the return keyword to pass back a value
}
}
Save, compile and run the file in directory c:\_ObjectsAndClasses in the usual way.
The above screenshot shows the output of running our StatCalls
class. The compiler doesn't like the fact that we are calling a non-static method from main()
method. Lets look at using instance
variables from a static method.
package info.java8;
/*
Test class for static calls
*/
public class StatCalls2 {
int number;
public static void main (String[] args) {
number = 5; // Calling instance variable
int aSquare = StatCalls2.squareNumber(5); // Calling static method
System.out.println(aSquare);
}
/*
A method that squares and returns the passed integer
*/
static int squareNumber(int number) {
int square = number * number;
return square; // Here we use the return keyword to pass back a value
}
}
Save, compile and run the file in directory c:\_ObjectsAndClasses in the usual way.
The above screenshot shows the output of running our StatCalls2
class. The compiler doesn't like the fact that we are calling an instance variable from the main()
method.
Of course there is no problem using instantiation from within your static method to access non-static content, or using a local reference from within your static method to access non-static content; otherwise you would never
be able to get out of the main()
method.
Static Variables Top
Java comes with three kinds of scope and we name variables according to the scope they reside in as detailed in the table below. In this section we focus on static variables and their scope.
Variable | Scope | Lifetime |
---|---|---|
static | Static variables apply to the class as a whole and are declared within the class but outside a method. | Exists for as long as the class it belongs to is loaded in the JVM . |
instance | Instance variables apply to an instance of the class and are declared within the class but outside a method. | Exists for as long as the instance of the class it belongs to. See the Instance Variables & Scope lesson for more information |
local | Local variables apply to the method they appear in. | Exists until the method it is declared in finishes executing. See the Method Scope lesson for more information |
Static variables are initialized as soon a class is loaded and before any instances of the class are instantiated.
Like instance variables, static variables are assigned a default value according to their type:
- object -
null
- boolean -
false
- char -
/u0000
- integer types (
byte
,short
,int
andlong
) -0
- floating-point types (
float
,double
) -0.0
Because static variables are independent of any instance they can be used by all instances of the class. To demonstrate what we mean by this lets write some code that keeps count of the instances we create.
package info.java8;
/*
A Donkey Class
*/
public class Donkey {
int count;
public Donkey() {
count++; // Increment a counter
System.out.println("Our donkey count = " + count);
}
}
Save and compile the file in directory c:\_ObjectsAndClasses in the usual way. Lets write a new test class for our Donkey
.
package info.java8;
/*
Test Class for Donkey
*/
public class DonkeyTest {
public static void main (String[] args) {
Donkey dan = new Donkey();
Donkey sam = new Donkey();
Donkey liam = new Donkey();
}
}
Save, compile and run the file in directory c:\_ObjectsAndClasses in the usual way.
The above screenshot shows the output of running our Donkey
class. We created three Donkey
instances and printed out a total after each. The total is always 1 as each time we create a new instance of
Donkey
we are creating a new count
variable as this is an instance variable. Lets revamp our Donkey
class and make the instance variable into a static variable:
package info.java8;
/*
A Donkey Class
*/
public class Donkey {
static int count; // We made this static
public Donkey() {
count++; // Increment a counter
// Prefix statics with the class name
System.out.println("Our donkey count = " + Donkey.count);
}
}
Save and compile the file in directory c:\_ObjectsAndClasses in the usual way and then rerun our DonkeyTest
class.
The above screenshot shows the output of running our Donkey
class. We created three Donkey
instances and printed out a total after each. The total now gets gets incremented each time we create a new
instance of Donkey
just like we want. Static variables apply to the whole class and are initialized when the class is loaded. There is only one copy of each static variable in a class which is shared by all
instances of that class. We prefix statics with the class name to avoid ambiguity and to highlight the fact that this is a static.
EncapsulationTop
Encapsulation is a language mechanism used to restrict access to an object's components. In Java parlance this is a mechanism to restrict access to the members (instance variables and methods) of a class, constructors and even to the class itself. So how do we achieve this in Java?. Well Java provides us with the access modifier mechanism for restricting access to our classes, which are the basic unit of encapsulation in Java. We can also restrict access to our instance variables whilst providing access to them via public
methods. We can limit construction to the class itself using the private
keyword, or to the package the implementation is in using the protected
keyword or with no modifier package-private / (the default). The table below lists access modifiers in more detail.
Access ModifiersTop
The table below shows the four types of access available in Java from the most open (public
) to the most restrictive (private
). We can only explicitly apply the public
access modifier to our top-level classes (the classes we compile) but for members and constructors we can explicitly apply the protected
and private
access modifiers as well. We will talk about packaging in the Packages lesson, but for now we are going to examine how to protect our class members from unwanted access and modification.
Access modifier | Class | Member | Constructor | Description |
---|---|---|---|---|
public | Yes | Yes | Yes | A top-level class may be declared with the public access modifier, and if it is the class is accessible to all other classes everywhere.A member may be declared with the public access modifier, and if it is the member is accessible to all other classes everywhere, assuming the class it resides in is accessible.A constructor may be declared with the public access modifier, and if it is the constructor is accessible to all other classes everywhere, assuming the class it resides in is accessible. |
protected | No | Yes | Yes | A member may be declared with the protected access modifier, and if so, is only accessible within its own package and also by a subclass of its class in other packages.
A constructor may be declared with the protected access modifier, and if so, it is only accessible to the package
the implementation is in.See the Packages lesson for more information on packaging. See the Inheritance Basics lesson for more information on subclassing. |
no modifier package-private / (the default) | Yes | Yes | Yes | If a top-level class has no explicit access modifier, which is the default and is also known as package-private,
it is accessible only within its own package. If a member has no explicit access modifier it is only accessible within its own package. If a constructor has no explicit access modifier, it is only accessible to the package the implementation is in. See the Packages lesson for more information on packaging. |
private | No | Yes | Yes | A member may be declared with the private access modifier, and if it is the member is only accessible within its own class.A constructor may be declared with the private access modifier, and if it is the constructor can only be constructed from within its own class. |
See the OO Concepts - Encapsulation lesson for example usage and information on how we use getters and setters to enforce tight encapsulation.
Class Access Modifiers
The table below shows the types of access available in Java for our top-level classes.
Access modifier | Description |
---|---|
public | A top-level class may be declared with the public access modifier, and if it is the class is accessible to all other classes everywhere. |
no modifier package-private / (the default) | If a top-level class has no explicit access modifier, which is the default and is also known as package-private, it is accessible only within its own package. |
- The only access modifier that can be used with a top-level class is
public
. - Only one class can be marked as
public
per source file. - If a class within a source file is marked as
public
then the name of the source file must exactly match the name of thepublic
class (followed by the.java
extension). - A source file can include multiple non-public classes.
- If a source file contains no public class then there is no naming constraints on that source file, ie. it doesn't have to match the name of one of the non-public classes.
- Aside from access modifiers classes can also be marked with the non-access modifiers
abstract
,final
andstrictfp
. Thestrictfp
is not part of the certification and so we won't go into details. When a class is marked asabstract
it has to be subclassed; when a class is marked asfinal
it can't be subclassed, so these two modifers can never be used together. - A class can extend a maximum of one other class.
/*
Some code showing class rules
*/
class A { } // OK
private class A { } // No, can only use public access modifier with top level class
protected class A { } // No, can only use public access modifier with top level class
public class A { } // OK
public class B extends A { } // OK
public class C extends B, A { } // No, can only extend one class
abstract class D { } // OK
final class E { } // OK
abstract final class F { } // No, cannot use both abstract and final
Method Access Modifiers
The table below shows the four types of access available in Java for members (variables, inner classes and methods).
Access modifier | Description |
---|---|
public | A member may be declared with the public access modifier, and if it is the member is accessible to all other classes everywhere, assuming the class it resides in is accessible. |
protected | A member may be declared with the protected access modifier, and if so, is only accessible within its own package and also by a subclass of its class in other
packages..See the Packages lesson for more information on packaging. See the Inheritance Basics lesson for more information on subclassing. |
no modifier package-private / (the default) | If a member has no explicit access modifier it is only accessible within its own package. |
private | A member may be declared with the private access modifier, and if it is the member is only accessible within its own class. |
Non-access Modifiers
The table below shows the types of non-access modifiers available for use with variables.
static variable and instance variable modifiers | local variable modifiers |
---|---|
final transient volatile | final |
ConstructorsTop
Constructors allow us to instantiate our objects via declaration, assignment and creation.
- Declaration - Here. we declare a reference variable named
moggy
of typeCat
and the JVM allocates space for it. - Creation - Tells the JVM to allocate space on The Heap for a new
Cat
object. - Assignment - Assign the new
Cat
object to the reference variablemoggy
.
Access Modifiers
The table below shows the types of access available in Java for constructors.
Access modifier | Description |
---|---|
public | A constructor may be declared with the public access modifier, and if it is the constructor is accessible to all other classes everywhere, assuming the class it resides in is accessible. |
protected | A constructor may be declared with the protected access modifier, and if so, it is only accessible to the package
the implementation is in.See the Packages lesson for more information on packaging. |
no modifier package-private / (the default) | If a constructor has no explicit access modifier, it is only accessible to the package the implementation is in.
See the Packages lesson for more information on packaging. |
private | A constructor may be declared with the private access modifier, and if it is the constructor can only be constructed from within its own class. |
Constructor Checklist
- A constructor runs when we code the
new()
operator followed by a class name. - Constructors must have the same name as the class and no return type.
- Constructors are used to initialize the instance variables (object state) of the object instance being constructed.
- If you don't code a constructor in your class the compiler will put in a default no arguments constructor.
- If you do code a constructor in your class, the compiler will NOT put in a default no arguments constructor, you will have to code it yourself.
- We can have more than one constructor in a class and the constructors are then known as overloaded constructors.
- When using overloaded constructors in a class, each constructor must have different argument lists so the compiler knows which constructor to use to construct our objects. Having the same argument types is fine as long as the order differs.
- You can refer to any member of the current object from within a non-static method or constructor by using the
this()
keyword. - You can invoke one constructor from another constructor within the same class by calling
this()
and doing so is known as explicit constructor invocation and is the only way to invoke a constructor. - If we decide to use
this()
it must be the first statement within our constructor or we get a compiler error. This means we can't usethis()
andsuper()
together. - We can use
super()
to invoke a superclass constructor and if we don't supply this explicitly, then the compiler inserts a no-argssuper()
for us as the first statement in the constructor if we haven't used thethis()
keyword. - When explicitly coding
super()
we can supply arguments to invoke a constructor in the superclass matching the signature of our call. - When explicitly coding
super()
it must be the first statement within the constructor or we get a compiler error. This means we can't usesuper()
andthis()
together. - When explicitly coding
super()
only methods and static variables can be used within the call. - Interfaces do not have constructors as they are not part of a particular classes inheritance tree.
- Abstract classes do have constructors, although we can't code them, as they are part of a classes inheritance tree and so are called via
super()
on concrete subclass instantiation.
/*
Some code showing constructor usage
*/
public class A {
public static void main(String[] args) {
A a = new A(); // OK, compiler puts in a default no arguments constructor so we can instantiate
}
}
public class B {
B() { } // OK, we code our own default no arguments constructor
}
public class C {
void C() { } // OK, this is a method with the same name as the class as it has a return type
public static void main(String[] args) {
C c = new C();
}
}
public class D {
D() { }
D(int i) { } // OK, overloaded constructor
public static void main(String[] args) {
D d = new D();
D d2 = new D(5);
}
}
public class E {
int i;
String s;
E(int i) {
this(i, "unknown"); // Invoke one constructor from another constructor within the same class
}
E(int i, String s) {
this.i = i;
this.s = s;
}
public static void main(String[] args) {
E e = new E(5);
}
}
/*
Following code will fail as compiler inserts a no arguments constructor for us which invokes
super() and there isn't a no arguments constructor in superclass
*/
public class F extends E {
}
public class G extends E {
G(int i) { // here we invoke existing super constructor so works fine
super(i);
}
public static void main(String[] args) {
G g = new G(5);
}
}
Overloaded Constructors Top
This isn't the end of the story though, not by a long chalk. Lets enhance our test class above to call a Cat
object with no arguments:
package info.java8;
/*
Test Class5 for Cat
*/
public class TestCat5 {
public static void main (String[] args) {
Cat moggy = new Cat("Henry", "black", 4); // Call new Cat constructor with three arguments
Cat tigger = new Cat("Kitty", "black", 15); // Call new Cat constructor with three arguments
Cat tabby = new Cat("Felix", "white", 8); // Call new Cat constructor with three arguments
Cat tommy = new Cat(); // Call Cat constructor with no arguments
System.out.println("Our " + moggy.colour + " cat called " + moggy.name + " is " + moggy.age);
System.out.println("Our " + tigger.colour + " cat called " + tigger.name + " is "
+ tigger.age);
System.out.println("Our " + tabby.colour + " cat called " + tabby.name + " is " + tabby.age);
System.out.println("Our " + tommy.colour + " cat called " + tommy.name + " is " + tommy.age);
}
}
Save and compile the file in directory c:\_ObjectsAndClasses in the usual way.
The above screenshot shows the output of compiling our TestCat5
class. Whoa! What happened here? It has given us an error when we try to create a new Cat
object using a no arguments constructor?? It
appears from the error that the compiler was looking for a constructor with (String,String,int
). But doesn't the compiler put in a default no arguments constructor for us? No it doesn't, as soon as we code
our own constructor the compiler doesn't get involved and leaves construction to us. So if we want a default no arguments constructor as well we have to code it. Ok lets do just that:
package info.java8;
/*
A Cat Class
*/
public class Cat {
String name, colour;
int age;
/*
no-arg constructor for our Cat Class
*/
public Cat() {
}
/*
Below is the new constructor for our Cat Class
*/
public Cat(String a, String b, int c) {
name = a;
colour = b;
age = c;
}
void talk() {
System.out.println("meow!");
}
}
Save and compile our revised Cat
class in directory c:\_ObjectsAndClasses in the usual way.
We now have two constructors in our Cat
class. When a class has more than one constructor they are known as overloaded constructors. Each constructor must have different argument lists so the compiler
knows which constructor to use to construct our objects. Having the same argument types is fine as long as the order differs. OK, our TestCat5
class should compile fine now, so compile and run it:
The above screenshot shows the output of running our TestCat5
class. As you can see from the output we now have a fourth line of output for a Cat
object, which was instantiated using our no-arg constructor with default values.
Related Java Tutorials
Objects & Classes - Reference Variables - The new Operator
Objects & Classes - Constructors
OO Concepts - Encapsulation
OO Concepts - Polymorphism
OO Concepts - Overriding Methods
Objects & Classes - Overloaded Methods
OO Concepts - Accessing Superclass Members
Inheritance Concepts - Superclass Constructors
OO Concepts - Static Overrides?
OO Concepts - IS-A and HAS-A Relationships