EECE 310: Software Engineering Lecture 2: Understanding Objects in Java and Types Why Java ? • Automated memory management • Strong type safety for security • Portability through VM • No legacy baggage of C • Excellent in-built libraries for networking/graphics 2 Brief history of Java … • Developed by James Gosling at Sun in 1995 – Initially code-named ‘Oak’, was meant to target small, embedded devices (such as microwaves) – Became popular with the growth of WWW – Netscape had support for Applets – Mature alternative to C/C++ by late nineties – MS develops C# as alternative to Java (early 2000) – Today: Java used mainly in server/business apps 3 Learning Objectives • Differentiate between objects on stack and heap and understand garbage collection • Understand differences between mutable and immutable objects and Java calling semantics • Define apparent types and actual types and identify them for various statements • Identify implicit type conversions in Java and overloading 4 Objects and Variables • Local variables – Confined to single context: allocated on stack – Primitive types such as int or object references – Must be initialized before use (or fail compilation) • Objects – Shared among multiple procedure contexts – Allocated on heap using new operator – Can be initialized after creation (by constructor) 5 Variables and Objects: Example int i = 6; int j; int [] a = {1, 3, 5, 7, 9}; int [] b = new int[3]; String s = “abcdef”; String t = null; j = i; b = a; t = s; heap i=6 1 3 5 7 9 j =j 6 a 0 0 0 b s “abcdef” t = tnull Stack 6 Object references • All object references are uninitialized initially – Can be initialized to null, but not necessary • Need to explicitly allocate the object on the heap or assign it to (the start of ) an existing object – No pointer arithmetic possible once assigned – No need to explicitly de-allocate the reference (garbage collection frees it when not in use) • Can be passed to procedures and copied around 7 Example of Objects and References { Reference b is allocated on stack and initialized to null Object b = null; { Reference a is allocated on stack Object a Object is allocated on the heap = new Object(); and reference a points to it b = a; b and a both point to the same object a goes out of scope, so only b points to object } c = b.hashCode(); } b goes out of scope too, so nobody points to the object. Object is automatically reclaimed by garbage collector 8 Learning Objectives • Differentiate between objects on stack and heap and understand garbage collection • Understand differences between mutable and immutable objects and Java calling semantics • Define apparent types and actual types and identify them for various statements • Identify implicit type conversions in Java and overloading 9 Object Mutability • By default, Java objects are mutable – Modifications made through one reference will be visible when the object is accessed through another reference to the object • Example: Arrays – int [] a = {1, 3, 5, 7, 9}; – a[3] = -1; – b = a; – b[4] = -2; 1 3 5 -1 7 -2 9 10 Exception: Immutable objects • State of immutable object never changes once it is assigned • Example: String object String s1 = “abcdef”; String s2 = “ghij”; String s3 = s1; s3 = s1 + s2; String s4 = s3; s4 = s2 + s1; “abcdef” “ghij” “abcdefghij” “ghijabcdef” Heap 11 Group Activity: Try it yourself What happens after these ? int[ ] a = {1, 2, 3}; int[ ] b = new int[2]; int[] c = a; int x = c[0]; b[0] = x; a[1] = 6; x = b[1]; int y = a[1]; What happens after these ? String s1 = “ace”; String s2 = “f”; String s3 = s1; String s4 = s3 + s2; s1 = s4; s4 = s1 + s2; 12 Java Calling Convention • Some textbooks will say the following – In Java, Objects are passed by reference, and primitives are passed by value… […] • This is wrong ! Java has only call-by-value – Both primitive types and object references are passed by value i.e., copied in to the stack frame – Can modify the object through the passed in reference provided object is not immutable 13 Calling convention: Call-by-value void foo(int a, int[] b) { a = a + 1; b[0] = 3; } int[] q = new int[3]; int p = 10; foo (p, q); // What are p and q’s value ? stack heap a = 11 10 b 0 3 0 0 p= 10 q 14 Method calls in Java – Example 1 public static void swap(int a, int b) { int temp = a; a = b; b = temp; } m = 5; n = 10; swap(m, n); // What are the values of m and n here ? // (HINT: It’s not what you expect) 15 Method calls in Java – Example 2 public static void findAndRemove(int[ ] a, int m) { if (a ==null) return; // avoid null pointer exception for (int i = 0; i < a.length; ++i) { if (a[i]==m) a[i] = 0; } } int[ ] b = { 0, 2, 4, 6, 8 }; findAndRemove( b, 2 ); // What is the value of the array b here ? 16 Method calls in Java: Example 3 public static void padChars(StringBuffer s, int n) { for (int i = 0; i < n; i++) s.append(‘a’); } String str = “hello”; padChars(str, 5); // What is the value of str ? 17 Learning Objectives • Differentiate between objects on stack and heap and understand garbage collection • Understand differences between mutable and immutable objects and Java calling semantics • Define apparent types and actual types and identify them for various statements • Identify implicit type conversions in Java and overloading 18 Type Safety • Java is strongly typed (i.e., type-safe) – No “unsafe” casts are possible (e.g., reference to int) – Type-safety enforced by compiler (by language design) • Memory safety follows from type-safety – No writing past the end of an object (buffer overflows) – Automatic garbage collection provided by runtime, so no explicit frees or dangling pointers 19 Type Checking • Consider the following function: public static void findAndRemove(int[] a, int m); The compiler checks the call-site of the function to ensure that it matches its type-signature. int[] b = [0, 2, 4, 8, 10]; int n = 5; String s = “hello”; findAndRemove(b, n); // Is this legal ? findAndRemove(n, b); // What about this ? findAndRemove(s, n); // Ok, what about this ? 20 Type Hierarchy • Consider a type S which is a sub-type of T (say S is derived from T). Now, S can be substituted in place of T whenever a function expects T. • Example: All objects in Java are sub-types of Object, which defines an equals method. String s1 = “hello; Object 01 = s1; if ( 01.equals(“hello”) ) ….; // legal if ( O1.length() ) …. ; // illegal 21 Apparent vs. Actual type • Apparent type -- the type inferred from declarations • Actual type -- the type received at (object) creation • NOTE: Apparent type is a super-type of the actual type Statement Apparent type Actual type String s = “abcdef”; String String Object o = s; Object String s = o; Illegal ! s = (String)o; String String int [] a = {0, 1, 2}; Int[] Int[] o = a; Object int[] a [2] = 3; Int Int 22 Group Activity • Which of the following will compile ? For the ones that will compile, determine the result (or exception thrown) Object o = “abc”; Boolean b = new Boolean( o.equals(“a, b, c”) ); char c = o.charAt(1); Object o2 = b; String s = o; String t = (String) o; String u = (String) o2; char d = t.charAt(1); 23 Learning Objectives • Differentiate between objects on stack and heap and understand garbage collection • Understand differences between mutable and immutable objects and Java calling semantics • Define apparent types and actual types and identify them for various statements • Identify implicit type conversions in Java and overloading 24 Type Conversions • Type-checking is done using the apparent type of an object, NOT its actual type – If the actual type supports a member function, but the apparent type does not, it is ILLEGAL to invoke the member directly • However, if we cast the apparent type of an object to its actual type, we can invoke its member functions String s1 = “hello; Object O1 = s1; if ( ( (String)O1 ).length() ) …. ; // legal NOTE: If the actual type of the object does not match the cast type, a runtime exception is raised (ClassCastException) Example: (Integer)(O1) will raise a runtime exception 25 Type overloading • Same function can have multiple definitions based on argument types and/or return value – static int compare(int, float); – static int compare(float, float); – static int compare(float, int); // defn 1 // defn 2 // defn 3 • The compiler “knows” which definition to call depending on the type of the parameters – compare(5.0, 3); // Calls defn 3 – compare(5.0, 6.0); // Calls defn 2 – compare(3, 5.0); // Calls defn 1 26 Implicit Type Conversions • Often, the compiler will implicitly convert one primitive type to another (widening) – int => float – int => long – But long => int, float=>int NOT possible • So which version of compare do these call ? – compare(3, 5.0); // Definition 1 or Definition 2 ? – compare(5.0, 6); // Definition 2 or Definition 3 ? 27 Matching Rule for Implicit Conversions • “Most specific” method – Find the method that matches the types of the parameters with the least number of type conversions – Example: • compare(3, 5.0); // Calls definition 1 • compare(5.0, 3.0); // Calls definition 2 • compare(3, 4); // What about this one ? – NO “most specific method” compilation error • Can be avoided by explicit type-casting in the call such as compare(3, (float)4 ); 28 Learning Objectives • Differentiate between objects on stack and heap and understand garbage collection • Understand differences between mutable and immutable objects and Java calling semantics • Define apparent types and actual types and identify them for various statements • Identify implicit type conversions in Java and overloading 29 Before the next class • Do exercises 2.1 to 2.7 in textbook for practice – Not graded, but will help in quiz preparation • Get acquainted with Java – Pick a partner by end of this week (or we’ll pick one) • Start working on Assignment 1 – Will involve basic Java programming – Due 3 weeks from today on your specific lab session 30