Chapter 4. methods use instance variables: How Objects Behave

Image

State affects behavior, behavior affects state. We know that objects have state and behavior, represented by instance variables and methods. But until now, we haven’t looked at how state and behavior are related. We already know that each instance of a class (each object of a particular type) can have its own unique values for its instance variables. Dog A can have a name “Fido” and a weight of 70 pounds. Dog B is “Killer” and weighs 9 pounds. And if the Dog class has a method makeNoise(), well, don’t you think a 70-pound dog barks a bit deeper than the little 9-pounder? (Assuming that annoying yippy sound can be considered a bark.) Fortunately, that’s the whole point of an object—it has behavior that acts on its state. In other words, methods use instance variable values. Like, “if dog is less than 14 pounds, make yippy sound, else...” or “increase weight by 5”. Let’s go change some state.

Remember: a class describes what an object knows and what an object does

A class is the blueprint for an object. When you write a class, you’re describing how the JVM should make an object of that type. You already know that every object of that type can have different instance variable values. But what about the methods?

Can every object of that type have different method behavior?

Well... sort of.*

Every instance of a particular class has the same methods, but the methods can behave differently based on the value of the instance variables.

The Song class has two instance variables, title and artist. The play() method plays a song, but the instance you call play() on will play the song represented by the value of the title instance variable for that instance. So, if you call the play() method on one instance you’ll hear the song “Havana”, while another instance plays “Blinding Lights”. The method code, however, is the same.

void play() {
    soundPlayer.playSound(title);
}



Song t2 = new Song();
t2.setArtist(“Travis”);
t2.setTitle(“Sing”);
Song s3 = new Song();
s3.setArtist(“Sex Pistols”);
s3.setTitle(“My Way”);
Image
Image

*Yes, another stunningly clear answer!

The size affects the bark

A small Dog’s bark is different from a big Dog’s bark.

The Dog class has an instance variable size, that the bark() method uses to decide what kind of bark sound to make.

Image
class Dog {
  int size;
  String name;


  void bark() {
    if (size > 60) {
       System.out.println(“Wooof! Wooof!”);
    } else if (size > 14) {
       System.out.println(“Ruff! Ruff!”);
    } else {
       System.out.println(“Yip! Yip!”);
    }
  }
}

_____________________________________________________

class DogTestDrive {

   public static void main (String[] args) {
     Dog one = new Dog();
     one.size = 70;
     Dog two = new Dog();
     two.size = 8;
     Dog three = new Dog();
     three.size = 35;

     one.bark();
     two.bark();
     three.bark();
   }
}
Image
Image

You can send things to a method

Just as you expect from any programming language, you can pass values into your methods. You might, for example, want to tell a Dog object how many times to bark by calling:

d.bark(3);

Depending on your programming background and personal preferences, you might use the term arguments or perhaps parameters for the values passed into a method. Although there are formal computer science distinctions that people who wear lab coats and who will almost certainly not read this book, make, we have bigger fish to fry in this book. So you can call them whatever you like (arguments, donuts, hair-balls, etc.) but we’re doing it like this:

A method uses parameters. A caller passes arguments.

Arguments are the things you pass into the methods. An argument (a value like 2, “Foo”, or a reference to a Dog) lands face-down into a... wait for it... parameter. And a parameter is nothing more than a local variable. A variable with a type and a name, that can be used inside the body of the method.

But here’s the important part: If a method takes a parameter, you must pass it something. And that something must be a value of the appropriate type.

Image

You can get things back from a method.

Methods can return values. Every method is declared with a return type, but until now we’ve made all of our methods with a void return type, which means they don’t give anything back.

void go() {
}

But we can declare a method to give a specific type of value back to the caller, such as:

int giveSecret() {
   return 42;
}

If you declare a method to return a value, you must return a value of the declared type! (Or a value that is compatible with the declared type. We’ll get into that more when we talk about polymorphism in chapter 7 and chapter 8.)

Whatever you say you’ll give back, you better give back!

Image

The compiler won’t let you return the wrong type of thing.

Image

You can send more than one thing to a method

Methods can have multiple parameters. Separate them with commas when you declare them, and separate the arguments with commas when you pass them. Most importantly, if a method has parameters, you must pass arguments of the right type and order.

Calling a two-parameter method, and sending it two arguments.

Image
Image

There are no Dumb Questions

Q: What happens if the argument you want to pass is an object instead of a primitive?

A: You’ll learn more about this in later chapters, but you already know the answer. Java passes everything by value. Everything. But... value means bits inside the variable. And remember, you don’t stuff objects into variables; the variable is a remote control—a reference to an object. So if you pass a reference to an object into a method, you’re passing a copy of the remote control. Stay tuned, though, we’ll have lots more to say about this.

Q: Can a method declare multiple return values? Or is there some way to return more than one value?

A: Sort of. A method can declare only one return value. BUT... if you want to return, say, three int values, then the declared return type can be an int array. Stuff those ints into the array, and pass it on back. It’s a little more involved to return multiple values with different types; we’ll be talking about that in a later chapter when we talk about ArrayList.

Q: Do I have to return the exact type I declared?

A: You can return anything that can be implicitly promoted to that type. So, you can pass a byte where an int is expected. The caller won’t care, because the byte fits just fine into the int the caller will use for assigning the result. You must use an explicit cast when the declared type is smaller than what you’re trying to return.

Q: Do I have to do something with the return value of a method? Can I just ignore it?

A: Java doesn’t require you to acknowledge a return value. You might want to call a method with a non-void return type, even though you don’t care about the return value. In this case, you’re calling the method for the work it does inside the method, rather than for what the method gives returns. In Java, you don’t have to assign or use the return value.

Reminder: Java cares about type!

You can’t return a Giraffe when the return type is declared as a Rabbit. Same thing with parameters. You can’t pass a Giraffe into a method that takes a Rabbit.

Image

Cool things you can do with parameters and return types

Now that we’ve seen how parameters and return types work, it’s time to put them to good use: Getters and Setters. If you’re into being all formal about it, you might prefer to call them Accessors and Mutators. But that’s a waste of perfectly good syllables. Besides, Getters and Setters fits the Java naming convention, so that’s what we’ll call them.

Getters and Setters let you, well, get and set things. Instance variable values, usually. A Getter’s sole purpose in life is to send back, as a return value, the value of whatever it is that particular Getter is supposed to be Getting. And by now, it’s probably no surprise that a Setter lives and breathes for the chance to take an argument value and use it to set the value of an instance variable.

Image
class ElectricGuitar {

   String brand;
   int numOfPickups;
   boolean rockStarUsesIt;

   String getBrand() {
      return brand;
   }

   void setBrand(String aBrand) {
      brand = aBrand;
   }

   int getNumOfPickups() {
      return numOfPickups;
   }

   void setNumOfPickups(int num) {
      numOfPickups = num;
   }

   boolean getRockStarUsesIt() {
      return rockStarUsesIt;
   }

   void setRockStarUsesIt(boolean yesOrNo) {
      rockStarUsesIt = yesOrNo;
   }
}
Image

Encapsulation

Do it or risk humiliation and ridicule.

Until this most important moment, we’ve been committing one of the worst OO faux pas (and we’re not talking minor violation like showing up without the ‘B’ in BYOB). No, we’re talking Faux Pas with a capital ‘F’. And ‘P’.

Our shameful transgression?

Exposing our data!

Here we are, just humming along without a care in the world leaving our data out there for anyone to see and even touch.

You may have already experienced that vaguely unsettling feeling that comes with leaving your instance variables exposed.

Exposed means reachable with the dot operator, as in:

theCat.height = 27;
Image

Think about this idea of using our remote control to make a direct change to the Cat object’s size instance variable. In the hands of the wrong person, a reference variable (remote control) is quite a dangerous weapon. Because what’s to prevent:

Image

This would be a Bad Thing. We need to build setter methods for all the instance variables, and find a way to force other code to call the setters rather than access the data directly.

Note

By forcing everybody to call a setter method, we can protect the cat from unacceptable size changes.

Image

Hide the data

Yes it is that simple to go from an implementation that’s just begging for bad data to one that protects your data and protects your right to modify your implementation later.

OK, so how exactly do you hide the data? With the public and private access modifiers. You’re familiar with public–we use it with every main method.

Here’s an encapsulation starter rule of thumb (all standard disclaimers about rules of thumb are in effect): mark your instance variables private and provide public getters and setters for access control. When you have more design and coding savvy in Java, you will probably do things a little differently, but for now, this approach will keep you safe.

Note

Mark instance variables private.

Mark getters and setters public.

“Sadly, Bill forgot to encapsulate his Cat class and ended up with a flat cat.”

(overheard at the water cooler).

Inline Java Exposed

This week’s interview: An Object gets candid about encapsulation.

HeadFirst: What’s the big deal about encapsulation?

Object: OK, you know that dream where you’re giving a talk to 500 people when you suddenly realize– you’re naked?

HeadFirst: Yeah, we’ve had that one. It’s right up there with the one about the Pilates machine and... no, we won’t go there. OK, so you feel naked. But other than being a little exposed, is there any danger?

Object: Is there any danger? Is there any danger? [starts laughing] Hey, did all you other instances hear that, “Is there any danger?” he asks? [falls on the floor laughing]

HeadFirst: What’s funny about that? Seems like a reasonable question.

Object: OK, I’ll explain it. It’s [bursts out laughing again, uncontrollably]

HeadFirst: Can I get you anything? Water?

Object: Whew! Oh boy. No I’m fine, really. I’ll be serious. Deep breath. OK, go on.

HeadFirst: So what does encapsulation protect you from?

Object: Encapsulation puts a force-field around my instance variables, so nobody can set them to, let’s say, something inappropriate.

HeadFirst: Can you give me an example?

Object: Doesn’t take a PhD here. Most instance variable values are coded with certain assumptions about the boundaries of the values. Like, think of all the things that would break if negative numbers were allowed. Number of bathrooms in an office. Velocity of an airplane. Birthdays. Barbell weight. Cell phone numbers. Microwave oven power.

HeadFirst: I see what you mean. So how does encapsulation let you set boundaries?

Object: By forcing other code to go through setter methods. That way, the setter method can validate the parameter and decide if it’s do-able. Maybe the method will reject it and do nothing, or maybe it’ll throw an Exception (like if it’s a null social security number for a credit card application), or maybe the method will round the parameter sent in to the nearest acceptable value. The point is, you can do whatever you want in the setter method, whereas you can’t do anything if your instance variables are public.

HeadFirst: But sometimes I see setter methods that simply set the value without checking anything. If you have an instance variable that doesn’t have a boundary, doesn’t that setter method create unnecessary overhead? A performance hit?

Object: The point to setters (and getters, too) is that you can change your mind later, without breaking anybody else’s code! Imagine if half the people in your company used your class with public instance variables, and one day you suddenly realized, “Oops– there’s something I didn’t plan for with that value, I’m going to have to switch to a setter method.” You break everyone’s code. The cool thing about encapsulation is that you get to change your mind. And nobody gets hurt. The performance gain from using variables directly is so miniscule and would rarely—if ever— be worth it.

Encapsulating the GoodDog class

Image

How do objects in an array behave?

Just like any other object. The only difference is how you get to them. In other words, how you get the remote control. Let’s try calling methods on Dog objects in an array.

Inline Declare and create a Dog array, to hold 7 Dog references.

Dog[] pets;
pets = new Dog[7];
Image

Inline Create two new Dog objects, and assign them to the first two array elements.

pets[0] = new Dog();
pets[1] = new Dog();

Inline Call methods on the two Dog objects.

pets[0].setSize(30);
int x = pets[0].getSize();
pets[1].setSize(8);
Image

Declaring and initializing instance variables

You already know that a variable declaration needs at least a name and a type:

int size;
String name;

And you know that you can initialize (assign a value) to the variable at the same time:

int size = 420;
String name = “Donny”;

But when you don’t initialize an instance variable, what happens when you call a getter method? In other words, what is the value of an instance variable before you initialize it?

Image

The difference between instance and local variables

Inline Instance variables are declared inside a class but not within a method.

class Horse {
   private double height = 15.2;
   private String breed;
   // more code...
}
Note

Local variables do NOT get a default value! The compiler complains if you try to use a local variable before the variable is initialized.

Inline Local variables are declared within a method.

class AddThing {
   int a;
   int b = 12;

   public int add() {
      int total = a + b;
      return total;
   }
}

Inline Local variables MUST be initialized before use!

Image
Image

There are no Dumb Questions

Q: What about method parameters? How do the rules about local variables apply to them?

A: Method parameters are virtually the same as local variables—they’re declared inside the method (well, technically they’re declared in the argument list of the method rather than within the body of the method, but they’re still local variables as opposed to instance variables). But method parameters will never be uninitialized, so you’ll never get a compiler error telling you that a parameter variable might not have been initialized.

But that’s because the compiler will give you an error if you try to invoke a method without sending arguments that the method needs. So parameters are ALWAYS initialized, because the compiler guarantees that methods are always called with arguments that match the parameters declared for the method, and the arguments are assigned (automatically) to the parameters.

Comparing variables (primitives or references)

Sometimes you want to know if two primitives are the same. That’s easy enough, just use the == operator. Sometimes you want to know if two reference variables refer to a single object on the heap. Easy as well, just use the == operator. But sometimes you want to know if two objects are equal. And for that, you need the .equals() method. The idea of equality for objects depends on the type of object. For example, if two different String objects have the same characters (say, “expeditious”), they are meaningfully equivalent, regardless of whether they are two distinct objects on the heap. But what about a Dog? Do you want to treat two Dogs as being equal if they happen to have the same size and weight? Probably not. So whether two different objects should be treated as equal depends on what makes sense for that particular object type. We’ll explore the notion of object equality again in later chapters (and appendix B), but for now, we need to understand that the == operator is used only to compare the bits in two variables. What those bits represent doesn’t matter. The bits are either the same, or they’re not.

Note

Use == to compare two primitives, or to see if two references refer to the same object.

Use the equals() method to see if two different objects are equal.

(Such as two different String objects that both represent the characters in “Fred”)

To compare two primitives, use the == operator

The == operator can be used to compare two variables of any kind, and it simply compares the bits.

if (a == b) {...} looks at the bits in a and b and returns true if the bit pattern is the same (although it doesn’t care about the size of the variable, so all the extra zeroes on the left end don’t matter).

Image

To see if two references are the same (which means they refer to the same object on the heap) use the == operator

Remember, the == operator cares only about the pattern of bits in the variable. The rules are the same whether the variable is a reference or primitive. So the == operator returns true if two reference variables refer to the same object! In that case, we don’t know what the bit pattern is (because it’s dependent on the JVM, and hidden from us) but we do know that whatever it looks like, it will be the same for two references to a single object.

Foo a = new Foo();
Foo b = new Foo();
Foo c = a;
if (a == b) { // false }
if (a == c) { // true }
if (b == c) { // false }
Image
Image
Image

BE the compiler

Each of the Java files on this page represents a complete source file. Your job is to play compiler and determine whether each of these files will compile. If they won’t compile, how would you fix them, and if they do compile, what would be their output?

Image

A

class XCopy {

  public static void main(String [] args) {

    int orig = 42;

    XCopy x = new XCopy();

    int y = x.go(orig);

    System.out.println(orig + “ ” + y);

  }



  int go(int arg) {

    arg = arg * 2;

    return arg;

  }

}
class Clock {
  String time;

  void setTime(String t) {
    time = t;
  }

  void getTime() {
    return time;
  }
}

class ClockTestDrive {
  public static void main(String [] args) {

    Clock c = new Clock();

    c.setTime(“1245”);
    String tod = c.getTime();
    System.out.println(“time: ” + tod);
  }
}
Image

A bunch of Java components, in full costume, are playing a party game, “Who am I?” They give you a clue, and you try to guess who they are, based on what they say. Assume they always tell the truth about themselves. If they happen to say something that could be true for more than one guy, then write down all for whom that sentence applies. Fill in the blanks next to the sentence with the names of one or more attendees.

Tonight’s attendees:

instance variable, argument, return, getter, setter, encapsulation, public, private, pass by value, method

Image
A class can have any number of these. ________________________________
A method can have only one of these. ________________________________
This can be implicitly promoted. ________________________________
I prefer my instance variables private. ________________________________
It really means ‘make a copy’. ________________________________
Only setters should update these. ________________________________
A method can have many of these. ________________________________
I return something by definition. ________________________________
I shouldn’t be used with instance variables. ________________________________
I can have many arguments. ________________________________
By definition, I take one argument. ________________________________
These help create encapsulation. ________________________________
I always fly solo. ________________________________

Inline Mixed Messages

A short Java program is listed to your right. Two blocks of the program are missing. Your challenge is to match the candidate blocks of code (below), with the output that you’d see if the blocks were inserted.

Not all the lines of output will be used, and some of the lines of output might be used more than once. Draw lines connecting the candidate blocks of code with their matching command-line output.

Image

Inline Pool Puzzle

Your job is to take code snippets from the pool and place them into the blank lines in the code. You may not use the same snippet more than once, and you won’t need to use all the snippets. Your goal is to make a class that will compile and run and produce the output listed.

Image

Output

Image
public class Puzzle4 {
  public static void main(String [] args) {
    ___________________________________
    int y = 1;
    int x = 0;
    int result = 0;
    while (x < 6) {
      ___________________________
      ___________________________
      y = y * 10;
      _________________
    }
    x = 6;
    while (x > 0) {
      _________________
      result = result + ___________________
    }
    System.out.println("result " + result);
 }
}
class ___________ {
  int ivar;
  ________ ______ doStuff(int _________) {
    if (ivar > 100) {
      return _________________________
    } else {
      return _________________________
    }
  }
}
Note

Each snippet from the pool can be used only once!

Image

Inline

Fast Times in Stim-City

When Buchanan jammed his twitch-gun into Jai’s side, Jai froze. Jai knew that Buchanan was as stupid as he was ugly and he didn’t want to spook the big guy. Buchanan ordered Jai into his boss’s office, but Jai’d done nothing wrong, (lately), so he figured a little chat with Buchanan’s boss Leveler couldn’t be too bad. He’d been moving lots of neural-stimmers in the west side lately and he figured Leveler would be pleased. Black market stimmers weren’t the best money pump around, but they were pretty harmless. Most of the stim-junkies he’d seen tapped out after a while and got back to life, maybe just a little less focused than before.

Five-Minute Mystery

Leveler’s ‘office’ was a skungy looking skimmer, but once Buchanan shoved him in, Jai could see that it’d been modified to provide all the extra speed and armor that a local boss like Leveler could hope for. “Jai my boy”, hissed Leveler, “pleasure to see you again”. “Likewise I’m sure...”, said Jai, sensing the malice behind Leveler’s greeting, “We should be square Leveler, have I missed something?” “Ha! You’re making it look pretty good Jai, your volume is up, but I’ve been experiencing, shall we say, a little ‘breach’ lately...” said Leveler.

Jai winced involuntarily, he’d been a top drawer jack-hacker in his day. Anytime someone figured out how to break a street-jack’s security, unwanted attention turned toward Jai. “No way it’s me man”, said Jai, “not worth the downside. I’m retired from hacking, I just move my stuff and mind my own business”. “Yeah, yeah”, laughed Leveler, “I’m sure you’re clean on this one, but I’ll be losing big margins until this new jack-hacker is shut out!” “Well, best of luck Leveler, maybe you could just drop me here and I’ll go move a few more ‘units’ for you before I wrap up today”, said Jai.

Image

“I’m afraid it’s not that easy Jai, Buchanan here tells me that word is you’re current on Java NE 37.3.2”, insinuated Leveler. “Neural Edition? sure I play around a bit, so what?”, Jai responded feeling a little queasy. “Neural edition’s how I let the stimjunkies know where the next drop will be”, explained Leveler. “Trouble is, some stim-junkie’s stayed straight long enough to figure out how to hack into my Warehousing database.” “I need a quick thinker like yourself Jai, to take a look at my StimDrop Java NE class; methods, instance variables, the whole enchilada, and figure out how they’re getting in. It should...”, “HEY!”, exclaimed Buchanan, “I don’t want no scum hacker like Jai nosin’ around my code!” “Easy big guy”, Jai saw his chance, “I’m sure you did a top rate job with your access modi... “Don’t tell me - bit twiddler!”, shouted Buchanan, “I left all of those junkie level methods public, so they could access the drop site data, but I marked all the critical Ware-Housing methods private. Nobody on the outside can access those methods buddy, nobody!”

“I think I can spot your leak Leveler, what say we drop Buchanan here off at the corner and take a cruise around the block”, suggested Jai. Buchanan reached for his twitch-gun but Leveler’s stunner was already on Buchanan’s neck, “Let it go Buchanan”, sneered Leveler, “Drop the twitcher and step outside, I think Jai and I have some plans to make”.

What did Jai suspect?

Will he get out of Leveler’s skimmer with all his bones intact?

Inline Exercise Solutions

A Class ‘XCopy’ compiles and runs as it stands ! The output is: ‘42 84’. Remember Java is pass by value, (which means pass by copy), the variable ‘orig’ is not changed by the go( ) method.

   class Clock {
     String time;
     void setTime(String t) {
       time = t;
B    }
     String getTime() {
       return time;
     }
   }
   
   class ClockTestDrive {
     public static void main(String [] args) {
       Clock c = new Clock();
       c.setTime(“1245”);
       String tod = c.getTime();
       System.out.println(“time: “ + tod);
     }
   }
Note

Note: ‘Getter’ methods have a return type by definition.

A class can have any number of these. instance variables, getter, setter, method
A method can have only one of these. return
This can be implicitly promoted. return, argument
I prefer my instance variables private. encapsulation
It really means ‘make a copy’. pass by value
Only setters should update these. instance variables
A method can have many of these. argument
I return something by definition. getter
I shouldn’t be used with instance variables public
I can have many arguments. method
By definition, I take one argument. setter
These help create encapsulation. getter, setter, public, private
I always fly solo. return

Puzzle Solutions

public class Puzzle4 {
  public static void main(String [] args) {
    Puzzle4b [ ] obs = new Puzzle4b[6];
    int y = 1;
    int x = 0;
    int result = 0;
    while (x < 6) {
      obs[x] = new Puzzle4b( );
      obs[x] . ivar = y;
      y = y * 10;
      x = x + 1;
    }
    x = 6;
    while (x > 0) {
      x = x - 1;
      result = result + obs[x].doStuff(x);
    }
    System.out.println(“result “ + result);
  }
}
class Puzzle4b {
  int ivar;
  public int doStuff(int factor) {
     if (ivar > 100) {
       return ivar * factor;
     } else {
       return ivar * (5 - factor);
     }
   }
}

Output

Image

Answer to the 5-minute mystery...

Jai knew that Buchanan wasn’t the sharpest pencil in the box. When Jai heard Buchanan talk about his code, Buchanan never mentioned his instance variables. Jai suspected that while Buchanan did in fact handle his methods correctly, he failed to mark his instance variables private. That slip up could have easily cost Leveler thousands.

Image

Get Head First Java, 3rd Edition now with O’Reilly online learning.

O’Reilly members experience live online training, plus books, videos, and digital content from 200+ publishers.