This chapter introduces some of the conceptual structure necessary to understand Java programs. It begins by considering what kinds of things a program can manipulate. Some things are very simple--like numbers--and others are much more complex--like radio buttons. Many complex things can actually act, either by themselves (e.g. a clock that ticks off each second) or when you ask them to (e.g. a radio that can play a song on request). These complex things are called objects.
To manipulate objects, you need to understand two important concepts: types and names. A type tells you what kind of thing an object is. It tells you what kind of behavior you can expect from that object. A type is a way of setting expectations -- for the computer program and for the software developer -- about the object. In Java, the type of a thing lets the computer keep track of what that thing can do.
A name is a way of referring to a thing that already exists. A name doesn't bring a thing into existence, but it is a useful way to get hold of a thing you've seen before. Every name has an associated type, which tells you what sorts of things the name can refer to. It also tells you what you can expect of the thing that that name refers to.
In other words, a type describes how you can interact with the thing that a name names. There are actually two different kinds of names in Java: primitive (dial) names and reference (label) names.
Sidebars in this chapter cover the details of legal Java names, Java primitive types, and other syntactic and language-reference details.
In the first section of this book, we have explored what computational systems are and how they are created. In this section, we shift our focus to the pieces out of which such systems are created. The previous section took a top-down approach to system design. In this section, we learn the basic building blocks that enable us to also approach the problem from the bottom up.
In building a computer program, we will make use of many Things. Some of these Things are relatively simple and, when we need them, we can just write them down. For example, 4 and -6.3 are Things we might want in our program, and we can put them there just by writing them down in the appropriate places. But other Things -- like the library's record for Moby Dick or the current location of the cursor on the computer screen -- are harder to write down explicitly in the way that we are able to write 4 or -6.3. For these kinds of Things, we need a way to refer to them without explicitly writing them down each time. We do this using a name.
A name is a way to refer to something in your program. At any given time, a name refers to at most one Thing. What the name refers to may change over time, though, so the current location of the cursor may be at coordinates (26, 155) now and at (101, 32) later. This is true in real life, too: the student whose birthday comes next changes every time someone celebrates becoming a year older.
In this chapter, we explore how names refer to Things in Java. We also explore some specific kinds of Things that can be included in a Java program. Although there are details in this chapter that are particular to Java, many of the principles we identify work in almost any computer programming language. These include:
In addition, in Java and in many other languages, each name can be used only to refer to Things of a particular type. A language in which a name is restricted to refer to Things of a particular type is called a strongly typed language. In a strongly typed language, like Java,
We will learn more about types and names below. To begin, let's look at Things themselves. What kinds of Things exist in computer programs?
You may have noticed that the word Thing is capitalized almost every time that it appears in this chapter. This is to indicate that, in this chapter, we are using it in a very particular way. In Java, no one word refers to all of the objects -- like KlingonStarships and BookIDs -- and also all of the simpler things in programs -- primitive data like 6 and -43.5 -- at the same time. To avoid using another word incorrectly or imprecisely, we'll use Thing with a capital 'T' to refer to all of the entities, objects, and primitive data that appear in programs.
We have already seen a number of different kinds of program Things. Some -- like 4 and -6.3 -- probably look quite familiar. Others, like Moby Dick or the current location of the cursor on the computer screen, may look different once we represent them inside the computer, but they, too, will be Things we can talk about in our Java programs.
Different programming languages allow you to talk more or less easily about different kinds of Things. Some languages -- like Basic -- are very restricted in the kinds of Things that a program can talk about explicitly. Other languages -- like Java -- allow you to create and talk about almost any kind of Thing that you can imagine. Java is one of a family of languages called object oriented programming languages. In Java, as in most object oriented programming languages, most Things -- and all of the Things that you will create -- are called objects. Almost any Thing that you can describe in a programming language can be an object, so, in Java, object is a pretty general word for "programming language Thing". Not all programming languages allow you to talk about objects, though, and -- towards the end of this chapter -- we will learn about a few Java Things that are not objects.
An object can be just about anything that you might want to represent in a computer program. Some example objects include the radio button that the user just clicked, the window in which your program is displaying its output, or the url of your home page. The Klingon starship racing across your computer screen -- in a Star Trek game -- is a Thing that the computer has to keep track of. If your Star Trek game is written in Java, that Klingon starship is almost certainly an object.
Objects are frequently complex Things with internal state. For example, the window may have a "close me" control or a background color; the url has a host computer name. Many objects also know how to act and can perform tasks. The radio button may be able to tell you whether it has been selected, or the window may know how to close. The library checkout desk of the previous chapter keeps track of book circulation while the card catalog can tell you who wrote what books. And, of course, the Klingon starship has a position and a velocity and a certain amount of ammunition left to shoot at you with....
Some objects can even act on their own without being asked to do anything; they are "born" or created with the ability to act autonomously. For example, an Animator may paint a series of pictures rapidly on a screen, so that it looks to a human observer like the picture is actually moving. The Animator may do this independently, without being asked to change the picture every 1/30th of a second. Similarly, an alarm clock may keep track of the time and start ringing when a preset time arises. A starship may move -- changing its position on the screen -- or shoot at you or even explode.
Objects are useful because we can ask them to act -- or have them take actions on their own. But how do we know what we can do with a particular Java object? In order to use an object, we need to know its type.
A type tells you what kind of behavior you can expect from an object. We have been using the idea of types all along, but we have not yet made it concrete and specific. For example, when we talk informally about a library book's representation in the computer or even something simple, like a number, we mean to be referring to a specific kind of Thing. In a programming language, we also talk about categories of Things this way. In English, we can refer informally to the kind of Thing, like "a number". In a programming language, we need to say what we mean by a number. In this chapter, we'll be using types that someone else has defined. In the next several chapters, we'll be learning about how to figure out what a certain type of Thing is like. In chapter [Classes and Objects], we will at last learn how to build our own types of Things.
A type specifies what a Thing can do (or what you can do with a Thing). Types are like contracts that tell you what kinds of interactions you can have with Things. What an object's structure is -- and what that object can do, or what you can do with it -- is fully determined by its type, i.e., what kind of object it is.
In the previous chapter, we saw a number of Things that make up a library system: the circulation desk and the card catalog, book IDs and patron IDs. If we were to write Java code corresponding to the system that we designed there, we would make each of these kinds of Thing a type of object. The description for the type CirculationDesk would tell us that a CirculationDesk can checkIn a bookID or checkOut a bookID to a patronID, for example. In other words, the type of the Thing -- CirculationDesk -- tells us what a particular CirculationDesk -- like the Smalltown Library's -- can do.
Java itself has certain predefined object types, such as DialogBox -- the little window that pops up on your computer screen to give you an urgent system message -- and URL-- the internet address of a web page. If you are using the cs101 course libraries, you'll also have access to object types such as AnimateObject-- something that can move by itself -- and DefaultFrame-- an easy kind of user interface window to use.
Other object types may include KlingonStarship (if you're building a space battle adventure game), IllustratedBook (if you're building an electronic library system), or PigLatinTranslator (if you're building a networked chat program). In the rest of this book, you will be learning to define object types -- and create instances of those types -- to do what you want. These types -- whether a part of the Java language, included in a library you choose to use, or of your own defining -- are all kinds of objects. Note that, by convention, the name of each object type -- each class -- starts with a capital letter.
A type itself doesn't do anything; it is objects of that type that are generally useful in one's programs. These individual objects are sometimes called instances (of the type). So KlingonStarship is a type, but the particular Thing streaking across your computer screen, phasers blasting, is an individual KlingonStarship instance.
A particular object types may describe many different individual objects -- the three specific KlingonStarships visible on your screen, the five hundred and seven IllustratedBooks in the children's library, or the particular PigLatinTranslatorthat your particular chat program is using. These instances share a type -- they are the same kind of Thing -- but are independent objects. For example, the KlingonStarship that you just destroyed is a different KlingonStarship instance from the one that is getting ready to fire its phasers at you. We will explore this idea in greater detail in chapter 7. By convention, an individual object -- as opposed to its type -- is generally given a name that starts with a lower case letter.
Each kind of object -- each object type -- determines what individual objects of that type can do. For example, windows can close; dictionaries can do lookups; KlingonStarships can fly around the screen. Each particular kind of object provides a particular set of services or actions that objects of that kind can do. Further, each individual object of that type can perform these actions. For example, if myWindow and yourWindoware two different window-type objects, myWindow can close, and so can yourWindow. But if myWindow closes, that doesn't in general affect yourWindow.
Each individual object comes ready-made with certain type-specific properties and behavior.It is tempting to say that this is typical behavior, and indeed this is just what the word typical means: pertaining to the type. An IllustratedBook has an author and an illustrator, for example. A PigLatinTranslator may be able to translate a word that we supply it into Pig Latin. We ask objects to act (including telling us about themselves) using specific services -- behaviors -- that these objects provide.
A common thing to do in a computer program is to ask a particular object to perform a particular service.Also to engage in a specific behavior, to take a particular action. As we shall see, the formal name for this is "method invocation". An object's services are requested by giving the name of the object we're asking followed by a dot (or period), followed by the request we're making of the object. So if theLittlePrince is the name of an IllustratedBook,
would be a request for the name of the author of the book: "Maurice de Saint Exupery". Similarly, if myTranslatoris a PigLatinTranslator, myTranslator.processString("Hello")might be a request to myTranslator to produce the Pig-Latin-ified version of "Hello", which is "ello-Hay". We will explore this service-requesting further in the next few chapters, but for now you can regard it as a special incantation to use when you want to ask a Thing for something that it knows how to do for you. These requests are the most basic form of interaction among the entities in our community.
Sometimes, the same Thing can be viewed in different ways, i.e., as having multiple types. For example, a person can be viewed as a police officer or as a mother, depending on the context. (When making an arrest, she is acting as a police officer; when you ask her for a second helping of dessert, you are treating her as a mother.) A Thing's type describes the way in which you are regarding that Thing. It does not necessarily give the complete picture of the Thing.
Now that we have seen how objects and types work, let's look at some useful objects and object types. We have begun -- this chapter and your programming experience -- by using objects and types that are provided to us, because it is important to learn how to interact with an object. Many of the objects that you will use throughout your programming career will be designed by other people for you to use. Later -- in chapter [Classes and Objects] -- we will learn how to build objects of our own.
One particularly useful kind of object -- built in to Java and to most programming languages -- is called a String. Astringis a piece of text, a sequence of characters. To describe a specific string -- for example, the message that your computer prints to its screen when you first boot it up -- you can write it out surrounded by double quotation marks: "Hi, how are you?"or "#^$%&&*%^$"or even "2 + 2" are strings. Note that the quotation marks are not actually part of the string; they're just there to make it clear where the string begins and ends. Your computer doesn't understandthe string, it just remembers it. (For example, the computer doesn't know of any particular relationship between the last example and the number 4-- or the string "4".)
Strings are useful, for example, to communicate with a program's user. Error messages, user input (i.e., what you type to a running Java program), titles and captions are all examples of strings. Strings can perform some (moderately) interesting tasks. For example, if myName is "Rigoberto Manchu", then myName.toLowerCase() is "rigoberto manchu" and myName.length() is 16. Strings are part of the Java language, so they are available to every Java program. For more information on the String type and what it can do, see the sidebar on Selected String Behavior.
Another useful object is Console, described in the next sidebar. Console is an object that can print a String to theJava console, a standard place on the computer screen where someone running a Java program can look for information. Console can also readln a String that the user types to the Java console.
Unlike String, Console is not built in to Java. It is a part of the cs101 libraries. This means that Console is only available to Java programs that use the cs101 libraries, a group of free code libraries developed for use with this textbook. Later in this book, we'll learn how to replicate the function of Console using only Things built in to Java, in case you don't always want to use the cs101 libraries.
There is another difference between Console and String: String is a kind of object -- a type -- while Console is actually a particular object. Console has a type, of course, but you will not be interacting with other similar objects. That is why the Console sidebar gives you information about the particular object, Console, but the String sidebar talks generically about all Strings.
Once you know the name of a particular object -- like Console -- and you know about the type of Thing that object is, you can ask it to perform tasks for you. For example, you can ask Console to print out "Hi there" on the screen. In Java, this is spelled Console.println("Hi there"). (Recall that the . and () are special syntax -- notation -- that indicate that we're asking the Thing called Console to do its println behavior (on the String "Hi there").) Specific information about the Things that you can do with Console is contained in the sidebar. In the next chapter, we'll explore in greater depth how you can find out what kinds of actions any particular kind of Thing can perform.
A few objects, like certain Strings, can be typed directly on your keyboard. If you want to use a particular String in your program, one option is to type it in right there, as we have done in the sidebar. Other objects, like Console, are always available for use through their names. When you want to use a particular object, you will need to figure out how to identify it so that you can use it in your program. A name is one way to do this, but it is not the only way.
A name -- like Console -- gives you direct access to the object it names. For example, I might have a robot that I call Robbie; then I can ask Robbie to move using its name. I can also tell you about Robbie using this name. Below, you will see how to give names to Things, and -- using that technique -- I could even give Robbie the nickname Fred by giving the robot a second name. A name like Robbie or Console names the object, and is like a label that allows you to access the object directly.
Imagine that, in your program, mobyDick names a book. You might be able to refer to the author of Moby Dick by using a name designated for this purpose, like hermanMelville. You can also refer to an object without using a name for it. You can do this, for example, by using a related object to help you. So, for example, mobyDick.author() might refer to the author of that book. (As with Console.println("Hi there"), above, the . and () are special syntax. In this case, we are asking the Thing called mobyDick to tell us its author.)
In this way, we can access an object -- like hermanMelville -- indirectly -- through mobyDick. This is useful if we don't have otherwise have a name for it. (The same trick works in English, too: Omoo was written by Moby Dick's author.)
There are differences between direct and indirect reference. One is the length and complexity of the way we say it: HermanMelville vs. mobyDick.author(). Another has to do with whether the referent -- the object referred to by the name or the service request -- is expected to change. Names like hermanMelville (or Console) might always refer to the same Thing, as would mobyDick.author(). But some indirect references are expected to produce different Things each time the service request is made. Imagine that fortuneTeller is the name of an object that knows how to produce a random pithy saying (a fortune). The name fortuneTeller might even always refer to the same oracle. But you'd hope that a request like fortuneTeller.getFortune() would produce different pity sayings from one request to another, or the Thing named fortuneTeller wouldn't be very interesting!
With all of these Things floating around in our program, it is pretty easy to see that we'll need some ways to keep track of them. The simplest way to keep track of Things is to give them names. This is called assigning a value to a name. Giving something a name is sort-of like sticking a label on the Thing. We sometimes say that the name is bound to that value.
Unfortunately, not every Thing in our program comes with a name. Consider the fortune teller of the preceding section. We can ask the fortuneTeller to produce a fortune, but if we don't do anything with that fortune, we will have no way to refer back to it. It is as if, as soon as we get the fortune from fortuneTeller, we drop it on the floor with all of the other Things that our program has created or used. Unless we somehow keep hold of what fortuneTeller gives us, we cannot get it back later.
We can solve this problem by putting a label on the first fortune when we get it. Then, if we want it back later, we can ask for it by name: the name on the label. In fact, that's just what names are for Java objects: labels that let us keep track of Things.
To actually assign a value to a name -- to create a binding between that name and that value, to stick the label on the Thing -- Java uses the syntax -- that is, the notation --
So we can remember the fortune our fortuneTeller provided by giving it a name:
This associates the fortune produced with the name myPersonalFortune. Once a particular name refers to a particular Thing, we can use the name wherever we would use its value, with the same effect:
The name becomes a stand-in for the Thing it refers to: the fortune told by the fortuneTeller. In the next chapter, we will see that a name is a simple kind of expression. @@The last sentence of this paragraph could conceivably be omitted.
A name, like a label, can only be affixed to one Thing at a time. In other words, only one value may be associated with a name at any given time. One Thing can be referred to by any number of names at once ( including, potentially, no names at all). The same person can be "the person holding my right hand", "my very best friend", and "Chris Smith". But only one person is "the person holding my right hand". Barring weird interpersonal pileups, of course.
But where do these names come from? Except for the rare name, like Console, that is available when your program is started -- and that is probably already being used to keep track of something important -- you will need to come up with your own names and to tell Java about them, i.e., to generate the labels that you'll want to stick on Things. The way that you do this is with a declaration
We already know that each Java Thing comes into the world with a type, i.e., an indication of what kind of Thing it is. In Java and other strongly typed languages, every name -- and every label -- also has a type. A Java name can only be used to label objects of the appropriate type. This type is associated with the name when the name is created. The type associated with a particular name never changes.
Since every Java name must have an associated type, the way that you create a name in Java is to tell Java what that type is. The term for telling a programming language what type a name has is declaration. Declaring a name means stating that that particular name is to be used for labeling values (Things, objects) of some particular type. A declaration creates a name -- a label -- suitable for sticking on objects of that particular type. The label can only be stuck on things of that type.
Names are declared using the type-of-thing name-of-thing rule:
The second word on each line is a name that is being declared. The first word on each line is the type that the name is being declared to have. In the first line of the example above, bookTitle is being declared to have type String. This is the Java type for a piece of text, like "The Forgotten Beasts of Eld". Finally, each declaration ends with a semicolon (;). So the first declaration here creates a name, bookTitle, suitable for naming pieces of text (or, in Java, Strings). The second line creates the name enemyFighter and says that it can refer to any Thing of type KlingonStarship.
In both of these cases, a new name -- a new label -- is created. That is, each of bookTitle and enemyFighter is now a label of the corresponding type. But neither of these statements says what the label is stuck on. In fact, it's quite possible that the label is stuck on nothing at all. Later in this chapter, we will see a special kind of name that doesn't create a label. But in Java, objects are named with label names.
A name has a certain lifetime, sometimes called its scope. Within that scope -- over its lifetime -- the name may be bound to many different values, though it can only be bound to one value at a time. For example, enemyFighter may initially be the big ship right in front of you, but later change to be the high-speed ship just entering your field of vision. The association between a name and a type persists for the lifetime of the name, however. enemyFighter can only name a KlingonStarship, not a Stringor a BookID.
Declaring a name begins its useful lifetime, or scope. At that time, nothing else necessarily needs to happen -- and frequently, it doesn't. But sometimes it is useful to associate the name with a value -- to stick the label onto something -- at the same time that it is declared. This combination of a declaration and an assignment is called a definition.
For example:
The first of these definitions makes use of a String literal, i.e., something that can just be typed in. It creates a label, bookTitle, and then immediately sticks it onto the String "Weaving the Web". The second definition creates a label, answer, suitable for labelling Strings, and sticks it on whatever the user types to the Console. The third definition uses mobyDick's ability to tell us its own author. The final definition makes the name myPet refer to the same Cat currently named by marigold. This is a case of marigold standing in for the actual Cat, that is, the name being used in place of the Thing it refers to. After the assignment completes, myPet is bound to the actual Cat, not to the name marigold. But to understand this fully, we need to really think about what it means for a name to be a label.
A Java object name really is just a label that that can be stuck onto an (appropriately typed) object. When a label-type name is declared, a new label suitable for affixing on Things with that type is created. For example, a building name might be a cornerstone label, a person's name might go on a badge, and a dog's name might belong on a collar. You can't label a person with a cornerstone or pin a badge on a dog, at least not without raising an error. Unlike cornerstones or dog tags, though, labeling a Java object doesn't actually change that object. It just gives you a convenient way to identify (or grab hold of) the object.
In Java terms, if we declare
this creates a label, myButton, that can be stuck onto Things of type RadioButton. Note that is not currently so stuck, though. At the moment,myButton is a label that isn't stuck to anything. Cornerstones and badges and dog tags don't come with buildings and people and dogs attached, either. Having a label is different from having something to label with it. Labels don't (necessarily) come into the world attached to anything. The value of a label not currently stuck onto anything is the special non-value null. That is,null doesn't point, or refer, to anything. So the declaration above is (in most cases) the same as defining
Of course, we can attach a label to something, though we need to have that something first. We'll return to the question of where Things come from in a few chapters. For the moment, let's suppose that we have a particular object with type RadioButton, and we stick the myButton label onto it. (Now myButton's value is no longer null.)
After we give myButton a value -- stick it onto a particular RadioButton-- we can ask it whether it is currently pressed:
This request will return either true -- yes, I'm pressed -- or false -- no, I'm not. Let's imagine myButton currently is pressed, so it returns true. This is an expression that returns a boolean value; see the discussion of expressions in chapter [Expressions].
Now, imagine that we declare
The result of this declaration is that a new label is created. This new label is attached to the same object currently labeled by myButton. Assignments of label-type names do not create new (copies of) objects. In this case, we have two labels stuck onto exactly the same object, and we say that the names myButtonand yourButton share a reference. This just like saying that "the morning star" and "the evening star" both refer to the same heavenly body.
Because myButton and yourButton are two names of the same object, we know that
and
will be the same: either the button that both names label is pressed, or it isn't. But we can separate the two labels -- say
-- and now the values of
and
might differ (unless, of course, someOtherButton referred to the same Thing as yourButton). Note that moving the myButton label to a new object doesn't have any effect on the yourButton label.
Note also that the labeled object is not in any way aware of the label. The actual radioButton doesn't know whether it has one label attached to it, or many, or none. A label provides access to the object it is labeling, but not the other way around.
Let's walk through an example of how Things are named and how names refer to Things. This example involves a story that took place some years ago at a fancy party, the kind of party where one leaves one's hat at the door and whose attendees might include a few famous names....This story concerns one such party and three such personages: Charlie Chaplin, King George VI of England, and Eleanor Roosevelt.
First among our characters to arrive was Charlie Chaplin. He was wearing his usual bowler hat.
The code above just tells us that charlieChaplinHat is a label suitable for naming a Hat, but we will also assume that the the charlieChaplinHat label is, as usual, stuck on the bowler:
[@@ insert more pics, too]
When Chaplin arrived in the lobby, he saw the hat check. He took off his hat and handed it to the hat check. (Fortunately, the hat check had a checkHat service, requiring a Hat:
Of course, now Charlie Chaplin wasn't wearing a hat:
So unburdened, he walked in to the party.
Next to arrive was the King of England. He was wearing his crown.
Again, we assume that -- prior to the execution of the rest of this code -- kingGeorgeHat is labelling the crown.
When King George arrived at the hat check, he, too, removed his hat and gave it to the hat check.
?
Then he, too, went in to the party. Both men had a lovely evening at the party. Mr. Chaplin left first. Reentering the lobby, he approached the hat check and observed that it also provided a returnHat() service. So he executed
Much to his surprise, the hat handed to him by the hat check was not his simple black bowler. Instead, it was the magnificent crown of the King of England. Chaplin was still staggering around the lobby under the weight of this crown when King George emerged from the party and approached the hat check.
I'm sure it won't surprise you to hear that the King now found himself in possession of a simple black bowler. Being a man of simple good taste and few pretensions, George was half tempted to leave with that hat, but it occurred to him that there might be some other gentleman who would then regret the loss of such a sturdy topper. Further, he knew well from experience that the Crown of England can be a heavy burden and he hated the thought that someone else might have to suffer under it. Turning, he saw Charlie Chaplin staggering under just that burden.
"Sir," King George observed, "It seems our headgear has been exchanged by the hat check. Perhaps we should remedy this situation."
And so the two men proceeded to try just that. But there was a problem. Between them, the men had only two Hat labels, and each was occupied. For example, they considered executing
but this would have resulted in both men holding the crown, and Mr. Chaplin's trusty bowler lost in limbo with no way to retrieve it (since it would have been labelless).
The two men were puzzling over this dilemma when who should emerge from the party but Eleanor Roosevelt. (She'd snuck in while the reader wasn't looking.) This savvy diplomat immediately took measure of the situation
"I see that you two gentlemen have run into a bit of difficulty. Perhaps I can be of some assistance. You see, I am not wearing a hat, and so my head can be a temporary resting place while the two of you work your exchange.
"First, we will need a label for my hat:
"You see, of course, that there's no Hatthere:eleanorRooseveltHatis null. It's simply a label that could be stuck on a Hat; it's the potential Hat-holder representing my head."
Next, the erstwhile Mrs. Roosevelt offered to take the Crown of England from Mr. Chaplin, to which he readily agreed:
Now, the tall thin diplomat and the short comic actor found themselves jointly holding England's crown. At this, Mrs. Roosevelt suggested that Mr. Chaplin release the crown by seizing instead the simple black bowler to which he was accustomed (and of which the King of England was growing overly fond).
Mrs. Roosevelt now had sole possession of the crown; Mr. Chaplin and King George both held the bowler. At this, King George released the bowler to take possession of his crown:
Finally, Mrs. Roosevelt released her hold on the crown, freeing her to return to important business:
(Of course, this step was not strictly necessary as each gentlemen now held the proper hat. Mrs. Roosevelt simply wanted to leave open her options for wearing other hats later.)
And the three figures left the party satisfied that all was well.
Objects are extremely useful and every Java program that you use will make use of objects. But there are a few other kinds of programming language Things that do not have the same complex internal structure or behavior. Java, like many programming languages, has some built-in facilities for handling and manipulating simple kinds of information, like the number 42 or the character '%'. These Things are not objects and they cannot act on their own or be asked to provide services. They do have types and can be named, but their names do not behave exactly like object names. Because they are simple, these types are called primitives.
Java object types may have complex internal state or the ability to perform interesting behaviors. Java primitive objects do not have any internal state, nor can they do anything by themselves. They cannot ring like an alarm clock, close like a window, or be selected like a radio button. They cannot even add themselves or display themselves on a screen. Only objects can be asked to perform actions. In chapter 5, we will learn how we can use primitive Things to accomplish useful tasks. But, unlike object Things, primitive Things cannot accomplish anything by themselves.
A type is Java's way of indicating what kind of Thing something is and what it can do. Like objects, Java primitive Things have types. But unlike objects, you cannot create any new Java primitive types. Java has exactly eight primitive types. These types are built into the Java language, so they are always available to you. Four of these types correspond to integers. Two of the types correspond to decimal numbers. One of the types is for single characters. The eighth type is for true-or-false values, or booleans. These are all and exactly the primitive types permitted in Java. The name of each of Java's primitive types begins with a lower case letter.
For example, Java knows about numbers. If you type 6 in a(n appropriate place in a) Java program, the computer will "understand" that you are referring to an integer greater than 5 and less than 7. The expression 6is a Java literal: an expression whose value is directly "understood" by the computer. In addition to integers, Java recognizes literals that approximate real numbers expressed in decimal notation as well as single textual characters.
All of the following are legitimate Things to say in Java:
Details of Java numeric literals -- and of all of the other literals discussed here -- are covered in the sidebar on Java Primitive Types. As we will see in chapter 5, you can perform all of the usual arithmetic operations with Java's numbers. Be warned, though, that non-integral values -- like 1/3 and 1.234567890123456789 -- are, in general, represented only approximately.
Java can also manipulate letters and other characters. When you type them into Java, you have to surround each character with a pair of single quotation marks: 'a', 'x', or '%', for example. Note that this enables Java to tell the difference between 6 (the integer between 5 and 7) and '6'(the character 6, which on my keyboard is a lower case '^'). The first is something that you can add or subtract. The second is not.
One character by itself is not often very useful, so Java can also manipulate sequences of characters called strings. Strings are used, for example, to communicate with the user. Error message, user input (i.e., what you type to a running Java program), titles and captions are all examples of Java strings. To describe a specific string in Java -- for example, the message that your computer prints to the screen when you boot it up -- you can write it out surrounded by double quotes: "Hi, how are you?" or "#^$%&&*%^$"or even "2 + 2". Your computer doesn't understand the string, it just remembers it. (For example, the computer doesn't know of any particular relationship between the last example and the number 4 -- or the string "4".)
It turns out that it's also useful for many programs to be able to manipulate conditions, too, so Java has one last kind of primitive value. For example, if we are making sandwiches, it might be important to represent whether we've run out of bread. We can talk about what to do when the bread basket is empty:
if the bread basket is empty, buy some more bread....
Conditions like this -- bread-basket emptiness -- are either true or false. We call this kind of Thing a boolean value. Booleans are almost always used in conditional -- or test -- statements to determine flow of control, i.e., what should this piece of the program do next? Java recognizes trueand false as boolean literals: if you type one of them in an appropriate place in your program, Java will treat it as the corresponding truth value.
As we have just seen, primitive-type Things can be referenced by literals. In addition, Strings can be referenced by literals, by using the double-quotation mark syntax: "What, me worry?" So all three of the following are literals -- "5" '5' and 5 -- but the first is an object-type Thing (a String), while the latter two are primitive-type Things (a char and an int, respectively).
There are a lot of rules about how these different Things work and how they are used. For details on Java's primitive types -- including their names and their properties, see the sidebar on Java Primitive Types.
If you want to refer to a Java object, you can do so using an appropriately typed name. You can also refer to a Java primitive Thing using a name. Declaration, assignment, and definition are used with primitive names in much the same way that they work with object names. For example:
The first line creates a new name, myLuckyNumber, and binds it to 6. The second line creates a new name, yourGuess, but does not give it any initial value. Whether yourGuess is given an initial value by this line depends at least on where the line appears within code and in some cases on the particular implementation of Java in which you are executing. It is always inadvisable to assume that yourGuess has been given a value, though -- being a dial -- it must, of course, be set to some value. The final line assigns the value of myLuckyNumber-- 6 -- to the name yourGuess.
So far, names with primitive type look a lot like object names. But it turns out that there are some important, if subtle, differences. Java names with primitive types aren't exactly labels, as object names are. You see, there may be an unpredictably large number of Buttons or KlingonStarships, and so a label is the best way to keep track of any particular KlingonStarship that comes along. But Java primitives are different.
For example, there are only two boolean values possible in Java: true and false. This means that we can use a very different mechanism for a name that has type boolean. Java does just that. A name that can have only one or the other of two values can be represented using a switch: It can be on, or it can be off. This is just what Java does: Boolean names are just switches. Let's say we have a boolean name, isSunny. This name is just a switch. It is always set in one of the two positions: on/true, or off/false. So if the switch corresponding to isSunny is on, we'll know that isSunnyis true. If the isSunny switch is off, we'll know that isSunny is false. We can tell the value corresponding to the boolean name just by inspecting the switch.
But if we use a switch to indicate true-or-false, how do we do assignment? When we use label names -- for objects -- we just stick a second label on the same object. When we use switches as names, creating a new name means creating a new switch. That is, dial name assignment copies one dial's setting to another. So what do we do when, for example, we have
(which means that I am happy if it's sunny, and not happy if it's not)? Simple enough: we set the new switch -- amHappy -- to the same position that isSunny is in. (Note: We do this once, at the time of the assignment. After that, the two switches are completely separate. More on this later....)
It turns out that this analogy works for all of the Java primitive types. For example, there are only a fixed, finite number of ints possible in Java. (See sidebar.) Although it might be confusing to imagine a switch with 4,294,967,296 positions, you can imagine that an int name is just a very large dial with those same 4 billion settings. By reading the setting of the dial, you can tell what value an int name corresponds to.
As remarkable as it may seem, each of the Java primitive types is represented in this way. The dial here is metaphorical, but the actual representation is very much as described. A Java primitive is stored in such a way that every name with a primitive type indicates its value just as the metaphoric dial does. A name corresponding to a byte is simply a dial with 256 positions. A long name has 264 positions. And even float and double names have only finite numbers of positions; this is why floating point numbers don't really represent real numbers and in fact aren't all that good for extreme precision calculations. Even a double precision floating point number can only represent 264 values between -1.8e 308 and 1.8e 308, so many values just can't be captured accurately. Note also that the actual precision of a double varies over this range. Char ranges over many more values than just a-Z, but there are still only 216possible characters in Java, so a char name is like a dial with that many positions.
For example,
associates i with a dial that's just the right size for a 32-bit integer.
How is this different from a label? There are at least three big differences.
In particular, assigning one label to another means that both are stuck on the same object (or both are null), so that they "share" a value. When one dial is assigned to another, the setting on the latter dial is copied onto the former. That's it; after that, the assignment is complete and the two dials go their separate ways. There is no further relationship between the values on the dials.
The last point is worth a closer look. Consider the following two very similar-looking sets of statements (one on the left, the other on the right):
In both cases, the first statement declares a name and the second statement assigns the name a value. The name i on the left is a dial-name and is set to 3; the name marigold on the right is a label-name and is set to a new Cat.
In both cases, the third statement declares another name and assigns the first name to the second. However, assignment has a different meaning in these two cases. On the left, the dial-name jis set to the same setting (3) as the dial-name i. On the right, the label-name phoebe is stuck onto the same object that the label-name marigold is stuck on.
In both cases, the fourth statement changes something by using the first name (i on the left and marigold; on the right). However, the effects are quite different. On the left, the value of i changes to 4, of course, but the value of j remains 3. If we asked whetherj is 4, the answer would be "No." On the right, the object referenced by marigold has kittens, so that (same) object referenced byphoebe has kittens. If we asked whether phoebe has had kittens, the answer would be "Yes!"
The left side of the figure shows the dial names i and j. The right side of the figure shows the label names Marigold and Phoebe. The middle row shows the different effects of assignment in the two cases.
To summarize:
A more formal term for dial types is value type.
asks object to perform service.
All other Java types are object types. By convention, we begin each object type with an upper-case letter.
Assume that the following declarations apply:
For each item below, give the type of the item.
For each of the following definitions, fill in a type that would make the assignment legal.
There are several answers to some of these, but in each case only one "most obvious" type. It is this "most obvious" type that we are after.
This problem checks your understanding of assignment.
Assume that the following statements are executed, in order.
What is the value of a? of b? of c? of d?
Assume that the following statements are executed, in order.
What is the value of a? Of b? Of c?
Assume that the following statements are executed, in order.
What is the value of a? Of b? Of c? Of d?
Assume that myObject is a name bound to an object (i.e.,myObjectis not null). After the following statements are executed in order,
Is the value of a null or non-null? What about b? What about c? What about myObject?
Assume again that myObject is a name bound to an object (i.e.,myObject is not null). After the following statements are executed in order,
is the value of d null or non-null? What about myObject?
Assume one more time that myObject is a name bound to an object (i.e., myObject is not null). After the following statements are executed in order,
Now is the value of of e null or non-null? What about myObject?
Which of the following could legitimately be used as a name in Java? (Note that none of them would be wise choices for names, except possibly in a Star Wars game, as none of them is likely to convey meaningful information to readers of a program.)
Assume that the following declarations have been made:
Complete the following table:
Name | dial or label? | Value (or null?) |
i | ||
j | ||
c | ||
d | ||
b | ||
s | ||
s2 | ||
o |
Assume that this fortune is "You will live a long and happy life." Now assume that the fortune teller is asked for another fortune:
Note that this fortune -- assume that it is "Things change." -- is not assigned explicitly to any label. At this point, we execute the fortune-printing statements from the same section:
What is printed?
Assume that there is an already -defined object type calledDate and that today is an already -defined Date name with a value representing today's date. Suppose that you wanted to declare a new name, yesterday, and give it the value currently referred to by today. This would be useful, for example, if it were nearly midnight and we might soon want to update the value referred to by today.
Explain why the following attempt will not successfully solve this problem.
At this point of this book, you should understand why the above will not work, but we have not yet discussed what would work. We'll see the basic ideas for a successful solution in Chapter 7,Building New Things: Classes and Objects. Also relevant is the discussion about @@ clone and Cloneable in Chapter 10, Inheritance.
Continuing the previous problem, now assume that today is an already -defined int (not Date) name with a value representing today's date, where 1 represents January 1, and 32 represents February 1, and 33 represents February 2, and so on, with 365 representing December 31. (Assume that this is not a leap year.) Again suppose that you wanted to declare a new name,yesterday, and give it the value currently referred to by today. Now, the problem is solvable with the tools from this chapter.
Give the solution (that is, declare yesterday appropriately and give it the value referred to by today). Then explain how this problem is different from the previous problem.
(From the footnote): In the tale of two hats, what would have happened if the King had executed his hat-checking lines in the opposite order?
Recall again the tale of two hats. Later, after the events of that story were long past, someone suggested that the problem here was that the hat check hadn't issued claim checks, which might have changed the circumstances. These claim checks would have been ints, not Hats.
"If the names had been dials rather than labels, would Mrs. Roosevelt's assistance still have been needed?"
As it happens, there were claim checks involved, but Charlie Chaplin and King George had clumsily dropped them, and they were unable to determine which claim check was whose. This is why they'd each used the hatCheck.returnHat() service, rather than a service that required a claim check as input.
Suppose that the situation were as follows:
After the mixup, Mr. Chaplin found himself holding claim check 2:
while King George was in possession of claim check 1:
However, the crown can only be retrieved with claim check 2, the bowler with check 1. So the two gentlemen are now faced with a swap of integers rather than hats. As the story originally unfolded, they gave up and later were forced to proceed with the hat swap. Imagine, instead, that Mrs. Roosevelt had walked up at this moment -- when the claim checks needed rearranging -- and write code to resolve the situation WITHOUT using the literals 1 and 2 further. (You may, of course, use charlieChaplinCheck and kingGeorgeCheck in your code.)
© 2003 Lynn Andrea Stein
This chapter is excerpted from a draft of Introduction to Interactive Programming In Java, a forthcoming textbook. It is a part of the course materials developed as a part of Lynn Andrea Stein's Rethinking CS101 Project at the Computers and Cognition Laboratory of the Franklin W. Olin College of Engineering and formerly at the MIT AI Lab and the Department of Electrical Engineering and Computer Science at the Massachusetts Institute of Technology.
Questions or comments:
<[email protected]>