Week 2 - Fundamental OOP Principles
Fundamental Object Oriented Principles¶
The Beginning
Encapsulation¶
Definitions
Encapsulation: Group single responsibilities and make sure sensitive data is hidden from users.
Below are the important things to remember about encapsulation:
- Private access modifiers should be used to protect instance variables you don’t wish to change outside the class
- Getters and Setters should be used to protect how objects interact with sensitive data and variables.
- Encapsulation provides access control like R, W, or RW
- Flexible: Proper encapsulation means developers won’t inadvertently change encapsulated code while working on another piece of code that utilizes it.
Inheritance¶
Definitions
Inheritance: Share/inherit instance variables/attributes/fields and methods from superclass (parent) to subclass (child). The child inherits attributes and methods from the parent.
Below are the important things to remember about inheritance:
- Every Java class extends the class Object
- Which means that every class we create inherits all the methods defined in the Object class (e.g. equals, hashCode, …)
-note
Here are all the methods that a Java class inherits from the Object class, which is the ROOT object hierarchy:
public final native Class<?> getClass()
: Returns the runtime class of this Object.public native int hashCode()
: Returns a hash code value for the object.public boolean equals(Object obj)
: Indicates whether some other object is “equal to” this one.protected native Object clone() throws CloneNotSupportedException
: Creates and returns a copy of this object.public String toString()
: Returns a string representation of the object.public final native void notify()
: Wakes up a single thread that is waiting on this object’s monitor.public final native void notifyAll()
: Wakes up all threads that are waiting on this object’s monitor.public final native void wait(long timeout) throws InterruptedException
: Causes the current thread to wait until either another thread invokes thenotify()
method or thenotifyAll()
method for this object, or a specified amount of time has elapsed.public final void wait(long timeout, int nanos) throws InterruptedException
: Causes the current thread to wait until another thread invokes thenotify()
method or thenotifyAll()
method for this object, or a specified amount of time has elapsed.public final void wait() throws InterruptedException
: Causes the current thread to wait until another thread invokes thenotify()
method or thenotifyAll()
method for this object.protected void finalize() throws Throwable
: Called by the garbage collector on an object when garbage collection determines that there are no more references to the object.public boolean equals(Object obj)
: Compares this object to the specified object. The default implementation is based on reference equality (==
).
- To inherit from a class, you must extend it (i.e.
public class Engine extends Part
). - Java can only inherit/extend a single parent (i.e. no multiple inheritance).
- Only public and protected methods can be inherited.
- So if a method should be private but inheritable, it should be protected
- To change inherited methods, they must be overridden by defining a new implementation in the child/subclass
- Mark a class final (i.e.
final class SomeClass { ... }
) if you don’t want it to be inherited. - Actual type of an object/instance dictates which method is executed (Show display from week 1 again).
- If the class to be created is a special case of an existing class, inheritance is OK
- If you notice that inheriting adds more responsibilities to a class, you should form multiple classes of the class. There should only be one reason for each class to change (Single Responsibility Principle).
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 |
|
1 2 3 4 5 6 7 8 9 10 11 12 |
|
Abstraction¶
Definitions
Abstraction: The process of hiding certain details and showing only essential information to the user.
We’ve already talked about using methods to encapsulate and abstract algorithms, but abstraction in OOP is more broad, and can be accomplished with two different Java constructs: Abstract classes and Interfaces.
Abstraction should be used frequently in APIs and libraries to hide implementation details that would only create complexity for the consumers of the API or library or to achieve class security by hiding instance variables or methods that the API/library designers know changing would change or alter desired functionality.
Abstract Class¶
Definitions
Abstract class: A class that cannot be used to create objects because only some of the instance methods are implemented (i.e. not empty).
Below are the important things to remember about Abstract Classes:
- They are defined by public abstract class …
- Useful when there exists a clear concept, but that concept is not a good candidate for an object in itself.
- They can contain normal implemented methods (usually methods common to concept).
- Abstract methods are defined public abstract void methodName();
- They must be inherited from another class, and the abstract methods (i.e. empty methods / method signatures) must be implemented to create objects.
- Inheritance is used to implement Abstract classes.
- Unlike Interfaces, Abstract Classes can contain Object/Instance variables and Constructors
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
|
Interface¶
Definitions
Interface: A completely abstract class, meaning all method bodies are empty (i.e. not implemented). Interfaces define behavior (i.e. actions, verbs, methods) that are required from a class without implementing those behaviors (i.e. methods).
Below are the important things to remember about Interfaces:
- They’re defined the same way that regular Java classes are, but public interface … is used instead of public class …
- An Interface Is a Contract of behavior (i.e. methods)
- Interfaces define behavior through method names and their return values (AKA method signatures).
- Interfaces are always abstract and public, so access modifiers are sometimes omitted.
- Interface attributes/fields are by default public, static and final
- An interface cannot contain a constructor because it cannot be used to create objects
- Interfaces must be implemented (kinda like inherited), but uses implements instead of extends.
- On implementation of an interface, you must override all of its methods.
- You can implement multiple interfaces in one class.
1 2 3 4 |
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 |
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 |
|
Polymorphism¶
Definitions
Polymorphism: The concept that many related classes can perform a single action in many different ways.
Regardless of the type of the variable, the method that is executed is always chosen based on the actual type of the object. Objects are polymorphic, which means that they can be used via many different variable types (i.e. Dog -> Animal -> Object). The executed method always relates to the actual type of the object. This phenomenon is called polymorphism.
Below are the important things to remember about Polymorphism:
- Polymorphism arises through inheritance when multiple related classes share common actions/methods, but those methods do different things.
- It is useful for code reuse of existing class methods and attributes.
- Objects/instances can be represented through all of its actual types.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 |
|
Example of Polymorphism: Actual Type Dictates Action¶
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 |
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 |
|
Walkthrough of Actual object Type Affecting Action (i.e. Polymorphism)
- A call of toString in the class Point3D does not exist, so the superclass is next to be examined.
- A call of toString in the superclass point is found, so the code inside the implementation of that method is executed
- So the exact code to be executed is
return "("+this.location()+") distance "+this.manhattanDistanceFromOrigin();
- The method
location
is executed first - Look for a definition of
location
in the class Point3D. It can be found, so its code is executed. - This
location
calls thelocation
of the superclass to calculate the result. - Next we look for a definition of
manhattanDistanceFromOrigin
in the Point3D class. It’s found and its code is then executed. - Again, the method calls the similarly named method of the superclass during its execution.
- So the exact code to be executed is