Object-oriented programming concepts in Java

Objectives

  • Create basic classes in Java
  • Create interfaces in Java
  • Explain inheritance options in Java
  • List and describe the access modifiers available in Java
  • Discuss the differences between inheritance and composition
  • Discuss the difference between static and instance variables
  • Discuss the difference between static and instance methods
  • Explain polymorphism in OOP
  • Explain what overriding a method is
  • Explain what overloading a method is
  • Use classes in Java to solve problems

Classes

  • Creating classes lesson from Oracle's "Learning the Java Language" tutorial
  • class vs. object:
    • Every object in Java has a class that defines its data and behavior.
    • A class is equivalent to a blueprint.
    • An object is an instance (realization) of a class.
    • The keyword new is used to create objects in Java.
    • Creating an object from a class is called instantiation.
    • There may be many objects created from a single class.
    • Members of an object are referenced using an object reference, a period, and the member name: car.getMileage()
    • Members of a class are referenced using a class name, a period, and the member name: Car.getNumberOfCarObjects()
  • If you compile a class that requires another class, the Java compiler will try to automatically find it and use it. That requires that the required classes be either in the same directory as the program you are compiling or in a classpath the compiler is using. The compiler will automatically try to compile source files if it can not find the compiled class files that it needs.
  • Java is designed to organize development into "packages." Packages are roughly equivalent to folders or directories. Related files for a project are separated into functional packages and the code that needs them uses appropriate import statements and compiler switches to access those packages.

Variables

  • scope: Variables are visible within the code block they are declared in (after they are declared).
  • lifetime: Local variables come into existence when a method starts running and cease to exist when a method finishes running.
  • Variables may be declared within methods or may be declared outside of all the methods in a class.
  • Variables declared outside of all methods in a class are visible to all of the methods in that class, and are often called fields, class-level variables, or even global variables.
  • Variables declared outside of all methods in a class may have an access modifier to specify what code has access to the variable.
  • final: The keyword final is used in variable declarations to specify that a variable is a constant and can not be modified after it is declared and initialized.
  • static (class) vs. instance variables: Static (class) variables are those variables declared outside of any method which use the keyword static. There is only a single copy of each static variable. It is created when the class is loaded. All objects made from that class share that same variable. Instance variables are those variables which are declared outside of any method, and which do not use the keyword static. Each object has its own copy of each instance variable. The instance variables are created as the objects they belong to are created.
  • The only thing you have to do with an object when you are done using it is to stop referencing it - Java will take care of reclaiming the memory.
  • Within an object, the this reference refers to the object itself.
  • The this reference is used within an object's methods to refer to itself.
  • All static and instance variables are automatically initialized: 0 for integers, 0.0 for floats, false for booleans, and null for object references.
  • Local variables inside methods are not initialized automatically.

Methods

  • constructors: Called when an object is being instantiated from the class.
    • A constructor looks like a method, but it has the same name as the class and no return data type.
    • A default constructor has no arguments.
    • A default constructor is automatically provided by Java if (and only if) no constructors have been specified in the source code.
    • The first statement in a constructor is a call to its superclass constructor. Since the name of the superclass can not be used, the keyword super() is used.
    • Problems can arise when the superclass has no default constructor, but Java automatically inserts a call to the default superclass constructor. The solution is to make the very first statement in your constructor a call to the appropriate superclass constructor.
    • Constructors are usually used to set instance variables and set up other resources.
    • Constructors in a class can call each other using the this keyword.
  • predicate methods: Return true or false; usually of form: isEmpty()
  • accessor (getter) methods: Return values of fields in object; usually of form: getName()
  • mutator (setter) methods: Used to set values of fields in object; usually of form: setName()
  • toString(): Used automatically in concatenation and by System.out.print. Great for debugging purposes. This is a method you want to write (override) as the one inherited from the base Object class doesn't provide very useful information.
  • destructor
    • There is only one destructor per class in Java
    • Destructors in Java don't function the same as destructors in C++
    • Since Java takes care of reclaiming memory from unused objects, the purpose of a destructor in Java is to release any other (non-Java) resources that might not otherwise get released automatically (such as network connections)
    • The destructor in Java has the following signature: rotected void finalize() throws Throwable
    • The finalize method is called before an object is destroyed in Java, except that objects not yet destroyed at the end of execution will have their destructor calls skipped.
    • A call to System.gc() suggests to the JVM that it should work on reclaiming unused memory, but there are no guarantees, and finalize() methods may not be called at this point
    • A call to System.runFinalizersOnExit(true) makes sure that the finalize() methods of all remaining objects are called when the application is ending execution. This method has a serious problem and has been deprecated.
    • A call to System.runFinalization() suggests to the JVM that it should run the finalize() method of all objects no longer used, but which haven't yet had finalize() called. This call is equivalent to Runtime.getRuntime().runFinalization()
    • To really make sure that the finalize() methods of all objects are called before the JVM shuts down, you can add an initialized, but unstarted thread to the shutdown procedure using Runtime.addShutdownHook(Thread)
  • static (class) vs. instance methods: Static methods use the keyword static. Instance methods are those methods which do not use the keyword static. Static methods do not have access to instance variables since those variables may not even exist when a static method is called. Instance methods are automatically given a reference (the "this" pointer) to the object that they are called on. That reference allows instance methods access to the instance variables of that object. You can call static methods of a class even if no objects have been created from that class. You can only call instance methods when referencing an object of the appropriate class.
  • There is only one copy of a method's code whether it is static or not. The difference is that instance methods receive a copy of the this pointer, while static methods do not. This means that only instance methods can access instance variables directly.

Interface

  • An interface is like a class except that it may only contain public abstract methods and public static final fields.
  • Because the members must be public, there is no requirement to specify it.
  • Because data members must be static and final, there is no need to specify it.
  • Because methods must be abstract, there is no need to specify it.
  • There is no "root" interface such as the "root" class Object for classes.
  • An interface may extend as many interfaces as desired.
  • Interfaces also don't implement other interfaces.
  • If you have programmed a GUI in Java, you have almost certainly used an interface such as WindowListener, ActionListener, MouseListener, etc.
  • Interfaces are like contracts that enforce any class that implements them to define all the methods described in the interface.
  • Classes may implement as many interfaces as desired.

Accessibility modifiers

  • public: Accessible to everything.
  • private: Accessible only to members of the same class.
  • protected: Accessible to members of the same class, subclasses, and other classes in the same package.
  • (default/package): Accessible to members of the same class and other classes in the same package.

Inheritance

  • A class can incorporate all of the data and methods from another class by extending it using the extends keyword.
  • Classes may extend only one other class.
  • If a class does not explicitly extend another class, then Java will automatically make the class extend the Object class.
  • Extending a class is known as subclassing.
  • A subclass is also called a derived class.
  • The class that is being extended is known as the superclass.
  • A superclass is also called a base class.
  • A subclass inherits the fields and methods of its superclass.
  • Inheritance implements an "is-a" relationship, such as "a bathroom is a room" (bathroom extends room).

Composition

  • Composition is when an object contains another object as one of its member fields.
  • Composition implements a "has-a" relationship, such as "a bathroom has a bathtub" (bathroom contains a bathub instance).

Method overloading, overriding, and final methods

  • Overloading is when multiple methods in a class have the same name, but different parameter lists (they may also have different return data types).
  • Overriding is when a subclass replaces an inherited method with another method of the same name and signature.
  • You can not reduce access to an overridden method in an extended class (you can make a protected method public, but not vice versa).
  • A method might not be implemented. If this is the case, there will be no method body. Such a method must be declared to be "abstract"
  • A class which has at least one abstract method must also be declared to be "abstract", and no objects may be instantiated from that class.
  • Methods marked as "final" can not be overridden.
  • On a side note, "final" classes can not be subclassed.

Polymorphism

  • Polymorphism gives us the ability to treat objects of different classes as if they are of the same class.
  • Objects can be referred to by reference variables of their superclasses, so any object can be referred to by the following variable: Object obj;

Advanced object/class concepts (optional)

  • You can include static initialization code blocks within a class, but outside of any methods; they are run when the class is first loaded.
  • You can include instance initialization code blocks within a class, but outside of any methods; they are run whenever an object is instantiated.
  • Objects are stored in a memory pool known as the heap.
  • Equality
    • The == operator tests for value equality with primitive data types, but identity equality with object references.
    • Identity equality means that two references refer to the exact same object, but does NOT tell you if two different objects are equivalent.
    • The equals method (inherited from Object) is used to test for equivalence and should be overridden.
    • Note the method signature: public boolean equals(Object obj);
    • A common mistake is to not use the Object data type for the parameter.
    • The hashCode() method usually has to be overridden whenever equals(Object) is overridden because hashCode() is required to return the same hashcode whenever two objects are equivalent, but the default inherited implementation will return different hashcodes for different objects (usually based on the internal addresses of the objects).
    • See the Java documentation for the equals(Object) method of Object to see the rules for overriding equals(Object)
  • Copying objects
    • All objects inherit (from Object): protected Object clone();
    • clone() creates a new object using a "shallow" copy.
    • Shallow copies do not create new objects for object references within the object being copied, but just copy the reference itself, which means any referenced objects become shared between the clones.
    • If you want to implement deep copying, then write a copy constructor that performs the task.
    • It is generally discouraged to override the clone method to provide deep copying.
    • Copy constructors can use any mix of shallow and deep copying depending on your needs.
  • Disposing of objects and finalize()
    • Note: This material is also covered above in the "Methods", "destructor" section.
    • Objects are automatically garbage collected when no more references to them exist.
    • You have no guarantee of when the garbage collector will run.
    • System.gc() is supposed to run the garbage collector immediately.
    • The garbage collector runs in a separate thread, so you can't guarantee timing.
    • The garbage collector calls the finalize() method of objects just before they are deleted if program is still running.
    • If program has ended, the finalize() method of objects are not called.

Demonstration programs available:

  • Basic class concepts
  • Class, interface, inheritance, composition demonstration:
    • Drawable.java: an interface that contracts for a draw method
    • Point.java: a simple class that specifies a point on a 2D grid
    • Shape.java: an abstract class the implements Drawable, and contains a Point
    • Circle.java: a subclass of Shape that implements Shape's abstract methods
    • Rectangle.java: a subclass of Shape that implements Shape's abstract methods
    • TestShapes.java: an Applet that tests out the classes and interface used for this demonstration; also demonstrates polymorphism
    • TestShapes2.java: the JApplet version of TestShapes.java
  • Advanced concepts