Published: July 1, 2003
By Richard G.
Baldwin
Java Programming Notes # 905
The situation
Many universities, colleges, and high schools (including the college where I teach) attempt to teach non-object-oriented (procedural) programming fundamentals using an object-oriented programming language such as C++, Java, or C#. This results in some significant problems.
The problem
The main problem is that persons who are attempting to learn programming
fundamentals are confronted with requirements to use objects, (such
as I/O objects and String objects) without an understanding of what
they are doing when they use those objects. This is a de-motivator
for those persons who prefer to understand what they are doing instead
of simply doing things by rote.
Help is available
This tutorial lesson is designed to help persons in this situation by
giving them an understanding of what they need to know in order to use
objects to the minimal extent necessary for courses in programming fundamentals.
The tutorial is also designed to help those persons who are trying
to teach themselves how to become programmers.
Supplemental material
In some cases, textbooks and professors explain classes and objects away
by simply saying, "Don't worry about why it works. Just do
it the way I tell you to do it."
In other cases, textbooks and professors attempt to explain classes
and objects, but fail to get the message across for a variety of reasons.
The material in this lesson is designed as a supplement to help persons who find themselves in either of the situations listed above.
For further reading, see my extensive collection of online Java tutorials
at Gamelan.com.
A consolidated index is available at www.DickBaldwin.com.
Study hint
You may find it useful to open another copy of this lesson in a separate browser window. That will make it easier for you to scroll back and forth among the different figures and listings while you are reading about them.
Will avoid the commonly used approach
In explaining classes and objects, I will not revert to the commonly used
approach of talking about a class such as the Vehicle class, which
can be subclassed into a Car class and a Truck class, and the
further subclassing of the Car class into a SportsCar class
and a FamilyCar class. Certainly such analogies are important
for those persons who are making a serious attempt to understand encapsulation,
inheritance, and polymorphism, the three pillars of object-oriented
programming. However, for those persons who simply need to understand
what it means to invoke a method on an object of the String class,
discussions of inheritance are a distraction and not a help.
Will explain from the viewpoint of type
Rather, I will explain a class and its objects from the viewpoint of a
non-primitive, user-defined type, and the operations that can be performed
on an entity of that type. Before doing that, however, I will
explain what is commonly meant by type in type-sensitive
languages. (Every modern programmer needs to understand the concept
of type, so there is no better time to learn about type than the present.)
To lay the groundwork for the discussion of types, I will explain what we mean by variables and objects, and the similarity between the two.
I will discuss and explain some of the common primitive types such as
short, int, double, boolean, and char,
and will then extend the concept of type to classes such as the String
class. I will discuss some of the operations that can be performed
on entities of the primitive types, and will relate that to some of the operations
that can be performed on an entity of type String.
Standard input and output
I will also discuss and explain certain aspects of objects used to support
standard input and output.
Intended to be general in nature
To a large extent, this tutorial will be couched within the Java programming
language, because that is the language that I know best. However,
the concepts that I will discuss are intended to be applicable to persons
using C++ and C# as well.
Let's go back to around the ninth grade where you probably learned a little about algebra and a little about geometry. Hopefully, you will remember the formula for calculating the area of a circle, as shown in Figure 1.
The area of a circle
a = pi * r * r |
The formula in Figure 1 tells us that the area of a circle is equal to
the constant pi multiplied by the radius squared. (Note that
the true value of pi actually contains more digits than are shown in Figure
1.)
(As is the case in programming, Figure 1 uses an asterisk (*) to indicate multiplication, as opposed to the use of an "x" or a dot that you probably used in your algebra class.)
Constants and variables
In the formula in Figure 1, pi is a named constant whose value is shown. Constants in programming mean pretty much the same thing that they mean in algebraic formulas. That is, the value of a constant never changes.
The terms a and r in the formula in Figure 1 are variables.
Going further, your algebra teacher may have told you that a
is the dependent variable while r is an independent variable.
That is to say, the value of the area is dependent on the value that you
assign to the radius before you calculate the area.
Variables also mean pretty much the same thing in programming that they
mean in algebraic formulas. Every variable has a name (such
as a or r) and the value of the variable can change.
In programming, this means that the value can change as the program
executes over time.
A variable is a named pigeonhole
You can think of a variable in an algebraic formula as the name of a value
that can change. You can think of a variable in programming as the name
of a pigeonhole in memory, which can be used to store values that can
change as the program executes.
A program named Area01
Let's take a look at the central part of a program that calculates and displays the area of a circle for different radius values, as shown in Listing 1. (The entire program is shown in Listing 9 near the end of the lesson.)
r = 1.0; |
Since you can probably do the arithmetic shown in Listing 1 in your head,
it should come as no surprise to you that the output produced by the
code in Listing 1 is shown in Figure 2.
For radius = 1.0, area = 3.141592653589793 |
Calculate values for different radii
The code in Listing 2 assigns two new values, 1.5 and 2.0, to the variable named r. Each time a new value is assigned to the variable r, a new area is calculated and the value is assigned to the variable named a. Then the values for r and a are displayed.
r = 1.5; |
Once again, you probably won't be surprised to learn that the value of the area for each of the different radius values is as shown in Figure 3.
For radius = 1.5, area = 7.0685834705770345 |
Now, let's set the concept of variables aside for a few minutes and discuss the concept of type.
Type-sensitive languages
Java, C++, C#, and some other modern programming languages make heavy use of a concept that we refer to as type, or data type. We refer to those languages as type-sensitive languages.
Not all languages are type-sensitive languages. In particular, some languages hide the concept of type from the programmer and automatically deal with type issues behind the scenes.
So, what do we mean by type?
One analogy that comes to my mind is international currency. For example, many years ago, I spent a little time in Japan and quite a long time on an island named Okinawa (I believe that Okinawa is now part of Japan).
Types of currency
At that time, as now, the type of currency used in the United States was the dollar. The type of currency used in Japan was the yen, and the type of currency used on the island of Okinawa was also the yen. However, even though two of those currencies had the same name, they were different types of currency, as determined by the value relationships between them.
The exchange rate
As I recall, at that time, the exchange rate between the Japanese yen and the U.S. dollar was 360 yen to the dollar. The exchange rate between the Okinawian yen and the U.S. dollar was 120 yen to the dollar. This suggests that the exchange rate between the Japanese yen and the Okinawian yen would have been 3 Japanese yen to the Okinawian yen.
Analogous to different types of data
So, why am I telling you this? I am telling you this to illustrate the concept that different types of currency are roughly analogous to different data types in programming.
Purchasing transactions were type sensitive
In particular, because these were three different types of currency, the differences in the types had to be taken into account in any purchasing transaction to determine the price in that particular currency. In other words, the purchasing process was sensitive to the type of currency being used for the purchase (type sensitive).
Different types of data
Type-sensitive programming languages deal with different types of data as well. Some data types involve whole numbers only (no fractional parts are allowed). We generally refer to these as integer types.
Other data types involve numbers with fractional parts. We generally refer to these types as floating point types, because a decimal point can float back and forth, separating the whole number part from the fractional part. (After a while, we get lazy and refer to these simply as floating types.)
An example of integer and floating-point types
Figure 4 contains a description of a problem involving both integer types and floating-point types.
Consider the problem of determining the number of cans
of paint that must be purchased in order to paint all 15 tables in a
restaurant. The number of tables is an integer type. We don't want
to paint 14.6 tables or 15.7 tables. We want to paint exactly 15
tables. (We don't want to have a fractional part of a table left
unpainted.) We know that one can of paint will cover 3.6 tables. The number of tables that can be painted with one can of paint is a floating-point value because it contains a whole number part and a fractional part. A little arithmetic tells us that 4.167 cans of paint will be required to paint all 15 tables. This is also a floating-point value, because it has a whole number part and a fractional part. However, the man at the hardware store is unwilling to sell us 4.167 cans of paint. He requires us to specify the number of cans of paint as an integer value. In this case, we will need to purchase 5 cans of paint in order to have enough paint available to paint all 15 tables, with a little paint left over at the end. Figure 4 Calculating the number of cans of paint
to purchase
|
Although all data in a computer is stored in
numeric format, some data types conceptually have nothing to do with numeric
values, but deal only with the concept of true or false
or with the concept of the letters of the alphabet and the punctuation characters.
I will have more to say about these types later.
Type specification
For every different type of data used with a particular programming language, there is a specification somewhere that defines two important characteristics of the type:
1. The set of all possible data values that can be stored in an instance of the type (we will learn some other names for instance later)?
2. The operations that you can perform on that instance alone, or in combination with other instances? (For example, operations include addition, subtraction, multiplication, division, etc.)
What do I mean by instance?
Think of the type specification as being analogous to the plan or
blueprint for a model airplane. Assume that you build three model
airplanes from the same set of plans. You will have created three
instances of the single set of plans.
We might say that an instance is the physical manifestation of a plan or a type.
Using mixed types
Somewhat secondary to this specification, but also extremely important, is a set of rules that defines what happens when you perform an operation involving mixed types (such as making a purchase using some yen currency in combination with some dollar currency). However, that is beyond the scope of this tutorial, so I won't get into it here.
An example, the short data type
There is a data type in Java, C++, and C# known as short. If you have an instance of the short type in Java, the set of all possible values that you can store in that instance is the set of all whole numbers ranging from -32,768 to +32,767.
This constitutes a set of 65,536 different values, including the value zero. No other value can be stored in an instance of the type short. For example, you cannot store the value 35,000 in an instance of the type short in Java. If you need to store that value, you will have to use some type other than short.
Sort of like an odometer
The short type is an integer type. Integer types are somewhat analogous to the odometer in your car (the thing that records how many miles the car has been driven). For example, depending on the make and model of car, there is a specified set of values that can appear in the odometer. The value that appears in the odometer depends on how many miles your car has been driven.
It is fairly common for an odometer to be able to store and to display the set of all positive values ranging from zero to 99,999. If your odometer is designed to store that set of values and if you drive your car more than 99,999 miles, it is likely that the odometer will roll over and start back at zero after you pass the 99,999-mile mark. In other words, that particular type of odometer does not have the ability to store a value of 100,000 or more miles. Once you pass the 99,999 mark, the data stored in the odometer is corrupt. It no longer represents the true number of miles for which the car has been driven.
A word or two about operations
Assume that you have two instances of the type short in a Java program. Here are some of the operations that you can perform on those instances:
What if you want to do something different?
If you want to perform an operation that is not allowed by the type specification, then you will have to find another way to accomplish that purpose.
For example, some programming languages allow you to raise whole-number types to a power (example: four squared, six cubed, nine to the fourth power, etc.). However, that operation is not allowed by the Java specification for the type short. If you need to do that operation with a data value of the Java short type, you must find another way to do it.
Two major categories of type
Java data types can be subdivided into two major categories:
What this means is that there is a core component to the language that is always available. Beyond this, individual programmers can extend the language to provide new capabilities. The primitive types discussed in this section are the types that are part of the core language. A later section will discuss user-defined types that become available when a programmer extends the language.
Four categories of primitive types
It seems that when teaching programming, I constantly find myself subdividing topics into sub-topics. I am going to subdivide the topic of primitive types into four categories:
The whole-number types, often called integer types, are probably the easiest to understand. These are types that can be used to represent data without fractional parts.
Purchasing applesauce and hamburger
For example, consider purchasing applesauce and hamburger. At the grocery store where I shop, I am allowed to purchase applesauce by the jar, only in whole-number or integer quantities.
For example, the grocer is happy to sell me one jar of applesauce and is even happier to sell me 36 jars of applesauce. However, she would be very unhappy if I were to open a jar of applesauce in the store and attempt to purchase 6.3 jars of applesauce.
A count of the number of jars of applesauce that I purchase is somewhat analogous to the concept of whole-number data types in Java. Applesauce is not available in fractional parts of jars, at least not at the store where I purchase my groceries.
On the other hand, the grocer is perfectly willing to sell me 6.3 pounds of hamburger. This is somewhat analogous to floating-point data types in Java.
Accommodating applesauce and hamburger in a program
Therefore, if I were writing a program dealing with quantities of applesauce and hamburger, I might elect to use a whole number type to represent jars of applesauce and to use a floating-point type to represent pounds of hamburger.
Different whole-number types
Four different whole-number types are built into the Java language:
Differences in operations
Although there are some subtle differences among these four types in terms of the operations that you can perform on them, I will defer a discussion of those differences until a more advanced lesson (for example some operations require instances of the byte and short types to be converted to type int before the operation takes place).
Algebraically signed values
All four of these types can be used to represent algebraically signed values ranging from a specific negative value to a specific positive value.
Range of the byte type
For example, the byte type can be used to represent the set of whole numbers ranging from -128 to +127 inclusive. (This constitutes a set of 256 different values, including the value zero.)
The byte type cannot be used to represent any value outside this range. For example, the byte type cannot be used to represent either -129 or +128.
No fractional parts allowed by byte type
Also, the byte type cannot be used to represent fractional values within the allowable range. For example, the byte type cannot be used to represent the value of 63.5 or any other value that has a fractional part.
Like a strange odometer
To form a crude analogy, the byte type is sort of like a strange odometer in a new (and unusual) car that shows a mileage value of -128 when you first purchase the car. As you drive the car, the negative values shown on the odometer increment toward zero and then pass zero. Beyond that point they increment up towards the value of +127.
Oops, numeric overflow!
When the value passes (or attempts to pass) +127 miles, something bad happens. (The value rolls over and starts at -128 again.) From that point forward, the value shown on the odometer is not a reliable indicator of the number of miles that the car has been driven.
Ranges for each of the whole-number types
The table in Figure 5 shows the range of values that can be accommodated by each of the four whole-number types supported by the Java programming language.
byte -128 to +127 short -32768 to +32767 int -2147483648 to +2147483647 long -9223372036854775808 to +9223372036854775807 Figure 5 Ranges for integer types
|
Can represent some fairly large values
As you can see, the int and long types can represent some fairly large values. However, if your task involves calculations such as distances in interstellar space (or the U.S. national debt), these ranges probably won't accommodate your needs. This will lead you to consider using the floating-point types discussed in the upcoming sections.
Operations on integer types
As mentioned earlier, some of the operations that can be performed on integer
types are as follows:
I will discuss other operations that can be performed on whole-number types in a subsequent lesson.
Floating-point types are a little more complicated than whole-number types. I found the following definition of floating-point in the Free On-Line Dictionary of Computing at this URL:
A number representation consisting of a mantissa, M, an exponent, E, and an (assumed) radix (or "base") . TheSo what does this really mean?
number represented is M*R^E where R is the radix - usually ten but sometimes 2.
Assuming a base or radix of 10, (which is probably what you have been using since your first kindergarten class), I will attempt to explain this concept using an example.
Consider the following value: 623.57185
I can represent this value in any of the following different ways (where
* indicates multiplication):
.62357185*1000 Figure 6 Different ways to represent a value |
In other words, I can represent the value as a mantissa (62357185) multiplied by a factor where the purpose of the factor is to represent a left or right shift in the position of the decimal point.
Now consider the factor
Each of the factors shown above represents the value of ten raised to some specific power, such as ten squared, ten cubed, ten raised to the fourth power, etc.
Exponentiation
If we allow the symbol ^ to represent exponentiation (raising to a
power) and allow the symbol / to represent division, then we can write
the values for the above factors in the ways shown in Figure 7. Note in
particular the numbers in blue, which I will refer to later as the exponents.
1000 = 10^+3 = 1*10*10*10
Figure 7 Representation of the factor |
For example, in the above notation, the term 10^+3 means 10 raised to the third power.
The zeroth power
By definition, the value of any value raised to the zeroth power is 1. (Check this out in your old high school algebra book.)
The exponent and the factor
Hopefully, at this point you will understand the relationship between the value shown in blue (the exponent) and the factor introduced earlier.
Different ways to represent the same value
Having reached this point, by using substitution, I can rewrite the original set of representations of the value 623.57185 in the different ways shown in Figure 8. (Compare Figure 8 with Figure 6.)
.62357185*10^+3 Figure 8 Different ways to represent a value |
It is very important to for you to understand that these are simply different ways to represent the same value.
A simple change in notation
Finally, by making a simplifying change in notation where I replace *10^
by E I can rewrite the different representations of the value
of 623.57185 in the ways shown in Figure 9.
.62357185E+3 Figure 9 Different ways to represent a value |
This is a relatively standard way to display floating-point values, using exponential notation (the letter E indicates an exponent).
Getting the true value
Floating-point types represent values as a mantissa containing a decimal point along with an exponent value, which tells how many places to shift the decimal point to the left or to the right in order to determine the true value.
Positive exponent values mean that the decimal point should be shifted to the right. Negative exponent values mean that the decimal point should be shifted to the left.
Advantages of floating-point types
One advantage of floating-point types is that they can be used to maintain fractional parts in data values.
Another advantage of floating-point types is that a very large range of values can be represented using a reasonably small amount of computer memory for storage of the values. For example (assuming that I counted the number of digits correctly) Figure 10 shows how to represent a very large value and a very small value as a floating-point type.
The very large value: 62357185000000000000000000000000000000.0 can be represented as 6.2357185E+37 The very small value: 0.0000000000000000000000000000062357185 can be represented as 6.2357185E-30 Figure 10 Representing a large range of values |
When would you use floating-point?
If you happen to be working in an area where you need to keep track of fractional parts (such as the amount of hamburger in a package), have to work with extremely large numbers (distances between galaxies), or have to work with extremely small values (the size of atomic particles), then you will need to use the floating-point types.
Two floating-point types
Java supports two different floating-point types:
float 1.4E-45 to 3.4028235E38 double 4.9E-324 to 1.7976931348623157E308 Figure 11 Range for floating-point
types
|
Operations on floating-point types
Floating-point types support the typical arithmetic and comparison operations. I will discuss the operations that can be performed on floating-point types in more detail in a subsequent lesson.
Computers deal only in numeric values. They don't know how to deal directly with the letters of the alphabet and punctuation characters.
The purpose of the character type is to make it possible to represent the letters of the alphabet, the punctuation characters, and the numeric characters internally in the computer. This is accomplished by assigning a numeric value to each character, much as you may have done to create secret codes when you were a child. (For example, in Java an upper-case A character is represented by the numeric value 65, whereas the upper-case B is represented by the numeric value 66.)
A single character type
Java supports a single character type named char. The char type uses a standard character representation known as Unicode to represent up to 65,535 different characters.
Why so many characters?
The reason for the large number of possible characters is to make it possible to represent the characters making up the alphabets of many different countries and many different languages.
Representing a character symbolically
Although each character is represented internally by a numeric value, as long as the characters that you use in your program appear on your keyboard, you usually don't have a need to know the numeric values associated with the different characters.
In Java, you usually represent a character to the program by surrounding it with apostrophes as follows: 'A'.
The Java programming tools know how to cross-reference that specific character symbol against the Unicode table to obtain the corresponding numeric value. (A discussion of the use of the char type to represent characters that don't appear on your keyboard is beyond the scope of this lesson.)
The char type supports the typical arithmetic and comparison operations. I will discuss the operations that can be performed on the char type in more detail in a subsequent lesson.
if some test
returns true, then Figure 12 Typical use of boolean type |
I will discuss the operations that can be performed on the boolean type in more detail in a subsequent lesson.
As mentioned earlier, Java is an extensible programming language. There is a core component to the language that is always available. Beyond this, different programmers can extend the language in different ways to meet their individual needs. (In addition, the programmers at Sun have created a large library of user-defined types, which you can use if you have access to the library.)
Creating new types
One of the ways that individual users can extend the language is to create new types. As indicated earlier, for every different type of data used with a particular programming language, there is a specification somewhere that defines two important characteristics of the type:
1. The set of all possible data values that can be stored in an instance of the type.
2. The operations that you can perform on that instance alone, or in combination with other instances.
Thus, when creating or defining a new type, the user must define the set of values that can be stored in an instance of the type, as well as the operations that can be performed on instances of the type. From the viewpoint of this tutorial lesson, the purpose of a class definition is to create a new type, and to define the attributes of the type listed above.
No magic involved
While this might initially seem like magic, once you get to the heart of the matter, it is relatively straightforward. Instances of new types are created by combining instances of primitive types and instances of other user-defined new types.
An example
For example, the String type, which can be used to represent a person's last name, is just a grouping of a bunch of instances of the primitive char type (plus a specification of the operations that can be performed on an instance of the new String type).
A new Person type, which could be used to represent a person's first name and last name, might simply be a grouping of two instances of the user-defined String type.
The company telephone book
A programmer responsible for producing the company
telephone book might create a new Employee type that could be
used to store the first and last names along with the telephone number
of an individual. Using this new type, the programmer could create
an instance of the new type for each employee in the company.
(At this point, let me sneak a little jargon in and tell you that we normally refer to such instances as objects. More specifically, we refer to instances of primitive types as variables, and we refer to instances of user-defined types as objects.)
A comparison operation
This programmer might define one of the allowable operations for the Employee type to be a comparison between two objects of the Employee type to determine which is greater in an alphabetic sorting sense. This operation could be used to sort the set of objects representing all of the employees into alphabetical order. The set of sorted objects could then be used to print a new telephone book.
A name-change operation
Another allowable operation that the programmer might define for the Employee type would be the ability to change the name stored in an object representing an employee.
For example when Suzy Smith marries Tom Jones, she might elect to thereafter be known as Suzy Jones, Suzy Smith-Jones, or Suzy Jones-Smith. In this case, there would be a need to modify the object that represents her to reflect her newly-elected surname. (Or perhaps Tom Jones might elect to thereafter be known as Tom Smith, in which case it would be necessary to modify the object that represents him.)
An updated telephone book
The programmer could use the name-changing operation to modify the object, use the sorting operation to re-sort the set of objects, and then print and distribute a modified version of the telephone book.
Many user-defined types already exist
Unlike the primitive types which are predefined, I am unable to give you much in the way of specific information about user-defined types, simply because they don't exist until the user defines them.
I can tell you, however, that when you obtain the Java programming tools from Sun, you not only receive the core language containing the primitive types, you also receive a large library containing several thousand user-defined types that have already been defined. A large documentation package is available from Sun to help you determine the individual characteristics of these user-defined types.
The most important thing
At this stage in your development as a programmer, the most important thing for you to know about user-defined types is that they are possible in Java, C++, and C#, as well as in some other object-oriented programming languages as well.
Unlike earlier procedural programming languages such as C and Pascal, when you use an extensible object-oriented programming language, you are no longer forced to adapt your problem to the available tools. Rather, you now have the opportunity to extend the tools to make them better suited to solve your problem.
The class definition
The specific Java mechanism that makes it possible for you to define a new type is a mechanism known as the class definition. In Java, whenever you define a new class, you are at the same time defining a new type. Your new type can be as simple, or as complex as you want it to be.
An object (instance) of your new type can contain a very small amount of data, it can contain a very large amount of data, or it may contain no data at all.
The operations that you allow to be performed on an object of your new type can be rudimentary, or they can be very powerful, or they may fall somewhere in between.
It is all up to you
Whenever you define a new class (type) you not only have the opportunity to define the data definition and the operations, you also have a responsibility to do so.
Much to learn and much to do
If you belong to the population for which this lesson
is intended, you still have much to learn and much to do before you will
need to define new types. There are a lot of fundamental programming concepts
that you will need to learn before you seriously embark on a study involving
the definition of new types.
However, in addition to learning fundamental programming
concepts, you will probably also need to learn how to create and use objects
of a few existing classes, such as the String class, and the classes
used for keyboard input and screen output. In order to use objects
of these classes, you simply need to understand how to create the objects,
and how to perform the operations defined for objects of those classes.
For the present then, simply remember that the capability to create new types is available. If you work to expand your knowledge of Java programming one small step at a time, when you reach the point where you need to define new types, you will be ready and eager to do so.
As stated earlier, the purpose of this lesson is to help persons in fundamental
programming courses by giving them an understanding of what they need to
know in order to use objects to the minimal extent necessary in such
courses. Hopefully by now, you know what a class is and what an object
is. I will show you a couple of examples of creating and using common
objects by invoking operations (methods) on those objects.
Creating an object of the String class
The following listings, beginning with Listing 3, show the central code
for a program named Basics01, which illustrates the use of an object
of the String class, as well as the use of objects of the PrintStream
class and the InputStream class. A complete listing of the
program is shown in Listing 10 near the end of the lesson.
One of the predefined classes in the Java standard class library is a class
named String. The purpose of the String class is to define
a type of object capable of encapsulating a string of characters (such
as a person's name, for example), and to provide operations that can
be performed on an object of the class.
Listing 3 shows one way to create a new String object containing the characters shown within the quotation marks, and to save a reference to that new object in a variable named aString.
aString = "Enter a character"; |
In Java, all that is necessary to create a new object of the type String
is to include characters within a pair of matching quotation marks.
Saving a reference to the object
If you are going to use the object later, you will need to save a reference
to the object in a variable as illustrated in Listing 3. Once you have a
reference to the object, you can use that reference to perform operations
on the object. (Performing operations on the String object
will be illustrated later in this program.)
Displaying information on the screen
The code in Listing 4 causes the String object created above to be displayed on the computer screen.
System.out.println(aString); |
Without getting into some rather complex details, let me simply state
that System.out in Listing 4 represents an object of the predefined
class named PrintStream. This object, which is automatically
created when a Java program starts running, makes it possible to cause information
to be displayed on the computer screen.
(Technically, the information is displayed on the standard output device, but I won't get into that level of detail here.)
Performing operations on objects
The standard way to perform operations on objects in Java is to invoke
methods, (such as the println method shown in Listing 4), on
those objects. An object of the PrintStream class supports
several different operations or methods, including the println method
shown in Listing 4, and a method named print, which you will see later.
You invoke the println method using the syntax shown in Listing 4, passing the information to be displayed as a parameter to the method within the parentheses. The code in Listing 4 causes the line of text shown in Figure 13 to be displayed on the computer screen. (Compare the text on the screen with the characters represented by the String object in Listing 3.)
Enter a character |
Getting a character from the keyboard
For this program, the line of text shown in Figure 13 is actually a prompt asking the user to press a character key on the keyboard and then to press the Enter key on the keyboard. When the user does this, the code in Listing 5 will capture the character and save it in a variable named aCharacter.
aCharacter = (char)System.in.read(); |
The System.in term in Listing 5 represents an object of the predefined
class named InputStream. This object, which is automatically
created when a Java program starts running, makes it possible to capture
information entered by the user at the keyboard.
(Technically, the information is captured from the standard input device, but I won't get into that here.)
Thus the code in Listing 5 captures the keyboard character as type int,
forces the type to be converted from type int to type char,
and saves the result in a variable named aCharacter.
(The type conversion is accomplished by (char), which is commonly referred to as a cast. The reason why this conversion is necessary is beyond the scope of this tutorial.)
Performing three operations on the PrintStream object
The code in Listing 6 performs three consecutive but separate operations on the PrintStream object to display the character on the computer screen.
System.out.print(aCharacter); |
The first two operations in Listing 6 invoke the print method on
the PrintStream object, passing the single character previously
captured from the keyboard as a parameter to the method. The third
operation invokes the println method on that same object, passing
the same character as a parameter.
Difference between print and println
The difference between the print operation and the println
operation is as follows. When the print operation is performed,
the method displays the information and then leaves the screen cursor immediately
to the right of that information ready to display additional information
at that location on the screen.
When the println operation is performed, the method displays the
information, and then moves the screen cursor down to the left side of
the next line on the screen, ready to display additional information on
the next line.
Assuming that the user entered the character z when requested above,
the code in Listing 6 causes that character to be displayed three times
in succession, as shown in Figure 14, and then moves the screen cursor down
to the next line on the screen.
zzz |
Performing another operation on the String object
bString = aString.substring(3,12); |
Display the substring
Finally, the code in Listing 8 uses the println method discussed earlier to display the substring on the computer screen.
System.out.println(bString); |
This produces the screen output shown in Figure 15. Compare this
output with that shown in Figure 13, and you should be able to see how the
substring relates to the original string. (When counting characters, start
counting with zero. In other words, the first character in Figure 13
is character number 0.)
er a char |
At this point, if you are already set up to compile and execute Java programs, you may want to paste the code from Listing 9 and Listing 10 into your text editor, save the two programs in files named Area01.java and Basics01.java, and then compile and execute the two programs. Experiment with the two programs, making changes and observing the results.
In this lesson, I have explained the concept of a class and its objects
from the viewpoint of a non-primitive, user-defined type, and the operations
that can be performed on an entity of that type.
I explained what is commonly meant by type in type-sensitive
languages.
I explained what we mean by variables and objects, and the similarity between the two.
I discussed and explained some of the common primitive types, and extended
the concept of type to classes such as the String class. I discussed
some of the operations that can be performed on variables of the primitive
types, and related that to some of the operations that can be performed on
an object of type String.
/*File Area01.java |
/*File Basics01.java |
Copyright 2003, Richard G. Baldwin. Reproduction in whole or in part in any form or medium without express written permission from Richard Baldwin is prohibited.
Richard has participated in numerous consulting projects, and he frequently provides onsite training at the high-tech companies located in and around Austin, Texas. He is the author of Baldwin's Programming Tutorials, which has gained a worldwide following among experienced and aspiring programmers. He has also published articles in JavaPro magazine.
Richard holds an MSEE degree from Southern Methodist University and has many years of experience in the application of computer technology to real-world problems.
-end-