Chapter 2
In This Chapter
How computers, phones, and other devices run Java programs
The parts of a typical Java program
Before I became an Android guy, I was a Java guy. A Java guy is a person who revels in the workings of Java programs. I wrote Java programs, read about Java programs, went to Java user group meetings, and wore Java T-shirts. That’s why I was thrilled to learn that Android’s application programming language is Java.
In the early 1990s, James Gosling at Sun Microsystems created Java. He used ideas from many programming language traditions, including the object-oriented concepts in C++. He created an elegant platform with a wide range of uses. In mid-2014 (which is “now” as far as my chapter-writing goes), Java runs on 88 percent of all desktop computers in the United States, and on 97 percent of all enterprise desktops, with nine million Java developers worldwide.* Do you have a Blu-ray player? Under the hood, your player runs Java.
In this minibook (Book II), this chapter and Chapters 3 and 4 introduce the ins and outs of the Java programming language. But these chapters don’t offer a comprehensive guide to Java. (To badly paraphrase Geoffrey Chaucer, “This book never yet no complete not Java coverage.”) Instead, these chapters hit the highlights of Java programming. For a more complete introduction to Java, read Java For Dummies, 6th Edition or Java Programming for Android Developers For Dummies (both published by John Wiley & Sons, Inc.). (Yes, I wrote those books, too.)
Before Java became popular, most programs went almost directly from the developer’s keyboard to the processor’s circuits. But Java added an extra translation layer, and then Android added yet another layer. This section describes the layers.
A Java program (such as an Android application program) goes through several translation steps between the time you write the program and the time a processor runs it. The reason for this is simple: What’s convenient for processors to run is not convenient for people to write.
People can write and comprehend the code in Listing 2-1.
Listing 2-1: Java Source Code
public void checkVacancy(View view) {
if (room.numGuests == 0) {
label.setText("Available");
} else {
label.setText("Taken :-(");
}
}
The Java code in Listing 2-1 checks for a vacancy in a hotel. You can’t run the code in Listing 2-1 without adding several lines. But at this stage of the game, those additional lines aren’t important. What’s important is that by staring at the code, squinting a bit, and looking past all the code’s strange punctuation, you can see what the code is trying to do:
If the room has no guests in it,
then set the label’s text to "Available".
Otherwise,
set the label’s text to "Taken :-(".
The stuff in Listing 2-1 is Java source code.
The processors in computers, phones, and other devices don’t normally follow instructions like the instructions in Listing 2-1. That is, processors don’t follow Java source code instructions. Instead, processors follow cryptic instructions like these:
A3 86 01 00 2A 85 00 00 00 4D 00 00 00 50 00 00
00 55 55 55 55 00 00 00 02 4D 00 05 00 07 00 80
00 14 00 80 40 38 25 00 00 40 4D 40 00 00 40 32
45 00 80 40 14 6B 65 72 6E 65 6C 00 5F 70 75 74
49 6E 4D 65 6D 6F 72 79 00 5F 6D 61 6B 65 49 6E
74 65 72 72 75 70 74 32 31 00 5F 69 6E 74 65 72
72 75 70 74 32 31 53 65 72 76 69 63 65 52 6F 75
74 69 6E 65 00 69 6E 74 72 00 5F 69 6E 74 65 72
72 75 70 74 00 20 60 55 89 E5 1E 8B 46 04 8B 76
06 8A 4E 08 8E D8 88 0C 1F 5D C3 55 89 E5 8B 46
04 1E 8C CB 8E DB BE 02 80 32 00 57 88 44 01 1F
8B 46 06 8B 5E 08 8B 4E 0A 8B 56 0C CD 00 B4 00
5D C3 BA 80 4D 00 52 1E B8 00 00 8E D8 BE 84 00
8C C8 89 44 02 89 14 1F C3 00
To be fair, this gobbledygook that I call “instructions” isn’t really numbers and letters. It’s just 0s and 1s. So the first A3
in my “instructions” is shorthand for 10100011
.
I once participated in a three-part translation conversation. I spoke English to my mother, who translated it into Yiddish for her cousin, who translated it into Russian for the cousin’s husband. A similar kind of thing happens when you create an Android app. You start by writing Java source code, like the code in Listing 2-1. Your development computer translates the Java source code into Java bytecode. For a look at Java bytecode, see Listing 2-2.
Listing 2-2: Java Bytecode
0 aload_0
1 getfield #19 <com/allmycode/samples/MyActivity/room
Lcom/allmycode/samples/Room;>
4 getfield #47 <com/allmycode/samples/Room/numGuests I>
7 ifne 22 (+15)
10 aload_0
11 getfield #41 <com/allmycode/samples/MyActivity/label
Landroid/widget/TextView;>
14 ldc #54 <Available>
16 invokevirtual #56
<android/widget/TextView/setText(Ljava/lang/CharSequence;)V>
19 goto 31 (+12)
22 aload_0
23 getfield #41 <com/allmycode/samples/MyActivity/label
Landroid/widget/TextView;>
26 ldc #60 <Taken :-(>
28 invokevirtual #56
<android/widget/TextView/setText(Ljava/lang/CharSequence;)V>
31 return
When you write a Java program, you write source code instructions (like the instructions in Listing 2-1). After writing the source code, you run the code through a program — you apply a tool to your source code, in other words. The program is a compiler. The compiler translates your source code instructions into Java bytecode instructions. In other words, the compiler takes code that you can write and understand (such as the code in Listing 2-1:) and translates your code into code that a computer can execute (such as the code in Listing 2-2).
Like the language relay involving me, my mother, and my mother’s cousins, the translation from source code to 0s and 1s doesn’t end with Listing 2-2. In 2007, Dan Bornstein at Google created Dalvik bytecode — another way of representing instructions for processors to follow. (To find out where some of Bornstein’s ancestors come from, run your favorite Map application and look for Dalvik in Iceland.) Dalvik bytecode is optimized for the limited resources on a phone or a tablet device. Listing 2-3 contains some sample Dalvik instructions.*
Listing 2-3: Dalvik Bytecode
.method public checkVacancy(Landroid/view/View;)V
.limit registers 4
; this: v2 (Lcom/allmycode/samples/MyActivity;)
; parameter[0] : v3 (Landroid/view/View;)
.line 30
iget-object
v0,v2,com/allmycode/samples/MyActivity.room
Lcom/allmycode/samples/Room;
; v0 : Lcom/allmycode/samples/Room; , v2 :
Lcom/allmycode/samples/MyActivity;
iget v0,v0,com/allmycode/samples/Room.numGuests I
; v0 : single-length , v0 : single-length
if-nez v0,l4b4
; v0 : single-length
.line 31
iget-object
v0,v2,com/allmycode/samples/MyActivity.label
Landroid/widget/TextView;
; v0 : Landroid/widget/TextView; , v2 :
Lcom/allmycode/samples/MyActivity;
const-string v1,"Available"
; v1 : Ljava/lang/String;
invoke-virtual
{v0,v1},android/widget/TextView/setText
; setText(Ljava/lang/CharSequence;)V
; v0 : Landroid/widget/TextView; , v1 : Ljava/lang/String;
l4b2:
.line 36
return-void
l4b4:
.line 33
iget-object
v0,v2,com/allmycode/samples/MyActivity.label
Landroid/widget/TextView;
; v0 : Landroid/widget/TextView; , v2 :
Lcom/allmycode/samples/MyActivity;
const-string v1,"Taken :-("
; v1 : Ljava/lang/String;
invoke-virtual
{v0,v1},android/widget/TextView/setText ;
setText(Ljava/lang/CharSequence;)V
; v0 : Landroid/widget/TextView; , v1 : Ljava/lang/String;
goto l4b2
.end method
When you create an Android app, Android Studio performs at least two compilations. The first compilation creates Java bytecode from your Java source files. (Your source filenames have the .java
extension; the Java bytecode filenames have the .class
extension.) The second compilation creates Dalvik bytecode from your Java bytecode files. (Dalvik bytecode filenames have the .dex
extension.) To perform the first compilation, Android Studio uses a program named javac, or the Java compiler. To perform the second compilation, Android Studio uses a program named dx (known affectionately as the dx tool).
Android Studio compiles Java bytecode (Listing 2-2) to get Dalvik bytecode (Listing 2-3). Does the compiling end here? Not at all. When a user’s mobile device gets ahold of some Dalvik bytecode, the device does even more compiling. One way or another, the device runs a virtual machine. “And what,” you ask, “is a virtual machine?” It’s funny that you should ask this question. Your question is the title of the very next section!
The instructions in Listings 2-2 and 2-3 are meant for processors to use, not for people to use. Even so, the processors in computers and mobile phones don’t execute Java bytecode instructions (Listing 2-2) or Dalvik bytecode instructions (Listing 2-3). Instead, each kind of processor has its own set of executable instructions, and each operating system uses the processor’s instructions in a slightly different way.
Imagine that you have two different devices — a smartphone and a tablet computer. The devices have two different kinds of processors. The phone has an ARM processor, and the tablet has an Intel Atom processor. (The acronym ARM once stood for Advanced RISC Machine. These days, ARM simply stands for ARM Holdings, a company whose employees design processors.) On the ARM processor, the multiply instruction is 000000. On an Intel processor, the multiply instructions are D8, DC, F6, F7, and others. Many ARM instructions have no counterparts in the Atom architecture, and many Atom instructions have no equivalents on an ARM processor. An ARM processor’s instructions make no sense to your tablet’s Atom processor, and an Atom processor’s instructions would give your phone’s ARM processor a virtual headache.
So what’s a developer to do? Does a developer provide translations of every app into every processor’s instruction set? No.
Virtual machines create order from all this chaos. Dalvik bytecode is something like the code in Listing 2-3, but Dalvik bytecode isn’t specific to one kind of processor or to one operating system. Instead, a set of Dalvik bytecode instructions runs on any processor. If you write a Java program and compile that Java program into Dalvik bytecode, your Android phone, your Android tablet, and even your grandmother’s supercomputer can run the bytecode. (To do this, your grandmother must install Android-x86, a special port of the Android operating system, on her Intel-based machine.)
Both Java bytecode and Dalvik bytecode have virtual machines. With a virtual machine, you can take a bytecode file that you created for one Android device, copy the bytecode to another Android device, and then run the bytecode with no trouble at all. That’s one of the many reasons why Android has become popular so quickly. This outstanding feature, which gives you the ability to run code on many different kinds of computers, is called portability.
Imagine that you’re the Intel representative to the United Nations Security Council. (See Figure 2-1.) The ARM representative is seated to your right, and the representative from Texas Instruments is on your left. (Naturally, you don’t get along with either of these people. You’re always cordial to one another, but you’re never sincere. What do you expect? It’s politics!) The distinguished representative from Dalvik is at the podium. The Dalvik representative speaks in Dalvik bytecode, and neither you nor your fellow ambassadors (ARM and Texas Instruments) understand a word of Dalvik bytecode.
But each of you has an interpreter. Your interpreter translates from Dalvik bytecode to Intel instructions as the Dalvik representative speaks. Another interpreter translates from bytecode to ARM-ese. And a third interpreter translates bytecode into Texas Instruments speak.
Think of your interpreter as a virtual ambassador. The interpreter doesn’t really represent your country, but the interpreter performs one of the important tasks that a real ambassador performs. The interpreter listens to Dalvik bytecode on your behalf. The interpreter does what you would do if your native language was Dalvik bytecode. The interpreter pretends to be the Intel ambassador and sits through the boring bytecode speech, taking in every word, and processing each word in some way or other.
You have an interpreter — a virtual ambassador. In the same way, an Intel processor runs its own bytecode interpreting software. That software is a virtual machine.
A virtual machine is a proxy, an errand boy, a go-between. The virtual machine serves as an interpreter between run-anywhere bytecode and your device’s own system. As it runs, a virtual machine walks your device through the execution of bytecode instructions. The virtual machine examines your bytecode, bit by bit, and carries out the instructions described in the bytecode. The virtual machine interprets bytecode for your ARM processor, your Intel processor, your Texas Instruments chip, or whatever kind of processor you’re using. That’s a good thing. It’s what makes Java code and Dalvik code more portable than code written in any other language.
Back in 2007, along with Dalvik bytecode, the folks at Google created a Dalvik virtual machine. This virtual machine runs Android apps on devices running Cupcake, Donut, and all the desserts up to and including KitKat. But in 2013, Google announced a replacement for Dalvik called ART. (The acronym ART stands for Android RunTime.) ART still uses Dalvik bytecode of the kind shown in Listing 2-3. (Despite what you read in the tabloids, Dalvik hasn’t gone away entirely.) But after your code is translated to Dalvik bytecode, ART takes advantage of the enhanced horsepower in newer smartphones. In general, an app that’s executed with ART runs much faster than the same app executed with Dalvik. By default, every app created for the Android Lollipop (and beyond) target runs on the newer ART virtual machine.
When you create a new project, Android’s tools create a small, no-nonsense Java class. I’ve copied the Java class in Listing 2-4.
Listing 2-4: A Minimalistic Android Activity Class
package com.allmycode.samples;
import android.app.Activity;
import android.os.Bundle;
import android.view.Menu;
import android.view.MenuItem;
public class MyActivity extends Activity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_my);
}
@Override
public boolean onCreateOptionsMenu(Menu menu) {
getMenuInflater().inflate(R.menu.my, menu);
return true;
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
int id = item.getItemId();
if (id == R.id.action_settings) {
return true;
}
return super.onOptionsItemSelected(item);
}
}
This chapter covers the Java language features used in Listing 2-4. So in this chapter, android.app.Activity
(from the second line of Listing 2-4) is only the name of something to import — nothing more. To read about the meaning of the word Activity and the word’s implications for Android, see Book III, Chapter 1.
Java is an object-oriented programming language. So, as a developer, your primary goal is to describe objects. Your closely related goal is to describe objects' close cousins — namely, classes.
In Java, nothing happens unless it happens inside an object or a class. The code in Listing 2-4 is a class. I created the code, so I get to make up a name for my new class. I chose the name MyActivity
because the code in Listing 2-4 describes one screen full of stuff on an Android device (and in Android, a screen full of stuff is an activity). So the code in Listing 2-4 contains the words public class MyActivity
.
The words public
and class
are Java keywords. What that means is that no matter who writes a Java program, the word class
always has the same meaning. The same holds true of the word public
(although some classes aren’t declared to be public
).
On the other hand, the word MyActivity
in Listing 2-4 is an identifier. I made up the word MyActivity
while I was creating the example for this chapter. (I could have changed the word to MainActivity
, YourActivity
or BoopADoop
if I wanted to do so.) The word MyActivity
is the name of a particular class — the class that I’m creating by writing this program.
A Java identifier can be any word containing only letters, digits, and underscores ( _
). An identifier must not begin with a digit. Other than that, there are no restrictions. Words like MainActivity
, LaFong3
, and a_b_c
are valid Java identifiers. A word like 1Mississippi
isn’t valid because it begins with a digit. A phrase like my activity
isn’t valid because it contains a blank space. A string like one~two
is invalid because the tilde (~
) isn’t a letter, a digit, or an underscore.
If you define a public class named DogAndPony
, the class’s Java code must go in a file named DogAndPony.java
, spelled and capitalized exactly the same way as the class name is spelled and capitalized. If you define a class named MySecretStuff
and write class MySecretStuff
instead of public class MySecretStuff
, you can put the MySecretStuff
code in any file whose extension is .java
. (Go ahead. Call your file Urkshjk98t.java
. See if I care.)
When you program in Java, you work constantly with classes and objects. Here’s an analogy: A chair has a seat, a back, and legs. Each seat has a shape, a color, a degree of softness, and so on. These are the properties that a chair possesses. What I describe is chairness — the notion of something being a chair. In object-oriented terminology, I’m describing the Chair
class.
Now peek over the edge of this book’s margin and take a minute to look around your room. (If you’re not sitting in a room right now, fake it.)
Several chairs are in the room, and each chair is an object. Each of these objects is an example of that ethereal thing called the Chair
class. So that’s how it works — the class is the idea of chairness, and each individual chair is an object.
It makes sense to think of an object as being a concrete instance of a class. In fact, the official terminology is consistent with this thinking. If you write a Java program in which you define a Chair
class, each actual chair (the chair that you’re sitting on, the empty chair right next to you, and so on) is called an instance of the Chair
class.
Here’s another way to think about a class. Imagine a table displaying three bank accounts. (See Table 2-1.)
Table 2-1 A Table of Accounts
Name |
Address |
Balance |
Barry Burd |
222 Cyberspace Lane |
24.02 |
John Q. Public |
140 Any Way |
–471.03 |
Jane Dough |
800 Rich Street |
247.38 |
Think of the table’s column headings as a class, and think of each row of the table as an object. The table’s column headings describe the Account
class.
According to the table’s column headings, each account has a name, an address, and a balance. Rephrased in the terminology of object-oriented programming, each object in the Account
class (that is, each instance of the Account
class) has a name, an address, and a balance. So, the bottom row of the table is an object with the name Jane Dough
. This same object has the address 800 Rich Street and a balance of 247.38. If you opened a new account, you would have another object, and the table would grow an additional row. The new object would be an instance of the same Account
class.
What does “six” mean? You can have six children, but you can also be six feet tall. With six children, you know exactly how many kids you have. (Unlike the average American family, you can’t have 2.5 kids.) But if you’re six feet tall, you could really be six feet and half an inch tall. Or you might be five feet eleven-and-three-quarter inches tall, and no one would argue about it.
A value’s meaning depends on the value’s type. If you write
int numberOfChildren = 6;
in a Java program, 6
means “exactly six.” But if you write
double height = 6;
in a Java program, 6
means “as close to six as you care to measure.” And if you write
char keystroke = ’6’;
in a Java program, ’6’
means “the digit that comes after the 5
digit.”
In a Java program, every value has a type. Java has eight primitive types (types that are built into the language) and has as many reference types as you want to create.
Table 2-2 lists Java’s eight primitive types.
Table 2-2 Java’s Primitive Types
Type Name |
What a Literal Looks Like |
Range of Values |
Whole number types |
||
|
|
–128 to 127 |
|
|
–32768 to 32767 |
|
|
–2147483648 to 2147483647 |
|
|
–9223372036854775808 to 9223372036854775807 |
Decimal number types |
||
|
|
–3.4 × 1038 to 3.4 × 1038 |
|
|
–1.8 × 10308 to 1.8 × 10308 |
Character type |
||
|
|
Thousands of characters, glyphs, and symbols |
Logical type |
||
|
|
true, false |
A literal is an expression whose value doesn’t change from one Java program to another. For example, the expression 42
means “the int
value 42” in every Java program. Likewise, the expression ‘B’
means “the second uppercase letter in the Roman alphabet” in every Java program, and the word true
means “the opposite of false
” in every Java program.
In addition to its primitive types, Java has reference types. The code in Listing 2-4 contains the names of five reference types.
The reference type android.app.Activity
is defined in the Android API (Android’s enormous library of ready-made declarations).
The reference types android.os.Bundle
, android.view.Menu
, and android.view.MenuItem
are also defined in the Android API.
MyActivity
is defined in Listing 2-4.How about that? Every class is a type!
When you write int numberOfChildren = 6
, you declare the existence of a variable named numberOfChildren
. The variable numberOfChildren
has type int
and has initial value 6
.
But in Listing 2-4, android.os.Bundle
, android.view.Menu
, and android.view.MenuItem
are also types. (They’re reference types.) In fact, android.os.Bundle
, android.view.Menu
, and android.view.MenuItem
are the names of classes that are declared as part of Android’s API. So, just as you can write int numberOfChildren
in a Java program, you can write Bundle savedInstanceState
in Listing 2-4. (You can abbreviate android.os.Bundle
to the simpler name Bundle
because of the import
declaration near the top of Listing 2-4.)
Because every class is a type, and because your newly declared MyActivity
type is a class, you can add a line such as
MyActivity anActivity;
to the code in Listing 2-4. This new line declares that the name anActivity
is a placeholder for a value (a value whose type is MyActivity
). In case this idea muddies your mind, Listing 2-5 has another example.
Listing 2-5: A Class Is a Type
public class Account {
String name;
String address;
double balance;
}
Account myAccount = new Account();
Account yourAccount = new Account();
myAccount.name = "Burd";
yourAccount.name = "Dough";
myAccount.balance = 24.02;
Listing 2-5 declares a class named Account
. This blueprint for an account has three fields. The first field — the name
field — refers to a Java String
(a bunch of characters lined up in a row). The second field — the address
field — refers to another Java String
. The third field — the balance
field — stores a double
value. (Refer to Table 2-2.)
A class is “the idea behind a certain kind of thing.” (I quote myself frequently.) An object is “a concrete instance of a class.” So in Listing 2-5, the variable myAccount
refers to an actual Account
object, and the variable yourAccount
refers to another Account
object. The last statement in Listing 2-5 assigns the value 24.02
to the balance
field of the object referred to by myAccount
.
A method is a chunk of code that performs some actions, and (possibly) produces a result. If you’ve written programs in other languages, you may know about functions, procedures, Sub procedures, or other such things. In Java, such things are called methods.
In Listing 2-4, the code
public boolean onCreateOptionsMenu(Menu menu) {
getMenuInflater().inflate(R.menu.my, menu);
return true;
}
declares the existence of a method. The method’s name is onCreateOptionsMenu
.
Somewhere, buried deep inside the Android’s virtual machine caverns, lives a line of code that looks something like this:
onCreateOptionsMenu(menu);
That line of code calls the onCreateOptionsMenu
method of Listing 2-4. In other words, when the Android’s virtual machine executes the onCreateOptionsMenu(Menu menu)
statement, the flow of execution jumps to the first instruction inside the onCreateOptionsMenu
method declaration in Listing 2-4.
The onCreateOptionsMenu
method’s call hides inside some unseen Android system code. This situation isn’t typical of methods and their calling statements. As an Android developer, you routinely declare a method in one part of your program and then call your own method in another part of the program.
The statements inside a method’s declaration are collectively called the method body. Take, for example, the onCreate
method in Listing 2-4. The onCreate
method’s body contains two statements (two instructions). The second statement, setContentView(R.layout.main)
, is a call to a method named setContentView
. (The setContentView
method’s declaration comes with every Android implementation, so you don’t declare the setContentView
method yourself.)
Like any method call, the call setContentView(R.layout.main)
starts with a method name. The stuff in parentheses after the method’s name is a parameter list. For insight into parameter lists, consider the code in Listing 2-6.
Listing 2-6: A Method and Two Method Calls
double monthlyPayment(double principal, double percentageRate, int years) {
int numPayments = 12 * years;
double rate = percentageRate / 100.00;
double effectiveRate = rate / 12;
return principal * (effectiveRate /
(1 - Math.pow(1 + effectiveRate, -numPayments)));
}
double myPayment = monthlyPayment(100000.00, 5.25, 30);
double yourPayment = monthlyPayment(100000.00, 5.00, 15);
The code in Listing 2-6 isn’t a complete Java program. You can’t run the code without adding a bunch of stuff to it. Even so, the code illustrates some important ideas about methods and their parameters:
monthlyPayment
.In the body of the monthlyPayment
method declaration, the processor computes the monthly payments on a mortgage.
You can follow this description of methods and method parameters without understanding anything about the calculations in Listing 2-6.
The body of the monthlyPayment
method uses certain names as placeholders.
For example, in the body of the monthlyPayment
method, the name years
stands for the number of years in the mortgage’s term. Likewise, the name principal
stands for the total amount borrowed.
The names principal
, percentageRate
, and years
are the method’s parameters. Each parameter is destined to stand for a particular value. But a parameter doesn’t stand for a value until an app executes a method call.
In Listing 2-6, the call monthlyPayment(100000.00, 5.25, 30)
gives the method’s first parameter (namely, principal
) the value 100000.00
. That same call gives the method’s second parameter (percentageRate
) the value 5.25
. Finally, that method call gives the method’s third parameter (years
) the value 30
.
The next method call in Listing 2-6 gives the monthlyPayment
method’s parameters different values (again 100000.00
for principal
, but 5.00
for percentageRate
and 15
for years). Each time you call a method, you supply values for the method’s parameters.
The types of parameters in a method call must match the types of the parameters in a method declaration.
The declaration of method monthlyPayment
in Listing 2-6 has a double
parameter (principal
), another double
parameter (percentageRate
), and an int
parameter (years
). Accordingly, the first method call in Listing 2-6 has two double
parameters (100000.00
and 5.25
) followed by an int
parameter (30
). The second method call in Listing 2-6 also has two double
parameters followed by an int
parameter.
You can declare the same method more than once, as long as each declaration has a different parameter list. For example, another method declaration in Listing 2-6 might have the same name monthlyPayment
but only two parameters: double monthlyPayment(double principal, double percentageRate)
. To call this alternative monthlyPayment
method, you write something like monthlyPayment(100000.00, 5.25)
. In this situation, the body of the alternative monthlyPayment
method probably contains a statement like years = 30
. You don’t call this two-parameter method unless you know that the mortgage’s term is 30 years.
A method call might stand for a value.
The first method call in Listing 2-6 (in the listing’s next-to-last line) stands for the double
value 552.20
(or a value very close to the number 552.20
). The value 552.20
comes from all the calculations in the body of the monthlyPayment
method when the principal
is 100000.00
, the percentageRate
is 5.25
, and the number of years
is 30
. Near the end of the monthlyPayment
method’s body, the formula
principal * (effectiveRate /
(1 - Math.pow(1 + effectiveRate, -numPayments)))
has the value 552.20
, and the word return
says “send 552.20
back to the statement that called this method.” So, in Listing 2-6, the end of the monthlyPayment
method body effectively says
return 552.20;
and the next-to-last line in the listing effectively says
double myPayment = 552.20;
Similarly, the second method call in Listing 2-6 (the listing’s last line) stands for the value 790.79
. Because of the second method call’s parameter values, the end of the monthlyPayment
method body effectively says
return 790.79;
and the last line in the listing effectively says
double yourPayment = 790.79;
A method’s declaration begins (much of the time) with the name of the return type.
In Listing 2-6, the monthlyPayment
method declaration begins with the type name double
. That’s good because the value returned at the end of the method’s body (either 552.20
or 790.79
) is of type double
. Also, the names myPayment
and yourPayment
store double
values, so it’s okay to assign the value of the call monthlyPayment(100000.00, 5.25, 30)
to myPayment
, and to assign the value of the call monthlyPayment(100000.00, 5.00, 15)
to yourPayment
.
Similarly, in Listing 2-4, the onCreateOptionsMenu
and onOptionsItemSelected
method declarations begin (more or less) with the type name boolean
. The type boolean
represents only one of two possible values — true
or false
. So the value returned at the end of the onCreateOptionsMenu
method’s body can be true
. Also, if the Android’s system’s code contains a line like
boolean menuResult = onCreateOptionsMenu(someMenu);
then menuResult
has type boolean
so everything is hunky-dory.
A method call doesn’t necessarily stand for a value.
In Listing 2-1, the word void
in the first line of the checkVacancy
method indicates that a call to checkVacancy
doesn’t stand for a value. That is, a call to checkVacancy
performs some actions, but the call doesn’t calculate an answer of any kind.
Similarly, the method onCreate
in Listing 2-4 doesn’t return a value.
Earlier, I introduce you to the Chair
class example, and how it’s the idea of chairness, and how each individual chair is an object … If you write a Java program in which you define a Chair
class, each actual chair (the chair that you’re sitting on, the empty chair right next to you, and so on) is called an instance of the Chair
class. I also encourage you to think of the table’s column headings as a class and to think of each row of the table as an object.
To drive this point home, consider the code in Listing 2-7.
Listing 2-7: What Is an Account?
package com.allmycode.samples;
public class Account {
public String name;
public String address;
public double balance;
public Account(String name, String address, double balance) {
this.name = name;
this.address = address;
this.balance = balance;
}
/** Called at the end of each month */
public String infoString() {
return name + " (" + address + ") has $" + balance;
}
}
Listing 2-7 is a souped-up version of the code in Listing 2-5. In Listing 2-7, an Account
has a name
, an address
, a balance
, and an infoString
method. The infoString
method describes a way of composing a readable description of the account.
The Account
class also has something that looks like a method, but isn’t really a method. In Listing 2-7, the text beginning with public Account(String name
is the start of a constructor. A constructor describes a way of creating a new instance of a class.
According to the code in Listing 2-7, each object created from the Account
class has its own name
, its own address
, and its own balance
. So, in Listing 2-7, the Account
constructor’s instructions say:
this.name = name;
When creating a new object (a new instance of the Account
class), make this
new object’s name
be whatever name
has been passed to the constructor’s parameter list. (See Figure 2-2.)
this.address = address;
When creating a new object (a new instance of the Account
class), make this
new object’s address
be whatever address
has been passed to the constructor’s parameter list.
this.balance = balance;
When creating a new object (a new instance of the Account
class), make this
new object’s balance
be whatever balance
has been passed to the constructor’s parameter list.
Listing 2-8 shows you how to use the code in Listing 2-7. In Listing 2-8, the statement Account account1 = new Account("Burd", "222 Cyberspace Lane", 24.02)
calls the constructor from Listing 2-7. As a result, the app has a brand-new instance of the Account
class. The variable account1
refers to that new object.
Listing 2-8: Using the Account Class
package com.allmycode.samples;
import android.app.Activity;
import android.os.Bundle;
import android.widget.TextView;
public class MyActivity extends Activity {
TextView textView1;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
Account account1 = new Account(“Burd”, "222 Cyberspace Lane”, 24.02);
textView1 =
((TextView) findViewById(R.id.textView1));
textView1.setText(account1.infoString());
}
}
Later in Listing 2-8, the text account1.infoString()
calls the new account1
object’s infoString
method. The method returns a handsome-looking string of characters, which the activity displays on its screen.
When you run the code in Listing 2-8, you get the screen shown in Figure 2-3.
Listing 2-4 contains the words extends Activity
. Apparently, the new MyActivity
class, declared in Listing 2-4, is some kind of extension of something called Activity
. So what’s this all about?
You can download the Android source code (the Java code that comprises Android’s many pre-declared classes). When you do, you can open the Activity.java
file with your favorite editor. Listing 2-9 contains an (admittedly unrepresentative) portion of the code in that file.
Listing 2-9: A Seriously Abridged Version of Android’s Activity Class
package android.app;
public class Activity extends ContextThemeWrapper {
protected void onCreate(Bundle savedInstanceState) {
mVisibleFromClient =
!mWindow.getWindowStyle().getBoolean(
com.android.internal.R.styleable.
Window_windowNoDisplay, false);
mCalled = true;
}
protected void onDestroy() {
mCalled = true;
// dismiss any dialogs we are managing.
if (mManagedDialogs != null) {
final int numDialogs = mManagedDialogs.size();
for (int i = 0; i < numDialogs; i++) {
final ManagedDialog md =
mManagedDialogs.valueAt(i);
if (md.mDialog.isShowing()) {
md.mDialog.dismiss();
}
}
mManagedDialogs = null;
}
// Close any open search dialog
if (mSearchManager != null) {
mSearchManager.stopSearch();
}
}
}
The Android SDK comes with an Activity
class, and the Activity
class contains methods named onCreate
and onDestroy
. (Actually, the Android’s Activity
class contains at least 140 methods. But who’s counting?) In Listing 2-4, the words MyActivity extends Activity
establish a relationship between the MyActivity
class and Android’s Activity
class. Among other things, the MyActivity
class inherits fields and methods belonging to the Activity
class. So without adding any code to Listing 2-4, you can rest assured that MyActivity
has an onDestroy
method. It’s as if you copied the onDestroy
method declaration from Listing 2-9 and pasted that declaration into Listing 2-4.
Aside from the extends
terminology, Java has several names for the relationship between the MyActivity
class and the Activity
class:
MyActivity
class is a subclass of the Activity
class.MyActivity
class is a child of the Activity
class.Activity
class is the superclass of the MyActivity
class.Activity
class is the parent of the MyActivity
class.If all this parent/child business reminds you of a family tree, you’re not alone. Java developers draw upside-down trees all the time. For example, a small part of the tree for the class in Listing 2-4 is pictured in Figure 2-4.
At the top of Figure 2-4, the tree’s root is Java’s ancestor of all classes — the Object
class. Android’s Context
class is a subclass of the Object
class. The Context
class has many subclasses, two of which (Application
and ContextWrapper
) are pictured in Figure 2-4. From there on, ContextWrapper
begets ContextThemeWrapper
, which begets Activity
, which begets the main activity class in a typical Android app.
Java has a feature that lets you lump classes into groups of classes. Each lump of classes is a package. The class in Listing 2-4 belongs to the com.allmycode.samples
package because of the listing’s first line of code.
In the Java world, developers customarily give packages long, dot-filled names. For instance, because I’ve registered the domain name allmycode.com
, I name a package com.allmycode.samples
or com.allmycode.
whateverIwant
. The Java API is actually a big collection of packages. The API has packages with names like java.lang
, java.util
, java.awt
, javax.swing
, and so on. The Android SDK is also a bunch of packages, with package names such as android.app
, android.view
, and android.telephony.gsm
.
An import
declaration starts with the name of a package and ends with either of the following:
For example, in the declaration
import android.app.Activity;
android.app
is the name of a package in the Android SDK, and Activity
is the name of a class in the android.app
package. The dotted name android.app.Activity
is the fully qualified name of the Activity
class. A class’s fully qualified name includes the name of the package in which the class is defined.
With an import
declaration, you don’t have to repeatedly use a class’s fully qualified name. For example, in Listing 2-4, you could write
public class MyActivity extends android.app.Activity
but because of the Listing’s import
declaration, you can get away with plain old
public class MyActivity extends Activity
In a declaration such as
import android.app.*;
the asterisk refers to all classes in the android.app
package. With this import
declaration at the top of your Java code, you can use abbreviated names for all classes in the android.app
package — names like Activity
, AlertDialog
, Fragment
, ListActivity
, and many others.
A class can be either public or non-public. If you see something like
public class SomeClass
you’re looking at the declaration of a public class. But, if you see plain old
class SomeClass
the class that’s being declared isn’t public.
If a class is public, you can refer to the class from anywhere in your code. The following example illustrates the point.
In one file, you have
package com.allmycode.somepackage;
public class SomeClass {
}
And in another file, you have
package com.allmycode.someotherpackage;
import com.allmycode.somepackage.*;
//You CAN extend SomeClass:
class SomeOtherClass extends SomeClass {
public void doStuff() {
//This works too:
SomeClass someObject = new SomeClass();
}
}
If a class isn’t public, you can refer to the class only from code within the class’s package. The following code makes that crystal clear.
In one file, you have
package com.allyourcode.somepackage;
class SomeClass {
}
And in another file, you have
package com.allyourcode.someotherpackage;
import com.allyourcode.somepackage.*;
//You can't extend SomeClass:
class SomeOtherClass extends SomeClass {
public void doStuff() {
//This doesn’t work either:
SomeClass someObject = new SomeClass();
}
}
The scope of a name is the range of code in which you (the developer) can use the name. So, to sum up the preceding section’s long-winded explanation:
A class’s members (the class’s methods and fields) can also be public. For example, the class in Listing 2-7 has the public fields name
, address
, and balance
, and has the public method infoString
. In fact, the story for class members is a bit more involved. The word public
is an access modifier, and a member of a class can be public
, private
, or protected
, or have no access modifier. (For example, the textView1
field in Listing 2-8 has no access modifier. The onCreate
and onDestroy
methods in Listing 2-9 have protected
access.)
Your access modifier choices break down as follows:
public
member’s scope includes all Java code.private
member’s scope includes the class in which the member is declared.protected
member’s scope includes the class in which the member is declared. The scope also includes any subclasses of the class in which the member is declared and all classes belonging to the package in which the member is declared.I don’t know about you, but I have trouble wrapping my head around the idea of protected
access. One of the difficulties is that, contrary to my intuitions, sporting the word protected
is less restrictive than sporting no access modifier at all. Anyway, when I encounter a member with protected
access, I stop and think about it long enough for my queasiness to go away.
In families, children often rebel against their parents' values. The same is true in Java. The MyActivity
class (in Listing 2-4) is a child of the Activity
class (in Listing 2-9). So at first glance, MyActivity
should inherit the onCreate
method declared in the Activity
class’s code.
But both the Activity
and MyActivity
classes have onCreate
method declarations. And the two onCreate
declarations have the same parameter list. In this way, the MyActivity
class rebels against its parent. The MyActivity
class says to the Activity
class, “I don’t want your stinking onCreate
method. I’m declaring my own onCreate
method.”
So when you fire up an app, and your phone creates a MyActivity
object, the phone executes the MyActivity
version of onCreate
, not the parent Activity
version of onCreate
.
Each @Override
word in Listing 2-4 is an example of an annotation. An annotation tells Java something about your code. In particular, each @Override
annotation in Listing 2-4 tells the Java compiler to be on the lookout for a common coding error. The annotation says, “Make sure that the method immediately following this annotation has the same stuff (the same name, the same parameters, and so on) as one of the methods in the Activity
class. If not, display an error message.”
So if I accidentally misspell a method’s name, as in
@Override
public void nCreate(Bundle savedInstanceState)
the compiler reminds me that my new nCreate
method doesn’t really override anything that’s in Android’s pre-declared Activity
class. Oops!
A comment is part of a program’s text. But unlike declarations, method calls, and other such things, a comment’s purpose is to help people understand your code. A comment is part of a good program’s documentation.
The Java programming language has three kinds of comments:
Block comments
A block comment begins with /*
and ends with */
. Everything between the opening /*
and the closing */
is for human eyes only. No information between /*
and */
is translated by the compiler.
A block comment can span across several lines. For example, the following code is a block comment:
/* This is my best
Android app ever! */
An end-of-line comment starts with two slashes and goes to the end of a line of type. So in the following code snippet, the text // A required call
is an end-of-line comment:
super.onCreate(savedInstanceState); // A required call
Once again, no text inside the end-of-line comment gets translated by the compiler.
JavaDoc comments
A JavaDoc comment begins with a slash and two asterisks (/**
). For example, in Listing 2-7, the text /** Called at the end of each month */
is a JavaDoc comment.
A JavaDoc comment is meant to be read by people who never even look at the Java code. But that doesn’t make sense. How can you see the JavaDoc comment in the Listing 2-7 comment if you never look at Listing 2-7?
Well, a certain program called javadoc
(what else?) can find any JavaDoc comments in Listing 2-7 and turn these comments into a nice-looking web page. A page of this kind is shown in Figure 2-5.
You can generate web pages like the one in Figure 2-5. Here’s how:
In Android Studio’s main menu, choose Tools ⇒ Generate JavaDoc.
When you do, a dialog box appears. The title of the dialog box is Specify Generate JavaDoc Scope (a slightly awkward title).
In the dialog box’s Output Directory field, enter the name of the directory (on your computer’s hard drive) where you want the new JavaDoc pages to live.
You can accept the defaults for other items in the dialog box.
Click OK.
When you do, Android Studio runs the javadoc
program to create web pages from the comments in your project. The main page opens in your default web browser.
18.118.23.147