Reflection Know Thy Self 2001 by Ashby M
Reflection Know Thy Self © 2001 by Ashby M. Woolf Revision 2
The Class Object Everything You Ever Wanted To Know About a Class © 2001 by Ashby M. Woolf Revision 2
The Initialization Process Create a new Object First Reference Run a static method Is this First Class no Reference a static variable yes new Foo() Static Method Requires Object Create New Object Run static method Run an object method yes no no new yes The Repository of Locate and load the. class file Allocate & zero member variables Create Class Object Initialize member declarations set Allocate & zero static variables Run initializer block Initialize static declarations set Run Constructor Run static initializer block © 2001 by Ashby M. Woolf new Allocate local storage Run method Local storage freed Information About the Class. Done Reference an object variable Revision 2
All Classes Inherit from the Object Class get. Class(); © 2001 by Ashby M. Woolf Revision 2
Remember Pet, Apet, Bird and Dog interface Pet { void speak(int i); void set. Name(String s); String get. Name(); } abstract String public } class APet implements Pet{ name; void set. Name(String s) { name = s; } String get. Name() { return name; } class Bird extends APet { public void speak(int i) { for(int k=0; k<i; k++) { System. out. println("Tweet"); } } } © 2001 by Ashby M. Woolf class Dog extends APet { public void speak(int i) { for(int k=0; k<i; k++) { System. out. println("Woof"); } } } Revision 2
import java. lang. reflect. *; Reflecting on a Dog public class About. AClass { public static void main(String[] args) { } } Object o = new Dog(); Class c = o. get. Class(); System. out. println(c); Method[] meths = c. get. Declared. Methods(); for (int i = 0; i < meths. length; i++) { System. out. println("Method - " + meths[i]); } Class sc = c. get. Superclass(); System. out. println("Superclass - " + sc); Class[] inter = sc. get. Interfaces(); for (int i = 0; i < inter. length; i++) { System. out. println("Interface for sc - " + inter[i]); } Field[] f = sc. get. Fields(); for (int i = 0; i < f. length; i++) { System. out. println("Field for sc - " + f[i]); } System. out. println("Package - " + sc. get. Package()); © 2001 by Ashby M. Woolf Revision 2
import java. lang. reflect. *; Reflecting on a Dog public class About. AClass { public static void main(String[] args) { Object o = new Dog(); Class c = o. get. Class(); System. out. println(c); Method[] meths = c. get. Declared. Methods(); for (int i = 0; i < meths. length; i++) { System. out. println("Method - " + meths[i]); } Class sc = c. get. Superclass(); System. out. println("Superclass - " + sc); Class[] inter = sc. get. Interfaces(); for (int i = 0; i < inter. length; i++) { System. out. println("Interface for sc - " + inter[i]); } Field[] f = sc. get. Fields(); for (int i =class 0; i Dog < f. length; i++) { System. out. println("Field for sc - " + f[i]); Method - public void Dog. speak(int) } Superclass - class APet System. out. println("Package - " + sc. get. Package()); Interface for sc - interface Pet } Field for sc - public java. lang. String APet. name } Package - null © 2001 by Ashby M. Woolf Revision 2
import java. lang. reflect. *; import java. util. *; Reflecting on an Array. List public class About. AClass { public static void main(String[] args) { } } Object o = new Dog(); Array. List(); Class c = o. get. Class(); System. out. println(c); Method[] meths = c. get. Declared. Methods(); for (int i = 0; i < meths. length; i++) { System. out. println("Method - " + meths[i]); } Class sc = c. get. Superclass(); System. out. println("Superclass - " + sc); Class[] inter = sc. get. Interfaces(); for (int i = 0; i < inter. length; i++) { System. out. println("Interface for sc - " + inter[i]); } Field[] f = sc. get. Fields(); for (int i = 0; i < f. length; i++) { System. out. println("Field for sc - " + f[i]); } System. out. println("Package - " + sc. get. Package()); © 2001 by Ashby M. Woolf Revision 2
import java. lang. reflect. *; import java. util. *; Reflecting on an Array. List public class About. AClass { class java. util. Array. List public staticjava. lang. Object void main(String[] args) { Method - public java. util. Array. List. clone() Method - public int java. util. Array. List. index. Of(java. lang. Object) Object o = int newjava. util. Array. List. last. Index. Of(java. lang. Object) Array. List(); Method - public Class c = o. get. Class(); Method - public java. lang. Object java. util. Array. List. get(int) System. out. println(c); Method - public boolean java. util. Array. List. add(java. lang. Object) Method[] = c. get. Declared. Methods(); Method - publicmeths void java. util. Array. List. add(int, java. lang. Object) for- (int = 0; i < meths. length; i++) { Method publici int java. util. Array. List. size() - " + meths[i]); Method System. out. println("Method - public java. lang. Object[] java. util. Array. List. to. Array() } - public boolean java. util. Array. List. contains(java. lang. Object) Method Class sc = void c. get. Superclass(); Method - public java. util. Array. List. clear() System. out. println("Superclass - " + sc); • Class[] inter = sc. get. Interfaces(); • for (int i • = 0; i < inter. length; i++) { for sc - " + inter[i]); Method System. out. println("Interface - public java. lang. Object java. util. Array. List. remove(int) } - public boolean java. util. Array. List. is. Empty() Method Field[] f = sc. get. Fields(); Method - protected void java. util. Array. List. remove. Range(int, int) for- (int = 0; java. util. Array. List. trim. To. Size() i < f. length; i++) { Method publici void for sc - " + f[i]); Method System. out. println("Field - public void java. util. Array. List. ensure. Capacity(int) } - private void java. util. Array. List. Range. Check(int) Method System. out. println("Package - " + sc. get. Package()); Superclass - class java. util. Abstract. List } Interface for sc - interface java. util. List } Package - package java. util, Java Platform API Specification, version 1. 3 © 2001 by Ashby M. Woolf Revision 2
The Containers Collection Map Set List Sorted. Map Sorted. Set Abstract. Collection Abstract. List Abstract. Set Abstract. Map Abstract. Sequential. List Array. List Linked. List © 2001 by Ashby M. Woolf Hash. Set Tree. Set Weak. Hash. Map Tree. Map Revision 2
import java. lang. reflect. *; //import java. util. *; I Didn't Know at Compile Time public class About. AClass { public static void main(String[] args)throws { Class. Not. Found. Exception { //Object o o = = new Array. List(); Class c = o. get. Class(); Class. for. Name("java. util. Array. List"); System. out. println(c); Method[] meths = c. get. Declared. Methods(); for (int i = 0; i < meths. length; i++) { System. out. println("Method - " + meths[i]); } Class sc = c. get. Superclass(); System. out. println("Superclass - " + sc); Class[] inter = sc. get. Interfaces(); for (int i = 0; i < inter. length; i++) { System. out. println("Interface for sc - " + inter[i]); } Field[] f = sc. get. Fields(); for (int i = 0; i < f. length; i++) { System. out. println("Field for sc - " + f[i]); } System. out. println("Package - " + sc. get. Package()); } } © 2001 by Ashby M. Woolf Revision 2
import java. lang. reflect. *; //import java. util. *; I Didn't Know at Compile Time public class About. AClass { class java. util. Array. List public staticjava. lang. Object void main(String[] args)throws Method - public java. util. Array. List. clone() Class. Not. Found. Exception { Method - public int java. util. Array. List. index. Of(java. lang. Object) //Object = new Array. List(); Method - publico int java. util. Array. List. last. Index. Of(java. lang. Object) Class c = Class. for. Name("java. util. Array. List"); Method - public java. lang. Object java. util. Array. List. get(int) System. out. println(c); Method - public boolean java. util. Array. List. add(java. lang. Object) Method[] = c. get. Declared. Methods(); Method - publicmeths void java. util. Array. List. add(int, java. lang. Object) for- (int = 0; i < meths. length; i++) { Method publici int java. util. Array. List. size() - " + meths[i]); Method System. out. println("Method - public java. lang. Object[] java. util. Array. List. to. Array() } - public boolean java. util. Array. List. contains(java. lang. Object) Method Class sc = void c. get. Superclass(); Method - public java. util. Array. List. clear() System. out. println("Superclass - " + sc); • Class[] inter = sc. get. Interfaces(); • for (int i • = 0; i < inter. length; i++) { for sc - " + inter[i]); Method System. out. println("Interface - public java. lang. Object java. util. Array. List. remove(int) } - public boolean java. util. Array. List. is. Empty() Method Field[] f = sc. get. Fields(); Method - protected void java. util. Array. List. remove. Range(int, int) for- (int = 0; java. util. Array. List. trim. To. Size() i < f. length; i++) { Method publici void for sc - " + f[i]); Method System. out. println("Field - public void java. util. Array. List. ensure. Capacity(int) } - private void java. util. Array. List. Range. Check(int) Method System. out. println("Package - " + sc. get. Package()); Superclass - class java. util. Abstract. List } Interface for sc - interface java. util. List } Package - package java. util, Java Platform API Specification, version 1. 3 © 2001 by Ashby M. Woolf Revision 2
Methods of the Class • static Class for. Name(String class. Name) – Returns the Class object associated with the class or interface with the given string name. • static Class for. Name(String name, boolean initialize, Class. Loader loader) – Returns the Class object associated with the class or interface with the given string name, using the given class loader. • Class[] get. Classes() – Returns an array containing Class objects representing all the public classes and interfaces that are members of the class represented by this Class object. © 2001 by Ashby M. Woolf Revision 2
Methods of the Class • Class. Loader get. Class. Loader() – Returns the class loader for the class. • Class get. Component. Type() – Returns the Class representing the component type of an array. • Constructor get. Constructor(Class[] parameter. Types) – Returns a Constructor object that reflects the specified public constructor of the class represented by this Class object. • Constructor[] get. Constructors() – Returns an array containing Constructor objects reflecting all the public constructors of the class represented by this Class object. © 2001 by Ashby M. Woolf Revision 2
Methods of the Class • Class[] get. Declared. Classes() – Returns an array of Class objects reflecting all the classes and interfaces declared as members of the class represented by this Class object. • Constructor get. Declared. Constructor(Class[] parameter. Types) – Returns a Constructor object that reflects the specified constructor of the class or interface represented by this Class object. • Constructor[] get. Declared. Constructors() – Returns an array of Constructor objects reflecting all the constructors declared by the class represented by this Class object. © 2001 by Ashby M. Woolf Revision 2
Methods of the Class • Field get. Declared. Field(String name) – Returns a Field object that reflects the specified declared field of the class or interface represented by this Class object. • Field[] get. Declared. Fields() – Returns an array of Field objects reflecting all the fields declared by the class or interface represented by this Class object. • Method get. Declared. Method(String name, Class[] parameter. Types) – Returns a Method object that reflects the specified declared method of the class or interface represented by this Class object. © 2001 by Ashby M. Woolf Revision 2
Methods of the Class • Method[] get. Declared. Methods() – Returns an array of Method objects reflecting all the methods declared by the class or interface represented by this Class object. • Class get. Declaring. Class() – If the class or interface represented by this Class object is a member of another class, returns the Class object representing the class in which it was declared. • Field get. Field(String name) – Returns a Field object that reflects the specified public member field of the class or interface represented by this Class object. © 2001 by Ashby M. Woolf Revision 2
Methods of the Class • Field[] get. Fields() – Returns an array containing Field objects reflecting all the accessible public fields of the class or interface represented by this Class object. • Class[] get. Interfaces() – Determines the interfaces implemented by the class or interface represented by this object. • Method get. Method(String name, Class[] parameter. Types) – Returns a Method object that reflects the specified public member method of the class or interface represented by this Class object. © 2001 by Ashby M. Woolf Revision 2
Methods of the Class • Method[] get. Methods() – Returns an array containing Method objects reflecting all the public member methods of the class or interface represented by this Class object, including those declared by the class or interface and those inherited from superclasses and superinterfaces. • int get. Modifiers() – Returns the Java language modifiers for this class or interface, encoded in an integer. • String get. Name() – Returns the fully-qualified name of the entity (class, interface, array class, primitive type, or void) represented by this Class object, as a String. © 2001 by Ashby M. Woolf Revision 2
Methods of the Class • Package get. Package() – Gets the package for this class. • Protection. Domain get. Protection. Domain() – Returns the Protection. Domain of this class. • URL get. Resource(String name) – Finds a resource with a given name. • Input. Stream get. Resource. As. Stream(String name) – Finds a resource with a given name. • Object[] get. Signers() – Gets the signers of this class. © 2001 by Ashby M. Woolf Revision 2
Methods of the Class • Class get. Superclass() – Returns the Class representing the superclass of the entity (class, interface, primitive type or void) represented by this Class. • booleanis. Array() – Determines if this Class object represents an array class. • boolean is. Assignable. From(Class cls) – Determines if the class or interface represented by this Class object is either the same as, or is a superclass or superinterface of, the class or interface represented by the specified Class parameter. © 2001 by Ashby M. Woolf Revision 2
Methods of the Class • boolean is. Instance(Object obj) – Determines if the specified Object is assignment-compatible with the object represented by this Class. • boolean is. Interface() – Determines if the specified Class object represents an interface type. • boolean is. Primitive() – Determines if the specified Class object represents a primitive type. • Object new. Instance() – Creates a new instance of the class represented by this Class object. © 2001 by Ashby M. Woolf Revision 2
Methods of the Class • String to. String() – converts the object to a string. © 2001 by Ashby M. Woolf Revision 2
RTTI Run Time Type Identification © 2001 by Ashby M. Woolf Revision 2
Traditional RTTI • "Safe" Downcasting • Knowing When a Downcast is OK • Determining Type © 2001 by Ashby M. Woolf Revision 2
Three Classes Top, Middle and Bottom class Top { void meth() { System. out. println("meth() at the Top"); } } class Middle extends Top { void meth() { System. out. println("meth() in the Middle"); } } class Bottom extends Middle { void meth() { System. out. println("meth() at the Bottom"); } } © 2001 by Ashby M. Woolf 5 Revision 2
Acceptable Implicit Casts for Class Instances Top Upcasting t Middle new Bottom Top t = new Bottom(); © 2001 by Ashby M. Woolf Revision 2
Acceptable Explicit Casts Downcasting Top t Middle m =m (Middle)t; = t; m Middle Bottom b = (Bottom)m; b Bottom Top t = new Bottom(); © 2001 by Ashby M. Woolf Revision 2
Unacceptable Explicit Casts Foo f = (Foo)t; Class. Cast. Exception Top f x Foo t Middle Bottom Top t = new Bottom(); © 2001 by Ashby M. Woolf Revision 2
RTTI Simple Tools for Downcasting © 2001 by Ashby M. Woolf Revision 2
Operator Precedence Unary Arithmetic Shift Comparison Logical Bit Boolean Ternary Assignment © 2001 by Ashby M. Woolf + - ++ -- ! ~ () * / % + << >> > < >= <= instanceof == != & | ^ && || ? : = (and += etc. ) Revision 2
instanceof Operator { public class Do. Instanceof public static void main(String[] args) { Object t = new Top(); Object m = new Middle(); Object b = new Bottom(); System. out. println("instanceof"); System. out. println("t. Topt. Middlet. Bottom"); System. out. print("tt" + (t instanceof Top)); System. out. print("t" + (t instanceof Middle)); System. out. println("t" + (t instanceof Bottom)); System. out. print("mt" + (m instanceof Top)); System. out. print("t" + (m instanceof Middle)); System. out. println("t" + (m instanceof Bottom)); System. out. print("bt" + (b instanceof Top)); System. out. print("t" + (b instanceof Middle)); System. out. println("t" + (b instanceof Bottom)); } } © 2001 by Ashby M. Woolf Revision 2
instanceof Operator { public class Do. Instanceof public static void main(String[] args) { Object t = new Top(); Object m = new Middle(); Object b = new Bottom(); System. out. println("instanceof"); System. out. println("t. Topt. Middlet. Bottom"); System. out. print("tt" + (t instanceof Top)); System. out. print("t" + (t instanceof Middle)); System. out. println("t" + (t instanceof Bottom)); System. out. print("mt" + (m instanceof Top)); System. out. print("t" + (m instanceof Middle)); System. out. println("t" + (m instanceof Bottom)); System. out. print("bt" + (b instanceof Top)); System. out. print("t" + (b instanceof Top. Middle)); Middle System. out. println("t" + (bt instanceof true Bottom)); false } m true } b true © 2001 by Ashby M. Woolf Bottom false true Revision 2
Checking Before Down Casting if (x instanceof Foo) Foo f = (Foo)x; © 2001 by Ashby M. Woolf Revision 2
Getting a Reference to a Class • Class. for. Name("Foo") • Foo f = new Foo(); f. get. Class() // Assume A Class Literal • Foo. class © 2001 by Ashby M. Woolf Revision 2
Class Literals • • • Foo. class boolean. class char. class byte. class short. class int. class long. class float. class double. class void. class © 2001 by Ashby M. Woolf • • • Boolean. TYPE Character. TYPE Byte. TYPE Short. TYPE Integer. TYPE Long. TYPE Float. TYPE Double. TYPE Void. TYPE Revision 2
is. Instance( ) Method Do. Is. Instance Do. Instanceof { public class public static void main(String[] args) { Object t = new Top(); Object m = new Middle(); Object b = new Bottom(); System. out. println("Top. class. is. Instance(t)"); System. out. println("instanceof"); System. out. println("t. Topt. Middlet. Bottom"); System. out. print("tt" + (Top. class. is. Instance(t))); (t instanceof Top)); System. out. print("t" + (Middle. class. is. Instance(t))); (t instanceof Middle)); System. out. println("t" + (Bottom. class. is. Instance(t))); (t instanceof Bottom)); System. out. print("mt" + (Top. class. is. Instance(m))); (m instanceof Top)); System. out. print("t" + (Middle. class. is. Instance(m))); (m instanceof Middle)); System. out. println("t" + (Bottom. class. is. Instance(m))); (m instanceof Bottom)); System. out. print("bt" + (Top. class. is. Instance(b))); (b instanceof Top)); System. out. print("t" + (Middle. class. is. Instance(b))); (b instanceof Middle)); System. out. println("t" + (Bottom. class. is. Instance(b))); (b instanceof Bottom)); } } © 2001 by Ashby M. Woolf Revision 2
is. Instance( ) Method Do. Is. Instance { public class public static void main(String[] args) { Object t = new Top(); Object m = new Middle(); Object b = new Bottom(); System. out. println("Top. class. is. Instance(t)"); System. out. println("t. Topt. Middlet. Bottom"); System. out. print("tt" + (Top. class. is. Instance(t))); System. out. print("t" + (Middle. class. is. Instance(t))); System. out. println("t" + (Bottom. class. is. Instance(t))); System. out. print("mt" + (Top. class. is. Instance(m))); System. out. print("t" + (Middle. class. is. Instance(m))); System. out. println("t" + (Bottom. class. is. Instance(m))); System. out. print("bt" + (Top. class. is. Instance(b))); Top. class. is. Instance(t) System. out. print("t" + (Middle. class. is. Instance(b))); Top Middle Bottom System. out. println("t" + (Bottom. class. is. Instance(b))); t true false } m true false } b true © 2001 by Ashby M. Woolf Revision 2
Using the == Operator Do. Is. Instance {{ public class Do. Equivalence public static void main(String[] args) { Object t = new Top(); Object m = new Middle(); Object b = new Bottom(); System. out. println(". get. Class() == "); System. out. println("Top. class. is. Instance(t)"); System. out. println("t. Topt. Middlet. Bottom"); (Top. class. is. Instance(t))); System. out. print("tt" + (t. get. Class() == Top. class)); (Middle. class. is. Instance(t))); System. out. print("t" + (t. get. Class() == Middle. class)); System. out. println("t" + (t. get. Class() (Bottom. class. is. Instance(t))); == Bottom. class)); (Top. class. is. Instance(m))); System. out. print("mt" + (m. get. Class() == Top. class)); (Middle. class. is. Instance(m))); System. out. print("t" + (m. get. Class() == Middle. class)); (Bottom. class. is. Instance(m))); System. out. println("t" + (m. get. Class() == Bottom. class)); (Top. class. is. Instance(b))); System. out. print("bt" + (b. get. Class() == Top. class)); (Middle. class. is. Instance(b))); System. out. print("t" + (b. get. Class() == Middle. class)); (Bottom. class. is. Instance(b))); System. out. println("t" + (b. get. Class() == Bottom. class)); } } © 2001 by Ashby M. Woolf Revision 2
Using the == Operator public class Do. Equivalence { public static void main(String[] args) { Object t = new Top(); Object m = new Middle(); Object b = new Bottom(); System. out. println(". get. Class() == "); System. out. println("t. Topt. Middlet. Bottom"); System. out. print("tt" + (t. get. Class() == Top. class)); System. out. print("t" + (t. get. Class() == Middle. class)); System. out. println("t" + (t. get. Class() == Bottom. class)); System. out. print("mt" + (m. get. Class() == Top. class)); System. out. print("t" + (m. get. Class() == Middle. class)); System. out. println("t" + (m. get. Class() == Bottom. class)); System. out. print("bt" + (b. get. Class() == == Top. class)); System. out. print("t" + (b. get. Class() Top== Middle. class)); Middle Bottom System. out. println("t" + (b. get. Class() t true == Bottom. class)); false } m false true false } b false true © 2001 by Ashby M. Woolf Revision 2
equals( ) Method public class Do. Equals Do. Equivalence Do. Equals { { { public static void main(String[] args) { { Object t =t new = new Top(); Object m =m new = new Middle(); Object b =b new = new Bottom(); System. out. println(". get. Class(). equals( System. out. println(". get. Class() == "); System. out. println(". get. Class(). equals(. class)"); System. out. println("t. Topt. Middlet. Bottom"); System. out. print("tt"+(t. get. Class(). equals(Top. class))); System. out. print("tt" + (t. get. Class(). equals(Top. class))); (t. get. Class() == Top. class)); System. out. print("t"+(t. get. Class(). equals(Middle. class))); System. out. print("t" + (t. get. Class(). equals(Middle. class))) (t. get. Class() == Middle. class)); System. out. println("t"+(t. get. Class(). equals(Bottom. class))); System. out. println("t" + (t. get. Class(). equals(Bottom. class) (t. get. Class() == Bottom. class)); System. out. print("mt"+(m. get. Class(). equals(Top. class))); System. out. print("mt" + (m. get. Class(). equals(Top. class))); (m. get. Class() == Top. class)); System. out. print("t"+(m. get. Class(). equals(Middle. class))); System. out. print("t" + (m. get. Class(). equals(Middle. class))) (m. get. Class() == Middle. class)); System. out. println("t"+(m. get. Class(). equals(Bottom. class))); System. out. println("t" + (m. get. Class(). equals(Bottom. class) (m. get. Class() == Bottom. class)); System. out. print("bt"+(b. get. Class(). equals(Top. class))); System. out. print("bt" + (b. get. Class(). equals(Top. class))); (b. get. Class() == Top. class)); System. out. print("t"+(b. get. Class(). equals(Middle. class))); System. out. print("t" + (b. get. Class(). equals(Middle. class))) (b. get. Class() == Middle. class)); System. out. println("t"+(b. get. Class(). equals(Bottom. class))); System. out. println("t" + (b. get. Class(). equals(Bottom. class) (b. get. Class() == Bottom. class)); } } © 2001 by Ashby M. Woolf Revision 2
equals( ) Method public class Do. Equals { public static void main(String[] args) { Object t = new Top(); Object m = new Middle(); Object b = new Bottom(); System. out. println(". get. Class(). equals(. class)"); System. out. println("t. Topt. Middlet. Bottom"); System. out. print("tt"+(t. get. Class(). equals(Top. class))); System. out. print("t"+(t. get. Class(). equals(Middle. class))); System. out. println("t"+(t. get. Class(). equals(Bottom. class))); System. out. print("mt"+(m. get. Class(). equals(Top. class))); System. out. print("t"+(m. get. Class(). equals(Middle. class))); System. out. println("t"+(m. get. Class(). equals(Bottom. class))); System. out. print("bt"+(b. get. Class(). equals(Top. class))); . get. Class(). equals(. class) System. out. print("t"+(b. get. Class(). equals(Middle. class))); Top Middle Bottom System. out. println("t"+(b. get. Class(). equals(Bottom. class))); t true false } m false true false } b false true © 2001 by Ashby M. Woolf Revision 2
Relating and Objects Classes Simple Syntax x instanceof Foo instanceof Top t true m true b true Middle false true Top. class. is. Instance(t) Top Middle t true false m true b true © 2001 by Ashby M. Woolf Bottom false true . get. Class() == Top t true m false b false Bottom false true . get. Class(). equals( Top Middle t true false m false true b false Middle false true false Bottom false true . class) Bottom false true Revision 2
Summary • The Class Object – Everything you always wanted to know and were afraid to ask. • Getting a Reference to a Class Object – get. Class() – Class. for. Name(String classname) – Class Literals • Safe Downcasting – Class. Cast. Exception – Determining Type at Runtime © 2001 by Ashby M. Woolf Revision 2
End of Content © 2001 by Ashby M. Woolf Revision 2
- Slides: 45