1 Aliasing and Immutability
Total Page:16
File Type:pdf, Size:1020Kb
Vocabulary: Accessors & Mutators Computer Science and Engineering The Ohio State University Accessor: A method that reads, but never changes, the Aliasing and Immutability (abstract) state of an object Computer Science and Engineering College of Engineering The Ohio State University Concrete representation may change, so long as change is not visible to client eg Lazy initialization Examples: getter methods, toString Lecture 8 Formally: restores “this” Mutator method: A method that may change the (abstract) state of an object Examples: setter methods Formally: updates “this” Constructors not considered mutators A Fixed Epoch Interface A Broken Time Period Class Computer Science and Engineering The Ohio State University Computer Science and Engineering The Ohio State University // Interface cover story goes here public class Period implements FixedEpoch { // Mathematical modeling … private Date start; // constructor private Date end; // requires start date < end date // initializes start and end dates // operations have specifications based on the model public Period(Date start, Date end) { // exercises … this.start = start; this.e nd = e nd; public interface FixedEpoch { } public Date getStart(); public Date getEnd(); } public Date getStart() { return start; } public Date getEnd() { return end; } } Problem: Aliasing A Better Period Class Computer Science and Engineering The Ohio State University Computer Science and Engineering The Ohio State University Assignment in constructor creates an alias public class Period implements FixedEpoch { private Date start; Client and component both have references to the private Date end; same Date object Class invariant can be undermined via alias public Period(Date start, Date end) { this.start = new Date(start.getTime()); Date t1 = new Date(300); this.e nd = neew Date (end.get Tim e()); Date t2 = new Date (500); } Period p = new Period (t1, t2); public Date getStart() { t2.setTime(100); //modifies p’s rep return start; Solution: “defensive copying” } Constructor creates a copy of the arguments public Date getEnd() { Copy is used to initialize the private fields return end; Metaphor: ownership } } 1 Problem 2: Aliasing (Again) A Better+2 Period Class Computer Science and Engineering The Ohio State University Computer Science and Engineering The Ohio State University Return value in accessor creates an alias public class Period implements FixedEpoch { private Date start; Client can still obtain a reference to the class’s private Date end; internal representation (the private fields) aka “privacy leak”, but really just an alias problem public Period(Date start, Date end) { this.start = new Date(start.getTime()); Class invariant can be undermined via alias this.e nd = ne w Date(e n d.getTim e()); Date t1 = new Date(300); } Date t2 = new Date (500); public Date getStart() { Period p = new Period (t1, t2); return new Date(start.getTime()); p.getEnd().setTime(100); //modifies p’s rep } Solution: “defensive copying” public Date getEnd() { Accessors create a copy of internal fields return new Date(end.getTime()); Copy is returned to the client } } Good Practice: Defensive Copies Immutability Computer Science and Engineering The Ohio State University Computer Science and Engineering The Ohio State University Always make defensive copies when An immutable object is one whose (abstract) needed value can never change Problem: Aliases undermine the privacy of a field Constructor allows initialization to different values Solution: Prevent aliases to fields No mutator methods Typical examples Whyyoud would we wa nt su ch a thing ? Parameters in constructors and mutators Because aliasing an immutable is safe! Return value from any method Having multiple references to the same immutable Note: There are some types of fields for is indistinguishable from having multiple which aliasing is never a concern! references to different immutables that have the Fields that are primitive (eg int, float) same value Fields that are enumerations (eg Suit, Colors) Defensive copies of immutables are not required! Fields that are… (next slide) How to Write an Immutable Interf. How to Write an Immutable Class Computer Science and Engineering The Ohio State University Computer Science and Engineering The Ohio State University Do not provide mutators Implement an (immutable) interface Result: no mutators Check alters clause of all methods You do that anyway, right? Make all fields private You do that anyway, right? Ensure exclusive access to any mutable objects referred to by fields Rule: If the class has fields that refer to mutable objects 1. Make defensive copies of parameters in constructors and mutators 2. Make defensive copies for return values from methods Defensive copies not needed for fields that are primitive, enumerations, or refer to immutable objects 2 Examples Good Practice: Immutable Idioms Computer Science and Engineering The Ohio State University Computer Science and Engineering The Ohio State University Period Declare all fields to be final Has fields that refer to mutables (Date) Guarantees immutability for primitives Needs defensive copies Underkill: For reference types, final is no String help Lots of methods look like they could be mutators Still considered an idiom that signals intent eg toUpperC()bCase(), substring (int,int ), to write an immutable class replace(char,char) Overkill: Only abstract state needs to be But these methods actually return a String immutable String str = new String(“Hello there”); Concrete state (ie fields) can change so long str.toUpperCase(); as client-view of object is unchanged System.out.println(str); //surprise Declare class to be “final” Wrapper classes We will talk about what this qualifier Integer, Long, Float, etc… means for classes later A Better+3 Period Class Wrapper Classes Computer Science and Engineering The Ohio State University Computer Science and Engineering The Ohio State University public final class Period implements FixedEpoch { Every primitive type has a corresponding private final Date start; wrapper class private final Date end; Integer, Long, Float, Double, … public Period(Date start, Date end) { The classes are immutable this.start = new Date(start.getTime()); So no aliasing worries this.e nd = ne w Date(e n d.getTim e()); } Do not provide a zero-argument constructor Do provide useful static constants public Date getStart() { Integer.MAX_VALUE, Integer.MIN_VALUE return new Date(start.getTime()); } Do provide useful static methods Converting from String to primitive: parseInt() public Date getEnd() { int i = Integer.parseInt(“33342”); return new Date(end.getTime()); Converting from primitive to String: toString() } } String str = Double.toString(123.99); Boxing and Unboxing Supplemental Reading Computer Science and Engineering The Ohio State University Computer Science and Engineering The Ohio State University Boxing: primitive --> wrapper Bloch’s “Effective Java” Integer integerObject = new Integer(42); Item 13: Favor Immutability Unboxing: wrapper --> primitive int i = integerObject.intValue(); Item 24: Make defensive copies when Java does this automatically for you needed Double price = 499.99; //auto-box IBM devel oper Work s paper price = price + 19.90; //auto-unbox then box “Java theory and practice: To mutate or But be very careful… not to mutate?” Integer i = new Integer(2); Integer j = new Integer(2); http://www.ibm.com/developerworks/java assert (i >= j); //success (unboxing) /library/j-jtp02183.html assert (i <= j); //success (unboxing) assert (i == j); //failure! (no unboxing) 3 Summary Computer Science and Engineering The Ohio State University Defensive copying Copy constructor arguments (reference types) Return only copies of fields (reference types) Immutable interfaces and classes Each instance represents a distinct value No mutators: no methods alter “this” Methods can return a new instance Defensive copying of mutable fields Examples of immutables String Wrapper classes (Integer, Long, Float…) Auto-boxing / auto-unboxing 4.