Architecture & DesignUnderstanding Java Objects and Java Classes

Understanding Java Objects and Java Classes

Developer.com content and product recommendations are editorially independent. We may make money when you click on links to our partners. Learn More.

Classes are a fundamental structure of any object-oriented programming language and Java is no exception. It is a blueprint or structural definition of a design upon which objects are built. Objects are instances of these designs. Analogically, if classes are a design map of a building structure, objects are the building built upon it. So, in a way, classes are generally an abstraction of a real-world entity. It is abstract because it does not give a form/shape, but a definition on how concrete classes would look. Because, in programming, we represents some data, classes that exactly fit that role, it is reasonable to call it an Abstract Data Type. And, by the way, objects are the concrete entity built upon that abstraction.

Overview of Java Classes

  • A class is known by its name and composition. However, there is a type of class, called an Anonymous class, that do not have a name. It is a different idea altogether.
  • A class comprises attributes and methods. They are only accessible by the object instantiated from it (except for elements that are declared as static).
  • A class is a template for objects.
  • A class is extensible by inheritance. However, the final keyword used with class is a restriction imposed upon its extensibility.

Overview of Java Objects

  • Objects can be treated as variables. Objects are created with the new keyword. The new keyword invokes the constructor defined in the class to create the object.
  • An object is a distinct entity instantiated from a class.
  • Objects have fields to store values and methods for action.
  • Fields and methods of one object are distinct from other objects of the same class.
Note: When a attribute/method of a class is declared as static, it becomes a class member element rather than an object member element. It means that, though several objects instantiated from the same class are distinct including every member function and variables, a static element is actually shared among all objects. It is a property of a class, not the object.

Composition of a Class

A class is known by the composition it keeps. That means, apart from the class name that distinguishes one class from another, a class is known exactly by what it is composed of. The item declared in the class are called its attributes that define its properties and the methods house the program statements that perform some tasks, usually on one/more attributes of the class. These methods are called member functions. The way to declare it in Java is as follows:

package org.mano.example;

public class Account {                          // Account is a class name

   private long acno;                           // attributes
   private String name;

   public Account(long acno, String name) {     // a constructor
      super();
      this.acno = acno;
      this.name = name;
   }
   // getter and setter member functions
   public long getAcno() {
      return acno;
   }
   public void setAcno(long acno) {
      this.acno = acno;
   }
   public String getName() {
      return name;
   }
   public void setName(String name) {
      this.name = name;
   }
}

Observe that there are two attributes declared in the class above and four member functions; collectively, they are called getters and setters. Apart from them, there is a function called a constructor. The main difference between other member functions and a constructor is that a constructor must have the same name as the class name, in this case Account, and there is no return type in the function signature. That means, unlike the getters or setters that return long, String, or void, a constructor returns nothing.

A constructor is called to create an object of this class. For example, to create an object, we may write code in the following way.

public static void main(String[] args) {
   Account a=new Account(1234, "Peter");
}

Encapsulation and Information Hiding

Now, there is an important factor to watch out for when designing a class. According to the Object modeling technique, a well-designed class should hide all its implementation details from other modules of the program. That means that the attributes of the class should be accessible only through its member functions. Although Java does not impose any stringent rules, we yet must endeavor to get as close to it as possible. This is an important tenet of software design, called by the name information hiding or encapsulation. This principle has manifold uses, even with slight glitches in performance. It leverages parallel development by decoupling class modules across a system. Because the classes become independent, they can be developed, maintained, tested, optimized, and used in isolation.

The private and public keywords used in the Account class are called access modifiers that support the idea of encapsulation. The private keyword means that the item is inaccessible outside the class and the member functions are the only way to access them. The public keyword means that the element is accessible by the object of that class (using a dot (.) operator). Apart from these two, there is another access modifier, called protected. The protected keyword means that the element will be accessible through inheritance. These are, of course, a very brief idea of the access modifiers. Readers may refer to the article “Understanding the intricacies of Java Access Modifiers” for a more elaborate description on this.

Inheritance

Inheritance is an important and broad concept of object-oriented modeling. It allows the creation of a hierarchical classification. The idea is to create a class with some specific traits. The behavior of the class can be extended by one/many of its subclasses. Java allows a single inheritance for classes; that means a class can extend only one superclass at a time. This restriction, however, does not apply to an interface. There can be multiple implementations of interfaces. Classes are inherited with the extend keyword and interfaces are extended with the implements keyword. The concept of inheritance is deep and delving into more detail that is out of the scope of this article. To give a glimpse, an example of inheritance of a class and interface implemented is as follows.

public class Shape {
   // ...
}

public class Oval extands Shape {
   // ...
}

public interface one { // ... }
public interface two { // ... }

public class interfaceImpl implements one, two {
   // ...
}

Types of Java Classes

There are different types of classes declared in Java. A class may be declared as abstract, final, generic, or interface. Each has its specific uses.

Abstract Classes

Abstract classes are primarily an incomplete implementation of a normal class. The characteristic of this class is that one or more member function is not defined or does not have a body. This is not a rule imposed, but it is assumed to be. Syntactically, there is no harm in making every class an abstract class though that defeats the reason behind the creation of abstract classes. The intention is to extend this class for re-implementation in an inheritance hierarchy whereby we define the non-defined member function by its inherited classes. An object of an abstract class can never be created. We, however, can create the object of a class that inherits the abstract class, provided the inherited class is also not abstract. For example, the preceding Account class can be implemented as an abstract class by adding a non-defined behavior called getInterestRate(), as follows:

package org.mano.example;

public abstract class Account {

   // ... same as above

   public abstract double getInterestRate();

}

Now, this is not allowed.

// not allowed, Account is abstract
Account a=new Account(1234, "Peter");

But, we can inherit this class and create an object, as follows:

package org.mano.example
public class SavingsAccount extends Account {

   public SavingsAccount(long acno, String name) {
      super(acno, name);
   }

   @Override
   public double getInterestRate() {
      return (6/100);
   }
}

An object can be created as follows:

Account a=new SavingsAccount(1234, "Peter");   // OK

A class declared as final is not allowed to inherit or cannot make any subclass of it. Any attempt to declare a subclass of a final class results in a compilation error. If a designer has a good reason to make a class non-inheritable, the final class is the answer.

Generic Classes

Generic classes associate a type binding that differs as objects of the class are instantiated, meaning this class behaves according the type it is associated with at runtime. Suppose we want to implement a Stack class that works equally well with any datatype. The ideal way to design this class as generic as follows:

package org.mano.example;

public class Stack<T> {
   private final int size;
   private int tos;
   private T[] items;

   public Stack() {
      this(5);
   }

   public Stack(int size) {
      this.size = size > 0 ? size : 5;
      tos = -1;
      items=(T[])new Object[size];
   }

   public void push(T val) {
      if (tos == size - 1)
         throw new FullException("cannot push value. ");
      items[++tos] = val;

   }

   public T pop() {
      if (tos == -1)
         throw new EmptyException("cannot pop value");
      return items[tos--];
   }

}

package org.mano.example;

public class FullException extends RuntimeException {
   private static final long serialVersionUID =
      -6357016388907299054L;

   public FullException() {
      this("Stack is full");
   }

   public FullException(String msg) {
      super(msg);
   }
}

package org.mano.example;

public class EmptyException extends RuntimeException {
   private static final long serialVersionUID =
      3824819887574046494L;

   public EmptyException() {
      this("Stack is empty");
   }

   public EmptyException(String msg) {
      super(msg);
   }
}

Refer to the articles “Getting Started with Java Generics” and “Using Java Generics to Leverage Refactoring” for more information on generics.

Interfaces

Interfaces are similar to abstract classes. But, there are some significant differences. Interfaces allow us to specify a set of methods that are implemented by one or more subclasses. Usually, interfaces do not have any methods definition, but a default method may be defined. Further, a class can implement multiple interfaces in contrast to a class that can inherit only one super class, be it an abstract class or a normal class. The provision for defining a default method in an interface is a recent inclusion (since Java 8).

package org.mano.example;
import java.util.Calendar;

public interface DemoInterface {
   static final double PI = 3.141592653589793;

   static String getDate() {
      Calendar c = Calendar.getInstance();
      return c.get(Calendar.DATE)
         + "-" + (c.get(Calendar.MONTH) + 1)
         + "-" + c.get(Calendar.YEAR);
   }

   default String getTime() {
      Calendar t = Calendar.getInstance();
      return t.get(Calendar.HOUR)
         + ":" + t.get(Calendar.MINUTE)
         + ":" + t.get(Calendar.SECOND) + " "
         + (t.get(Calendar.AM_PM) == 1 ? "PM" : "AM");
      }
   }


public class DemoInterfaceImpl implements DemoInterface{
   public DemoInterfaceImpl(){
      super();
   }
}

package org.mano.example;

public class Main {

   public static void >main(String[] args) {
      DemoInterface di=new DemoInterfaceImpl();
      System.out.println(di.getTime());
      System.out.println(DemoInterface.getDate());
   }
}

Nested Classes

Java supports defining a class as nested within another class. The scope of the nested class is bounded by the enclosing class. It can access all the members, including private members of the class in which it is nested. An inner class is another connotation used for a special nested class. This type of class can be defined even within an expression. When the inner class does not have an assigned name, it is called an anonymous class. All of them have their uses under certain circumstances. For example, an inner class can be used in the following manner:

package org.mano.example;

import java.awt.FlowLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;

import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JOptionPane;

public class MyFrame extends JFrame {
   private static final long serialVersionUID =
      4618894960445661880L;
   private final JButton hiButton=new JButton("Say Hi!");
   private final JButton byeButton=new JButton("Say Bye!");

   public MyFrame(){
      super("Demo");
      setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
      setLayout(new FlowLayout(FlowLayout.CENTER));
      getContentPane().add(hiButton);
      getContentPane().add(byeButton);
      hiButton.addActionListener(new ButtonHandler());
      byeButton.addActionListener(new ButtonHandler());
      pack();
      setVisible(true);
   }

   class ButtonHandler implements ActionListener{

      @Override
      public void actionPerformed(ActionEvent e) {
         if(e.getSource()==hiButton)
            JOptionPane.showMessageDialog(null, "Hi!
            Nice to meet you.");
         if(e.getSource()==byeButton)
            JOptionPane.showMessageDialog(null, "Goodbye!
            Have a nice day.");
      }
   }
}

package org.mano.example;

public class Main {
   public static void< main(String[] args) {
      new MyFrame();
   }
}

The preceding example can be rewritten using an anonymous class, as follows:

package org.mano.example;

import java.awt.FlowLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;

import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JOptionPane;

public class MyFrame extends JFrame {
   private static final long serialVersionUID =
      4618894960445661880L;
   private final JButton hiButton = new JButton("Say Hi!");
   private final JButton byeButton = new JButton("Say Bye!");

   public MyFrame() {
      super("Demo");
      setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
      setLayout(new FlowLayout(FlowLayout.CENTER));
      getContentPane().add(hiButton);
      getContentPane().add(byeButton);
      hiButton.addActionListener(new ActionListener() {

         @Override
         public void actionPerformed(ActionEvent e) {
            JOptionPane.showMessageDialog(null, "Hi!
            Nice to meet you.");
         }
      });
      byeButton.addActionListener(new ActionListener() {
         @Override
         public void actionPerformed(ActionEvent e) {
            JOptionPane.showMessageDialog(null,"Goodbye!
            Have a nice day.");
         }
      });
      pack();
      setVisible(true);
   }
}

Conclusion

Objects and classes are such a fundamental concept that, when you talk about this subject, you tend to include every aspect of the object-oriented paradigm. Objects and classes are just a veil, a simple definition, such as one is a structure and another is an example of that structure. It iss just an oversimplification. Once you penetrate this idea and have a peek through the veil, a whole new world emerges, the world of object-oriented technology that is definitely more than Java. As a result, we can almost say, if Object-Oriented Technology is a class, Java is an object of it.

Get the Free Newsletter!

Subscribe to Developer Insider for top news, trends & analysis

Latest Posts

Related Stories