JBay Solutions Development Blog on Java, Android, Play2 and others
RSS RSS RSS RSS

Java Tutorial 4 - Classes, Constructors and Methods

  1. Introduction
  2. Variables Scope
  3. Classes and Objects
  4. Creating methods
    1. Setter Methods
    2. Getter Methods
  5. Constructors
  6. Exercise
  7. What else about methods?

Introduction

In the previous tutorials we dabbed into Primitive variables, did a few operations with them, nothing special or exciting.

In this tutorial however, we'll now look at Objects and Reference Variables, and we'll start with understanding the Scope of variables.



Variables Scope

In our previous examples, the ones shown in the previous tutorial, all our variables were defined and used inside a method. What this means is that those variables are only available inside that method, they are created and erased and recreated with each time that method is executed.

Look at the next Class:

public class Scope {

    int classVariable = 1;

    public void methodNumber1() {

        int methodVariable1 = 2 ;

    }

    public void methodNumber2() {

        int methodVariable2 = 3 ;

    }
}

There are a total of 3 variables defined in this Class.

  • classVariable: This variable can be accessed from anywhere inside the Class and it can be accessed from inside any of the methods inside that Class. Just as a side note, this is called a variable with Class Level Scope.

  • methodVariable1 and methodVariable2 : These variables can be accessed only from inside the methods they are defined in. In fact, they don't exist outside of the execution of their method, and therefore, methodNumber2 cannot access (read, write... print) methodVariable1, because that variable is only defined inside methodNumber1. This is called having Method Level Scope.

The names Class Level Scope and Method Level Scope are not really important to know, but what they imply is. methodVariable1 and methodVariable2 exist only inside their respective methods. They could even have the exact same name, it wouldn't matter, they don't exist outside of the methods.

Code indentation (writing code in an organized way, like we have been doing so far) really helps a lot to understand the scope of variables.

Classes and Objects

To explain the concept of Objects and Classes, we'll implement a very rudimentary system that creates and stores Users and some attributes of each of the Users, and then prints out a listing of this information, formatted in some particular way.

Because we know we will be storing Users, and those users have attributes, we know that the best way to organize this information would be to have a "template" for what a user should have. We'll start with the creation of a User class.

Create a new file called User.java inside an empty folder that will be used for this tutorial, and write the code for the class:

public class User {

}

This Class, as it is, will store absolutely nothing, and it has no methods defined, so in practice it will do nothing.

Lets say that our Users will all have a name and an age:

public class User {

    String name;
    int age;

}

So this class can now be used to store two pieces of data :

  • a name, of type String
  • an age, of type int

But let us discuss it a bit further.



As we saw in the previous tutorial, and int is a primitive type that uses 32bits. It can be a number that goes as high as 2^31-1, so it is very unlikely (if not biologically impossible) that someone will ever be that age. We could actually use a byte to store the age of the User, it would save memory (if that is a concern) .

We'll choose to continue using an int, for no particular reason.

We also have a variable named name of type String. String is a very particular type, it is not a primitive (it is in a way a collection of chars) but can be declared like a primitive, and also some operators work on it ( like the + operator, when we concatenate Strings). We'll talk about String in a second.

Another difference from what we have been doing so far, is that there is no main method on this class. This means that you cannot execute this class, and therefore the main method must exist in another class, if the project is to be executed.

Without closing the User.java file, create another file, right next to the User.java file, and call it "LessonExecution3.java" . This will be the Class that starts the program, and will make use of the User class. Create the LessonExecution3 class and create a main method in it. It should look like this:

public class LessonExecution3 {

    public static void main(String[] args) {

    }

}

Now, lets create a User and store it, we'll specify the name and the age of the user, and then, we will print that data:

public static void main(String[] args) {
    User user = new User();
    user.name = "Rui";
    user.age = 35;

    System.out.println( "User Name: " + user.name );
    System.out.println( "User Age: " + user.age );
}

Compile and run both files like this:

javac User.java LessonExecution3.java
java  LessonExecution3

The output should be something like:

User Name: Rui
User Age: 35

Lets look at the inside of the main method we have just created inside the LessonExecution3 class.

We start with the statement:

User user = new User();

We know that User is a class, and therefore what we are doing here is creating a variable of that Type, and assigning a newly created Object of that type to the variable:

  • User user : creating a variable of type User
  • new User() : creating an Object of type User
  • User user = new User() : Assigning the object to the variable.

When creating an object, the notation is always new Object , with emphasis on the word new .

So. after we create and assign an Object of type User to the variable named user, we access the variables inside that object using the . (dot) notation:

user.name = "Rui";
user.age = 35;

Notice that when we access the variables inside the newly created object, we use name of the variable of the object, and the name of the variable inside that object. Looking at user.name we can break it down like this:

  • user : the name of the variable , not the name of the Class!
  • name : the name of the variable inside that particular object!

Remember, we don't do something like User.name because User is the name of the Class, and the Class, like we said before is just a template for objects to be created.

After we access the variables to assign them values, we perform the System.out.println() statements, where we access the variables inside the particular Object and print those values out.

This works, but lets make it better!



Creating Methods

Now, the printing of data of the User object is being done on the main method, which is not very wise if one wants to print the contents of several User objects, because it would mean that there would have to be as many System.out.println as twice the number of User objects created.

A method that prints this same data could be easily created. Lets do it.

Go to the User class source code file, and modify it to look like this :

public class User {

    String name;
    int age;

    public void printData() {
        System.out.println( "User Name: " + name );
        System.out.println( "User Age: " + age );
    }

}

In this updated version of the User class, we have now a method called printData that :

  • returns nothing : void
  • receives nothing : ()
  • performs some System.out.println() statements inside.

Notice that when we do the printing inside this method, we access the variables directly, without using the dot notation. This is because :

  • the scope of those variables makes them accessible from that method
  • Also, the variable User user does not exist on this class, it is only accessible from the LessonExecution3 class, inside the main method.

Now the main method of LessonExecution3 must be modified to call the method printData instead of having the two System.out.println statements. We do it like this:

public class LessonExecution3 {

    public static void main(String[] args) {
        User user = new User();
        user.name = "Rui";
        user.age = 35;

        user.printData();  // <------------
    }

}

On this new version, the System.out.println statements were removed, and replaced by the user.printData() statement, which has inside some other System.out.println statements. We call the method by using the variable of the object we want to access, and using the dot notation specify the method we want to execute. In this particular case, because printData receives no arguments, we place the ( ) with nothing inside the brackets.

Setter Methods

But we can improve this code a lot still. When we declare the user variable and instantiate it, we then access the variables inside that object to assign values to them. This is actually a bad practice.

Instead of accessing the variables directly, we should be using methods to both set values of these variables and to get the values of these variables.

We'll now implement a method to set the variable name. We call methods that specifically set values for variables Setter Methods, and a modified version of the User class with a setter method for the name variable can be seen next:

public class User {

    String name;
    int age;

    public void printData() {
        System.out.println( "User Name: " + name );
        System.out.println( "User Age: " + age );
    }

    /*
    Setter method for the name variable
    */
    public void setName(String newname) {
        name = newname ;
    }

}

There is now a method with the signature like public void setName(String newname), which means:

  • the method receives only one argument, which we call newname
  • the method return nothing : void

Then, inside the method, we set the Class Variable name with the value of the received variable newname , like this : name = newname ; . Simple yes?

But having this Setter method does not stop programmers from accessing the variable name directly and modifying it! It is just another way to modify the Class variable.

There is a way to make it impossible for a user to access the variable directly, which the use of Access Modifiers, and we'll see about it on the next Tutorial.

Now lets modify the main method inside LessonExecution3 to use the setter method for name instead of accessing it directly:

public static void main(String[] args) {
    User user = new User();
    user.setName( "Rui" );   //   <-------- Using setter method for name
    user.age = 35;    //  <-------- Accessing age variable directly

    user.printData();
}

Because the setName method requires a String parameter as input, the method is called with the value to be assigned to that parameter inside the () brackets, like this: ( "value" ) .



If, for example, the required parameter was a number, of type int , then calling the method and providing a String as argument would make the program not compile.

Now, do exactly the same thing to the variable age . Create a setter method and modify the main method to call the setter method for age instead of accessing it directly.

The resulting User class should look something like this :

public class User {

    String name;
    int age;

    public void printData() {
        System.out.println( "User Name: " + name );
        System.out.println( "User Age: " + age );
    }

    /*
      Setter method for the name variable
    */
    public void setName(String newname) {
        name = newname ;
    }

    /*
      Setter method for the age variable
    */
    public void setAge(int newage) {
        age = newage ;
    }

}

Notice that we have started putting comments before the methods, explaining what they will be doing.

And then the main method should look like this:

public static void main(String[] args) {
    User user = new User();
    user.setName( "Rui" );
    user.setAge( 35 );

    user.printData();
}

Now that we already made 3 methods, including two that are setter methods, it makes sense to create also the getter methods for those variables!

Getter Methods

Getter methods are just what their name say, they are methods to get values of specific variables.

For example, from looking to our class User to get the values of both name and age variable a programmer would need to access them directly. This is not desired, accessing variables from other classes directly is a bad practice, and therefore we need a way to access the values of those variables.

Accessing variables from other classes directly is a bad practice

To create a getter method for the variable name, we need to write a method whose signature should look like this: public String getName() , which means:

  • the method returns one String : String
  • the method does not require any parameters ; ( )

Now the question is, how does one make a method return a value? Simple, we use the return keyword :

/*
  Getter method for the Name variable
*/
public String getName() {
    return name;
}

So, if somewhere on our code, from outside of the User class, we would like to get the value of name of a particular object, we can now instead use this getter method. Lets exemplify using our main method inside of LessonExecution3 :

public static void main(String[] args) {
    User user = new User();
    user.setName( "Rui" );
    user.setAge( 35 );

    user.printData();

    // ---- Testing the getter method ----
    String valueFromObject = user.getName();
    System.out.println("Testing getter method : "  + valueFromObject );
}

Modify your classes accordingly, compile and give it a run. The output should look something like :

User Name: Rui
User Age: 35
Testing getter method : Rui

Now, as an exercise implement a getter method for the age variable, that returns an int and test the getter method on the main method, like we did before.

The resulting User class should look like this:

public class User {

    String name;
    int age;

    public void printData() {
        System.out.println( "User Name: " + name );
        System.out.println( "User Age: " + age );
    }

    /*
      Setter method for the name variable
    */
    public void setName(String newname) {
        name = newname ;
    }

    /*
     Getter method for the name variable
    */
    public String getName() {
        return name;
    }

    /*
      Setter method for the age variable
    */
    public void setAge(int newage) {
        age = newage ;
    }

    /*
    Getter method for the age variable
    */
    public int getAge() {
        return age;
    }

}

And the resulting LessonExecution3 class should look like this:

public class LessonExecution3 {

    public static void main(String[] args) {
        User user = new User();
        user.setName( "Rui" );
        user.setAge( 35 );

        user.printData();

        String valueFromObject = user.getName();
        System.out.println("Testing getter name method : "  + valueFromObject );

        int ageFromObject = user.getAge();
        System.out.println("Testing getter age method : "  + ageFromObject );

    }

}

But we can still make it better!

If we look at the previous code, to create a User object with complete information (with name and age) we must do it in 3 different statements!

If we accept that a User must always have a name and age , then this code will not do it, because we are not forcing these to be defined at creation, which means that if someone creates a User object and then forgets to call the setters for name and age, the User object would not have these variables defined.

For this, there is a special kind of method, which is called a Constructor that can only be called at the creation of the object.



Constructor

A Constructor is a method that does not return anything, and has the exact same name as the Class and is called during instantiation of the new Object.

Each class must have at least one Constructor, but if none is provided, one is created automatically, called the default constructor, which takes 0 parameters and does absolutely nothing.

In the previous version of the code, the User class has no constructor, which mean that one is created automatically (behind the scenes), which is equivalent to this :

public class User {

    /*
     The Default Constructor
    */
    public User() {

    }

    String name;
    int age;

    [ ETC ETC ETC ] 
}

And when in the main method we were doing:

User user = new User();

the new User() is actually saying : create a new object of type User, using the "no arguments" Constructor.

As you can see, the constructor :

public User() {

}
  • Has no return type defined, because it is a constructor
  • Has the same name as the Class

A class can have multiple Constructors, as long as they have different signatures, which in this particular case means that each different Constructor must have different types of parameters that they take as input (or the number of parameters vary). For example, having these constructors all on the same class would be acceptable:

  • public User()
  • public User(String newname)
  • public User(String newname, int age)
  • public User(int age, String newname)

Having a class with all these constructors would be illegal:

  • public User()
  • public User(String firstname)
  • public User(String surname)

Because the last two Constructors are identical.

So, recapping, if no Constructor is defined, then one is automatically created, that takes no arguments, and does absolutely nothing. And if one Constructor is specified, then the automatic "no arguments" constructor is not created.

Getting back to our code, because we decided that there would make no sense to have User objects without name and age, we'll create a Constructor that must receive both these parameters, and we delete the "no arguments" Constructor if there is one:

public class User {

    String name;
    int age;

    public User(String newname, int newage) {
        name = newname;
        age = newage;
    }

    [ETC ETC ETC]

}

At this point we have a User class that has only one constructor, and that constructor must take 2 arguments, the newname String and the newage int.

If you tried to compile now you would get an error like this :

LessonExecution3.java:4: error: constructor User in class User cannot be applied to given types;
        User user = new User();
                    ^
  required: String,int
  found: no arguments
  reason: actual and formal argument lists differ in length
  1 error

This happens because we are creating the user object using a constructor that does not exist! Remember, before we had no Constructor defined, and because of that one automatic one was created. Now there is one, and because there is only one, we must use that constructor!

We must now modify the main method to make use of that constructor:

public static void main(String[] args) {
    User user = new User("Rui" , 35);
    user.setName( "Rui" );
    user.setAge( 35 );

    user.printData();

    String valueFromObject = user.getName();
    System.out.println("Testing getter name method : "  + valueFromObject );

    int ageFromObject = user.getAge();
    System.out.println("Testing getter age method : "  + ageFromObject );

}

Notice that now we are creating the object using new User("Rui" , 35); , which tells us that we are using the Constructor that takes one String and one int, in that particular order.

Afterwards we have :

user.setName( "Rui" );
user.setAge( 35 );

This is unnecessary, because the values are already being set in the Constructor. Lets remove that, and we end up with :

public static void main(String[] args) {
    User user = new User("Rui" , 35);

    user.printData();

    String valueFromObject = user.getName();
    System.out.println("Testing getter name method : "  + valueFromObject );

    int ageFromObject = user.getAge();
    System.out.println("Testing getter age method : "  + ageFromObject );

}

Compile everything now and run it, to verify that the values are being set correctly:

User Name: Rui
User Age: 35
Testing getter name method : Rui
Testing getter age method : 35

Exercise

As an exercise, create another constructor on the User class, that takes an int and a String, is this new order and create another object of type User in a variable called user2 , using the new Constructor, and call the printData method on that object!

The code for the User class should end up looking like this:

public class User {

    String name;
    int age;

    public User(String newname, int newage) {
        name = newname;
        age = newage;
    }

    public User(int newage, String newname) {
        name = newname;
        age = newage;
    }

    public void printData() {
        System.out.println( "User Name: " + name );
        System.out.println( "User Age: " + age );
    }

    [ETC ETC ETC]

}

And the code for the LessonExecution3 should look something like this:

public class LessonExecution3 {

    public static void main(String[] args) {
        User user = new User("Rui" , 35);

        user.printData();

        User user2 = new User(99, "Old Man");

        user2.printData();

        String valueFromObject = user.getName();
        System.out.println("Testing getter name method : "  + valueFromObject );

        int ageFromObject = user.getAge();
        System.out.println("Testing getter age method : "  + ageFromObject );

    }

}

At this point you should know how to implement methods and constructors , create new classes , and create instances of those classes (creating new Objects of the class type). All of this speaks to the absolute basic mechanics of Object-Oriented programming.

There are a few more considerations to know about methods, that you might have figured out already, but we'll put it in writing.



What else about Methods?

A method can have both input and output at the same time. Look at this valid method, which is totally unrelated to the code we have been producing:

public int sumTwoNumbers(int number1 , int number2) {
    return number1 + number2 ;
}

This method is completely acceptable, and valid. It receives two ints and returns the sum of those ints .

Variables that are declared inside the method cannot be accessed outside of that method:

public void  testFunction ( ) {
    int specialNumber;   // <--- Declared
    specialNumber = 20 ;  // <--- Assigned

    specialNumber = specialNumber + 10 ; 

    System.out.println("Value now is : "  + specialNumber); // <-- will print 30

    // HERE 
}

In the previous example, each time the method testFunction is executed, a variable is created called specialNumber, and just before the method finishes, this variable stops existing. Remember, those variables only exist inside the method!

Now, if the declaration is outside of the method, in the Class:

int specialNumber;   // <--- Declared

public void  testFunction ( ) {

    specialNumber = 20 ; 
    specialNumber = specialNumber + 10 ; 

    System.out.println("Value now is : "  + specialNumber); // <-- will print 30

}

in this case, the variable specialNumber will exist for each object , and can be accessed from any method on that Class.

And that is it for this tutorial! In the next tutorial we will look into Packages and Access Modifiers, like the keyword public that we have been using.

Lets go, next Tutorial: Tutorial 5 - Packages and Access Modifiers



comments powered by Disqus