02 OOPS - Access Modifiers & Constructors
02 OOPS - Access Modifiers & Constructors
Access Modifiers
Getters & Setters
Constructors
Shallow & Deep Copy
Java Memory Model - Objects & References
Life & Death on Objects on Heap
Project : Guess Game using OOPS Concepts
Access Modifiers
The access modifiers in Java specifies the accessibility or scope of a field, method,
constructor, or class. We can change the access level of fields, constructors,
methods, and class by applying the access modifier on it. Let's understand it through
an example.
In the above class, guess is private, name is default, handle is public. What
does't it mean? Let understand the meanings of above acess modifiers.
protected - The access level of a protected modifier is within the package and
outside the package through child class. If you do not make the child class, it cannot
be accessed from outside the package.
private - The access level of a private modifier is only within the class. It cannot
be accessed from outside the class.
default - The access level of a default modifier is only within the package. It
cannot be accessed from outside the package. If you do not specify any access level,
it will be the default.
If you try to read or write a private data member, outside the class, you will get a
compile error. In order to work with private data members, you might need to create
special public methods called getters() and setters() in the class for specific data
members as shown below.
//Setter Method
public int setGuess(int guess){
//Setters can have their validation logic before updating class member
if(guess>=0){
this.guess = guess;
}
}
// Getter Method
public int getGuess(){
return this.guess;
}
}
The advantage of this approach is you can set the value if it satisfies the class
specific validation logic.
Constructors
A constructor is a special method that is called when an object is created. It is used
to initialize the object. It is called automatically when the object is created. It
can be used to set initial values for object attributes.
Constructors are the gatekeepers of object-oriented design. Let us create a class for
students:
Student.java
public class Student {
The above class can be used to create objects of type Student. This is done by using
the new keyword:
You can notice that we did not define a constructor for the Student class. This brings
us to our first type of constructor
Default constructor
A default constructor is a constructor created by the compiler if we do not define any
constructor(s) for a class.
public Student() {
// no-argument constructor
}
}
Notice a few things about the constructor which we just wrote. First, it's a method,
but it has no return type. That's because a constructor implicitly returns the type of
the object that it creates. Calling new Student() now will call the constructor above.
Secondly, it takes no arguments. This particular kind of constructor is called a no-
argument constructor.
Syntax of a constructor In Java, every class must have a constructor. Its structure
looks similar to a method, but it has different purposes. A constructor has the
following format <Constructor Modifiers> <Constructor Declarator> <Constructor Body>
Constructor declarations begin with access modifiers: They can be public, private,
protected, or package access, based on other access modifiers. Unlike methods, a
constructor can't be abstract, static, final, native, or synchronized.
The declarator is the name of the class, followed by a parameter list. The parameter
list is a comma-separated list of parameters enclosed in parentheses. The body is a
block of code that defines the constructor's behavior.
Parameterised Constructor
Now, a real benefit of constructors is that they help us maintain encapsulation when
injecting state into the object. The constructor above is a no-argument constructor
and hence value have to be set after the instance is created.
The above approach works but requires setting the values of all the fields after the
instance is created. Also, we won't be able to validate or sanitize the values. We can
add the validation and sanitization logic in the getters and setters but we wont be
able to fail instance creation. Hence, we need to add a parameterised constructor. A
parameterised constructor has the same syntax as the constructors before, the onl
change is that it has a parameter list.
Copy constructor
A copy constructor is a member function that initializes an object using another
object of the same class. A copy constructor has the following general function
prototype:
class Student {
private String name;
private String email;
//Copy Constructor
public Student(Student student) {
this.name = student.name;
this.email = student.email;
}
}
//Copy Constructor
Test(Test X){
//Copying the references (Shallow Copy)
this.n = X.n;
this.name = X.name;
this.arr = X.arr;
}
}
public class Main {
public static void main(String[] args) {
//Parametrised Constructor
Test t1 = new Test(6,"Test1");
//Copy Constructor Call
Test t2 = new Test(t1);
t2.n = 7;
t2.name = "Test2";
t2.arr[0] = 56;
In the above example, we see we are creating a shallow copy in Line Copy Constructor
of Test Class. Both the array references point to the same memory, the ideal way to do
it would be to create a new array inside the copy constructor.
class Test{
...
Test(Test X){
this.n = X.n;
this.name = X.name;
You might be wondering why didn't we create a deep copy for int and String data-
types. This is because of the way java memory model works, for primitive data types
like int, float etc Java always create new memory for different objects, and for
strings because of immutability whenever you try to update the value of a String
object, a new String object is automatically created in the string pool and the
reference starts pointing to it. Hence for `int' and 'string' even if they are changed
in T2 object, the changes won't be reflected in T1.
Here p1 stores the location of object on the heap, and hence p1 in a reference to
the newly created player object.
Player.java
package GuessGame;
//Methods
Player(String name){
this.name = name;
}
int getGuess(){
return guess;
}
void makeGuess(){
this.guess = (int)(Math.random()*9) + 1;
System.out.println(this.name + " guessed "+this.guess);
}
}
Game.java
package GuessGame;
while(true){
System.out.println("Computer Guessed" + this.computerGuess);
p1.makeGuess();
p2.makeGuess();
p3.makeGuess();
if(checkWinner()){
System.out.println("Game Over");
break;
}
else{
this.computerGuess = (int)(Math.random()*9) + 1;
}
}
}
}
Launcher.java
package GuessGame;