9.10. Shared Class MembersEach object of a class has its own copy of all the instance variables of the class. However, in certain cases, all class objects should share only one copy of a particular variable. A program contains only one copy of a Shared class variable in memory, no matter how many objects of the class have been instantiated. A Shared class variable represents class-wide informationall class objects share the same piece of data. The declaration of a Shared member begins with the keyword Shared. Let us use a video game example to explain the need for Shared class-wide data. Suppose we have a video game in which Martians attack other space creatures. A 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 there are fewer than five Martians present, a Martian becomes cowardly. For this reason, each Martian must know the martianCount. We could endow class Martian with a martianCount instance variable. If we were to do this, then every Martian would have a separate copy of the instance variable, and every time we create a Martian, we would have to update the instance variable martianCount in every Martian. The redundant copies waste space, and updating those copies is time-consuming. Worse yet, while we are updating the individual copies of martianCount, there will be periods of time during which some of these copies have not yet been updated, so we could have inconsistent bravery behavior among the Martians. Instead, we declare martianCount to be Shared so that martianCount is class-wide data. Each Martian can then see the martianCount as if it were instance data of that Martian, but Visual Basic maintains only one copy of the Shared martianCount to save space. We also save time, in that the Martian constructor increments only the Shared martianCountthere is only one copy, so we do not have to increment separate copies of martianCount for each Martian object. This also prevents inconsistent bravery behavior among the Martians. Performance Tip 9.1
Shared class members have class scope. A class's Public Shared members can be accessed through the class name using the dot separator (e.g., className.sharedMember-Name). A class's Private Shared class members can be accessed by clients only indirectly through non-Private methods of the class. Shared class members are available as soon as the class is loaded into memory at execution time; like other variables with class scope, they exist for the duration of program execution, even when no objects of that class exist. To allow clients to access a Private Shared class member when no objects of the class exist, you must provide a non-Private Shared method or property. Unlike non-Shared methods, a Shared method has no Me reference, because Shared class members exist independently of any class objects and even when there are no objects of that class. So a Shared method cannot access non-Shared class members. Common Programming Error 9.4
Shared ConstructorsWhen Shared variables require more complex initialization than can be accomplished in a Shared variable declaration, you can create a Shared constructor to initialize them. A Shared constructor is declared like an instance constructor, but is preceded by the Shared modifier and can be used only to initialize Shared variables. A Shared constructor is implicitly Public, must be declared with no parameters, cannot call other constructors of the class and is guaranteed to execute before a program creates any objects of the class or accesses any Shared class members. A class can have both a Shared constructor and a non-Shared parameterless constructor. Common Programming Error 9.5
Class Employee with Shared VariablesClass Employee (Fig. 9.10) demonstrates a Private Shared class variable and a Public Shared Property. The Shared class variable countValue is initialized to zero by default (line 6). It maintains a count of the number of Employee objects that have been instantiated and currently reside in memory, including objects that have already been marked for garbage collection but have not yet been reclaimed by the garbage collector. Figure 9.10. Employee class objects share Shared variable.
When objects of class Employee exist, Shared member countValue can be used in any method of an Employee objectin this example, the constructor (lines 915) increments countValue (line 12) and method Finalize (lines 1823) decrements countValue (line 19). (Note that method Finalize is declared using keywords Protected and Overridesmethod Finalize's header must contain these keywords, which we discuss in Chapters 1011.) If no objects of class Employee exist, member countValue can be referenced through a call to Property Count (lines 4044)this Property is Shared, and therefore we do not have to instantiate an Employee object to call the Get method of the Property. Also, by declaring property Count as ReadOnly, we prevent clients from changing the value of countValue directly, thus ensuring that clients can change count-Value's value only under the tight control of class Employee's constructors and finalizer. Testing Shared VariablesModule SharedTest (Fig. 9.11) demonstrates the Shared members of Fig. 9.10. Lines 5 6 use the ReadOnly Shared Property Count of class Employee to obtain the current value of countValue. No Employee objects exist yet, so we must call Count using the class name Employee. Lines 89 then instantiate two Employee objects, causing countValue to be incremented by 2. Lines 1314 print the countValue by using ReadOnly Shared Property Count. Lines 1721 display the names of the employees. Lines 2425 set these objects' references to Nothing, so that employee1 and employee2 no longer refer to the Employee objects. This "marks" the objects for garbage collection, because there are no more references to these objects in the program. Figure 9.11. Shared class member demonstration.
Common Programming Error 9.6
Normally, the garbage collector is not invoked directly by the user. Either the garbage collector reclaims the memory for objects when it deems garbage collection is appropriate, or the operating system recovers the unneeded memory when the program terminates. Line 29 uses PublicShared method Collect from class GC (namespace System) to request that the garbage collector execute. Before the garbage collector releases the memory occupied by the two Employee objects, it invokes method Finalize for each Employee object, which decrements the countValue value by a total of 2. The last two lines of the sample output show that the Employee object for Bob Blue was finalized before the Employee object for Susan Baker. However, the output of this program on your system could differ. The garbage collector is not guaranteed to collect objects in a specific order, nor is it guaranteed to run at all before the program terminates. |