Notes

What I learned

Static methods are used mainly for convenience. If you create a regular method, you need to create an object to execute the method. However, an object does not need to be created to access a static method.

Polymorphism: This is used with Java extends. When a method in the subclass has the same name as the superclass, the subclass's method will override the superclass's.

Late binding results in overriding, or using the specific subclass's method during run time. On the other hand, if two methods have the same name but different parameters, using one method over the other would be called overloading.

private vs protected: Private only allows access within the class, while protected allows access in the same package or subclasses.

Below is a piece of code that illustrates many parts of a class.

public class Person {
    private int age; 
    private int height; 

    public Person(){

    }
    

    public int getAge() {
        return this.age; 
    }

    public void setAge(int age) {
        this.age = age; 
    }

    public int getHeight() {
        return this.height; 
    }

    public void setHeight(int height) {
        this.height = height; 
    }



    public static void main(String[] args) {
        Person person1 = new Person(); 
        person1.setAge(20);
        person1.setHeight(65); 
        System.out.println("person1's age is: " + person1.getAge());
        System.out.println("person1's height is: " + person1.getHeight()); 
    }
}
Person.main(null)
person1's age is: 20
person1's height is: 65

Explanation of items in the code

A class is like a blueprint for an object. In this case, the class is Person (names of classes by convention have the first letter capitalized). The Person class has an empty constructor. Common things found in a class are getters and setters. Getters are created with getvariable name, and setters are created with setvariable name. In both cases, the first letter of the variable name should be capitalized, as in accordance with Java variable naming conventions. Getters and setters are used to protect your data so that you do not assign unintended values to your variables. Lastly, the this keyword is used to refer to the declared variables. this is used to differentiate between the declared variables and the variables that are passed into a method as parameters and who may have the same name.

Access modifiers

public allows visibility outside of the declared class, while private only allows visibility within the class.

public class Access{
    public int x = 5; 
}

public class AccessTwo {
    public static void main(String[] args) {
        Access variableDemo = new Access(); 
        System.out.println(variableDemo.x); 
    }
}
AccessTwo.main(null)
5

Compare with this:

public class Access{
    private int x = 5; // x is private
}

public class AccessTwo {
    public static void main(String[] args) {
        Access variableDemo = new Access(); 
        System.out.println(variableDemo.x); 
    }
}
AccessTwo.main(null)
|           System.out.println(variableDemo.x); 
x has private access in Access

On the other hand, protected allows access only in the same package and subclasses.

public class Access{
    protected int x = 5; // x is private
}

public class AccessTwo extends Access {
    public static void main(String[] args) {
        AccessTwo variableDemo = new AccessTwo(); 
        System.out.println(variableDemo.x); 
    }
}
AccessTwo.main(null)
5

Static vs nonstatic

In short, to access a variable from a static method, the variable must be declared with static.

static variables can be accessed in both static and nonstatic methods. nonstatic variables can only be accessed in nonstatic methods

public class staticDemo{
    
    static int staticVar = 5;

    public static void main(String[] args) {
        System.out.println(staticVar); 
    }
}
staticDemo.main(null)
5

This will produce an error because there is no static!

public class staticDemo{
    
    int staticVar = 5;

    public static void main(String[] args) {
        System.out.println(staticVar); 
    }
}
staticDemo.main(null)
|           System.out.println(staticVar); 
non-static variable staticVar cannot be referenced from a static context

Static variables can be accessed in nonstatic methods!

public class staticDemo{
    
    static int staticVar = 5;

    public void printVar() {
        System.out.println(staticVar); 
    }

    public static void main(String[] args) {
        staticDemo a = new staticDemo(); 
        a.printVar();
    }
}
staticDemo.main(null)
5

Tester methods

Tester methods can be used to test if your code is working the way you want it to work.

Inheritance

public class Cat{

    public boolean hasTail() {
        return true; 
    }

    public void sayMeow() {
        System.out.println("Meow!"); 
    }
}
public class TabbyCat extends Cat {
    public String furType() {
        return "striped"; 
    }

    public boolean hasTail() {
        return super.hasTail(); 
    }

    public static void main (String[] args) {
        TabbyCat cat1 = new TabbyCat(); 
        cat1.sayMeow(); 
        System.out.println("Tabby cat fur type: " + cat1.furType()); 
        System.out.println("Tabby cat has tail? " + cat1.hasTail()); 
    }
}
TabbyCat.main(null)
Meow!
Tabby cat fur type: striped
Tabby cat has tail? true

In the example above, the superclass is Cat, while the subclass is TabbyCat. Extends helps save time from copying and pasting code. TabbyCat has access to all of the methods in Cat, but also has its specific method, furType(). The super keyword calls the superclass.

One interesting thing is that if the subclass has the same method as the superclass, the subclass's method will override the superclass. This is called polymorphism. See below:

public class TabbyCat extends Cat {
    public String furType() {
        return "striped"; 
    }

    public boolean hasTail() {
        return false; // oof
    }

    public static void main (String[] args) {
        TabbyCat cat1 = new TabbyCat(); 
        System.out.println("Tabby cat has tail? " + cat1.hasTail()); 
    }
}
TabbyCat.main(null)
Tabby cat has tail? false

During compilation though, the hasTail() method will be looked for in the Cat class. Only during run time, the method will be resolved to the TabbyCat object. This is called late binding (using overriding)

Something very cool in Java is that you can have methods with the same name, as long as they have different parameters. This would result in overloading.

Abstract classes

Objects can not be created from abstract classes. Abstract classes serve as a blueprint that other classes can extend from.

abstract class AbstractCat {
    public void sayMeow() {
        System.out.println("meow"); 
    }
}
class TabbyCatAbstract extends AbstractCat{
    public String furType() {
        return "striped";
    }

    public static void main(String[] args) {
        TabbyCatAbstract tabbycat = new TabbyCatAbstract();
        System.out.println(tabbycat.furType()); 
    }
}
TabbyCatAbstract.main(null)
striped

toString()

toString changes the value into a String object

Integer x = 5; 

System.out.println("Data type of x is: " + x.toString().getClass().getSimpleName());
Data type of x is: String

hashCode()

hashCode returns the hash code for an object. If obj1.equals(obj2), then obj1.hashCode() == obj2.hashCode();

String text = new String("foo"); 
String text2 = new String("foo"); 

if (text.equals(text2)) {
    System.out.println(text.hashCode() == text2.hashCode()); 
}
true

Big O notation

Big O provides the worst case time complexity of an algorithm. It is written in the format of O(n), where n is the size of the input. The worst case time complexity is taken in that say if the function was 2n+3, you would write it as O(n) because as n increases, the 3 becomes less important.

The Big O notation for hash maps is O(1), which is the fastest possible running time. Binary search is O(logn). A single loop is O(n), while a nested loop is O(n^2).

2019 FRQ #2

Initial attempt

public class StepTracker {
    private int numDay;
    private int activeSteps; 
    private int totalSteps; 
    private int numActiveDays;

    public StepTracker(int steps) {
        activeSteps = steps; 
    }

    public int activeDays() {
        return numActiveDays; 
    }

    public double averageSteps() {
        return totalSteps/numDay;  
    }

    public void addDailySteps(int steps) {
        totalSteps += steps; 
        numDay++;
        if (steps >= activeSteps) {
            numActiveDays++; 
        }
    }


}

Comments:

In the method averageSteps(), I did not do a type conversion to double in my return statement. A type conversion is needed because totalSteps and numDay are integers.

I also did not account for when numDay = 0, because the return statement can not be divided by 0. Therefore, an if statement is needed to return an average step of 0.

Corrections:

public class StepTracker {
    private int numDay;
    private int activeSteps; 
    private int totalSteps; 
    private int numActiveDays;

    public StepTracker(int steps) {
        activeSteps = steps; 
        
    }

    public int activeDays() {
        return numActiveDays; 
    }

    public double averageSteps() {
        if (numDay == 0) {   // corrections
            return 0.0; 
        } else {
            return (double) totalSteps/numDay;  
        }
    }

    public void addDailySteps(int steps) {
        totalSteps += steps; 
        numDay++;
        if (steps >= activeSteps) {
            numActiveDays++; 
        }
    }
 


}