Defining Own Classes in Java

classconstructorvar

In the previous blog, we learned about the Predefined Classes in Java. If you want to know more about Predefined Classes, visit Predefined Classes in Java. In this blog, we will see how to create our own class without the main() method.

Defining the class

We have already seen that classes have instance variables and methods. When we create an application there are multiple classes defined and each class contains the instance variables and methods. The syntax of creating our own class:

Syntax:

class className {
  variable1;
  variable2;
  ---------- -

  constructor1;
  constructor2;
  ---------- -

  method1();
  method2();
  ---------- -
}

For better understanding we will go through the example of creating our own class

e.g

public class AtrowelStudentTest {
  AtrowelStudent atrowelValue[] = new AtrowelStudent[2];
  atrowelValue[0] = new AtrowelStudent("John","Canada",21,45,65,43);
  atrowelValue[1] = new AtrowelStudent("Sam","London",21,65,43,76);

  for(int i =0; i < 2; i++) {
      atrowelValue[i].atrowelDisplayResult();
      atrowelValue[i].atrowelCalculate();
  }
}

class AtrowelStudent {
  private String atrowelName;
  private String atrowelAddress;
  private int atrowelAge;
  private int    atrowelLangC;
  private int atrowelLangCPP;
  private int atrowelLangJava;
  private int atrowelAverage;
  public AtrowelStudent(String name, String address,int age, int c, int cpp, int java) {
      atrowelName = name;
      atrowelAddress = address;
      atrowelAge = age;
      atrowelLangC = c;
      atrowelLangCPP = cpp;
      atrowelLangJava = java;
  }

  public void atrowelDisplayResult() {
      System.out.println("Name:" + atrowelName + " "
      + "Address:" + atrowelAddress + " "
      + "Age:" + atrowelAge + " "
      + "C:" + atrowelLangC + " "
      + "CPP:" + atrowelLangCPP + " "
      + "Java:" + atrowelLangJava );
  }

  public void atrowelCalculate() {
      atrowelAverage = atrowelLangC + atrowelLangCPP + atrowelLangJava / 3;
      System.out.println("Average:" + atrowelAverage);
  }
}

Output:

Name:John
Address:Canada
Age:21
C:45
CPP:65
Java:43
Average:124

Name:Sam
Address:London
Age:21
C:65
CPP:43
Java:76
Average:133

In the above example we have created two classes i.e. AtrowelStudentTest and AtrowelStudent. In AtrowelStudent class we have defined variables, a constructor with the name AtrowelStudent for initializing the values, and two methods as follows:

Displays the output of all the fields using altrowelDisplayResult():

public void atrowelDisplayResult(){
  System.out.println("Name:"+atrowelName+ " "+"Address:"+atrowelAddress+" "+"Age:"+atrowelAge+" "+"C:"+atrowelLangC+" "+"CPP:"+atrowelLangCPP+" " +"Java:"+atrowelLangJava);
}

Calculates the average of the subjects using atrowelCalculate():

public void atrowelCalculate(){
  atrowelAverage = atrowelLangC + atrowelLangCPP + atrowelLangJava/3;
  System.out.println("Average:"+ atrowelAverage);
}

In the AtrowelStudentTest class we have used the main() method. In the main() method we have created the array of objects of the class and have initialized the values using the constructor.

AtrowelStudent atrowelValue[] = new AtrowelStudent[2];
atrowelValue[0] = new AtrowelStudent("John","Canada", 21, 45, 65, 43);
atrowelValue[1] = new AtrowelStudent("Sam","London", 21, 65, 43, 76);

and then we have used the for loop for displaying the result of each student

for(int i = 0; i < 2; i++) {
  atrowelValue[i].atrowelDisplayResult();
  atrowelValue[i].atrowelCalculate();
}

Now for saving the code we must use the name of the public class. We must have only one public class and other non-public classes. After saving the program, when the program is compiled, the compiler creates two class files i.e. AtrowelStudentTest.class and AtrowelStudent.class. Once the program is compiled successfully then we should give the name of the class which contains the main method in order to run it.

java AtrowelStudentTest

Constructor defined in AtrowelStudent Class

We will go through the constructor using the example:

public AtrowelStudent(String name, String address, int age, int c, int cpp, int java) {
  atrowelName = name;
  atrowelAddress = address;
  atrowelAge = age;
  atrowelLangC = c;
  atrowelLangCPP =  cpp;
  atrowelLangJava = java;
}

In the above code, the name of the constructor is same as that of classname i.e.the name of the class is AtrowelStudent and the constructor name is also AtrowelStudent. The constructor used in this code is parameterized constructor. Parameterized constructor is a constructor that takes the parameters. The purpose of the constructor is to create objects and initialize the objects.

new AtrowelStudent("Sam", "Delhi", 23, 46, 75, 39);

The instance variables which we have defined in the above example holds the following values:

atrowelName = Sam;
atrowelAddress = Delhi;
atrowelAge = 23;
atrowelLangC = 46;
atrowelLangCPP =  75;
atrowelLangJava = 39;

The main difference between constructor and methods is the constructor is called with a new operator, and cannot use the constructor to reset the values of the instance variables of an existing class.

e.g

atrowelValue.AtrowelStudent("Sam", "Delhi", 23, 46, 75, 39);

The above statement will give us error if we try to execute it.


Rules of Constructor

  1. The name of the constructor should be the same as the classname.
  2. Constructors don’t have any return type, not even void.
  3. Class can have more than one constructor.
  4. Constructor can have 0, 1,2, or more parameters.
  5. The constructor is called using a new operator.

Note - One thing to make a note of is that we cannot use the same names of the instance variables as the local variables in the constructor.

e.g

public AtrowelStudent(String name, String address, int age, int c, int cpp, int java) {
  String atrowelName = name;
  String atrowelAddress = address;
  int atrowelAge = age;
  String atrowelLangC = c;
  String atrowelLangCPP = cpp;
  String atrowelLangJava = java;
}

The variables mentioned above are the local variables and can be accessible only inside the constructor. If the same names are used for instance variables and local variables, then it will confuse the compiler with which one to use. So it will give us an error. Many times we make this mistake, which is so hard to find out when it is a big application. So we must take caution not to use the same names for local variables and instance variables.


Var Keyword

From Java 10, the var keyword is used for declaring the local variables instead of specifying the value of the variable.

e.g

AtrowelStudent atrowelValue = new AtrowelStudent("Sam","Delhi", 23, 46, 75, 39);

instead we can write it as:

var atrowelValue = new AtrowelStudent("Sam","Delhi", 23, 46, 75, 39);

The good thing of var keyword is that it avoids the repetition of the type name AtrowelStudent. But var can be used only when we know the type from the right-hand side. We cannot use the var keyword with int, float, and double(primitive) datatypes. We can use the var keyword only with local variables inside the method.


Null References

In the Object and Object Variables blog, we have seen that object variables can hold null values in order to indicate the absence of an object. But we should be very careful while using the null values. If we use null values in the method, then it gives us a NullPointerException.

e.g

AtrowelStudent atrowelValue = null;
String aValue = atrowelValue.toString();

The above statement will throw a NullPointerException. So we should be very careful about the values because if the compiler fails to catch the exception, then the program will get terminated. While defining a class we should be clear that which field can be null. In the above code, age will never be null because primitive datatypes cannot be null. Now if we take a look into other fields then it can be null if the constructor passes the null values. Two solutions can be used for this problem. The first approach is to convert the null arguments to non-null values.

e.g

if(name == null){
  atrowelName = "Unkown Value Passed";
} else {
  atrowelName = name;
}

The other approach is to use the method of Objects class

e.g

public AtrowelStudent(String name, String address,int age, int c, int cpp, int java) {
  name = Objects.requireNonNullElse(name, "unknown value passed");
  ----- -
}

Use of Implicit and Explicit parameters

public void atrowelCalculateArea(int r) {
  double atrowelResult = 3.14 *r;
  System.out.println(atrowelResult);
}

In the above method atrowelCalculateArea() sets the new value of an instance variable i.e. atrowelResult in the object on which the method is called.

Consider the following statement

atrowelObject.atrowelCalculateArea(3);

Here it calculates the area by using the radius as 3 and displays the result. The call will be executed as follows:

double atrowelResult = 3.14 * atrowelObject.r;
System.out.println(atrowelResult);

The method atrowelCalculateArea() consists of two parameters. The first parameter is the implicit parameter which is the object of type Circle which comes before the method called i.e.atrowelObject and the other parameter is the explicit parameter which is the number inside the parentheses of the method name i.e.3. The difference between implicit parameters and explicit parameters is that implicit parameter are not listed in the method declaration, but the explicit parameters are listed explicitly in the method declaration i.e. int r. We can use this keyword which is an implicit parameter and can be used in all methods.

e.g

public void atrowelCalculateArea(int r) {
  double atrowelResult  = 3.14 * this.r;
  System.out.println(atrowelResult);
}

Advantages of Encapsulation

We will go through the example in order to understand the advantages of Encapsulation:

class AtrowelStudent {
  private String atrowelName;
  private String atrowelAddress;
  private int atrowelAge;
  private int atrowelLangC;
  private int atrowelLangCPP;
  private int atrowelLangJava;
  private int atrowelAverage;

  public AtrowelStudent(String name, String address,int age, int c, int cpp, int java) {
      atrowelName = name;
      atrowelAddress = address;
      atrowelAge = age;
      atrowelLangC = c;
      atrowelLangCPP = cpp;
      atrowelLangJava = java;
  }

  public String getAtrowelName() {
      return atrowelName;
  }

  public String getAtrowelAddress() {
      return atrowelAddress;
  }

  public int getAtrowelAge() {
      return atrowelAge;
  }

  public int getAtrowelLangC() {
      return atrowelLangC;
  }

  public int getAtrowelLangCPP() {
      return atrowelLangCPP;
  }

  public int getAtrowelLangJava() {
      return atrowelLangJava;
  }

  public void atrowelCalculate() {
      atrowelAverage = atrowelLangC + atrowelLangCPP + atrowelLangJava/3;
      System.out.println("Average:"+ atrowelAverage);
  }
}

Output:

Name    : John
Address : Canada
Age     : 21
C       : 45
CPP     : 65
Java    : 43
Average : 124

Name    : Sam
Address : London
Age     : 21
C       : 65
CPP     : 43
Java    : 76
Average : 133

Now here getAtrowelName(), getAtrowelAddress(), getAtrowelAge(), getAtrowelLangC(), getAtrowelLangCPP(), getAtrowelLangJava() are accessor methods. They are also known as field accessors, as they only return the value of the instance fields. atrowelName, atrowelAddress, atrowelAge, atrowelLangC, atrowelLangCPP, atrowelLangJava are read-only fields. So we are sure that their values will never change, because once the values are set by the constructor, then there is no method that can change it.

When we want to set and get the values of the instance variables, then we must remember the following points.

  1. The instance variables should be declared as private.
  2. To set the values of those variables we must have public mutator methods.
  3. To get the values of those variables we must have public accessor methods.

Making the instance fields private is a tiring job, but it has benefits. Firstly if there are some use cases where we want to change the internal implementation then we can change it without affecting another, it will impact only the code of that method. For example, if the instance variable atrowelName is changed to atrowelFirstName and atrowelLastName,

e.g

String atrowelFirstName;
String atrowelLastName;

Here as the instance variables are modified then getAtrowelName() will also get change and will return atrowelFirstName and atrowelLastName.


Class-Based Access Privileges

As we have seen above, the method can access the private data of the object on which it is called. The surprising part is that private data of all objects of a class can be accessed by its method.

e.g

class AtrowelStudent {
  ----- -

 public boolean equals(AtrowelStudent student) {
     return atrowelName.equals(other.atrowelName);
 }
}

Then we call the method:

if(atrowelName1.equals(atrowelName2)){
  -----
}

The above method accesses the private field of atrowelName1. It also accesses the private fields of atrowelName2. It is valid because atrowelName2 is of the type atrowelStudent, and the method of AtrowelStudent is allowed to access the private fields of any object of the type AtrowelStudent.


Private Methods

As we have seen that all the data fields are made private because making them public may be dangerous, because if it gets modified then the application will get into trouble. As far as methods are concerned we have seen that almost all methods are public, but we can use private methods for particular situations where we want to break the code for computation. For implementing private methods we use a private keyword instead of public. When we make the method public, then there is no compulsion to make it available. As long as the method is private, then it is guaranteed that it will never be used by anyone or anywhere, so we can easily drop it. But that is not the case with public methods, we cannot drop them, because there may be a high possibility that other code may depend on it.


Final Instance Fields

The instance fields can be defined as final. It is initialized after the creation of the object, i.e. its value is set after the end of the constructor. The field which is defined as final cannot be modified. Its value remains constant. For example, we can declare the instance field atrowelName as final if we don’t want to change its value.

e.g

class AtrowelStudent{
    private final atrowelName;
}

The final keyword is used mostly with the primitive datatypes or immutable types(immutable means its value never gets modified e.g. String). But we cannot use the final keyword with the mutable classes, because it can be confusing.

Get in Touch

Atrowel will be pleased to receive your feedback and suggestions. Those of you who would like to contribute, please send us an email.