static Class Members

Every object has its own copy of all the instance variables of the class. In certain cases, only one copy of a particular variable should be shared by all objects of a class. A static variable is used in such cases. A static variable represents classwide informationall objects of the class share the same piece of data. The declaration of a static variable begins with the keyword static.

Let's motivate static data with an example. Suppose that we have a video game with Martians and other space creatures. Each Martian tends to be brave and willing to attack other space creatures when it is aware that there are at least four other Martians present. If fewer than five Martians are present, each Martian becomes cowardly. Thus each Martian needs to know the martianCount. We could endow class Martian with martianCount as an instance variable. If we do this, every Martian will have a separate copy of the instance variable, and every time we create a new Martian, we will have to update the instance variable martianCount in every Martian. This wastes space on redundant copies, wastes time updating the separate copies and is error prone. Instead, we declare martianCount to be static, making martianCount classwide data. Every Martian can access the martianCount as if it were an instance variable of class Martian, but only one copy of the static martianCount is maintained. This saves space. We save time by having the Martian constructor increment the static martianCountthere is only one copy, so we do not have to increment separate copies of martianCount for each Martian object.

Software Engineering Observation 9 8

Use a static variable when all objects of a class must use the same copy of the variable.

The scope of a static variable is the body of its class. A class's public static members can be accessed by qualifying the member name with the class name and the dot (.) operator, as in Math.PI. A class's private static class members can be accessed only through the methods and properties of the class. Actually, static class members exist even when no objects of the class existthey are available as soon as the class is loaded into memory at execution time. To access a private static member from outside its class, a public static method or property can be provided.

Common Programming Error 9 7

It is a compilation error to access or invoke a static member by referencing it through an instance of the class, like a non-static member.

Software Engineering Observation 9 9

Static variables and methods exist, and can be used, even if no objects of that class have been instantiated.

Our next application declares two classesEmployee (Fig. 9.12) and EmployeeTest (Fig. 9.13). Class Employee declares private static variable count (Fig. 9.12, line 10), and public static property Count (lines 5258). We omit the set accessor of property Count to make the property read-onlywe do not want clients of the class to be able to modify count. The static variable count is initialized to 0 in line 10. If a static variable is not initialized, the compiler assigns a default value to the variablein this case 0, the default value for type int. Variable count maintains a count of the number of objects of class Employee currently in memory. This includes objects that are already inaccessible from the application, but have not yet had their destructors invoked by the garbage collector.

Figure 9.12. static variable used to maintain a count of the number of Employee objects in memory.

(This item is displayed on pages 432 - 433 in the print version)

 1 // Fig. 9.12: Employee.cs
 2 // Static variable used to maintain a count of the number of
 3 // Employee objects in memory.
 4 using System;
 5
 6 public class Employee
 7 {
 8 private string firstName;
 9 private string lastName;
10 private static int count = 0; // number of objects in memory
11
12 // initialize employee, add 1 to static count and
13 // output string indicating that constructor was called
14 public Employee( string first, string last )
15 {
16 firstName = first;
17 lastName = last;
18 count++; // increment static count of employees
19 Console.WriteLine( "Employee constructor: {0} {1}; count = {2}",
20 FirstName, LastName, Count );
21 } // end Employee constructor
22
23 // subtract 1 from static count when the garbage collector
24 // calls destructor to clean up object;
25 // confirm that destructor was called
26 ~Employee() 
27 { 
28  count--; // decrement static count of employees 
29  Console.WriteLine( "Employee destructor: {0} {1}; count = {2}",
30  FirstName, LastName, Count ); 
31 } // end destructor 
32
33 // read-only property that gets the first name 34 public string FirstName 35 { 36 get 37 { 38 return firstName; 39 } // end get 40 } // end property FirstName 41 42 // read-only property that gets the last name 43 public string LastName 44 { 45 get 46 { 47 return lastName; 48 } // end get 49 } // end property LastName 50 51 // read-only property that gets the employee count 52 public static int Count 53 { 54 get 55 { 56 return count; 57 } // end get 58 } // end property Count 59 } // end class Employee

When Employee objects exist, member count can be used in any method of an Employee objectthis example increments count in the constructor (line 18) and decrements it in the destructor (line 28). When no objects of class Employee exist, member count can still be referenced, but only through a call to public static property Count (lines 5258), as in Employee.Count, which evaluates to the number of Employee objects currently in memory.

Note that the Employee class has a destructor (lines 2631). This destructor is included to decrement static variable count, then show when the garbage collector executes in this application. Unlike constructors and methods, the destructor cannot be invoked explicitly by any programmer-written code. It can only be invoked by the garbage collector, so it does not need an access modifierin fact, it is a syntax error to include one.

EmployeeTest method Main (Fig. 9.13) instantiates two Employee objects (lines 1415). When each Employee object's constructor is invoked, lines 1617 of Fig. 9.12 assign the Employee's first name and last name to instance variables firstName and lastName. Note that these two statements do not make copies of the original string arguments. Actually, string objects in C# are immutablethey cannot be modified after they are created. Therefore, it is safe to have many references to one string object. This is not normally the case for objects of most other classes in C#. If string objects are immutable, you might wonder why we are able to use operators + and += to concatenate string objects. String concatenation operations actually result in a new string object containing the concatenated values. The original string objects are not modified.

Figure 9.13. static member demonstration.

 1 // Fig. 9.13: EmployeeTest.cs
 2 // Static member demonstration.
 3 using System;
 4
 5 public class EmployeeTest
 6 {
 7 public static void Main( string[] args )
 8 {
 9 // show that count is 0 before creating Employees
10 Console.WriteLine( "Employees before instantiation: {0}",
11 Employee.Count );
12
13 // create two Employees; count should become 2
14 Employee e1 = new Employee( "Susan", "Baker" );
15 Employee e2 = new Employee( "Bob", "Blue" ); 
16
17 // show that count is 2 after creating two Employees
18 Console.WriteLine( "
Employees after instantiation: {0}",
19 Employee.Count );
20
21 // get names of Employees
22 Console.WriteLine( "
Employee 1: {0} {1}
Employee 2: {2} {3}
",
23 e1.FirstName, e1.LastName,
24 e2.FirstName, e2.LastName );
25
26 // in this example, there is only one reference to each Employee,
27 // so the following statements cause the CLR to mark each 
28 // Employee object as being eligible for destruction 
29 e1 = null; // object e1 no longer needed 
30 e2 = null; // object e2 no longer needed 
31
32 GC.Collect(); // ask for garbage collection to occur now
33 // wait until the destructors 
34 // finish writing to the console 
35 GC.WaitForPendingFinalizers(); 
36
37 // show Employee count after calling garbage collector and
38 // waiting for all destructors to finish
39 Console.WriteLine( "
Employees after destruction: {0}",
40 Employee.Count );
41 } // end Main
42 } // end class EmployeeTest
 
 Employees before instantiation: 0
 Employee constructor: Susan Baker; count = 1
 Employee constructor: Bob Blue; count = 2

 Employees after instantiation: 2

 Employee 1: Susan Baker
 Employee 2: Bob Blue

 Employee destructor: Bob Blue; count = 1
 Employee destructor: Susan Baker; count = 0

 Employees after destruction: 0

When Main has finished using the two Employee objects, references e1 and e2 are set to null at lines 2930, so they no longer refer to the objects that were instantiated on lines 1415. The objects become "eligible for garbage collection" because there are no more references to them in the application.

Eventually, the garbage collector might reclaim the memory for these objects (or the operating system will reclaim the memory when the application terminates). C# does not guarantee when, or even whether, the garbage collector will execute, so in line 32, this application explicitly calls the garbage collector using static method Collect of class GC to indicate that the garbage collector should make a "best-effort" attempt to reclaim objects that are inaccessible. This is just a best effortit is possible that no objects or only a subset of the eligible objects will be collected. When method Collect returns, this does not indicate that the garbage collector has finished searching for memory to reclaim. The garbage collector may still, in fact, be executing. For this reason, we call static method WaitForPendingFinalizers of class GC. If the garbage collector has marked any objects eligible for destruction, invoking WaitforPendingFinalizers in line 35 stops the execution of the Main method until the destructors of these objects have been completely executed.

In Fig. 9.13's sample output, the garbage collector did reclaim the objects formerly referenced by e1 and e2 before lines 3940 displayed the current Employee count. The last output line indicates that the number of Employee objects in memory is 0 after the call to GC.Collect(). The third- and second-to-last lines of the output show that the Employee object for Bob Blue was destructed before the Employee object for Susan Baker. The output on your system may differ, because the garbage collector is not guaranteed to execute when GC.Collect() is called, nor is it guaranteed to collect objects in a specific order. In fact, if you omit the call to WaitForPendingFinalizers, it is likely that lines 3940 will execute before the garbage collector has a chance to call the destructors.

[Note: A method declared static cannot access non-static class members directly, because a static method can be called even when no objects of the class exist. For the same reason, the this reference cannot be used in a static methodthe this reference must refer to a specific object of the class, and when a static method is called, there might not be any objects of its class in memory. The this reference is required to allow a method of a class to access non-static members of the same class.]

Common Programming Error 9 8

A compilation error occurs if a static method calls an instance (non-static) method in the same class by using only the method name. Similarly, a compilation error occurs if a static method attempts to access an instance variable in the same class by using only the variable name.

Common Programming Error 9 9

Referring to the this reference in a static method is a syntax error.


readonly Instance Variables

Preface

Index

    Introduction to Computers, the Internet and Visual C#

    Introduction to the Visual C# 2005 Express Edition IDE

    Introduction to C# Applications

    Introduction to Classes and Objects

    Control Statements: Part 1

    Control Statements: Part 2

    Methods: A Deeper Look

    Arrays

    Classes and Objects: A Deeper Look

    Object-Oriented Programming: Inheritance

    Polymorphism, Interfaces & Operator Overloading

    Exception Handling

    Graphical User Interface Concepts: Part 1

    Graphical User Interface Concepts: Part 2

    Multithreading

    Strings, Characters and Regular Expressions

    Graphics and Multimedia

    Files and Streams

    Extensible Markup Language (XML)

    Database, SQL and ADO.NET

    ASP.NET 2.0, Web Forms and Web Controls

    Web Services

    Networking: Streams-Based Sockets and Datagrams

    Searching and Sorting

    Data Structures

    Generics

    Collections

    Appendix A. Operator Precedence Chart

    Appendix B. Number Systems

    Appendix C. Using the Visual Studio 2005 Debugger

    Appendix D. ASCII Character Set

    Appendix E. Unicode®

    Appendix F. Introduction to XHTML: Part 1

    Appendix G. Introduction to XHTML: Part 2

    Appendix H. HTML/XHTML Special Characters

    Appendix I. HTML/XHTML Colors

    Appendix J. ATM Case Study Code

    Appendix K. UML 2: Additional Diagram Types

    Appendix L. Simple Types

    Index



    Visual C# How to Program
    Visual C# 2005 How to Program (2nd Edition)
    ISBN: 0131525239
    EAN: 2147483647
    Year: 2004
    Pages: 600

    Flylib.com © 2008-2020.
    If you may any questions please contact us: flylib@qtcs.net