More Implications of Inheritance COMP 204 Bernhard Pfahringer
More Implications of Inheritance COMP 204, Bernhard Pfahringer
Immutable objects n n cannot be changed after “construction” how to: n do not allow modification by not providing “mutators” (methods that change state) n making data fields “private” (always good idea) n (most likely) prevent against subclassing useful for “value” types, like Integer, String, and so on; safe to use as keys for Hash. Maps (see code example for explanation) hash. Code “rule”: n a. equals(b) == true => a. hash. Code() == b. hash. Code() [only this direction, different objects can have the same hash. Code]
Object construction n no explicit constructor: system adds “default constructor”: n n n public A() { super(); } At least one constructor given explicitly: no “default constructor” will be added first line in the constructor can explicitly pass on to constructor of the super-class or same class (if not, system will add “super(); ”) n n public A() { super(“info”); /* more code */ } public A() { this(0); /* more code */ }
Construction order n n Data fields are allocated and initialized to default values (0, null, …) *before any* code blocks or constructors; Then the process is top-down (most general class first to most specific last), each time: n n n Data fields are initialized to their actual values (e. g. 1 in the code example), in order Local code blocks are run, in order The respective constructor is run
Bad Inheritance example import java. util. *; public class Instrumented. Array. List extends Array. List { // The number of attempted element additions private int add. Count = 0; public Instrumented. Array. List() { } public Instrumented. Array. List(Collection c) { super(c); } public Instrumented. Array. List(int initial. Capacity) { super(initial. Capacity); }
cont. public void add(int index, Object o) { add. Count++; super. add(index, o); } public boolean add. All(Collection c) { add. Count += c. size(); return super. add. All(c); } public int get. Add. Count() { return add. Count; } public static void main(String[] args) {� Instrumented. Array. List s = new Instrumented. Array. List(); s. add. All(Arrays. as. List(new String[] {”A", ”B", ”C"})); System. out. println(s. get. Add. Count()); } }
Better: use Composition import java. util. *; public class Instrumented. List implements List { private final List s; private int add. Count = 0; public Instrumented. List(List s) { this. s = s; } public void add(int index, Object o) { add. Count++; s. add(index, o); } public boolean add. All(Collection c) { add. Count += c. size(); return s. add. All(c); }
Composition, cont. public int get. Add. Count() { return add. Count; } // plus all necessary forwarding methods public void clear() { s. clear(); } public boolean contains(Object o) { return s. contains(o); } public boolean is. Empty() { return s. is. Empty(); } … and so on …
Utilities: Arrays class, Collections n lots of useful utilities, have a look at the Javadoc, e. g. n Arrays. sort(…) n Arrays. binary. Search(. . ) n Arrays. to. String(. . ) n Arrays. fill(. . ) n Arrays. hash. Code(. . ) n Arrays. equals(. . ) n Arrays. as. List(. . ) n Arrays. deep. Equals(. . ), deep. To. String(. . ) deep. Hash. Code(. . ) n Collections. shuffle(. . )
Utilities: System class n again lots of useful utilities, have a look at the Javadoc, e. g. n System. arraycopy(. . ) n System. nano. Time() n System. identity. Hash. Code(. . ) n System. getenv(. . ) n …
- Slides: 10