Chapter:Objects - Questions and Answers

From Juneday education
Jump to: navigation, search

Questions and Answers on Java Objects

Q: "Objects are entities with data and behavior, you say. How is the data actually stored in an object and how do we invoke an object's behavior?"
The data is stored inside the object in the memory space for the object in the JVM's so called "heap memory". This happens when the program is running and the code of the program creates a new object somehow (usually be calling a constructor in the class which describes obects of this type and this is done using the operator new). The data inside an object can also be called "the object's state". The code in the class describing objects of a particular type declares variables to store the state of the object. Normally, this is done using the keyword private, which effectively hides the variable name from uses by code in other classes (code that use and manipulate the objects). To change or use the state of an object, one typically invoke one of the instance methods of the object. Instance methods are methods also written in the class describing a particular type of objects, and they may access the instance variables (even if they are marked private because code in the same class is the only code that have access to private stuff).

In order to invoke some behavior, i.e. calling an instance method, for an object, you need to have a reference variable which refers to the object you want to use. A reference variable is a variable whose type is the same as the type of the object (often the class of the object). The reference variable is your handle to the object in the heap memory. Invoking a method on an object is done by using the reference variable and the dot separator and the name of the instance method together with any arguments the method might need.

You have already used objects via reference variable, perhaps without knowing so. When you used the System.out.println("Hello"); statement, you were actually using the reference object out (which belongs to the class System). Via the reference variable out, you invoked the instance method println(String str) for the object which out referred to.

In coming chapters, we will learn how to write our own classes. Hopefully things will get clearer then, when you yourself write the code for instance variables and instance methods. For now, you can think of classes as compilation units for a program. This units (classes) describe common state variables and common instance methods for a type of objects. Classes are written once and used many times. You use a class as the type of reference variables you use in a program. Reference variables are then assigned references to objects, usually as the result of calling the constructor of the class that describes a certain type of objects.

Q: "Can you say that classes, then, are descriptions of objects of the same type?"
That's one way of putting it. But beware that not all classes are used as the blueprint or description of objects! For instance, you have already learned that a small Java program requires at least one class, the one containing the main method. It is not sure that such a class will be used for creating objects (but it is possible).

Many Java books define classes simply as the blueprint for similar objects. While this is true most of the time, it is not true in every case. You have, for instance, used the System class (because it's the one which has the out reference variable we use for printing stuff to the standard output stream). The System class can't even be instantiated (you cannot create objects using System as the type or description). There are actually quite a few classes like that in the Java standard API. Another example is the class Math. You use the class Math because it offers a lot of mathematical methods directly to the programmer. You don't have to create a Math object in order to invoke for instance the sqrt (square root) method. In fact, you cannot create an instance of Math. The reason for this design decision is probably convenience (smoother to invoke a method directly using the class name) and the fact that it doesn't make sense to have many objects representing "Mathematics".

Q: "You say that some classes can't be instantiated, i.e. you cannot create objects from them. What keeps some programmer from simply calling the constructor using the operator new on for instance the System class?"
It is done using the private keyword. Anything in a class marked as private cannot be used from outside the class itself. You have seen what a constructor looks like. Do you remember? Usually a constructor looks like this:

public ClassName() {
  //some clever code which initializes the state of the ClassName
  //object which is being created here... 
}

The pattern is public followed by ClassName (the name of the class) and parentheses with arguments (if any) to be used in the constructor body for initialization. But what if you substitute private for public? Then the constructor itself cannot be called from outside the class! This means that no one can create objects of this class (provided there are no public constructors at all in the class). This is what the only constuctor in System looks like:

    /** Don't let anyone instantiate this class */
    private System() {
    }

This is taken directly from the source code of java.lang.System. Note the comment in the source code!

Q: "You say instance methods must be invoked using a reference to some object. Yet you say that there are methods in for instance Math but we cannot create objects of type Math. How can this be?"
That's a very good observation! Instance methods are always only relevant for some object and you need to invoke them using a reference to the object which you want to use. But methods in the class Math, for instance, are not instance methods. I'm sorry to break it to you, but there are actually two types of methods. Methods that you can call without objects or references are called "class methods" (because they belong to the class itself and not any particular object) or "static methods" (because they are written with the keyword static like the good old public static void main(String[] args). The method sqrt in class Math for instance, is defined like this:

public static double sqrt(double a) {
  //some clever code which calculates the square root of "a" 
}

Note the static keyword! It means that this method should be called using the class name such as:

  double c = Math.sqrt( a*a + b*b );
}

Q: "But if static methods, or class methods as you also call them, are more convenient than instance methods, why do we need instance methods?"
Again, a great question, but a little harder to answer. The thing about static methods, is that they are not very common in typical Java program (if you don't count methods from simple programs in Java text books). Programming in the object oriented style means that we package data and behavior together in objects and we let the objects do all the work in our program. Static methods cannot operate on instance variables (since they cannot know if there are any instances, and which instance to use if threre are). So static methods can only operate on the data we send to them as arguments (and data that is stored directly in the class). This is the opposite of the object oriented way of thinking! We don't want to manage a lot of data and send them to methods. We'd rather talk about objects and let the objects keep track of their data, and we humbly ask the objects to do some work for us, taking their state into account.

Static methods are mainly there as convenience methods for performing rather mechanical and static work, like calculating the square root of some number. Objects, on the other hand, are much more lifelike creatures. A program for a computer game, for instance, might have several Player objects (perhaps running around in a maze trying to find a treasure). All Player objects share the same characteristics but they are individuals. One Player object might be green and very fast, while another Player object might be Pink and not so fast (but has the ability to jump over large rocks). All players are described in the Player class, but their state varies. We can invoke the same type of behavior using the instance methods described in the class on them, but the result would be different depending on their state. Invoking the run() method on the first player would result in fast movement but if we invoke the same behaviour (run) on the second player, the movement wouldn't be so fast. This could be done using a private speed variable which keeps track of the maximum speed for particular Player objects. The first player had a large number stored in its speed variable while the second player had a smaller number in its speed variable. But the actual variables are private and hidden from the users of the Player class (the programmer writing the logic of the game). The program using the Player class uses reference variables to invoke behavior on a Player object like calling the run method on one of them. The object itself now knows how to run (and how fast it can run) which lets our programmer focus on things on a much higher level of abstraction.

Q: "The String class seems to be very useful. There are lots of program which handle text. But it seems a little special. Could you say something about what makes the String class and objects of type String (reference to String, as you seem to prefer to say)?"
The String class has some properties which makes it a little different from other classes. The first thing that comes to mind here, is that we can create new String objects simply by typing a text string inside quotes. That's very untypical for object creation. The reason for Java to allow this weird behavior is that it actually makes the creation of String objects very simple. And since String objects are so common in programs, why not offer a simple way to create them? You can use constructors for creating String objects too. But there is a subtle difference between a String created like this: String name = "Adam"; and a String created like this String name = new String("Adam");. The difference is very subtle but very important to understand later in the course (or if you keep studying Java). Strings created using the double quotes are re-used. By re-used, we mean that in a program where two Strings with the exact same text are created using double quotes doesn't actually create two different String objects. The JVM will discover that there already exists a String object with the same text as the second object created with quotes. So any reference variables referring to the String object created with quotes, will refer to the same object in the memory:

  String myName   = "Adam";
  String yourName = "Adam";
}

In the code above, threre is only one String object created. Both myName and yourName now refers to that same object in the memory. Such objects are said to be put in the "string constants pool". If you really need two different String objects with the same text, for some reason, you would have to use the constructor and the operator new for at least one of them. Using the constructor for any class of object, always guarantees a new distinct object.

At this point you don't have to care about this subtle difference so much, but it would be wrong for us not to mention it at least. If you keep using or studying Java, however, these things might get important for you to understand the exact behavior of a program written in Java.

Another thing that makes String convenient to use is that it is part of the java.lang package. The special thing about that package is that you can use classes in that package directly without having to import their path to the program using the import statement. You may think of it as the java.lang package always automatically (implicitly) being imported.

Lastly, there is another subtle thing about the String class and its objects. Objects of type String are what is called immutable. That simply means that you cannot change the state of a String object (you cannot change the text of a String object). If you call, for instance, the toUpperCase() instance metod of a String, you might think that you change all the letters in the String to upper case. You don't. What happens is that the method creates a new String (with the same letters but all upper case) and returns a reference to that object to you. The old object will get discarded from memory automatically:

  String name = "Adam";
  name = name.toUpperCase();

In the code above, first a String is created representing the text "Adam" and the variable name is assigned the reference to it. On the second line, the instance method toUpperCase() creates a new String object representing "ADAM" and returns a reference to that object. The reference to this new object is assigned to name. The first object (representing "Adam") is now long gone and forgotten about. It will be "garbage collected" by the JVM since there are no references to it any more, so it can't be used anyway.

Q: "Phew! Strings seem to be complicated creatures. Should I worry?"
Don't worry. This is an introductory course and we will not use these special cases against you! We are only telling you about them so that we don't feel that we've kept secrets from you. If you don't understand these subtleties now, you don't have to worry. Hopefully they will become clearer when you have read more chapters and seen more lectures later on. Why not revisit this explanation after a few more lectures? However, we will not require that you understand and remember these quirks after the course. Topics we feel are very important will always be part of lectures and/or exercises. These Questions and Answers are for the curious and ambitious student who always want to learn more!

Q: "Packages seems to be an important concept in Java, because every class seems to belong to a package. When we write our own classes, like in the exercises, the package declaration always matches the path to the source code (and binary class) file for the class (only that dots are used to separate directories where the shell would use a forward slash). But when we import for instance java.util.Properties, I don't understand where the path "java/util/Properties.class" would lead? Is there really directories somewhere for the java api packages and their classes?
That was very observant of you! Yes, the packages in the API (like java.lang, java.util and all the rest) are actually also paths to the compiled versions of the classes in the packages. The only difference, is that the whole API (with all its directories for packages and all the class files in those directories) are packaged together in a file called rt.jar. If you think about it, how could it work to use java.lang.String for instance, if there was no compiled class file called String.class on your system? And how could the compiler and JVM find it if the package didn't symbolize a path with directories, like when we create our own classes?

When you install the JDK (Java Development Kit), you get the API as a part of the installation (otherwise we couldn't use String or Properties etc). The part which actually contain all these API classes is a kind of zip file (compressed archive file) with a large directory structure inside it. The file is called rt.jar (jar is a Java type of compressed archive file format).

To prove we are not lying to you we'll show you that the directory structure is there, using some bash command trickery:

$ ls /usr/lib/jvm/java-7-openjdk-amd64/jre/lib/rt.jar
/usr/lib/jvm/java-7-openjdk-amd64/jre/lib/rt.jar

$ file /usr/lib/jvm/java-7-openjdk-amd64/jre/lib/rt.jar
/usr/lib/jvm/java-7-openjdk-amd64/jre/lib/rt.jar: Java Jar file data (zip)

$ jar tf /usr/lib/jvm/java-7-openjdk-amd64/jre/lib/rt.jar | grep '/System.class'
java/lang/System.class

$ jar tf /usr/lib/jvm/java-7-openjdk-amd64/jre/lib/rt.jar | grep '/Math.class'
java/lang/Math.class

What we did there, was to list the rt.jar on a computer with Java 7 installed. Next, we used the file command to investigate what kind of file the rt.jar was. The answer was "Java Jar file data (zip)" (file is a very capable command for investigating files!). After that, we used the jar utility command (also included in the JDK) to list the files in the rt.jar, but since there are thousands of classes there, we filtered using grep the result for some familiar classes mentioned above. As you can see, the System.class was in the directory java/lang/System.class and the Math.class file was in the same directory. The directories correspond the the package names! java.lang.Math corresponds to the compiled class file found in java/lang/Math.class in the rt.jar archive.

Q: "In one of the more complicated solution suggestions to the Loop Challenge exercise, you were using List instead of ArrayList. You said something about List not being a class but something called an interface. What is the difference between a class and an interface?"
We will talk a lot about interfaces in a chapter to come, but since you ask already, I'll try to be brief and explain some basic differences between classes and interfaces. As usual, you don't have to understand this yet, since we haven't gotten to the Interfaces chapter yet, but here goes anyway!

A class can define both instance variables for storing the state of objects to be created using the class and instance methods. Classes are in this regard quite closely related to objects. You can use a class to create an object. Interfaces (in the most common case) only concern themselves with describing the behavior (instance methods) of a group of objects. Interfaces describe what messages (what methods can be called) for a related type of objects. So interfaces also define a type of objects. But interfaces do this in a very abstract way, as they only describe the names, return types and arguments of methods for the type. Interfaces don not define the code for what the methods actually should do, just that they exist. An interface, then, is a construct much less related to specific classes of objects, since we use them when we only care about what methods exist for objects of an interface type, and how to use these methods.

List is an interface describing the methods common to different sorts of lists. ArrayList is a concrete type of list, described in a class. But the class ArrayList is said to implement the List interface, which means that all the methods abstractly described in List exist "for real" in the ArrayList class.

This construct allows us to declare references of type List so that we only care about what messages we can send to the actual object referred to (and the signature of the methods). If we use a List reference variable to refer to some List type object, the actual object may very well be an ArrayList (or some other list). We don't have to worry about that, since we will only send the messages (call the methods) declared in the List interface. You could, in this sense, say that it is easier to program against an interface type, than against a concrete (class) type.

In the actual example code where you found the use of List, the reference was assigned like this:

List<String> argList = Arrays.asList(args);

The asList() method in the Arrays class (by the way, a static method) takes as argument an array and converts it into an object of interface List type, and returns the reference. The actual object created most certainly is an ArrayList but we don't care, since we are only using the for-each loop to traverse the list in our program anyway. List type objects can be used in for-each loops, which was what we wanted to do in our program.

Q: "Talking about advanced solutions to challenges, the org/progund/lists/ArgumentHelper.java class, used in the suggested solution to the LoopChallenge in this chapter, the object oriented version, has a lot of instance methods, I guess. But why are some of them marked as private and some marked as public?"
We will talk a lot more about so called "access modifiers" (public and private for instace) in the next chapter, but in short private means "can only be used by code in this class". So only code in the ArgumentHelper class may call any of the private methods in the same class. On the other hand, public means that code from any class may call it. The ArgumentHelper class is used to create an object in the main method of the LoopChallengeOOVersion class. Code in this class can only call the public instance methods of the ArgumentHelper object.

Methods that are of no concern or use directly to users of objects should be declared as private (to keep people from using them or even knowing about them). The public methods in a class are what users of objects of the class see and can use. The public methods of an object can be said to be the "programming interface" to the object. The programming interface is what you can do with an object. As you saw in the solution, some of the public methods needed to get help from other methods but sometimes such helper methods are not meant to be part of the public interface of objects created from the class. So we hide them from users of the objects, which makes our objects easier to use. The fewer public methods an object has, of course, the easier it is to use and understand the object's capabilities.

More on this in coming chapters!

Chapters about Objects

Here are the chapters about objects in this book:

You have now finished the Objects chapters of the Programming with Java book. Well done! If you feel confident about the topic of objects, then you are ready to move on. Next topic: Classes. Enjoy!

Links

Further reading

Where to go next

Next page is the beginning of a new topic, Classes: Classes_-_Introduction

« PreviousBook TOCNext »