A method that always does the same thing to the same values is not much use. Parameters are what make a method general: they are the blanks in the definition, filled in fresh at every call. Getting the vocabulary straight makes the rest of this topic much easier — a parameter lives in the definition, an argument lives at the call, and Java's job is to match them up.
| Term | Where it appears | Example |
|---|---|---|
| Parameter | In the method definition, with a type | public static int square(int n) — n is the parameter |
| Argument | At the call, as a value | square(7) — 7 is the argument |
| Matching | Done by Java, at compile time | Number, order and type must all line up |
public static void showRecord(int wins, int losses) {
System.out.println(wins + " wins and " + losses + " losses");
}
// in main:
showRecord(3, 7); // 3 wins and 7 losses
showRecord(7, 3); // 7 wins and 3 losses -- compiles fine, means something else
// showRecord(3); // will not compile: wrong number of arguments
// showRecord(3, "7"); // will not compile: String cannot become intPass by value
This is the single most misunderstood rule in the unit. When you pass a primitive such as an int or a double, Java copies the value into the parameter. The parameter is a brand new variable that happens to start with the same contents, created when the method starts and destroyed when it ends. Changing it changes the copy and nothing else, so the caller's variable is completely safe — and completely unaffected, which is the part that surprises people. Even if the parameter had the same name as the caller's variable, it would still be a separate box in memory.
public class PassByValue {
public static void addTen(int number) {
number = number + 10;
System.out.println("Inside the method: " + number);
}
public static void main(String[] args) {
int score = 5;
addTen(score);
System.out.println("Back in main: " + score);
}
}
// Output:
// Inside the method: 15
// Back in main: 5public static int addTen(int number) {
return number + 10;
}
// in main:
int score = 5;
score = addTen(score); // the assignment is what changes score
System.out.println(score); // 15Scope and shadowing
Scope is the region of code where a name is recognized. In Java the rule is mechanical: a variable exists from the line that declares it to the closing brace of the block that contains it, and nowhere else. Outside that block the name simply does not exist, so using it is a compile error rather than a run-time surprise. This is a feature — it means a counter called i in one method can never collide with a counter called i in another. It also means a variable declared inside a loop body is created and destroyed on every pass, which is right for a scratch value and wrong for an accumulator.
public static void main(String[] args) {
int total = 0; // scope: the whole of main
for (int i = 1; i <= 3; i++) { // scope of i: the for loop only
int doubled = i * 2; // scope of doubled: this pass of the body
total = total + doubled; // total is visible here -- inner sees out
}
System.out.println(total); // 12 (2 + 4 + 6)
// System.out.println(i); // error: cannot find symbol
// System.out.println(doubled); // error: cannot find symbol
}public class Shadow {
static int count = 10; // class variable
public static void show() {
int count = 99; // local variable shadows the class one
System.out.println(count); // 99 -- the nearest declaration wins
System.out.println(Shadow.count); // 10 -- named explicitly
}
public static void main(String[] args) {
show();
System.out.println(count); // 10 -- the class variable never changed
}
}Overloading
Java lets several methods share a name as long as their parameter lists differ — in the number of parameters, their types, or their order. This is called overloading, and Java picks the right one by looking at the arguments at the call. It is why System.out.println works with an int, a double, a String or a boolean: those are separate overloaded methods, not one clever one.
public static int add(int a, int b) {
return a + b;
}
public static double add(double a, double b) { // different types
return a + b;
}
public static int add(int a, int b, int c) { // different count
return a + b + c;
}
// in main:
System.out.println(add(2, 3)); // 5 -- picks the int version
System.out.println(add(2.5, 3.5)); // 6.0 -- picks the double version
System.out.println(add(1, 2, 3)); // 6 -- picks the three-parameter version