Chapter:Inheritance - Every class extends Object - Exercises

From Juneday education
Jump to: navigation, search

Exercises

In the exercises below we want you to (evetually) use the following directory structure:

.
`-- com
    `-- sportmanagers
        `-- sportman
            |-- main
            |   `-- Main.java
            |-- Member.java
            |-- Team.java
            `-- test
                |-- MemberTest.java
                `-- TeamTest.java

This means we strongly suggest you enter the directory where the com dir is located - but do not enter the com directory. This way the relative paths to the files corresponds directly with the package names and you will have a much nicer time compiling and running your program.

The task for the exercises below is to start writing parts for a system to manager sport clubs. We start by writing class to represent a member and the club itself. To make sure we're writing code for the same kind of system we will decide the package structure, class names and class strucure. Feel free to write the classes the way you want it but it may mean that the suggested solutions will not help you.

A member need to have a name, an email addres and an id.

A team need to have a name and a list (possibly empty) of members (players)

Q1

Write a class, Member with the following private instance variables:

  • name (String)
  • email (String)
  • id (int)

The class should be located in the package: com.sportmanagers.sportman.

Expand using link to the right to see a suggested solution/answer.

Suggested solution:

package com.sportmanagers.sportman;

public class Member {

    private String   name;
    private String   email;
    private int      id;
}

Q2

Add public constructor for setting the three instance variables

Expand using link to the right to see a suggested solution/answer.

Suggested solution:

    public Member(String name, String email, int id) {
	this.name  = name;
	this.email = email;
	this.id    = id;
    }

Q3

Add public methods for users of your class (or rather instances from that class) that return the instance variables (in separate methods of course).

Expand using link to the right to see a suggested solution/answer.

Suggested solution:

    public int id() {
	return id;
    }

    public String name() {
	return name;
    }

    public String email() {
        return email;
    }

Q4

Ok, time to test our class. We will not (why should we?) add a main method to our Member class just as there's no main method in the String class. So write a test class for Member. Let's call it MemberTest. Write a main method which creates three objects and stores them in an ArrayList. Use the package name com.sportmanagers.sportman.test for the test class.

Hint: in the chapters about Objects and Classes you created ArrayLists in some of the exercises (Chapter:Objects_-_Using_-_Exercises#Exercise_4._Using_ArrayList here for instance). Go back and check there, and possibly redo the exercise, if you don't know how to create ArrayLists

Expand using link to the right to see a suggested solution/answer.

Suggested solution:

package com.sportmanagers.sportman.test;

import java.util.ArrayList;
import com.sportmanagers.sportman.Member;

public class MemberTest {

    public static void main(String[] args) {

        ArrayList<Member> register = new ArrayList<>();

	register.add(new Member("Ada", "ada@lovelace.org", 1));
	register.add(new Member("Bart", "bart@simpson.net", 2));
        register.add(new Member("Marge", "marge@simpson.net", 3));

        // The above is a shorter way of writing the code below
        //
        // We create the Members and store the references to them
        // directly without using a variable name.
        //
        // It is a reference (or references) to instance(s) we store
        // in an variable(s), array or ArrayList, never the actual
        // object.
        //
        /*
        Member m1 = new Member("Ada", "ada@lovelace.org", 1);
        Member m2 =new Member("Bart", "bart@simpson.net", 2);
        Member m3 =new Member("Marge", "marge@simpson.net", 3);
        register.add(m1);
        register.add(m2);
        register.add(m3);
        */
        // or another example:
        /*
        Member m1 = new Member("Ada", "ada@lovelace.org", 1);
        register.add(m1);

        m1 =new Member("Bart", "bart@simpson.net", 2);
        register.add(m1);

        m1 =new Member("Marge", "marge@simpson.net", 3);
        register.add(m1);
        */


    }


}

Q5

Compile and run test test class

Expand using link to the right to see a suggested solution/answer.

To compile:

javac com/sportmanagers/sportman/test/MemberTest.java

To execute:

java com.sportmanagers.sportman.test.MemberTest

... and if you, as we would like to suggest, compile and execute (only if compilation succeeds) at the same time:

javac com/sportmanagers/sportman/test/MemberTest.java  && java com.sportmanagers.sportman.test.MemberTest

Q6

Nothing is printed. Have the objects been created if we don't "see" them?

Expand using link to the right to see a suggested solution/answer.

The objects have been created. Both the Member instances as well as the ArrayList instance. Outputing text to a stream does not do anything magic. Fact is that most of the things a program do, whether it is creating objects, calculating or what have you is done without printing anything).

Q7

Add a printout to check the "content" of the objects. Do this by looping (e.g. use the for each-loop) through the object references in the ArrayList and call System.out.println and pass the object reference as argument to println.

Hint: We've printed the user arguments (String instances in an array) in earlier exercises.

Expand using link to the right to see a suggested solution/answer.

Suggested solution

        for (Member m : register) {
            System.out.println(m);
        }

Q8

Why is the output looking like it does?

The output is not very impressing. But this is enough for now. We will continue with this Member class in the next section.

So we can consider our Member class to be ready to be used. So let's continue with the Team class.

Expand using link to the right to see a suggested solution/answer.

What happens when we invoke println and pass an object reference, is that the method toString() (eventually) is called on that reference, to get a String representation of that Member object.

We inherit this version of the method toString() from Object. In one implementation of Java we can find the following source code in Object.java:

    public String toString() {
        return getClass().getName() + "@" + Integer.toHexString(hashCode());
    }

So when we print an object, by passing a reference to System.out.println(), we eventually end up invoking the method above. This explains the look of the printout. The printout is neither magic nor a string representation of a reference.

Q9

Write a new class, Team with the following private instance variables:

  • name (String)
  • members (ArrayList)

Expand using link to the right to see a suggested solution/answer.

Suggested solution:

package com.sportmanagers.sportman;

import java.util.ArrayList;

public class Team {

    private String    name;
    private ArrayList<Member> members;

}

Q10

Write a constructor for Team that can be used to set the name

Note: the constructor should create an internal empty ArrayList. This is needed if adding members later on.

Expand using link to the right to see a suggested solution/answer.

Suggested solution:

    public Team(String name) {
	this.name = name;
        this.members = new ArrayList<>();
    }

Q11

Write a constructor for Team that can be used to set the name and the list of members. This is convenient if someone has already a list of Member references, and wishes to create a team. This person can then use this constructor and provide both a name for the team as well as a list of the team's members.

Expand using link to the right to see a suggested solution/answer.

Suggested solution:

    public Team(String name, ArrayList<Member> members) {
	this.name   = name;
	this.members = members;
    }

Comment from the teachers:

It is a little questionable to force creators of a Team (code that creates a new Team) to first create an ArrayList of Members. Actually, this creates a dependency between such code and the Team class which makes it harder both to use the Team class (you need to import and use ArrayList) and also harder to change the Team class (if we decide it shouldn't use an ArrayList but some other kind of list or even an old array for its members. But we allow for this now, because we also have a constructor which only sets the name, and soon we'll have an addMember(Member) method, which allows for adding a member at the time.

We thought we'd make this comment to get you thinking about what consequences design decisions like this might have on the code which uses your classes.

Q12

Class diagram showing the association between a Team and Member objects

Write two public methods that can return the name and the list of members. BTW, Does the Team class need a main method?

Expand using link to the right to see a suggested solution/answer.

    public String name() {
        return name;
    }

    public ArrayList<Member> members() {
        return members;
    }

No, we don't need to add a main method. Just as String does not need a main method. Team is not a program - it is soon to be part of a program.

Also, add a method public int numberOfMembers() which returns the number of members of this team.

Hint: You can use the ArrayList instance method size() to get the number of members. This is what you should return from the method!

Expand using link to the right to see a suggested solution/answer.

  public int numberOfMembers() {
    return members.size();
  }

This method allows code using the Team class to get the number of members, without first having to get the whole list of members and then ask the list for its size! It's much more convenient to ask the Team directly, for how many members it has. Why shouldn't the Team object be able to answer this simple question itself? Objects should be capable and not cheap bastards who let the code using them do all the work!

Q13

Let's start writing tests to make sure our Team class works.

  • Let's call the class TeamTest. Write a main method which:
  • Use the package name com.sportmanagers.sportman.test for the test class.
  • Creates a Team instance by invoking the second constructor by passing;
    • a name, e g "My Team", and
    • an ArrayList with three Members
  • Verify that the number of members in the team is correct.

Hint: ask the Team instance for the list of members and count the members (or is there a method in the ArrayList that already does this?)

Expand using link to the right to see a suggested solution/answer.

Suggested solution:

package com.sportmanagers.sportman.test;

import java.util.ArrayList;

import com.sportmanagers.sportman.Member;
import com.sportmanagers.sportman.Team;

public class TeamTest {

  public static void main(String[] args) {

    // Create an ArrayList with three members (to pass to the constructor)
    ArrayList<Member> threeMembers = new ArrayList<>();
    threeMembers.add(new Member("Ada", "ada@lovelace.org", 1));
    threeMembers.add(new Member("Bart", "bart@simpson.net", 2));
    threeMembers.add(new Member("Marge", "marge@simpson.net", 3));

    // Crete a team, pass a name and the list of three members
    Team myTeam = new Team("One Team", threeMembers);

    // Verify size (three members - so the size should be three)
    System.out.print("Checking size of myTeam:       ");
    assert (myTeam.numberOfMembers() == 3) : "Number of members wasn't three!";
    System.out.println("ok");
  }
}

Q14

Create one more team in the TeamTest class' main method. When creating this Team you should use the constructor with only one parameter. Verify the amount of members.

Expand using link to the right to see a suggested solution/answer.

Suggested solution:

        // Create another team, pass a name ... no list
        Team myOtherTeam = new Team("One More Time");

        // Verify size (no members - so the size should be 0)
        System.out.print("Checking size of myOtherTeam:  ");
        assert (myOtherTeam.numberOfMembers() == 0) : "Number of members wasn't zero!";
        System.out.println("ok");

Q15

How do we add members? Add a method, public void addMember(Member m) to the Team class.

Hint: Something like this:

public void addMember(Member m) { 
  // fill in your code here 
}

Expand using link to the right to see a suggested solution/answer.

    public void addMember(Member m) {
        members.add(m);
    }

You might wonder why you should need the addMember method. Actually, it is not a good design to force the clients of the Team class to know about the fact that a Team holds an ArrayList of its members. And it's not nice to force clients to create an array list of members to be able to create a team. It is better to just create a Team with a name, and then allow for members to be added one-by-one.

Imagine if the class java.util.ArrayList forced you to provide a normal array with the elements, in order to create an ArrayList! That would suck, wouldn't it?

But... what if we have a lot of members in some kind of list, and want to add them all to the team? A nice compromise would then be to offer both an addMember(Member m) method and another method addManyMembers(List<Member> members) so that the user can choose between the two. This wouldn't force the user to always add a list of members, so we're fine.

Q16

Add three Member instances to the second Team instance you created. Verify that the amount of members is correct in that team.

Expand using link to the right to see a suggested solution/answer.

        // Add the members to the second team
        myOtherTeam.addMember(new Member("Lisa", "lisa@simpson.net", 4));
        myOtherTeam.addMember(new Member("Maggie", "maggie@simpson.net", 5));
        myOtherTeam.addMember(new Member("Ned", "ned@flanders.org", 6));

        // Verify size (we just added three members - so the size should be 3)
        System.out.print("Checking size of myOtherTeam:  ");
        assert (myOtherTeam.numberOfMembers() == 3) : "Wrong size: " + myOtherTeam.numberOfMembers() + " expected 3";
        System.out.println("ok");

Q17

Output the first team, using System.out.println().

Expand using link to the right to see a suggested solution/answer.

Suggested solution:

        System.out.println("myTeam: " + myTeam);

Q18

Output the first team like above but do an explicit call to toString().

Expand using link to the right to see a suggested solution/answer.

Suggested solution:

        System.out.println("myTeam: " + myTeam.toString());

Q19

Since you have not added (or at least was not instructed to) a toString() method you need to think about how that method can exist in the Team instance.

Hint: System.out.println(myTeam.toString());

Expand using link to the right to see a suggested solution/answer.

It is inherited from Object. Each and every object inherits from Object - either directly or indirectly - so each and every object has a toString() method.

Add a toString() method to Team which returns the name followed by a space followed by the list of members (if you use + between the space (" "") and the members list variable, the list's toString() will be invoked for you!

Expand using link to the right to see a suggested solution/answer.

 @Override
 public String toString() {
   return name + " " + members;
 }

Q20

You now have two Team objects. We are going to compare them, but first let's check one thing:

  • Have you written a method in your Team class called equals?

Note: If you have written such a method we kindly ask you to "comment it out" - that is wrap the method in comments to make the compiler ignore it

Expand using link to the right to see a suggested solution/answer.

No, you have not written any method yourself in your class. Yes, as some of you may remember your class is inheriting Object and therefore inherits that method - but the question was if you had written on such method yourself so the answer is no.

Q21

Write code to compare the two Team objects, using your reference variables. You compare the objects, actually check if they are "equal", by using the method equals. Can you compile the code - please note that you do not have a method called equals?

Hint: Invoke equals on one object and pass the other object as parameter. A simple and stupid example of comparing two String objects below:

        String oneString     = "Blah blah blah";
        String anotherString = "New values";

        System.out.print("\"" +
                         oneString +
                         "\" and \"" +
                         anotherString +
                         "\" are ");
        if (!oneString.equals(anotherString)) {
            System.out.print("not ");
        }
        System.out.println("equal.");

Expand using link to the right to see a suggested solution/answer.

Suggested solution:

        System.out.print("Comparing my teams.. they are");
        if ( ! myTeam.equals(myOtherTeam)) {
            System.out.print(" not");
        }
        System.out.println(" the same");

Q22

If you change the name of the method you invoke from equals to checkIfEquals (note that you have not written a method in your class with that name), will the code compile? Why?

Expand using link to the right to see a suggested solution/answer.

It will not compile since there's no such method. Example printout from the compiler below:

com/sportmanagers/sportman/test/TeamTest.java:49: error: cannot find symbol
        if ( ! myTeam.checkIfEquals(myOtherTeam)) {
                     ^
  symbol:   method checkIfEquals(Team)
  location: variable myTeam of type Team
1 error

Q23

Change the code so that is uses the equals method again. Is the comparison done by the equals method as inherited from Object satisfying?

Expand using link to the right to see a suggested solution/answer.

It is not satisfying, since we'd expect an equals method to check if two objects should be considered equal (in terms of their state - that is, in terms of what their variables hold).

Q24

Create two Team instances with the same name using the first constructor (with one parameter). Compare these objects the same way as you did with the other Team objects. If we go back to the real world and think about how you interpret the clubs "AS Roma" and "AS Roma" mentioned twice in an article. We consider this to be the same club. So our Team object should do the same. The teams objects both referr to the same team - since the teams have the same name - so they should be "equal". Are they? Why?

Expand using link to the right to see a suggested solution/answer.

Suggested solution:

        Team teamWithName     = new Team("AS Roma");
        Team teamWithSameName = new Team("AS Roma");
        System.out.print("Comparing two teams objects with the same name.. they are");
        if ( ! teamWithName.equals(teamWithSameName)) {
            System.out.print(" not");
        }
        System.out.println(" the same");

We get this result since we're inheriting a very basic equals from Object. We need to write our own equals method, which by pure conincidence is something we're going to do in the next chapter.

For the keen student: the equals() method inherited from Object, only compares the references - if you pass in two references referring to the same object, then they are considered "equal" by the equals method defined in Object.

Therefore, we usually define our own equals method which does some more - like comparing all the variables in order to figure out if two objects should be considered equal. This is, like we said, stuff for the next chapter!

Links

Further reading

Solutions - Source code

You can find complete source code to the suggested solutions below in the every-class-extends-object directory in this zip file or in the git repository.

Where to go next

Next page is: Inheritance_-_Overriding_methods_in_Object

« PreviousBook TOCNext »