1. Objects

Everything in Java is an object.

More accurately, there are very few things in Java that are not objects. For example, primitive types. But this is a rather rare exception to the rule.

So what is an object?

An object is an entity that groups data together with methods that process the data. When we say "data", we mean variables, of course.

An object's variables are called its "data" or "state".

An object's methods are said to be its "behavior". It is customary to change an object's state (variables) only using that object's methods. Changing an object's variables directly (not using its methods) is considered bad form.

Every object, as well as every variable, has a type. This type is determined once when the object is created and cannot be changed in the future. An object's type is its class.

Each object has its own copy of instance variables (fields). If a non-static int a variable is declared in a class, and your program creates 10 objects of that class, then each object will have its own int a variable.

Interacting with an object

The most convenient way to work with an object is to store a reference to it in a variable, and then call methods on that variable. This will look familiar to you:

variable.method()

Where variable is a variable that stores a reference to an object, and method is a method of that class.

If you want to refer to a field (variable) of an object, then you also need to use the dot operator:

variable.field

Where variable is a variable that stores a reference to an object, and field is an instance variable (field).


2. new operator

To create an object of a certain class, you need to use the new operator. In general, here's what it looks like to create an object:

Class variable = new Class(arguments);

Where Class is the name of the class of the variable variable as well as the name of the class of the object to be created. And variable is a variable that stores a reference to the created object. And arguments is a placeholder for a comma-delimited list of arguments passed to the constructor.

The specific list of arguments that can be passed is decided by the programmers who write the class.

You've created objects before and even used this particular construct. You haven't forgotten, I hope?

Scanner console = new Scanner(System.in);
int x = console.nextInt();

Scanner console — this creates a console variable whose type is Scanner. new Scanner(System.in) — this creates a new Scanner object. And the assignment operator sets the console variable equal to a reference to the newly created object.

In the second line, we call the nextInt() method on the Scanner object, using the console variable, which stores a reference to the Scanner object.

Examples of object creation:

Code Description
String s = new String("Hello");
Create a String object
Scanner console = new Scanner("");
Create a Scanner object
int[] data = new int[10];
Create an int[]: a container of 10 int elements

The created objects are called objects of the class or instances of the class, while the class is called the class of the object. For example, the s variable stores a reference to an instance of the String class.



3. Introducing classes

I think you've already seen how very convenient it is to use classes written by other programmers. But what about writing your own classes?

How do you know when and where you need your own class and how to make one?

Programmers usually create their own classes when they want to bring a new entity into the program. Does that sound confusing? Then I'll try to explain, but I'm going to start from far away.

Group of data

Simplifying a little, we can say that an object in Java is a block of memory that contains the variables declared in a class (instance fields). Or, in other words, variables combined into a group.

Let's say your program needs to store the coordinates of 100 points and needs a method to display them on the screen. This can be done using arrays. For example, like this:

class Solution
{
   public static void printPoints(int[] x, int[] y, int[] color)
   {
     for (int i = 0; i < x.length; i++)
       System.out.println("Color of (" + x[i] + ", " + y[i] + ") = " + color[i]);
   }

   public static void main(String[] args)
   {
     int[] x = new int[100];
     int[] y = new int[100];
     int[] color = new int[100];
     printPoints(x, y, color);
   }
}

It would be much more convenient if we had a single type for storing all of the information about a point: x, y, color. If such a type doesn't exist in Java, you can create it yourself.

To do this, we'll write code for a Point class:

public class Point
{
   public int x;
   public int y;
   public int color;
}

Now the code above can be rewritten as:

class Solution
{
   public static void printPoints(Point[] points)
   {
     for (int i = 0; i < points.length; i++)
       System.out.println("Color of (" + points[i].x + ", " + point[i].y + ") = " + points[i].color);
   }

   public static void main(String[] args)
   {
     Point[] data = new Point[100];
     for (int i = 0; i < data.length; i++)
       data[i] = new Point();
     printPoints(data);
   }
}

Now let's add a method to the Point class that will display information about the object:

public class Point
{
   public int x;
   public int y;
   public int color;
   public void print()
   {
     System.out.println("Color of (" + x + ", " + y + ") = " + color);
   }
}

Now the Solution class looks like this:

class Solution
{
   public static void printPoints(Point[] points)
   {
     for (int i = 0; i < points.length; i++)
       points[i].print();
   }

   public static void main(String[] args)
   {
     Point[] data = new Point[100];
     for (int i = 0; i < data.length; i++)
       data[i] = new Point();
     printPoints(data);
   }
}

We skillfully hid the point's coordinates and color information inside the Point class along with the method that displays the point's state.

Classes are a way to manage program complexity. A large program becomes less complex when it is broken up into many small classes.


4. Mutable vs immutable objects

Once upon a time, we studied constants in Java and came to a conclusion that is not very comforting. Constants let you protect variables from being changed, but they can't prevent changes to the objects to which they refer.

To solve this problem, Java came up with constant objects. Or, as they are more frequently called, immutable objects.

By the way, you already know such class, whose objects cannot be changed: String. A String object remains forever unchanged after it is created. And how did Java's creators achieve this?

First, all variables of the String class are hidden, i.e. declared private.

Second, you cannot inherit the String class: its class declaration includes the final modifier.

Third, and most interestingly, all methods of the String class, which, in theory, you would expect to change the existing object, do not actually change it, but instead return a new one.

For example, the toUpperCase() method makes all the letters in the string uppercase. But instead of changing the object on which the method is called, it returns a new String object consisting of capital letters:

String text = "This is a very important message";
String message = text.toUpperCase();

This is what will be in memory after executing this code:

Mutable vs immutable objects

So feel free to pass your strings to any method: no one will change them.