Static Methods
Different ways of calling methods
-
Usually you call a method by using the “dot operator” (member access operator) on an object, like this:
Rectangle rect = new Rectangle(); rect.SetLength(12);The
SetLengthmethod is defined in theRectangleclass. In order to call it, we need an instance of that class, which in this case is the objectrect. -
However, sometimes we have written code where we call a method using the dot operator on the name of a class, not an object. For example, the familiar
WriteLinemethod:Console.WriteLine("Hello!");Notice that we have never needed to write
new Console()to instantiate aConsoleobject before calling this method. -
More recently, we learned about the
Array.Resizemethod, which can be used to resize an array. Even though arrays are objects, we call theResizemethod on theArrayclass, not the particular array object we want to resize:int[] myArray = {10, 20, 30}; Array.Resize(ref myArray, 6); -
Methods that are called using the name of the class rather than an instance of that class are static methods
Declaring static methods
-
Static methods are declared by adding the
statickeyword to the header, like this:class Console { public static void WriteLine(string value) { ... } } -
The
statickeyword means that this method belongs to the class “in general,” rather than an instance of the class -
Thus, you do not need an object (instance of the class) to call a static method; you only need the name of the class
static methods and instances
-
Normal, non-static methods are always associated with a particular instance (object)
-
When a normal method modifies an instance variable, it always “knows” which object to modify, because you need to specify the object when calling it
-
For example, the
SetLengthmethod is defined like this:class Rectangle { private int length; private int width; public void SetLength(int lengthParameter) { length = lengthParameter; } }When you call the method with
rect.SetLength(12), thelengthvariable automatically refers to thelengthinstance variable stored inrect.
-
-
Static methods are not associated with any instance, and thus cannot use instance variables
-
For example, we could attempt to declare the
ComputeAreamethod ofRectangleas a static method, but this would not compile:class Rectangle { private int length; private int width; public void SetLength(int lengthParameter) { length = lengthParameter; } public static int ComputeArea() { return length * width; } }- To call this static method, you would write
Rectangle.ComputeArea(); - Since no
Rectangleobject is specified, which object’s length and width should be used in the computation?
- To call this static method, you would write
Uses for static methods
-
Since static methods cannot access instance variables, they do not seem very useful
-
One reason to use them: when writing a function that does not need to “save” any state, and just computes an output (its return value) based on some input (its parameters)
-
Math-related functions are usually written as static methods. The .NET library comes with a class named
Maththat defines several static methods, like these:public static double Pow(double x, double y) { //Computes and returns x^y } public static double Sqrt(double x) { //Computes and returns the square root of x } public static int Max(int x, int y) { //Returns the larger of the two numbers x and y } public static int Min(int x, int y) { //Returns the smaller of the two numbers x and y }Note that none of them need to use any instance variables.
-
Defining several static methods in the same class (like in class
Math) helps to group together similar or related functions, even if you never create an object of that class -
Static methods are also useful for providing the program’s “entry point.” Remember that your program must always have a
Mainmethod declared like this:class Program { static void Main(string[] args) { ... } }- When your program first starts, no objects exist yet, which means no “normal” methods can be called
- The .NET run-time (the interpreter that runs a C# program) must decide what code to execute to make your program start running
- It can call
Program.Main()without creating an object, or knowing anything else about your program, becauseMainis a static method
-
Static methods can be used to “help” other methods, both static and non-static
-
It’s easy to call a static method from within the same class: You can just write the name of the method, without the class name, i.e.
MethodName(args)instead ofClassName.MethodName(args) -
For example, the
Arrayclass has a static method namedCopythat copies the contents of one array into another array. This makes it very easy to write theResizemethod:class Array { public static void Copy(Array source, Array dest, int length) { //Copy [length] elements from source to dest, in the same order } public static void Resize<T>(ref T[] array, int newSize) { T[] newArray = new T[newSize] Copy(array, newArray, Math.Min(array.Length, newSize)); array = newArray; } }Since arrays are fixed-size, the only way to resize an array is to create a new array of the new size and copy the data from the old array into the new array. This Resize method is easy to read because the act of copying the data (which would involve a
forloop) is written separately, in theCopymethod, and Resize just needs to callCopy. -
Similarly, you can add additional static methods to the class that contains
Main, and call them from withinMain. This can help you separate a long program into smaller, easier-to-read chunks. It also allows you to re-use the same code multiple times without copying and pasting it.class Program { static void Main(string[] args) { int userNum1 = InputPositiveNumber(); int userNum2 = InputPositiveNumber(); int part1Result = DoPart1(userNum1, userNum2); DoPart2("Bananas", part1Result); } static int InputPositiveNumber() { int number; bool success; do { Console.WriteLine("Please enter a positive number"); success = int.TryParse(Console.ReadLine(), out number); } while(!success || number < 0); return number; } static int DoPart1(int a, int b) { ... } static void DoPart2(string x, int y) { ... } }In this example, our program needs to read two different numbers from the user, so we put the input-validation loop into the
InputPositiveNumbermethod instead of writing it twice in theMainmethod. It then has two separate “parts” (computing some result with the two user-input numbers, and combining that computed number with a string to display some output), which we write in the two methodsDoPart1andDoPart2. This makes our actualMainmethod only 4 lines long.
-
Static Variables
Defining static variables
-
The
statickeyword can be used in something that looks like an instance variable declaration:class Rectangle { private static int NumRectangles = 0; ... } -
This declares a variable that is stored with the class definition, not inside an object (it is not an instance variable)
-
Unlike an instance variable, there is only one copy in the entire program, and any method that refers to
NumRectangleswill access the same variable, no matter which object the method is called on -
Since it is not an instance variable, it does not get initialized in the constructor. Instead, you must initialize it with a value when you declare it, more like a local variable (in this case,
NumRectanglesis initialized to 0). -
It’s OK to declare a
staticvariable with thepublicaccess modifier, because it is not part of any object’s state. Thus, accessing the variable from outside the class will not violate encapsulation, the principle that an object’s state should only be modified by that object.-
For example, we could use the
NumRectanglesvariable to count the number of rectangles in a program by making itpublic. We could define it like this:class Rectangle { public static int NumRectangles = 0; ... }and use it like this, in a
Mainmethod:Rectangle myRect = new Rectangle(); Rectangle.NumRectangles++; Rectangle myOtherRect = new Rectangle(); Rectangle.NumRectangles++;
-
Using static variables
-
Since all instances of a class share the same static variables, you can use them to keep track of information about “the class as a whole” or “all the objects of this type”
-
A common use for static variables is to count the number of instances of an object that have been created so far in the program
-
Instead of “manually” incrementing this counter, like in our previous example, we can increment it inside the constructor:
class Rectangle { public static int NumRectangles = 0; private int length; private int width; public Rectangle(int lengthP, int widthP) { length = lengthP; width = widthP; NumRectangles++; } } -
Each time this constructor is called, it initializes a new
Rectangleobject with its own copy of thelengthandwidthvariables. It also increments the single copy of theNumRectanglesvariable that is shared by allRectangleobjects. -
The variable can still be accessed from the
Mainmethod (because it is public), where it could be used like this:Rectangle rect1 = new Rectangle(2, 4); Rectangle rect2 = new Rectangle(7, 5); Console.WriteLine(Rectangle.NumRectangles + " rectangle objects have been created");When
rect1is instantiated, its copy oflengthis set to 2 and its copy ofwidthis set to 4, then the singleNumRectanglesvariable is incremented to 1. Then, whenrect2is instantiated, its copy oflengthis set to 7 and its copy ofwidthis set to 5, and theNumRectanglesvariable is incremented to 2.
-
-
Static variables are also useful for constants
- The
constkeyword, which we learned about earlier, is actually very similar tostatic - A
constvariable is just astaticvariable that cannot be modified - Like a
staticvariable, it can be accessed using the name of the class where it is defined (e.g.Math.PI), and there is only one copy for the entire program
- The
Static methods and variables
-
Static methods cannot access instance variables, but they can access static variables
-
There is no ambiguity when accessing a static variable: you do not need to know which object’s variable to access, because there is only one copy of the static variable shared by all objects
-
This means you can write a “getter” or “setter” for a static variable, as long as it is a static method. For example, we could improve our
NumRectanglescounter by ensuring that theMainmethod can only read it through a getter method, like this:class Rectangle { private static int NumRectangles = 0; private int length; private int width; public Rectangle(int lengthP, int widthP) { length = lengthP; width = widthP; NumRectangles++; } public static int GetNumRectangles() { return NumRectangles; } }-
The
NumRectanglesvariable is now declaredprivate, which means only the Rectangle constructor will be able to increment it. Before, it would have been possible for theMainmethod to execute something liekRectangle.NumRectangles = 1;and throw off the count. -
The
GetNumRectanglesmethod cannot accesslengthorwidthbecause they are instance variables, but it can accessNumRectangles -
The static method would be called from the
Mainmethod like this:Rectangle rect1 = new Rectangle(2, 4); Rectangle rect2 = new Rectangle(7, 5); Console.WriteLine(Rectangle.GetNumRectangles() + " rectangle objects have been created");
-
Summary of static access rules
-
Static variables and instance variables are both fields of a class; they can also be called “static fields” and “non-static fields”
-
This table summarizes how methods are allowed to access them:
Static Field Non-static Field Static method Yes No Non-static method Yes Yes
Static Classes
-
The
statickeyword can also be used in a class declaration -
If a class is declared
static, all of its members (fields and methods) must be static -
This is useful for classes that serve as “utility libraries” containing a collection of functions, and are not supposed to be instantiated and used as objects
-
For example, the
Mathclass is declared like this:static class Math { public static double Sqrt(double x) { ... } public static double Pow(double x, double y) { ... } }There is no need to ever create a
Mathobject, but all of these methods belong together (within the same class) because they all implement standard mathematical functions.