Never confuse education with intelligence, you can have a PhD and still be an idiot.
- Richard Feynman -



Difference between revisions of "Chapter:Classes - Static members"

From Juneday education
Jump to: navigation, search
(Created page with "=Meta information about this chapter= See introduction in previous chapter Chapter:Classes for meta information. ==Chapter Videos== * Classes III [https://vimeo.com/cha...")
 
(Fixed navigation)
Line 161: Line 161:
 
=Chapter Links=
 
=Chapter Links=
 
==External links==
 
==External links==
 +
* [https://docs.oracle.com/javase/tutorial/java/javaOO/classvars.html Oracle tutorial - Class variables (static)]
 
* [https://docs.oracle.com/javase/tutorial/java/javaOO/classes.html Oracle's tutorial section on Classes]
 
* [https://docs.oracle.com/javase/tutorial/java/javaOO/classes.html Oracle's tutorial section on Classes]
 
* [https://en.wikipedia.org/wiki/Java_class_file Wikipedia on Java classes]
 
* [https://en.wikipedia.org/wiki/Java_class_file Wikipedia on Java classes]
* [https://docs.oracle.com/javase/tutorial/java/concepts/package.html Oracle's tutorial section on Packages]
 
* [https://en.wikipedia.org/wiki/Java_package Wikipedia on Java packages]
 
  
==Books this chapter is a part of==
+
==Where to go next==
=== Programming with Java book ===
+
[[Chapter:Classes - Defining methods - Exercises|« Previous]] • [[Programming_with_Java#Chapters|Book TOC]] • [[Chapter:Classes_-_Static_members_-_Exercises|Next »]]
 +
<!--
 
[[Programming_with_Java#Chapters|Book TOC]] | [[Chapter: Classes II|previous chapter]] | [[Chapter:Inheritance|next chapter]]
 
[[Programming_with_Java#Chapters|Book TOC]] | [[Chapter: Classes II|previous chapter]] | [[Chapter:Inheritance|next chapter]]
 +
-->

Revision as of 09:43, 22 June 2017

Meta information about this chapter

See introduction in previous chapter Chapter:Classes for meta information.

Chapter Videos

See below for individual links to the videos.

Classes III - classes conclusion

Static variables and methods

Description

So far, we have focused on instance variables, i.e. variables which every instance hold their own copy of. Now it's time to introduce variables that rather belong to the class itself and that every instance of the class "share". Such variables are called "class variables" or "static variables". The latter name comes from the fact that we use the modifier static when we declare such variables.

If you think about it, there are values which are not unique to every instance of a class, but rather shared. One example would be the interest rate of a bank account of some type. It is common that every bank account of the same type (e.g. a savings account) have the same interest rate. If every savings account have the same interest rate, say 0,01%, and if this interest rate would change for every bank account, should the bank decide to change it, then it is practical to have a mechanism for expressing that the variable holding the current interest rate is shared between all instances of the class SavingsAccount.

The modifier static has precisely this meaning when applied to a variable declared in the block of a class. An example with the interest rate could look something like:

public class SavingsAccount{
  private static double interestRate = 0.01; // percent, shared by all instances
  // instance variable declarations like balance etc...
  // constructors...
  // methods...
}

An indication that a variable should be static is that the variable holds some value which is relevant to talk about without any relation to specific instances of the class. Another indication is that it is safe and natural that the variable has the same impact on every instance of a class, in the sense that if the variable's value changes, every instance will be effected by the change.

If you compare this to an instance variable such as the balance for an instance of SavingsAccount, you will see that the opposite holds for instance variables. It is not desirable that when one instance of a bank account changes the amount of the balance, every other instance of a bank account should also be affected. And it is not relevant to talk about the balance without the context of a particular instance of a bank account. The balance is the balance of one particular bank account! Therefore the balance is an instance variable which every bank account object will have its own copy of (so that they can have different balance). But the interest rate of some class of bank account, like a SavingsAccount, is relevant to talk about, even before any accounts have been created (the first customer enters the bank and decides she wants a savings account, because she agrees with the interest rate).

What about static methods, then (aka class methods)? Like with static variables, a static method is declared using the modifier static, and like static variables, static methods exist independent of any instances of the class it belongs to. Going back to the SavingsAccount class, there could be a static method for changing the static variable interestRate, something like this:

public class SavingsAccount{
  private static double interestRate = 0.01; // percent
  public static void changeInterestRate(double newRate){
    // Some logic to check that it is a feasible value...
    interestRate = newRate;
  }
  // instance variables...
  // constructors...
  // instance methods...
}

Another potential case for static methods are convenience methods which only calculate something from its parameters, like the many static methods declared in java.lang.Math, for instance public double sqrt(double d) which calculate the square root of its parameter (given as argument in the calling code). Such a method only operates on its parameters and can therefore exist totally independent of any instances. In fact, you cannot create instances of the class Math!

So how do we call a public static method? We use the class name (where the method is declared) and a dot followed by the method and arguments:

  /*
  
   |\
 A | \ C
   |__\
     B
  
  Calculate the length of C when we know the lengths of
  A (4)
  B (3)
  */
  double a = 4.0;
  double b = 3.0;
  double c = Math.sqrt(3*3+4*4); // Pythagoras...

A class method, or as it's also called, a static method, can only operate on static variables and its parameters. Why? Because we can call it regardless of any instances, even before any instances of the class is constructed. It is not possible to use instance variables inside a static method, because we don't know if there is any instances or which instance they would belong to. This is because we can call a static method via the class name so there is no reference to any specific instance known to the method.

While instance methods always have the keyword this as a reference to the instance for which the instance method was called, there is no such thing for a static method, since they are called using the class name.

Videos

Exercises on static variables and methods

Let's go back to our Member class. We added a variable separator that we used to store the separator between values in our printout. We also discussed if we needed to have one separator variable per object. We don't. Instead we can let the class have a variable common for every object. This means that this variable belongs to (is associated with) the class instead of a separate object.

  1. Change the separator variable into a class variable, using the keyword static.
  2. Let's assume someone wants to know what separator is used when calling toString on Member objects. To let people get this value we can either:
    * make the variable public. A drawback of this is that people can change it. This makes it not usable for us.
    * keep the variable private and add a public method, getSeparator.
    Your job is to write the method as described last. Should this method be public or private? Should it be static or non-static?.
  3. Now, say that we want to change the value of the separator variable. Add a method, setSeparator(String separator), to change it.
  4. Can you motivate keeping the separator variable private when everyone can change it using the set method?
  5. Write a new class, StaticConfusion. Don't use any packages in this class (which makes the class get the nameless package). Write a main method that invokes the method email(). The class can look something like this:
    import net.supermegacorp.orgmanager.Member;
    
    public class StaticConfusion {
    
        public static void main(String[] args) {
    
            Member.email();
    
        }
    
    }
    
    Compile. Did it work? Why?

Solutions to static variables and methods

Expand using link to the right to see the full content.

  1. Suggested solution (parts of the class):
    package net.supermegacorp.orgmanager;
    
    public class Member {
    
      private String name;
      private String email;
      private static String separator = ";";
    
      public String toString() {
        return name + separator + email;
      }
    }
    
  2. Suggested solution (parts of the class):
    package net.supermegacorp.orgmanager;
    
    public class Member {
    
      private String name;
      private String email;
      private static String separator = ";";
    
      public static String getSeparator() {
        return separator;
      }
    
      public String toString() {
        return name + separator + email;
      }
    }
    
    We need to make the method public since we want others to be able to use it. It does not have to be static since all objects can reach the class, but we suggest making it static to reflect that the variable is static.
  3. Suggested solution:
        public static void setSeparator(String separator) {
            Member.separator = separator;
        }
    
  4. The authors can not motivate Getters and Setters like this. But we will use the method in the next section so let's keep it for now.
  5. The class StaticConfusion will not compile. You'll get an error message similar to this:
    StaticConfusion.java:7: error: non-static method email() cannot be referenced from a static context
            Member.email();
                  ^
    1 error
    
    The method email() is an instance method which means it is associated with an object. Calling the method with an association to the class and no object does not make sense. This is similar to asking the blueprint of a mobile phone what phone number is has - it is instances of the mobile phone blueprint that has phone numbers.
    We have noticed that a common solution to this, even among teachers and supervisors, to make the method email() static. Try doing this and you'll find that you also need to make the instance variable email static. Et voila, it works. The "only" problem now is that all Member instances will share the same email address. So we urge you not to fall in to the common pattern we (the authors) are calling 'the static swamp anti-pattern'. Think about if asking the class for an email address is wise in the first place and you'll directly remove or replace the call to Member.email(). Another solution is to create an object of the type Member, which is probably you wanted in the first place.


Chapter Links

External links

Where to go next

« PreviousBook TOCNext »