Java

Skipped: Recursion

Lecture Notes

Source Code: '.java' files you write source code in.

Java is a statically-typed language (must assign type to variable in declaration; variables can't switch types)

Portable 'byte' Code: the compiler (javac) generates byte code in a ‘.class’ file which can be run on any Java Virtual Machine (JVM). JVM efficiently interprets* byte code in the .class file into native machine code (binary) and executes it.

The Java Platform consists of 2 parts:

  1. JVM

  2. Java API (huge library of handy software packages that programmers can use)

When running Java Programs:

  • javac filename.java = compile code.

    • The compiler (javac) generates the '.class' file which contains instructions for the JVM.

    • '.class' files contain 'byte code' which you can't edit

  • java filename.java = execute code

Create 1 Folder per program as to organize and group the .class files to their corresponding .java files.

In Java, every statement must end in a semicolon.

Integer Division and Remainder

  • When integers divide into each other, the result is an integer.

  • Integer division loses all fractional parts of the result and does not round.

    int result = 7 / 4; // 1 from 1.75

The Main Method

  • The main() method is required and you will see it in every Java program. Any code inside the main() method will be executed.

  • Remember that every Java program has a class name which must match the filename, and that every program must contain the main() method.


Comments

Single-line: // comment

Multi-line: /* comment */


Formatting with printf()

neat shortcut in printing instead of print() and println()

Syntax

​ Formatters: ​ %d - int ​ %f - double ​ %.2f - 2 decimals places after period (3.141592653589 -> 3.14) ​ %c - char ​ %s - string ​ %b - boolean ​ %n - newline


Variables

Variables are containers for storing data values, and there are different types of variables:

Variable Declaration

  • declaring a variable means specifying a variable name and its data type.

Variable Initialization

  • initializing a variable means assigning a value to the variable.

(Note that if you assign a new value to an existing variable, it will overwrite the previous value.)

Final Variable Types

  • When a variable is defined with the reserved word final, its value can never be changed.

  • It is customary (not required) to use all UPPER_CASE letters for constants (easy to pick out constants in the code)

Variable Scope

  • Local Scope - variables declared and only existing inside methods ie. formal parameter variables.

  • Block Scope - variables decalred and only existing within their parent { }'s.

  • Global Scope - variables which can be used and changed by code anywhere.

General rules for variable naming:

  • can contain letters, digits, underscores, and dollar signs

  • must begin with a letter

  • snakeCase

  • can also begin with $ and _

  • are case sensitive

  • Reserved words cannot be used as names


Data Types

  • Data types are divided into two groups:

  1. Primitive data types

    • specifies the size & type of variable values, and has no additional methods.

    • int

      • whole numbers between -2,147,483,647 (Integer.MIN_VALUE) and +2,147,483,647 (Integer.MAX_VALUE). Use long/short outside this range.

      • Whole number

    • float

      • The single-precision floating-point type with about 7 decimal digits and a range of about +/- 1e38.

    • double

      • The double-precision floating-point type, with about 15 decimal digits and a range of about +/- 1e308.

    • short

      • The short integer type with range -32,768 ... +32767.

      • Whole number

    • long

      • The long integer type with about 19 decimal digits.

      • Whole number

    • byte

      • The type describing a byte consisting of 8 bits, with range -128 ... 127

      • Whole number

    • char

      • The character type representing code units in Unicode

      • Characters (no math)

    • boolean

      • True or False

  2. Reference data types

    • are called reference types because they refer to objects.

    • Class, object, array, string, and interface

The main differences between the two:

  • Primitive types are predefined in Java. Non-primitive types are created by the programmer and is not defined by Java (except for String).

  • Non-primitive types can be used to call methods to perform certain operations, while primitive types cannot.

  • A primitive type has always a value, while non-primitive types can be null.

  • A primitive type starts with a lowercase letter, while non-primitive types starts with an uppercase letter.

  • The size of a primitive type depends on the data type, while non-primitive types have all the same size.

Note:

  • Strings use "" and chars use ''

  • Max and Min value for an int is +2,147,483,647 and -2,147,483,647, respectively (for any values above max or below min, use the long , short, or double data type). This value is found in Integer.MAX_VALUE and Integer.MIN_VALUE.

Number Literals

  • Sometimes when you just type a number in an expression, the compiler has to ‘guess’what type it is:


Type-Casting

Variable Conversion:

Ex.


Operators

Arithmetic Operators: +, -, *, /, %, ++, --

  • Note: comparison operators have lower precedence than arithmetic operators so:

Assignment Operators

Operator
Example
Same As

=

x = 5

x = 5

+=

x += 3

x = x + 3

-=

x -= 3

x = x - 3

*=

x *= 3

x = x * 3

/=

x /= 3

x = x / 3

%=

x %= 3

x = x % 3

&=

x &= 3

x = x & 3

|=

x |= 3

x = x | 3

^=

x ^= 3

x = x ^ 3

>>=

x >>= 3

x = x >> 3

<<=

x <<= 3

x = x << 3

Comparison Operators: ==, !=, >, >=,<, <=

  • most of these comparison operators ( >, <, >=, and <=) can be applied only to primitives. Two (== , !=) can be used for any object but when applied to reference types, they test if they point to same object rather than have same value.

Logical Operators: &&, ||, !


Methods

Creating and Calling Methods

Method Parameters

  • Formal Parameters: parameters in function signature

  • Actual Parameters: actual values passed to function call

Return

  • Code underneath a return call is unreachable code.

  • The type of the value returned must match the return-type specified in a method's signature.

  • A method can use multiple return statements.

  • Methods are not required to return a value. In this case, the return-type in the method signature should be void

Method Overloading

  • multiple methods can have the same name with different parameters. It will call the function whose actual parameters match the formal parameters types and positions in the function call.

Method Comments

  • To write a Javadoc comment above each method:

    • /**

      • Note the purpose of the method

      • @param - describe each parameter variable

      • @return - describe the return value

    • */


String Methods

toLowerCase() - converts a string to lower case letters.

toUpperCase() - converts a string to upper case letters.

length() - returns int value of the number of characters in string. The length of an empty string is 0

contains()- finds out if a string contains a sequence of chars. Returns true if the chars exist; false if not.

equals() - compares two strings, and returns true if the strings are equal, and false if not.

equalsIgnoreCase() - compare strings to find out if they are equal AND IGNORE CASE DIFFERENCES

  • Don't compare strings using the == operator since it will check if the two Strings point to the same object since Strings are reference types.

compareTo(), compareToIgnoreCase() - returns An int value:

  • 0 if the string is equal to the other string.

  • < 0 if the string is lexicographically less than the other string.

  • > 0 if the string is lexicographically greater than the other string (more characters).

indexOf() - returns the index of the first occurrence of specified char(s) in a string

lastIndexOf() - returns the index of the last occurrence of specified char(s) in a string

concat()- appends/concatenates a string to the end of another string

replace() - searches string for specified char(s), and returns new string where specified char(s) are replaced

trim() - removes whitespace from both ends of a string. This method does not change the original string

startsWith() - checks whether a string starts with the specified char(s).

endsWith() - checks whether a string ends with the specified char(s).

charAt() - returns the char at the specified index in a string

split() - splits a string at a specified char and creates an array; parameter is what's being removed.

If you split a string and an int, they both become strings so convert using Integer.valueOf()

subString() - returns a substring of this string; from the first index to the second (exclusive); otherwise extends to the end of this string

copyValueOf() - returns a String that contains the characters of the character array


Math Methods import java.lang.Math;

xxxValue() - returns the primitive data type that is given in the signature.

parseXXX() - used to get the primitive data type of a certain String.

abs() - gives the absolute value of the argument.

ceil() - returns the smallest integer that is greater than or equal to the argument.

floor() - returns the largest integer that is less than or equal to the argument.

rint() returns the integer (double.0) that is closest in value to the argument. Parameter must be double

round() - returns the closest long or int to the argument. Parameter must be double or float

min() - gives the smaller of the two arguments

max() - gives the larger of the two arguments

pow() - returns the value of the first argument raised to the power of the second argument.

sqrt() - returns the square root of the argument.

cbrt() - returns the cube root of the argument.

Math.PI - returns the value of pi to the 15th decimal.

random() used to generate a random number between 0.0 and 1.0


Conditionals

If

If-Else

Else-If

For

For-Each (arrays)

While

Do-While

Continue - breaks out of the inner loop and goes to the top of the outer loop.

Break - breaks out of the current loop

Switch-Case

Modulo

Try-Catch


Ternary Operator

The Java ternary operator functions like a simplified Java if statement.

  • The ternary operator consists of a condition that evaluates to either true or false, plus a value that is returned if the condition is true and another value that is returned if the condition is false.

Format

  • System.out.println( expression ? "true" : "false");

  • System.out.println( expression ? "true" : expression2 ? "false" : "maybe");

Here are some simple Java ternary operator examples:

  • ? checks if statement is true; if yes, print what follows the question mark

  • : separates the "arguements". If the first one is false, it goes to second argument


Misc

Swapping Values;

Import Keyword

The import keyword is used to import a package, class or interface.

class
highlight

java.lang.String

used to create / operate immutable string literals

java.lang.Exception

helps deal with exception and error handling

java.util.ArrayList

implementation of array data structure

java.util.HashMap

implementation of a key-value pair data structure

java.lang.Object

contains early methods like equals, hashcode, clone, toString, etc

java.util.Date

used to work with date and current time

java.util.Iterator

allows use of an 'Iterator' object that can be used to loop through Lists and HashSets

Input

  • The Scanner class allows you to read keyboard inputs from the user.

  • Reading certain variables:

    int
    sc.nextInt();

    double

    sc.nextDouble();

    String

    sc.nextLine(); or sc.next();

    char

    sc.char().charAt(0);

    boolean

    sc.nextBoolean();

Escape Sequences

  • allows us to use special characters inside strings as visual components rather than functional ones. Ex. using quotes "" inside a String which has ""s already gives some funky errors.

  • Preface the special character with a \

  • does a newline in a string

Use of Epsilon

  • Use a very small value to compare the difference if floating-point values are ‘close enough’

  • The magnitude of their difference should be less than some threshold.

Enum

  • Enum is short for "enumerations", which means "specifically listed".

  • Use enums when you have values that you know aren't going to change.

  • An enum is a special "class" that represents a group of constants.

  • To create an enum, use the enum keyword and separate the constants with a comma.

  • You can access enum constants with dot notation

  • Enum iteration

    • The enum type has a values() method, which returns an array of all enum constants. This method is useful when you want to loop through the constants of an enum:

Sentinel Values

  • Sentinel values are often used when you don't know how many things you're going to get from input.

  • A Sentinel value is simply a value which when picked up by the Scanner, will stop reading the input and do something else.

  • A Sentinel value denotes the end of a data set, but it's not apart of the data!

  • But sometimes you might even have -1 in the dataset, so instead you can use a non-numeric sentinel (entering a non-numeric value as input would end the input)

Static Blocks

  • A block of code which is executed before the main method at the time of classloading.

Wrapper Classes

  • Java provides wrapper classes for primitive types

  • Conversions are automatic using auto-boxing:

  • Primitives and their Wrapper-Equals:

    • byte=Byte, boolean=Boolean, char=Character, double=Double, float=Float, int=Integer, long=Long, short=Short.

  • You cannot use primitive types in an ArrayList, but you can use their wrapper classes


Data Structures

¬ Arrays

  • Arrays are used to store multiple values in a single variable, instead of declaring separate variables for each value.

  • You don't need to import any packages for Arrays (you do though for Arraylists)

  • With arrays, the size cannot be modified. If you wanted to add or remove elements from an array, you'd have to create a new one.

    • Use an Array if: The size of the array never changes, You have a long list of primitive values (efficiency reasons), Your instructor wants you to.

    • Use an ArrayList if: For just about all other cases, Especially if you have an unknown number of input values.

Declaration - define the variable type with square brackets:

Initialization - use an Array literal to insert values; place the values inside curly braces:

Printing - import java.util.Arrays;

Accessing Elements - access an array element by referring to the index number (arrays start at 0)

  • Make sure the index you provided is exists or else you'll get a IndexOutOfBoundsError

  • Empty arrays hold null values by default

Changing Array Elements - to change the value of a specific element, refer to the index number

  • Arrays are mutable

Array Length - find out how many elements an array has, use the .length property

Iterating over an Array

Iterating using For-Each loop

  • For-each loops are used exclusively to loop through elements in arrays. This loop goes through the array 1 by 1 and assigns it to the variable.

Common Array Algorithms:

  • Sum and Average Values

  • Find the Maximum or Minimum

  • Linear Search

  • Removing an Element and maintaining order

  • Inserting an Element and maintaining order

  • Growing an Array

  • Copying Arrays - Not the same as copying only the reference; Copying creates two set of contents!

  • Reading Input

    • Case A: Known number of values to expect - Make an array that size and fill it one-by-one

    • Case B: Unknown number of values - Make maximum sized array, maintain as partially filled array


¬ 2D Arrays

  • You don't need to import any packages for 2D Arrays.

  • 2D Arrays have Rows & Columns and is aka ''Matrix'.

Declaration

  • Use two ‘pairs’ of square braces: <type>[][] <name> = new <type>[#rows][#cols]

  • #rows is basically the number of arrays in the the 2d array

  • #cols is basically the size of each array in 2d array (given they are all the same size)

Accessing

  • Use two index values: int value = counts[3][1]; gets element at index-3 ROW & index-1 COL.

Iteration

  • Use nested for loops where Outer row(i) , inner column(j):

Locating Neighbouring Elements

![Screen Shot 2022-01-31 at 1.04.36 PM](/Users/dev/Library/Application Support/typora-user-images/Screen Shot 2022-01-31 at 1.04.36 PM.png)


¬ ArrayLists

(import java.util.ArrayList)

  • The ArrayList is a resizable array where elements can be added and removed from an ArrayList whenever you want.

  • Recall that arrays' size cannot be modified (if you wanted to add/remove elements, you'd have to create a new one)

Declaration

  • Creating an ArrayList object: ArrayList<TYPE> NAME = new ArrayList<TYPE>();

Initialization - you can pass an iterable in the declaration using the Arrays.asList( item1 , ... , itemN )

Add Items - add()

Printing Lists - unlike arrays, you can simply println arraylists:

Getting Index of Items - indexOf()

  • indexOf() returns the first occurence of the specified item in the list, otherwise returns -1:

Checking for Item - contains()

  • To check the existence of an item in a list, use the contains() method, which returns true/false:

Accessing Items - get()

  • To access an element in the list, use the get() method and refer to the index number:

Changing Items - set()

  • To modify an element, use the set() method and refer to the index number and the new element:

Removing Items - remove() , clear()

  • To remove an element, use the remove() method and refer to the index number:

  • To remove all elements in the list, use the clear() method:

Size - size()

  • To find out how many elements an ArrayList have, use the size() method

Sorting List (+reverse)

  • import java.util.Collections;

  • use the 'Collections' class to sort() lists alphabetically (uppercase take priority over lowercase) or numerically (least to greatest)

  • To sort in reverse order {greatest to least} and {descending alphabetical order}, add Collections.reverseOrder() to the Collections.sort() call as a second argument:

Iterating Through List

  • There are two ways of looping through a list: a for-loop, and a for-each loop:


¬ Stacks

(import java.util.Stack)

  • Stacks are an abstract data type with a bounded(predefined) capacity.

  • To help visualize Stacks, parallel it to a stack of video games, where the first element added to the stack is at the bottom. Every time you add a video game, it gets added ontop of the stack.

Declaration

Adding to Stack

Accessing Values

Removing from Stack

Peeking

Check for Element

Check If Empty

Size


¬ Queues

(import java.util.Queue | java.util.LinkedList)

  • Java Queues order elements in a FIFO (First In First Out) manner. In FIFO, first element is removed first and last element is removed at last.

  • To help visualize Queues, parallel it to a line at backyard bbq (or anything where people line up for something), where you give bbq to the person infront of the line. After, they've been served, they leave the line. Queues work in just that way!

Declaration

Adding to Queue

Removing from Queue

Peeking

Size of Queue

Check for Element

Convert to Array

Iterating Queue


¬ HashMaps

(import java.util.HashMap)

  • Hashmaps store items in key/value pairs (equivalent of Python's Dictionaries)

  • HashMap is known as HashMap because it uses a technique called Hashing - technique of converting a large String to a small String that represents the same String. A shorter value helps in indexing and faster searches

  • In ArrayLists, you learned that Arrays store items as an ordered collection, and you have to access them with an index number. A Hashmap however, stores items in "key/value" pairs where you can access the 'value' if you provide the 'key'.

Hashmaps can store different types:

  • (String keys && Integer values) or the same type (String keys && String values)

Creating a Hashmap

Adding to Hashmap

Accessing Items

Removing Items

Replacing Values

Retrieving

Checking for Key/Value

Size

Looping over HashMap


OOP

OOP stands for Object-Oriented Programming.

  • Procedural Programming - writing procedures or methods that perform operations on the data.

  • Object-Oriented Programming - creating objects that contain both data and methods

Container Class vs. Definition Class

Container Class - a collection of static methods that aren't bound to any particular object. These static methods usually have something in common.

  • The Math class is an example of a container class. It's essentially a container for math utility methods. Notice that you call these static methods with dot notation: <ContainerClass>.<StaticMethod ie. Math.sqrt()

  • However, for even moderately complex programs a large collection of methods can quickly becomes difficult to manage

Definition Class - these classes define new objects. THIS IS THE FOCUS IN CPS209

Classes & Objects

¬ Class

  • used to define a new data type aka a blueprint for creating objects.

  • Each class contains fields / attributes (variables) and behaviours (methods).

  • The ClassName should always start with an uppercase first letter and match the name of the java file.

  • To create a class, use the class keyword:

  • CLASS - an abstract view

    • We usually begin by creating an abstraction of a Class:

      1. What does an object of this class represent?

      2. What's the interface (methods) of this class?

        • The class interface is realized via methods

      3. What's the internal state of the class?

        • We use variables/fields to represent the internal state.

    • EX. Consider the Abstract view of a Clock Class

      1. A Clock class object represents a 12-hr clock

      2. It's interface (methods) allow telling the clock that a second has elapsed (one method for this), and querying the clock to retrieve the time (one for this).

¬ Object

  • a specific instance of a class with defined attributes.

  • the new keyword is used to create an object instance of a class. [ ClassName objName = new ClassName(params)]

  • To create an object:

  • Object References

    • Object reference variables store the location of an object in memory, not the object itself. That is, the new operator returns the location (a memory address) of the new object and stores this location in the reference variable.

    • Multiple reference variables can refer to the same object:

    • In memory, the addresses of clock1 & clock2 reference variables hold the same address of the Clock Object (ie. 0x7104).

    • Null Reference

      • A reference variable may be set to point to no object at all (null)

      • You can't call methods of an objcet using a refernce variable that's pointing to null; Causes a run-time error

    • Garbage Reference

      • Reference vars. that's aren't initialized refer to random locations in memory; You can only call methods using the Reference var. if it is referring to a valid object

Constructors

  • special method that's used to initialize objects.

  • The constructor is called when an object of a class is created, and is used to initialize the attributes in a newly created object.

  • The line of code which defines the constructor name and other info is called the constructor signature.

  • Rules for creating constructors:

    • must have the same name as the class

    • cannot have a return type (void)*

    • cannot be abstract, static, or final

    • (can still be private, protected, public or default)

  1. Default (No-Argument) Constructor - created by default by the java compiler at the time of class creation if no other constructor is declared in the class. Doesn't contain any parameters

  2. Parameterized Constructor - contains one or more parameters used to initialize attributes

Overloading Parameterized Constructors

  • You can overload parameterized constructors

  • Basically: multiple constructors with same name but different parameters; different ones get called when creating an object depending on which parameters are passed

Constructors vs. Normal Methods

Constructor
Method

used to initialize the instance variables of an object.

used to expose the behavior of an object.

must be void.

doesn't have to be void.

invoked implicitly (when object is created).

invoked explicitly (you have to call it).

Java compiler provides a default constructor if you don't have any constructor in a class.

The method is not provided by the compiler in any case.

constructor name must be same as the class name.

can be named anything.

Instance Variables

  • A variable which is created inside the class but outside constructors/methods is known as an instance variable.

  • You can acess and update instance variables (which aren't 'final') using dot notation:

  • Ways to Initialize Objects

    1. via assigning values to instance variables manually with dot notation:

    2. via setter methods:

    3. via constructor (most common)

Static Methods

  • methods which have the static keyword in their signature belong to a class rather than an instance of a class.

  • Static methods can only reference static variables or local variables (within the method)

  • Static methods can't read/set instance variables because they can't refer to this or instance variables since they're called with the CLASSNAME, not an OBJECT.

  • You can call it without creating an object; They are called by the class name itself: <className>.<staticMethod>();. If you're referencing static variables/methods in the same class, treat them with global scope.

Instance Methods

  • The method of the class is known as an instance method.

  • It's a non-static method defined in the class.

  • Unlike static methods, instance methods can access static variables.

  • Before calling or invoking the instance method, it is necessary to create an object of its class

  • There are 2 types of instance method:

    1. Accessor Method (GETTER)

      • Methods used to get instance variables

      • Usually prefixed with 'get'

      • Asks the object for info and normally returns a value of some variable

    2. Mutator Method (SETTER)

      • Methods used to update values of instance variables usually prefixed with 'set'

      • Return type is normally void.

      • Usually take a parameter that will change an instance variable.

this

  • The keyword this can be used in a class to refer to the current calling object

  • 'this' is used in the constructor to set the instance variables.

  • Static methods cannot refer to this or instance variables because they are called with the classname, not an object, so there is no this object.

  • You may invoke the method of the current class by using the this keyword:

4 Pillars of OOP

1. Encapsulation

  • process of wrapping code and data together into a single unit.

  • The goal is to make sure that "sensitive" data is hidden from users.

  • This is achieved via:

Packages

  • A java package is a group of similar types of classes, interfaces and sub-packages. (Think of it as a folder in a file directory)

  • We use packages to avoid name conflicts, and to write a better maintainable code (modularize code).

  • Packages are divided into two categories:

    1. Built-in Packages (packages from the Java API)

    2. User-defined Packages (create your own packages)

  • To create a package:

    1. use the package keyword:

      • The package name should be written in lower case to avoid conflict with class names

    2. Save the file as MyPackageClass.java, and compile the file:

    3. Compile the package:

      • This forces the compiler to create the "mypack" package.

      • The -d keyword specifies the destination for where to save the class file (. is current working directory)

    4. When we compiled the package above, a new folder was created, called "mypack".

Access Modifiers

  • access modifiers specify the scope of a field (variable), method, constructor, or class.

  • There are many non-access modifiers, such as static, abstract, synchronized, native, volatile, transient, etc

  • A member is a variable/method/constructor of a class; members of a class can be declared the following 4 access modifiers (listed st. first is most restrictive, and last, the least):

    1. Private

      • private scope is only within the class; it cannot be accessed from outside the class.

      • If you make any constructor private, you cannot create the instance of that class from outside the class.

      • With Private, we perform data-hiding; hide the internal implementation of the class by declaring its state variables and auxiliary methods as private. (Encapsulation)

    2. Default

      • default scope is only within the package; it cannot be accessed from outside the package.

      • If you do not specify any access level, it will be the default.

    3. Protected

      • protected scope is within the package and outside the package through child class.

      • If you do not make the child class, it cannot be accessed from outside the package.

    4. Public

      • public scope is everywhere; it can be accessed from within the class, outside the class, within the package and outside the package.

      • If you don't want to reveal the internal state of the object’s data don't declare its state variables as public. (Encapsulation)

    Access Modifier
    within class
    within package
    outside package by subclass only
    outside package

    Private

    Y

    N

    N

    N

    Default

    Y

    Y

    N

    N

    Protected

    Y

    Y

    Y

    N

    Public

    Y

    Y

    Y

    Y

    Note: If you are overriding any method, the overridden method (ie. declared in subclass) must not be more restrictive

    • ie. you can't override a protected (#3 restrictive) method with a default (#2 restrictive) method since #2 is more restrictive than #3. This causes a compile-time error.

Providing GETTER(s) & SETTER(s)

  • By providing only a getter / only a setter method, you can make the class read-only / write-only.

  • This allows for: more control over the data , data hiding , and easy testing.

2. Inheritance

  • Inheritance is a mechanism in which one class can inherit all attributes (variables) & behaviours (methods) of a parent class.

    • parent class | | superclass - class being inherited from.

    • child class | | subclass - class that is inheriting.

    Inheritance represents the IS-A relationship which is also known as a parent-child relationship

  • Inheritence is great because it allows: code reusability & runtime polymorphism.

    • Code reusability = when you inherit from an existing class, you can reuse attributes and behaviours of the parent class. Moreover, you can add new attributes and behaviours in your current class.

Types of Inheritence

  1. Single - when a class inherits another class. (a -> b)

  2. Multilevel - when there is a chain of inheritance. (a -> b -> c)

  3. Hierarchical Inheritance - when two or more classes inherits a single class. (a, b -> c)

Types of inheritance in Java

IS-A vs. HAS-A

IS-A :

  • An IS-A relationship is inheritance. The child class is a type of parent class.

  • static (compile time) binding.

HAS-A :

  • A HAS-A relationship is composition; meaning creating instances which have references to other objects.

  • dynamic (run time) binding.

  • To make a subclass inherit from a superclass, use the extends keyword:

  • While a person can have two parents, a Java class can only inherit from one parent class. If you don't specify a superclass with 'extends', the class will default-inherit from the Object class.

Substitution Principle

  • You can always use a subclass object when a superclass object is expected as a parameter to a method.

Super()

  • Subclasses inherit public methods from the superclass that they extend, but they cannot access the private instance variables of the superclass directly and must use the public GETTERs & SETTERs.

  • Subclasses do not inherit constructors from the superclass

  • super() solves the quesiton of: "how do you initialize the superclass’ private variables if you don’t have direct access to them in the subclass?"

  • The superclass constructor can be called from the first line of a subclass constructor by using the special keyword super() and passing appropriate parameters

  • If a subclass doesn't call the superclass' constructor with super() as the first line in a subclass constructor then the compiler will automatically add a super() call as the first line in a constructor.

  • The keyword super can be used to call a superclass’s constructors and force-use its methods.

  • You want to still execute the superclass method, but you also want to override the method to do something else. But, since you have overridden the parent method how can you still call it? There are two uses of the keyword super:

    1. super(); or super(arguments); - calls just the super constructor if put in as the first line of a subclass constructor.

    2. super.method(); - calls a superclass’ method (not constructors).

Overriding Methods

  • We also usually add more methods or instance variables to the subclass.

  • overriding inherited methods - providing a public method in a subclass with the same method signature (name, parameter type list, and return type) as a public method in the superclass.

  • The method in the subclass will be called instead of the method in the superclass.

  • You may see the @Override annotation above a method. This is optional but it provides an extra compiler check that you have matched the method signature exactly:

  • NOTE: YOU SHOULD NEVER OVERRIDE VARIABLES. Each object would have two instance fields of the same name. ("Shadow Variable")

Overloading methods

  • Overloading inherited methods - when several methods have the same name but the parameter types, order, or number are different.

So with overriding, the method signatures look identical but they are in different classes, but in overloading, only the method names are identical and they have different parameters.

Superclass References

  • A superclass reference variable can hold an object of that superclass or of any of its subclasses.

  • This is a type of polymorphism.

Passing subclass objects as parameters

  • We can write methods with parameters of the superclass type and pass in subclass objects to them.

  • Similar for arraylists:


3. Polymorphism

  • Poly = many, morphism = forms; so Polymorphism = many forms

  • Polymorphism in Java is the ability of an object to take many forms; allows us to perform the same action in many different ways.

  • Any Java object that can pass more than one IS-A test is considered to be polymorphic (really all objects in Java which have even just one IS-A, are polymorphic since all Java objects by default, inherit from Object)

  • JVM looks at type of object the reference variable is pointing to (i.e at run time)and executes the correct method for that object.

  1. It's always OK to convert subclass reference to superclass reference but not other way around.

  2. If you want to convert superclass ref. variable to subclass, you must cast:

    • Make sure superclass ref. variable is referring to a subclass object using the instanceof keyword:


Object: The superclass of all classes

  • All classes etend Object

  • most useful methods in class Object:

    1. String toString()

      • Returns a string representation of the object

      • Useful for debugging

      • ie. toString() in class Rectangle returns something like:

        • java.awt.Rectangle[x=5,y=10,width=20,height=30]

      • toString() is used by concatenation operator

      • toString() in class Object returns class name and object address:

        • ie. Employee@d2460bj

      • It's common to OVERRIDE the toString() method

    2. boolean equals(otherObj)

      • equals() tests for equal contents

      • note: == tests for equal memory locations of objects

      • Must cast the "otherObj" parameter to subclass

    3. clone()


Abstract Methods and Classes

  • When you extend a class, you have the choice to override a method (or not)

  • Sometimes want to force the subclass creator to override a method

    • method might be common to all subclasses so should define it in superclass but there is no good default implementation

  • You can make the method abstract (just signature, no body)

    • ie. abstract public double area();

    • Now subclass can implement method area();

  • If a class has >= 1 abstract method, whole class must be made abstract

    • ie. class is made abstract by: abstract public class BankAccount

  • You can’t create objects of abstract classes; abstract classes are used to define a common interface and behavior for all subclasses.

  • Abstract classes can have instance variables, abstract methods, concrete methods.

    • A subclass inherits said instance variables and methods. It must then implement abstract methods. If the subclass doesn't implement the abstract method(s), it too becomes abstract

  • You can also prevent others from creating subclasses and overriding methods using the final keyword.


Interfaces

In general terms, an interface is a container that stores the signatures of the methods to be implemented in code segments. (it's an outline for a class)

An interface can be thought of as a 'connector' b/n the general methods in the container and your code segments.

$ Defining

  • An Interface can only have method signatures, fields and default methods (skeleton code). You have to write the code for these methods inside your class.

  • To define an interface, use the interface keyword:

$ Implementing

  • The interface alone is not of much use, but they're used along with Classes which help further define them.

  • Use the implements keyword to indicate that a class implements an interface type.

  • A class can implement > 1 interface.

  • There are ground rules:

    • The Class must implement ALL of the methods in the interface

    • The methods must have the exact same signature as described in the interface

    • The class doesn't need to declare the fields; only the methods.

    • An interface can't contain a constructor method. Therefore, you can't create instances of the Interface itself.

Interfaces vs. Classes

  • An interface type is similar to a class, but there're some important differences:

    1. All methods listed in an interface type are abstract;

      • i.e. they don't have any code!!

    2. All methods listed in an interface type are automatically public

    3. An interface type does not have instance variables!

  • Inheritance (Class) defines a is-a relationship

    • Strong relationship b/n super and cubclass

  • Interface defines a has-a relationship:

    • Share some behaviour, but that's all

Converting b/n Class & Interface types

  • You can convert an instance variable from a class type --> interface type, provided the class implements the interface.

  • To convert the instance variable from a interface type --> back to --> class type, use (casting):

Polymorphism & Interfaces

  • Interface reference variable holds reference to object of a class that implements the interface:

  • Note:

    • the object to which m points to is not of type Measurable. It's type is the class that implements the Measurable interface (BankAccount).

    • The variable m itself is of type Measurable

  • Say two classes BankAccount & Clock both implement Measurable interface. Each class will have their own implementation of the getMeasure().

    • How will we know whose getMeasure() is being called?

    • Polymorphism says that it depends on the actual object.

    • So if m refers to a BankAccount, it'll call BankAccount's getMeasure(). If it refers to a Clock, then it'll call Clock's getMeasure().

  • Polymorphism - behaviour (methods) can vary depending on the type of the object calling it.

    • "Binding" is the association of a method call with the method definition. There are 2 types of binding:

      1. late-binding - happens at compile time.

      2. early-binding - happens at run time.

Polymorphism vs. Overloading:

  • Similarity: both describe a situation where one method name can denote multiple methods.

  • Difference:

    • overloading is resolved early by the compiler, by looking at the types of the parameter variables.

    • Polymorphism is resolved late, by looking at the type of the implicit parameter object just before making the call


Exception Handling & IO

> Throwing Exceptions

  • Throwing exceptions is the solution to the problem of erroneous functions which may or may not throw errors.

  • Exceptions can't be overlooked/ignored and are sent directly to an exception handler (not just to the caller of the failed method)

  • You THROW an EXCEPTION OBJECT to signal an exceptional condition; there's no need to store this object in a variable.

  • When an exception is thrown:

    1. Method terminated immediately (kinda like 'return')

    2. Excecution continues in an exception handler

> Checked & Unchecked Exceptions

There are 2 types of exceptions:

  1. Checked - compiler checks that you don't ignore them

    • they're due to external circumstances that the programmer can't prevent ie. User I/O

    • ie. IOException

  2. Unchecked - extends the class RuntimeException or Error

    • they're typically the programmer's fault

    • Examples of runtime exceptions: NullPointerException

    • Examples of errors: OutOfMemoryError

> Exception Handlers

  • exception handlers are created with try/catch blocks

    try - contains statement that may cause an exception

    catch - contains handler code to deal w/ particular exception type


I/O

  • To read a local file, construct a file object, then use the file object to construct a scanner object:

  • To write to a file, construct a PrintWriter object

  • You must close a file after you're done processing it:

Handling FileNotFoundException

  • When a FileNotFoundException occurs (thrown by the File constructor), you have 2 choices:

  1. Handle the exception inside the method (with a try-catch)

  2. Tell the compiler that you want the method to be terminated when the exception occurs.

    • The throws keyword indicates that the method will [potentially] throw a CHECKED EXCEPTION. For multiple exceptions, just separate with comma:

    • Keep in mind the INHERITANCE HIERARCHY for exceptions; if a method can throw IOException & FileNotFoundException, we know that FileNotFound inherets from IO therefore, only use IOException.

Catching Exceptions

Creating Custom Exception Types

  • You can design your own exception types (subclasses of Exception or RuntimeException)

  • Make it an UNCHECKED exception

  • Extend RuntimeException or one of its subclasses

  • Supply 2 constructors:

    1. default constructor

    2. constructor that accepts a message string describing reason for exception


Collections

A collection is simply an object that represents a group of objects into a single unit.

Collection Framework - a unified architecture or a set of classes and interfaces for representing and manipulating collections. i.e. collection framework is used to store, retrieve and manipulate collections.

> Lists & Sets

  • A list is a collection that maintains the order of its elements

  • Ordered Lists:

    • ArrayList –– stores a list of items in a dynamically sized array

    • LinkedList –– allows speedy insertion and removal of items from the list

  • A set is an unordered collection of unique elements.

  • Unordered Sets:

    • HashSet –– uses hashtables to speed up finding/adding/removing elements

    • TreeSet –– uses a binary tree to speed up finding, adding, and removing elements

> Stack & Queues & PriorityQueues

  • Another way of gaining efficiency in a collection is to reduce the number of operations available. 2 examples are:

    • Stack –– remembers the order of its elements, but it does not allow you to insert elements in every position. You can only add and remove elements at the top.

    • Queue –– add items to one end (the tail), remove them from the other end (the head).

    • PriorityQueues –– collects elements, each of which has a priority. Remove lowest number first

> Maps

  • A map stores keys, values, and the associations between them

  • Keys –– provides an easy way to represent an object

  • Values –– actual object associated with the key

> LinkedList

  • use references to maintain an ordered lists of nodes.

    • The head of the list references the first node.

    • Each node has a value and a reference to the next node.

  • Efficient Operations

    • Insertion of a node –– Find the elements it goes between. Remap the references.

    • Removal of a node –– Find the element to remove. Remap neighbor’s references

    • Visiting all elements in order

  • Inefficient Operations

    • Random access.


Iterators

List Iterators

  • When traversing a LinkedList, use a ListIterator to:

    • keep track of where you are in the list.

    • access elements inside a linked list.

    • visit other than the first and the last nodes.

Note:

  • When calling .add(...) ,

    • the new node is added AFTER the Iterator.

    • the Iterator is moved past the new node.

  • When calling .remove() ,

    • it removes the object that was returned with the last call to next or previous.

    • it can be called only once after next or previous.

    • You cannot call it immediately after a call to add.

Last updated