|
home—info—exams—lectures—labs—hws
Recipe—Laws—lies—syntax—java.lang docs—java.util docs
Recall the first methods we wrote, which were part of class PizzaServer: the method pizzaArea, as well as methods like crustArea and wedPizzaArea. Those methods were a bit odd, because it didn't matter which PizzaServer was asked; they all gave the same answer. That is, the answer didn't depend on the PizzaServer's state. We could make a million PizzaServers, and they'd all ask the same thing. (In fact, we might want that question answered even before any PizzaServers are created.)
Actually, it is possible to write methods which aren't tied to a particular instance.
A static method is a method which is not called through an individual instance. Instead, it is associated only with a class (but no instances of that class). This means you can call that method even if an instance has never been created.Really, pizzaArea should have been a static method:
class PizzaServer { public double MINIMUM_WAGE = 5.75; private double salary = MINIMUM_WAGE; private double balance = 0; private String almaMater; // ...Constructors, setters omitted public static double pizzaArea( double diam ) { double radius = diam/2; return 3.14 * radius * radius ); } } |
Then, from the code pad, we can now write:
PizzaServer.pizzaArea(12) PizzaServer.pizzaArea(1) PizzaServer.pizzaArea(0) |
- To write a static method: include the adjective “static” in front of the signature.
- To call a static method: write “Class-dot-methodName”, instead of “instance-dot-methodName”.
- When to make a method static:
- When its answer does not depend on which instance which you ask.
- Relatedly: if it makes sense to call the method even if no instances have yet been created, then you'll need the method to be static.
Or, consider Math.sqrt. It's natural question to ask what the square root of some number is; but it's odd to say you must ask some particular Math object. I'd lied earlier; there is no Math object (we never called new, so there couldn't have been an object!). Instead, Math is just a class chock full of static methods. It's called a “utility class” — you never make a new math object, you only call static methods.
Or, consider:
when writing Explorer methods, we really wish
we had a method createNewLint().
Clearly, such a method would belong in class Treasure.
But: it seems odd that you walk up to one Treasure (say, a chocolate egg)
and ask it to create a Lint for you.
Really, we want a method which we can call even if no (other) Treasures
have been created yet.
warning: The Java keyword “static” means “associated with the class, not a particular instance”. It does not mean “unchanging”. (It also does not mean that you will get zapped if you touch it, so there is no reason to be nervous about static methods.)
You cannot mention this in a static method.This means you can't call (non-static) methods from inside a static method: you can't say this.getSalary(). (This further means that you can't even write getSalary(), because java just rewrites that as java.getSalary() behind your back.)
If you see the error message “cannot call a non-static method
from a static context”,
it means you're using this inside a static method.
If you get this message, stop and think:
Is the method you're writing really supposed to be static?
If so, only then wonder about
the method you're calling -- if it wasn't static, should it have been?
Example:
// ERROR: // non-static method getBalance cannot be referenced from a static context. static boolean inDebt() { return (getBalance() < 0); } |
Note that you might have object-references that were passed in as arguments; you can certainly invoke methods on those parameters:
static PizzaServer theRicherOf( PizzaServer p1, PizzaServer p2 ) { if (p1.getBalance() < p2.getBalance()) { return p1; } else { return p2; } } |
// ERROR: // non-static method getBalance cannot be referenced from a static context. static PizzaServer theRicherOf( PizzaServer p1, PizzaServer p2 ) { if (p1.getBalance() < getBalance()) { // ← an implicit `this` return p1; } else { return p2; } } |
Remember, the solution to the error message “cannot access method/field from a static context” is probably not making that other method or field static. Although that gets rid of the error message, it's almost certainly not what you to do, if the enclosing method (“context”) really was meant to be static. The proper solution is to think:
Discuss: functions for converting between int and double, from lect04c—bad arithmetic:
(new Double(2.718)).intValue() |
Double.parseDouble( Integer.toString(45) ); |
We currently have tension between a law of programming, and a rule-of-thumb:
class PizzaServer() { /** The wage, in $/hr. */ private double salary; /** The minimum wage (in $/hr). */ public static double MINIMUM_WAGE = 5.75; /** Constructor. * @param The initial salary (in $/hr) */ PizzaServer( double _startSalary ) { if (_salary < MINIMUM_WAGE) { this.salary = MINIMUM_WAGE; } else { this.salary = _salary; } } /** Set this PizzaServer's salary (subject to federal minimum wage). * @param _salary The new salary rate. * If _salary is below the min.wage ({@value MINIMUM_WAGE}), we use that instead. */ void setSalary( double _salary ) { if1 (_salary < MINIMUM_WAGE) { this.salary = MINIMUM_WAGE; } else { this.salary = _salary; } } } |
Thus we have an easy solution to the above tension: write static methods to do the work which you want to call from a constructor as well as other places:
/** Return the * @param The proposed salary. */ static double legalSalary( double _salary ) { if (_salary < MINIMUM_WAGE) { return MINIMUM_WAGE; } else { return _salary; } } /** Constructor. * @param The initial salary (in $/hr) */ PizzaServer( double _startSalary ) { this.startSalary = PizzaServer.legalSalary( _startSalary ); } /** Set this PizzaServer's salary (subject to federal minimum wage). * @param _salary The new salary rate. * If _salary is below the MINIMUM_WAGE, we use that instead. */ void setSalary( double _salary ) { this.salary = PizzaServer.legalSalary( _salary ); } |
Recall from lab08b—printing: Pair O' Dice: the last method you wrote was a method which rolled a pair and printed the result to the screen, and then did it again. This was meant purely for testing (as long as you're willing to pore over the results on the console and check everything looks correct).
class PairODice { // ... /** Test one of our objects by rolling it a few times; * see the console window after calling this method, to check * that things look okay. */ void makeTestRolls() { this.roll(); System.out.println( this.toString() ); this.roll(); System.out.println( this.toString() ); } } |
With static methods, we can go one better: we can make a static method which creates several PairODice objects, rolls them, and prints them. (This is almost as good as unit testing!)
class PairODice { // ... /** A test driver: * Test one of our objects by rolling it a few times; * see the console window after calling this method, to check * that things look okay. */ public static void test() { PairODice p1; PairODice p2; p1 = new PairODice(); p2 = new PairODice(); p1.roll(); System.out.println( p1.toString() ); p1.roll(); System.out.println( p1.toString() ); p2.roll(); System.out.println( p2.toString() ); p2.roll(); System.out.println( p2.toString() ); } } |
In the case of BlueJ's “record” feature, some tests are hard to make: in particular, when you want to take the result of some method-call and do further work with it, before asserting an answer:
expl1.dropLeft(); expl1.grab( new Treasure("pewter cup", "dull", 1.0, "" ) ); // Did the cup really get grabbed (regardless of what // String the method returned)? expl1.getLeft().getName().equals( "pewter cup" ); |
if (expl1.getLeft().getName().equals( "pewter cup" )) { System.out.println( "passed the pewter-cup-pickup test." ); } else { System.out.println( "Didn't put pewter cup into empty left pocket!" ); System.out.println( expl1.inventory() ); } |
1This if-statement could expressed more concisely
using Java's conditional operator:
2Or as alluded to in the precding point, you can think about more complicated tests. ↩
home—info—exams—lectures—labs—hws
Recipe—Laws—lies—syntax—java.lang docs—java.util docs
©2008, Ian Barland, Radford University Last modified 2008.Mar.19 (Wed) |
Please mail any suggestions (incl. typos, broken links) to ibarlandradford.edu |