0% found this document useful (0 votes)
11 views5 pages

Lab 3 - Prelab Reading

The document discusses key concepts in Java, including classes, inheritance, and the Object class, emphasizing that all classes inherit methods like toString and equals from java.lang.Object. It also explains the differences between references and objects, highlighting the risks of shallow copying, and introduces the concept of immutability, particularly in relation to String and StringBuilder types. Key takeaways include the importance of using equals for reference types and the benefits and drawbacks of immutability in Java.

Uploaded by

adamdiab117
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
11 views5 pages

Lab 3 - Prelab Reading

The document discusses key concepts in Java, including classes, inheritance, and the Object class, emphasizing that all classes inherit methods like toString and equals from java.lang.Object. It also explains the differences between references and objects, highlighting the risks of shallow copying, and introduces the concept of immutability, particularly in relation to String and StringBuilder types. Key takeaways include the importance of using equals for reference types and the benefits and drawbacks of immutability in Java.

Uploaded by

adamdiab117
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
You are on page 1/ 5

CSC245B Lab 3 – Prelab Reading

Spring 2025

1 Classes and Inheritance


In lab 2, you saw an example of a class definition, where a new reference type Book was created. You have also seen an
example usage of the Book type and how objects of type Book can be created using the new keyword.
Another object-oriented functionality in Java is inheritance. In Java, a class can inherit from another class. For example,
we can create a Person class which represents person objects and includes attributes of a person (e.g., name, age), and we
can also create subclasses of Person (classes that inherit the attributes and methods of Person). For example, Student,
Teacher, and Musician can be defined as classes that inherit from the class Person because students, teachers, and musicians
are people, and therefore, they inherit all the attributes of a Person. This is a very brief idea about inheritance; you will
learn about it in detail in later lectures and labs.

1.1 java.lang.Object
For the sake of this week’s lab, you are only required to know that all classes in Java inherit (directly or indirectly) from
the class Object (java.lang.Object), which means that they inherit all the methods defined in this class. Only the class
Object itself does not have a parent class (it is on the top of the inheritance hierarchy).

Examples of methods inherited from java.lang.Object:


• toString(): returns a String representation of the object (called implicitly whenever you print an object or concatenate
it with a String)

• clone(): returns a copy of the object


• equals(Object other): returns whether the self-object (this) is equal to the object passed as argument (other).

When we created the Book class, it automatically inherited all the methods above. To verify that our Book class inherits
the methods in Object, create two Book objects, book1 and book2, then try the following codes:
1 System .out. println ( book1 . toString ()); // equivalent to System .out. print ( book1 )
2 System .out. println ( book1 . equals ( book2 ));

(The clone() method cannot be used directly because it is not public.)

Note (common misconception): when we say that System.out.println(book1.toString()); is equivalent to


System.out.println(book1);, it does not mean that book1 is equivalent to book1.toString()! We are simply saying that the
print method will call toString implicitly.

1.2 Overriding Inherited Methods


It is common to override the default implementations of the inherited methods. Examples:

• toString(): returns a String that is a function of the class name and memory location of the object (try the codes
above). Typically, we would want a different String representation; for example, we might want the book to be
represented by its title and author, rather than by a code that is a function of its memory location.

1
• equals(): by default is equivalent to ==, that is, it returns if the two references are aliases (i.e., if they are pointing to
the same memory location.. more explanation on this in the next section). So even if book1 and book2 have the same
title, author, and publication year, comparing them with equals will return false by default unless they are aliases.
We might want to change (override) this default behavior, and this is what you will do in lab 3.
• clone(): has a default implementation that is good enough, but the method is not public, so we need to override its
visibility to public. In lab 3, you will override the visibility of the clone method, and you will also give your own
implementation for it (although we can reuse the inherited implementation, but this would require additional coding
related to exception handling, which we will not deal with in this lab).

1.3 == vs. equals


• For primitive types (int, double, boolean, etc.), the equality check == checks if the values are equal.
• For reference types (e.g., String or Book), == checks if the objects are aliases (see more explanation in the next section).
• The equals method can only be used with reference types, and as mentioned above, it is equivalent by default to ==:
for example, book1.equals(book2) is equivalent to book1==book2 assuming that the default behavior of equals is not
overridden. However, typically, equals is overridden to compare contents and attributes (not memory locations). For
example, in the String class, the equals method is overridden to compare the String objects based on the sequence of
characters they contain rather than their memory addresses.

Key Takeaways
• All classes in Java inherit directly or indirectly from the Object class, which provides some useful methods like
toString, clone, and equals. We can directly use these methods with their default implementations, or we can
override (i.e., customize) their behavior for our newly created types.
• The proper way of comparison for primitive types (e.g., int, double) is using ==, whereas the proper way of
comparison for reference types (e.g., String, Book) is using the equals method, which is inherited from Object.
By default, i.e., if it is not overridden, equals is equivalent to ==.

2
2 References vs. Objects, and Copying Objects
There is a distinction between references and objects: References “point to” objects in memory, and multiple references can
point to the same object.

2.1 Example
Consider the definitions below from the skeleton of problem 2 in lab 3:
1 Book originalBook = new Book(" Mornings in Jenin ", " Suzan Abulhawa ", 2010) ;
2 Book copiedBook = new Book( originalBook );// copy constructor
3 Book clone = originalBook . clone ();
4 Book shallowCopiedBook = originalBook ; //A shallow copy (alias )

The above lines of code create four references but only three distinct objects in memory. Particularly, shallowCopiedBook
and originalCopy point to the same object; i.e., they are aliases. This is illustrated in Figure 1.

Figure 1: References vs. Objects

2.2 Shallow Copying Risks


We can see from the diagram above that if shallowCopiedBook’s title is changed, then originalBook’s title is also changed,
but copiedBook and clone’s titles are not affected because they are in different memory locations. This demonstrates the risk
of shallow copying using the assignment operator.

Key Takeaways
To safely copy objects, use clone() or a copy constructor or any equivalent copying technique that ensures creating a
new memory location; do not use the assignment operator for copying except in these cases:
1. If it is your intention to create aliases (and you are aware of the consequences)
2. If the copied object is of a primitive type (e.g., int x = 3; int y = x;)

3. If the copied object is of an immutable type (see the next section)

3
3 Immutability
3.1 What is Immutability
The String type in Java is immutable. This means that a String object at a given memory location cannot be mutated,
and even if you attempt to mutate (by concatenating additional characters for example), the contents of the existing memory
location do not change; instead, a new String object (in a new memory location) is created to hold the modified value,
leaving the old location unchanged, as demonstrated in the example of Figure 2.

Figure 2: String concatenation

On the other hand, StringBuilder is another type in Java which is similar to String, but it is mutable; that is,
StringBuilder has methods that mutate the object (at the same memory location), as shown in the example of Figure 3.

Figure 3: StringBuilder concatenation

In both of the examples above, the outcome is “ab”, so what is the difference? Mutability impacts are mainly
seen when multiple references point to the same object in memory. If a mutable object is modified, all aliases are affected,
whereas if it is immutable, then the aliases are not affected, as illustrated in the example below.

Figure 4: Effect of mutations on aliases

3.2 So Which is Better?


Is it better to use the immutable String or the mutable StringBuilder? Answer: it depends!

3.2.1 Advantages of immutability:


• It is safe: immutability allows for avoiding unintended mutations and thus avoiding potential logical/runtime errors.

4
• Because it is safe, we can make many aliases pointing to the same memory location, thus saving memory space: this is
actually used for the String type, where Java keeps a pool of the commonly used String literals to be re-used: when
a String object is created using this syntax: String s = “hello”, if an object “hello” already exists in memory, then
java will typically reuse it where s will be safely made an alias to it (no new object created unnecessarily). On the other
hand, if the String object is created using the new keyword (not recommended): String s = new String(“hello”),
then the creation of a new String object is forced.

3.2.2 Disadvantages of immutability:


• Generally poorer performance (slower running time) when mutations occur. As shown in the examples above, appending
just one character to a String requires copying all the old characters (could be many!) into a new memory location
before appending the new character. This is not needed for StringBuilder where the mutation happens quickly
in-place.

Key Takeaways
Immutability is one way to avoid the risks of shallow copying. For example, you can always copy String objects using
the assignment operator without worrying about the risks of shallow copying. This is because String is immutable and
any changes to one String reference will not really change its content, but rather create a new String and make it point
to it without affecting the old String or any aliases pointing to it.

You might also like

pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy