450 likes | 515 Views
Instance vs. Class Declarations. Instance vs. Class Declarations. Don’t be fooled. Just because a variable might be declared as a field within a class – that does *not* imply that it is a “class variable.” It could be: a class variable, or an instance variable!
E N D
Instance vs. Class Declarations • Don’t be fooled. Just because a variable might be declared as a field within a class – that does *not* imply that it is a “class variable.” • It could be: • a class variable, or • an instance variable! • Likewise, each method is indeed declared within a class, but that does *not* imply that it is a “class method.” • It could be: • a class method, or • an instance method. • “Class variable” and “class method” both mean something very specific.
Instance vs. Class Declarations • A distinction that applies to both variables and methods • An instance <variable or method> is one that belongs to each object of a class. • A class <variable or method> is one that belongs only to the class itself. (N.B. It will be accessible to the objects) • The keyword static: • indicates a class variable or class method. • absence of the keyword static indicates an instance variable or instance method.
Instance vs. Class Variables Suppose we wanted to track the total number of objects created. Consider: class Human { String name; int population = 0; public Human (String name) { this.name = name; population++; //WRONG! } // of constructor } // of Human Declares a name String for each instance. Thus, each Human will have its own name. But . . . Also declares a population counter for each instance of Human. Thus, each Human will have its own populationvariable, each having a value of 1. This makes no sense!
Instance vs. Class Variables class Human { String name; static int population = 0; public Human (String name) { this.name = name; population++; } // of constructor } // of Human NOTE: Each Human does not get a population counter. This declares a single population counter for the class Human itself. It is a class variable. Thus, each Human will increment this single shared counter by 1. One change! Each instance will still have a String name Thus, each Human will have its own name.
Instance vs. Class Variables: When to Use Quiz Alert! • Use instance variableswhenever each object should have its own variable. • E.g., • attributes of the particular object. • name, ssn, age, weight • Use a class variablewhenever the class itself should maintain a single copy of datum pertaining to all instances of the class. • E.g., • population counts summary data • assigning lot numbers shared resources.
Instancevs.Class Variables We now see the reason behind declaring most constants as ‘static’ as well as ‘final’. Declares a different-but-identical constantfor each instance of the class. Wasteful with zero benefit. Constants Revisited: class ConstantExample { final int iMAXSIZE = 10; } // of ConstantExample class ConstantExample { static final int iMAXSIZE = 10; } // of ConstantExample Declares a single constant for use by all instances of the class.
Quiz Yourself Consider why the following code will not compile: public class Test { public void sayHello() { System.out.println (“Hello”); } public static void main (String arg[]){ sayHello(); } }
Classes and Objects • The error produced is: “Can't make static reference to method void sayHello() in class test.” • Why? The answer lies in the difference between objects and classes. As noted in previous slides, classes are composed of member objects, primitives and methods. When properly designed, classes provide state and behavior for objects. • As an OO language, Java emphasizes the use of objects to manipulate data. Thus, we must make instances of a class in order to drive a program.
Another Perspective t1 t2 public class Test { public void sayHello() { System.out.println (“Hello”); } public static void main (String arg[]) { sayHello(); // WRONG! } }//class Test public class Test { public void sayHello() { System.out.println (“Hello”); } public static void main (String arg[]) { sayHello(); // WRONG! } } }//class Test t3 public class Test { public void sayHello() { System.out.println (“Hello”); } public static void main (String arg[]) { sayHello(); // WRONG! } }//class Test public class Test { public void sayHello() { System.out.println (“Hello”); } public static void main (String arg[]) { sayHello(); // WRONG! } } }//class Test When we create the class Test, there are potentially an infinite number of instances available. Test t1 = new Test(); Test t2 = new Test(); // etc.
INSTANCES CLASS Test t1 = new Test(); t1.x = 5; // should use accessor public class Test { int x; static int y = 2; }//class Test t1 public class Test { int x; // now 5 static int y; // 2 }//class Test static int y; New class instances (objects) get unique copies of every member--except for static or “class” members. We can think of static as meaning “only one copy” Test t2 = new Test(); t2.x = 3; // should use accessor t2 public class Test { int x; // now 3 static int y; // 2 }//class Test static int y;
t1 public class Test { public void sayHello() { System.out.println (“Hello”); } public static void main (String arg[]) { sayHello(); // WRONG! } }//class Test t2 public class Test { public void sayHello() { System.out.println (“Hello”); } public static void main (String arg[]) { sayHello(); // WRONG! } }//class Test So, when Java encounters our class, it sees: * a potentially infinite number of Test instances, each with their own behavior (sayHello() ), and * only one (static) main shared between all the classes
public class Test { public void sayHello() { System.out.println (“Hello”); } public static void main (String arg[]) { sayHello(); // WRONG! } }//class Test Potentially many Only one Thus, the error of making a “static reference to a method” might be understood as a problem of ambiguity. We have not told Java which of the many possible instances of class Test we intend to call “sayHello()” on.
Class vs. Instance Members class test { public void sayHello(){ // etc. etc. } class test { public void sayHello(){ // etc. etc. } class test { public void sayHello(){ // etc. etc. } }//class test }//class test }//class test SHARED BY ALL The “class” or static members are defined for all instances. Every instance has access to static members, and can change them for all other members. INSTANCES CLASS class test { public void sayHello(){ // etc. etc } public static void main (String[] argv) { } }
Solution I public class Test { public void sayHello() { System.out.println (“Hello”); } public static void main (String arg[]) { Test t = new Test(); t.sayHello(); // Corrected } }//class Test One merely needs to resolve this ambiguity to correct the program. Thus, just make an instance of the class, and reference/invoke the object’s members.
Solution 2 public class Test { public static void sayHello() { System.out.println (“Hello”); } public static void main (String arg[]) { sayHello(); // Corrected } }//class Test One merely needs to eliminate this ambiguity to correct the program. Thus, just make the method static.
Warning You will find this course very difficult, if not impossible, if you did not grasp the previous slides. Misuse of static is the second most pernicious bug found in previous courses.
Do you follow this? public class Ouch { int w = 0; static int x = 0; final int y = 0; final static int z = 0; public static void main(String [] args) { Ouch one = new Ouch(); Ouch two = new Ouch(); Ouch three = new Ouch(); // see questions } // main } // Ouch How many w’s are in memory? How many x’s? How many y’s? How many z’s? Are any constant?
Little secrets Class methods and class variables exist and can be used even when *no* objects have been instantiated! Instance methods and instance variables do not exist on their own, but only as part of an instance. Objects can be used to access both class and instance members. Classes can be used to access only class members!
Announcements • Read webpage continuously!You are playing a risky game without it!
Strings vis-a-vis Objects Every String is an instance of Java’s built-in class String. Thus, Strings are objects. Java provides extra support for Strings as a convenience because of the frequency with which Strings are used. (That’s why they can seem like primitives – but they are not.) Three obvious String support features: 1. You need not explicitly instantiate Strings with the ‘new’ keyword. Java automatically instantiates a String object when it encounters a text string within double-quotes. For example . . .
str1 = “Hello World”; box1 = iLn, iWd, iHt; str1box1 Hello World ERROR: must use new “new” and call constructor str1box1 Hello World str1 = “Hello World”; box1 = new Box(iLn, iWd, iHt); iLn, iWd, iHt str2 ?default? str2 = new String(); str2 = “Glib Folksies”; ?default? str2 Glib Folksies Strings vis-a-vis Objects Assignment w/References to Strings/Objects: Code: Memory: String str1; Box box1; str1 box1
Important Digression • Given: • String s = new String(); • How can we be sure of the default behavior? • Remember that thing - the API? Download it! • (http://www.javasoft.com/docs) • Go to class String • Click on constructors • Look for the default one and read it’s documentation • Mystery solved! • Now back to the show…..
Strings vis-a-vis Objects • Again, Java automatically creates a new String object whenever it encounters text within double-quote marks. • Thus, the code: • String str1 = “Hello World”; accomplishes three things: • 1. It creates str1 as a reference to a String. • 2. It creates an instance of a String. 3. It initializes that String to “Hello World”. • This is inconsistent with how Java treats standard objects. • With standard objects, you must explicitly: • instantiate (via new), and • initialize (via a constructor).
String Stuff Three obvious String support features: 1. You need not explicitly instantiate Strings. 2. The ‘+’ operater overloaded for Strings, to supportconcatenation, e.g., System.out.println(“This string is an example of” + “ one that is too long to fit on one line. Your TAs take off points” + “ for lines that exceed 80 column characters.”); 3. Several predefined methods provided in built-in class String. Among them are: length( ) // a string knows its length – note it is a method! charAt(iIndex) // returns letter at position iIndex; 1st char is position 0 substring(iStartIndex) // returns the substring fromposition // iStartIndex to end of string substring(iStartIndex, iEndIndex) // returns substring from position // iStartIndex until but NOT INCLUDING position iEndIndex continued
String Stuff -- Examples 0 1 2 3 4 H e l l o String strExample = “Hello”; char c = strExample.charAt(1); // c gets ‘e’ String strBritishHowdy = strExample.substring(1); strBritishHowdy ---> “ello” String strTemperatureOutside = strExample.substring(0, 4); strTemperatureOutside --> “Hell”
Strings vis-a-vis Objects • Also . . . • One cannot change contents of a String object. (We say: “Strings are immutable”.) • You may think you are modifying a String. But, what happens • in memory is: • a new String is created • you change the String reference to refer to that new one • your old String may be ‘garbage collected’; you no longer • have a reference to the old String • For example: str1 Hello World String str1 = “Hello World” str1 = str1.substring(4) str1 Hello World o World Optional: see class StringBuffer for ways to work around this limitation.
Objects and References: The special case of String Caution: In the next few slides, we will cover what is one of the more confusing parts of Java for CENG217 students. If you get lost, just remember what we’ve covered so far: 1. When comparing primitives (int, float, etc.), use ‘==‘ 2. When comparing objects (String, or any class you create), use the equals() method. 3. When you create a class that serves as a data type or record, remember to include an equals() method. In the slides ahead we will note some rare exceptions where the ‘==‘ comparison will work for objects. (Yes, you can use == to compare objects, but not in all circumstances!) When in doubt, please just follow the principles above.
Objects and References: Review of the normal case Remember the general pattern of our previous example: box1 = new Box(1, 2, 3); box2 = new Box(8, 5, 7);box1 = box2; System.out.println(box1 == box2); // prints true // Does box1 reference the same object that box2 references? System.out.println(box1.equals(box2)); // prints true // Does box1 reference an object that has the same contents// as the object referenced by box2? box1 box2 L=1, W=2, H=3 memory L=8, W=5, H=7
Equality with References to Objects: Strings are special As part of the Java Language Specification (the ‘rules’ for the Java Language), Strings have a special characteristic. It turns out that in some circumstance (BUT NOT ALL), you can use ‘==‘ to compare Strings, in addition to .equals(). Consider: String strHello1 = “Hello”; String strHello2 = “Hello”; We would expect these lines to produce the following memory changes Hello strHello1 strHello2 Hello In fact, it produces the following results in memory: strHello1 strHello2 Hello
Huh? Why are Strings treated differently? Strings are sometimesa special case of equivalency in Java. When the compiler encounters the lines: String strHello1 = “Hello”; String strHello2 = “Hello”; the compiler is smart enough to know that the two Strings are identical. So, it decides it will save a few bytes of memory and point to the same location in memory. The same result would occur even if you wrote: String strHello2 = “Hell” + “o”; This means that for the above lines of code, equals() and ‘==‘ both work: System.out.println (strHello1.equals(strHello2)); // true System.out.println (strHello1 == strHello2); // also true, but // dangerous . . .
Exception to the exception with String But this special case for ‘==‘ comparison of Strings DOES NOT ALWAYS WORK . . . Consider: If one of the Strings were created with use of the ‘new’ keyword, the two Strings would no longer share memory. (That is, ‘==‘ would be false, but equals() would still be true, if the contents of the Strings are the same.) So, there’s an exception to the exception for Strings when you don’t use the String exception to object instantiation. Confusing? Exceptionally so! LESSON: DON’T USE THE EXCEPTION. Don’t compare Strings, or any Object, with ‘==‘, even if you think the exception will apply. REMEMBER: Just compare primitives with ‘==‘, Objects, including Strings, with equals() -- and it always works fine!
toString()or not to String... Debugging:
Debugging Strategies • Incremental Programming: • The Idea: Find and repair bugs “in the small” before you have a program with several components. The hardest thing is finding the errors. So, find them as you create each class. • Thus, donot: • write your entire program, then • type in your entire program, then • attempt to test your entire program • Instead: • design your program at high level, then • focus on one class at a time, • for each class, write and test before going on to the next one. • This way, you deal with bugs when it‘s easiest!
Debugging Strategies • Potential problems with state objects: • State incorrectly modified by modifer methods. • State incorrectly represented by accessor methods. • Need: • A way to see the state of the object. • Means: • public String toString ( ) • Create one “toString” method per class. • Now we can use a reference to an object directly as an argument in: • System.out.println ( );
Debugging Strategies Example of using toString: If we have a method for Class Box: public String toString ( ) { String returnStr; returnStr = new String(“Box: length = “ + iLength + “, Width = “ + iWidth + “height = “ + iHeight); return (returnStr); } // of toString Then we can do: Box subwooferBox = new Box(40, 50, 60); … System.out.println ( subwooferBox ); // what???????? // wait a minute where was the call to “toString”????
Special invocation of toString method • Using an object reference when a String is needed will implicitly invoke the object’s toString method. Bonus! • This is why it is critical that you actually provide a meaningful toString method for practically every class you create. • Excellent for debugging!
Debugging Strategies One “main” per Class • According to Java, you only need one main per program. . . not one per class. • But Java doesn’t know how to program! • To test/debug a class, create a main method for the class as part of the class . . . • Include in “test mains” the: • declaration of variables • the invocation of methods • the generation of output (e.g. using toString()) • that will allow you to see what the class actually does! • Then, invoke the main as part of your testing process. • The main can stay there as part of your class . . . invoked only when you call it for purpose of testing.
What? • Suppose you have class A, class B, and class C; each has a main method for debugging purposes. • Class C has the real main for your overall program, and uses classes A & B. • How can you invoke a particular main? • javac A.java <- compile class A • java A <- invokes A’s main for testing A • javac B.java <- compile class B • java B <- invokes B’s main for testing B • javac C.java < compile class C • java C <- invokes C’s main
Debugging Strategies • Define a boolean constant in every class called DEBUG public static final boolean DEBUG = true; • Wherever appropriate insert... if(DEBUG) System.out.println("method>var = "+var); • Customize as necessary!