In Java, a class is a blueprint or a template for creating objects. It encapsulates data and behavior into a single unit, making it easy to manage and organize code. A class contains fields, which represent the data associated with an object, and methods, which define the behavior of the object. In addition, a class can have constructors, which are special methods used to create and initialize objects. Classes can be organized into packages, which help to group related classes together. In Java, classes are used extensively to create objects that interact with each other to build complex systems. Understanding classes is a fundamental concept in object-oriented programming, and mastering it is essential for building robust and maintainable applications.
Designing a Class in Java with Fields and Methods
Before moving further, remember that, if you define a class with a public access modifier, then the source file must be named after that class name with a .java extension. So, you can not create two classes, where both have a public access modifier, in a single source file. But, you can create infinite numbers of classes, in a single source file, if the classes do not contain any public access modifier or only one class contains a public access modifier. In our next few examples, we will place the main() in the Test Class. This test class will have a public static modifier. And the source file name will be after this class with a .java extension.
Now let us move on. As the title suggests, we are going to discuss classes in java in great detail in this tutorial.
If you search google with a series name, the google server presents you with something like:
In this tutorial, we will not try to do something this complicated. We only want to design a class called Series that has the following field:
- seriesName
- releasedYear
- genre
- numberOfSeasons
- IMDBRating
- rottenTomatoesRating
and it has one method which only prints “Playing the Series” and another method that shows the series information.
playIt();
showSeriesInformation();
class Series {
//declaring the field names and types
String seriesName;
int releasedYear;
String genre;
int numberOfSeasons;
double IMDBRating;
int rottenTomatoesRating;
public String getSeriesName() {
return seriesName;
}
public int getReleasedYear() {
return releasedYear;
}
public String getGenre() {
return genre;
}
public int getNumberOfSeasons() {
return numberOfSeasons;
}
public double getIMDBRating() {
return IMDBRating;
}
public int getRottenTomatoesRating() {
return rottenTomatoesRating;
}
//method to show the information of an object
public void showSeriesInformation() {
System.out.print("Information of Series: ");
System.out.println("Series Name: "+seriesName +", Released Year: "+releasedYear+", Genre: "+genre+", Number of Seasons: "+numberOfSeasons+", IMDB Rating: "+IMDBRating+", Rotten Tomatoes Rating: "+rottenTomatoesRating+"%.");
}
public void playIt(){
System.out.println("Playing the Series!");
}
}
public class SeriesTest {
public static void main(String[] args) {
//Creating an object of type Series
Series one = new Series();
//setting field value/instance variable's value of the newly created object
one.seriesName = "The Expanse";
one.releasedYear = 2015;
one.genre = "sci-fi";
one.numberOfSeasons = 6;
one.IMDBRating = 8.5;
one.rottenTomatoesRating = 94;
//displaying each field value one by one
System.out.println("Series one name: " + one.getSeriesName());
System.out.println("Series one released year : "+one.getReleasedYear());
System.out.println("Series one genre : "+one.getGenre());
System.out.println("Series one number of seasons : "+one.getNumberOfSeasons());
System.out.println("Series one IMDB rating : "+one.getIMDBRating());
System.out.println("Series one rotten tomatoes rating : "+one.getRottenTomatoesRating());
//printing a blank line
System.out.println();
//displaying all the field values of object one at the same time
one.showSeriesInformation();
one.playIt();
}
}
Output:
Series one name: The Expanse
Series one released year : 2015
Series one genre : sci-fi
Series one number of seasons : 6
Series one IMDB rating : 8.5
Series one rotten tomatoes rating : 94
Information of Series: Series Name: The Expanse, Released Year: 2015, Genre: sci-fi, Number of Seasons: 6, IMDB Rating: 8.5, Rotten Tomatoes Rating: 94%.
Playing the Series!
The SeriesTest class creates objects (instances) of the Series class and uses the dot operator (.) to set the instance variables to a specific value. The SeriesTest class also invokes (calls) two methods on the object “one”.
Now it’s time for you to create objects. Create three Series objects.
Fill in the below chart with the values the three objects have at the end of main().
Getting Out of main()
You’re not doing object-oriented programming as long as you’re in main(). A test program running within the main method is fine, but in an OO application, you need objects talking to other objects, not a static main() method creating and testing objects. In this case, talking means objects calling methods on one another.
The two uses of main:
- To test your real class
- To launch/start your Java application
In the previous section, we looked at how to use a separate Test class’s main() method to create and test the methods and variables of another class. In a future tutorial, we’ll look at how to use a class with a main() method to kick off a real Java application (by making objects and then turning those objects loose to interact with other objects, etc.).
Here’s an example of how a real Java application might behave as a “sneak preview.” Because we’re still in the early stages of learning Java, we’re working with a small toolkit, so this program is clunky and inefficient. You might want to consider what you could do to improve it, and that’s exactly what we’ll do in later tutorials. Don’t worry if some of the code is unclear; the main point of this example is that objects communicate with one another.
According to wikipedia:
Tic-tac-toe (American English), noughts and crosses (Commonwealth English), or Xs and Os (Irish English) is a paper-and-pencil game for two players who take turns marking the spaces in a three-by-three grid with X or O. The player who succeeds in placing three of their marks in a horizontal, vertical, or diagonal row is the winner. It is a solved game, with a forced draw assuming best play from both players.
Gameplay
In the following example, the first player (X) wins the game in seven steps:
Tic-tac-toe is played by two players, who alternately place the marks X and O in one of the nine spaces, on a three-by-three grid. The players either take X or O. Suppose you are X and your friend is O. There is no universally accepted rule regarding who plays first, but the convention that X plays first is used in this article. Each player takes turns placing their mark in an empty square. The winner is the first player to get three of their marks in a row (up, down, across, or diagonally). The game ends when all nine squares are filled. If no player scores three points in a row, the game is a tie.
In our version, one player is the user, and the other is the computer.
Players quickly learn that a draw results from the finest play from both sides. Consequently, young children who might not have figured out the best method frequently play tic-tac-toe. We would consider ourselves children for this example. While implementing the Tic-Tac-Toe we assume that there would always be a winner.
The classes required for this game to run are listed below.
Game
This class would only have one instance – one game object. A singleton class is demonstrated here. The Game class would have to allow the two players to alternate turns, check to see if anyone had won after each go, and end the game if they had. Because we start to play by starting the game, this class could contain the main method.
Board
This would require a 3X3 grid and the ability to display it. A singleton once more.
Human player
The human player would be represented by this singleton. It would have to allow for a human turn, with the board displayed and the user able to choose where to go.
Computer Player
This singleton is the human’s opponent. The most important method in this class would be to decide where to go.
Summary
The tic-tac-toe involves a ‘game’ object, a ‘board’ object, and two ‘player’ objects.
Classes:
Game.class Board.class Human.class Computer.class
For simplicity of compilation we will put all the classes in the same source file. We will only make the Game class public and name the source file Game.java.
The Logic:
- The main() method is found in the Game class, which is where the application is launched.
- A Game object is created in the main() method, and its play() method is invoked.
- The game is played in the play() method of the Game object. It first generates three objects – a board, and two players – a human and a computer. Then in an infinite loop, the game is played in turns. First, the human player makes a move and the computer player waits for the first player to put X on the empty cell in the grid. Then the board object checks whether the human has won. If after making the move the player has won then the game is over and player one is the winner. If not then the computer gets to put O in the grid. Then the board object again checks whether the computer has won. If after making the move the computer has won then the game is over and the computer is the winner. If not, then the board is displayed.
First, we will design the Board Class. We need a board to play tic-tac-toe. So it’s logical to make the board first.
class Board {
// data member - an array of characters
private char cells[][] = new char[3][3];
// construct a board
public void createBoard() {
// fill the array with space characters
for (int i = 0; i < 3; i++) {
for (int j = 0; j < 3; j++) {
cells[i][j] = ' ';
}
}
}
// mark an 'X' or 'O'
void set(int row, int col, char ch) {
// check is valid
if (row > -1 && row < 3 && col > -1 && col < 3 && (ch == 'O' || ch == 'X')) {
cells[row][col] = ch;
}
}
char getCell(int row, int col) {
return cells[row][col];
}
// return true if someone's won, otherwise return false
boolean checkWin(char ch) {
boolean result = false;
// check rows
if (cells[0][0] == ch && cells[0][1] == ch && cells[0][2] == ch) {
result = true;
}
if (cells[1][0] == ch && cells[1][1] == ch && cells[1][2] == ch) {
result = true;
}
if (cells[2][0] == ch && cells[2][1] == ch && cells[2][2] == ch) {
result = true;
}
// check columns
if (cells[0][0] == ch && cells[1][0] == ch && cells[2][0] == ch) {
result = true;
}
if (cells[0][1] == ch && cells[1][1] == ch && cells[2][2] == ch) {
result = true;
}
if (cells[0][2] == ch && cells[1][2] == ch && cells[2][2] == ch) {
result = true;
}
// leading diagonal
if (cells[0][0] == ch && cells[1][1] == ch && cells[2][2] == ch) {
result = true;
}
// other diagonal
if (cells[0][2] == ch && cells[1][1] == ch && cells[2][0] == ch) {
result = true;
}
return result;
}
// display the board
void display() {
for (int row= 0; row < 3; row++) {
// display a row
for (int col = 0; col < 3; col++) {
System.out.print("| " + cells[row][col] + " ");
}
// new line at end of row:
System.out.println("|");
}
}
}
public class Game{
public static void main(String[] args) {
Game game = new Game(); //make a game object
game.startGame();//start the game invoking startGame() method on game
game.play(); // play it
}
}
We also created the Game class here to test if the board works! This game class has the main() method in it. The Application starts from here. This class has more functionality in it. We all add them on the go. Remember to save the source file as Game.java
Compile this Game.java source file and run the Application. You will see an empty tic-tac-toe ready to be played.
Fields/Instance Variables
Explanation
Do not worry about the private keyword. It is an access modifier just like the public. We will discuss it later when we discuss encapsulation. Encapsulation is a feature of OOP. We have mentioned it here just to give you a flavor.
Methods:
As of now the code in the main() method of the Game class is self-explanatory. So we will not explain it here. We will explain this once this becomes more complicated.
Compile this Game.java source file and run the Application. You will see an empty tic-tac-toe ready to be played.
Now, we will design both the players’ classes too.
The Human Class
import java.util.Scanner;
class Human {
private Scanner scanner = new Scanner(System.in);
private Board board;
public void setBoardForHuman(Board b) {
board = b;
}
void go() {
System.out.println("Enter row, column);");
int row = scanner.nextInt();
int col = scanner.nextInt();
board.set(row, col, 'X');
}
}
Explanation
Fields
Methods
Computer Class
import java.util.Scanner;
class Computer {
private Board board;
public void setBoardForComputer(Board b) {
board = b;
}
void go() {
// at random, find a space
int row = (int) (Math.random() * 3);
int col = (int) (Math.random() * 3);
//check whether that cell is empty or not,if not empty continuously search for an empty cell
while (board.getCell(row, col) != ' ') {
row = (int) (Math.random() * 3);
col = (int) (Math.random() * 3);
}
// and put an O there
board.set(row, col, 'O');
}
}
The computer is not too bright. It chooses cells at random until it finds one which is empty, and goes there.
Explanation
Fields
Now it is time to design the Game class, where all the objects talk to each other, and let us play the beautiful game of Tic-Tac-Toe.
Game Class
public class Game{
// data fields
private Board board;
private Human human;
private Computer computer;
public void startGame() {
// create the 3 objects which are part of a Game object
board = new Board();
human = new Human();
computer = new Computer();
//pass a reference to the board to the human and computer using their respective setBoard methods
// this lets them refer to the board
board.createBoard();
human.setBoardForHuman(board);
computer.setBoardForComputer(board);
board.display();
}
// play the game:
private void play() {
while (true) { // loop forever
human.go(); // human's turn
// check if they've won
if (board.checkWin('X')) {
break; // leave loop if checkWin() returns true
}
computer.go(); // computer's turn
if (board.checkWin('O')) {
break; // leave loop if computer has won
}
board.display(); // show board and loop
}
// if leave loop, somebody's won:
System.out.println("Game over:");
board.display();
}
public static void main(String[] args) {
Game game = new Game(); //make a game object
game.startGame();//start the game invoking startGame() method on game
game.play(); // play it
}
}
Explanation
Fields
Methods
Correction: createBoard() method is invoked on the board to create a new board.
The main() method is self-explanatory so we will not bother explaining it.
The implementation of the Tic-Tac-Toe is given below:
import java.util.Scanner;
class Board {
// data member - an array of characters
private char cells[][] = new char[3][3];
// construct a board
public void createBoard() {
// fill the array with space characters
for (int i = 0; i < 3; i++) {
for (int j = 0; j < 3; j++) {
cells[i][j] = ' ';
}
}
}
// mark an 'X' or 'O'
void set(int row, int col, char ch) {
// check is valid
if (row > -1 && row < 3 && col > -1 && col < 3 && (ch == 'O' || ch == 'X')) {
cells[row][col] = ch;
}
}
char getCell(int row, int col) {
return cells[row][col];
}
// return true if someone's won, otherwise return false
boolean checkWin(char ch) {
boolean result = false;
// check rows
if (cells[0][0] == ch && cells[0][1] == ch && cells[0][2] == ch) {
result = true;
}
if (cells[1][0] == ch && cells[1][1] == ch && cells[1][2] == ch) {
result = true;
}
if (cells[2][0] == ch && cells[2][1] == ch && cells[2][2] == ch) {
result = true;
}
// check columns
if (cells[0][0] == ch && cells[1][0] == ch && cells[2][0] == ch) {
result = true;
}
if (cells[0][1] == ch && cells[1][1] == ch && cells[2][2] == ch) {
result = true;
}
if (cells[0][2] == ch && cells[1][2] == ch && cells[2][2] == ch) {
result = true;
}
// leading diagonal
if (cells[0][0] == ch && cells[1][1] == ch && cells[2][2] == ch) {
result = true;
}
// other diagonal
if (cells[0][2] == ch && cells[1][1] == ch && cells[2][0] == ch) {
result = true;
}
return result;
}
// display the board
void display() {
for (int row= 0; row < 3; row++) {
// display a row
for (int col = 0; col < 3; col++) {
System.out.print("| " + cells[row][col] + " ");
}
// new line at end of row:
System.out.println("|");
}
}
}
class Human {
private Scanner scanner = new Scanner(System.in);
private Board board;
public void setBoardForHuman(Board b) {
board = b;
}
void go() {
System.out.println("Enter row, column:");
int row = scanner.nextInt();
int col = scanner.nextInt();
board.set(row, col, 'X');
}
}
class Computer {
private Board board;
public void setBoardForComputer(Board b) {
board = b;
}
void go() {
// at random, find a space
int row = (int) (Math.random() * 3);
int col = (int) (Math.random() * 3);
//check whether that cell is empty or not,if not empty continuously search for an empty cell
while (board.getCell(row, col) != ' ') {
row = (int) (Math.random() * 3);
col = (int) (Math.random() * 3);
}
// and put an O there
board.set(row, col, 'O');
}
}
public class Game{
// data fields
private Board board;
private Human human;
private Computer computer;
public void startGame() {
// create the 3 objects which are part of a Game object
board = new Board();
human = new Human();
computer = new Computer();
//pass a reference of the board to the human and computer using their respective setBoard methods
// this lets them refer to the board
board.createBoard();
human.setBoardForHuman(board);
computer.setBoardForComputer(board);
board.display();
}
// play the game:
private void play() {
while (true) { // loop forever
human.go(); // human player makes the move
// check if the human player won after making the move
if (board.checkWin('X')) {
break; // if checkWin() returns true then the human won, break out of the loop
}
computer.go(); // computer player makes the move
// check if the computer player won after making the move
if (board.checkWin('O')) {
break; // // if checkWin() returns true then the human won, break out of the loop
}
board.display(); // show the current state of the board after both the players made their move and
// loop again
}
// checkWin() returns true, somebody has won and so the loop breaks and the statements after the while loop
// block will now execute
System.out.println("Game over:");
board.display();
}
public static void main(String[] args) {
Game game = new Game(); //make a game object
game.startGame();//start the game invoking startGame() method on game
game.play(); // play it
}
}