# Java: OOP Summary

Objects
  - All objects are allocated on the heap.
  - Objects consist of instance fields for the class of the object, plus instance fields for its superclasses.
  - Every object is created by a class constructor. Interfaces don't have constructors.
Reference variables
  - All non-primitive variables contain only references to objects on the heap. They never contain the object. C++ object variables may be either, but Java supports only object references.
Assignment
  - Reference variable assignment is fast because only the reference is copied (currently 4 bytes).
  - Making a copy of an object requires using `clone()`.
  - Assigning up the inheritance hierarchy is always possible without a cast. (is-a is obvious)
  - Assigning down the inheritance hierarchy is only possible with a cast. Downcasting makes a run-time check to be sure it's legal. (is-a is possible)
  - Assignment to an interface type variable from a reference type implements that interface is possible without a cast. (is-a is obvious).
  - Assignment to an interface type variable from a reference type that does not implement that interface requires an explicit cast which causes a run-time check to make sure that the object's class really does implement this interface. (is-a is possible)
  - `null` can be assigned to any reference type.
Inheritance and interfaces
  - Every class has one superclass, except Object, which is the root class for all other classes.
  - A class may implement many interfaces, but extend only one class.
Overriding and polymorphism
  - Methods (non-final) may be redefined in a subclass.
  - The `@Override` annotation provides compiler checking.
  - Polymorphism: When a method is called, the overridden method corresponding to the actual object type is called, regardless of reference variable type.
Generics
  - Generics add compile-time checking and documentation.
  - Java uses type erasure so generic types are actually implmented as Object.
Terminology
  - Superclass - subclass. Parent class - child class. Base class - derived class.
  - Overloading is reusing method names with different parameters.
Interfaces
  - Interfaces list methods that implementing classes must define.
  - Interfaces have no constructors.
Static variables
  - There is only one copy of a static variable, not one per object.
Constructors
  - A default no-parameter constructor is created automatically when no constructor is defined.
  - If you define any constructor, no default constructor is created.
  - Constructor chaining. The first statement of a constructor is either a call to another constructor in the same class using `this`, or a call to the super class constructor using `super`. If not called explicitly, a call to the no-parameter super constructor is inserted by the compiler.
Inner classes
  - A class that is defined inside another class is called an inner class. There are four kinds of inner classes, but only two are commonly used: named inner classes, which are members of the outer class, and anonymous inner classes which are created in a code block (eg, in a method).
  - Typical use: An inner class is commonly used for listeners, comparators, and other interface implementations as an easy way to provide an object with the required methods.
  - Advantage: An inner class can access the outer class's instance variable. For example, this lets an inner class button listener refer to GUI text fields, etc.
  - Two common kinds: named inner classes, and anonymous inner classes.
  - Named inner classes
    - Defined within the outer class.
    - May extend any class.
    - May implement many interfaces.
    - May have constructors like any normal class.
    - May reference the enclosing classes instance variables.
  - Anonymous inner classes
    - Defined inside a method.
    - Subclass of Object.
    - Implement exactly one interface.
    - Are instantiated at the point of definition.
    - No constructor.
    - Have names created by the compiler. Usually have a $ in them.
Casting

  Casting an object reference is necessary when the compiler can't tell that the actual object is of the needed type. The cast creates a runtime check to make sure. There are two cases where a cast is required:

  - To cast down the inheritance hierarchy. For example,

          Object ob = "abc";      // No cast needed to assign up hierarchy.
          String s = ob;          // BAD. Requires a cast
          String s = (String)ob;  // Required.

    All Strings are Objects, but not all Objects are Strings.

  - To cast from an interface type to a class type. (String implements Comparable)

          Comparable com = "def"; // No cast to assign to implemented interface
          String s = com;         // BAD. Requires a cast.
          String s = (String)com; // Required.

    All Strings are Comparables, but not all Comparables are Strings.