Casting

type casting - to convert variable values from one type to another

Situation to use casting: If you have integers and you want a double result from some mathematical operation cast one of the integers to a double using (double)

casting operators (int) and (double) - used right next to a number or variable to create a temporary value converted to a different data type

System.out.println((double) 1 / 3);
0.3333333333333333

Values of type double can be rounded to the nearest integer by adding or subtracting .5 and casting with (int) using formulas like the following.

int nearestInt = (int)(number + 0.5); int nearestNegInt = (int)(negNumber – 0.5);

Wrapper Classes

Provide a way to use primitive data types (int, boolean, etc..) as objects.

Must use wrapper classes when working with ArrayList (collection objects), where primitive types cannot be used (the list can only store objects)

wrapperClass

ArrayList<String> names = new ArrayList<String>();

Concatenation

Concatenation - the operation of joining two strings together. can join strings using either the addition (+) operator or the String’s concat() method

System.out.println("pan" + "handle"); //addition operator
panhandle
public String concat(String s) //syntax for String's concat() method
public class Test {

    public static void main(String args[]) {
       String s = "Strings are immutable";
       s = s.concat(" all the time");
       System.out.println(s);
    }
 }

Test.main(null);
Strings are immutable all the time

Mixed type Concatenation

int age = 12;
System.out.println("My age is " + age);
My age is 12

Math class (Random usage)

The java.lang.Math.random() method returns a pseudorandom double type number greater than or equal to 0.0 and less than 1.0.

double rand = Math.random();
System.out.println(rand); //output: 0.0~1.0
0.0870647020554971

Compound Boolean Expression

If two boolean values/expressions are combined with a logical and (&&) and the first expression is false, then the second expression won't be executed The logical AND (&&) (logical conjunction) operator for a set of boolean operands will be true if and only if all the operands are true. Otherwise it will be false.

int a = 3;
int b = -2;

System.out.println(a > 0 && b > 0); //false because b is less than 0
System.out.println(a > 0 || b > 0); //true because one expression evaluates to true
false
true

De Morgan's Law

the complement of the union of two sets will be equal to the intersection of their individual complements

show how to handle the negation of a complex conditional, which is a conditional statement with more than one condition joined by an and (&&) or or (||), such as (x < 3) && (y > 2)

< becomes >=

"> becomes <="

== becomes !=

<= becomes >

">= becomes <"

!= becomes ==

deMorgan's

!(a || b) == !a && !b

not (A or B) = not A and not B

"I don't like chocolate or vanilla" = "I do not like chocolate and I do not like vanilla"

deMorgan's

// using De Morgan's Law, outputs are the same
int x = 2;
int y = 2;
     System.out.println(!(x < 3 && y > 2)); 
     System.out.println(x >= 3 || y <= 2); // < becomes >=; > becomes <=; and && becomes ||
true
true
// if not use De Morgan's Law correctly, you will get different outputs
int x = 2;
int y = 2;
     System.out.println(!(x < 3 && y > 2)); 
     System.out.println(x >= 3 || y < 2);    // > should become <=
true
false

.compareTo()

.compareTo() compares two strings lexicographically returns 0 if the string is equal to the other string. A value less than 0 is returned if the string is less than the other string (less characters) and a value greater than 0 if the string is greater than the other string (more characters)

if(guess1.compareTo(guess2) > 0) { 
    return guess1;
}
else
    return guess2;

Comparing String vs Comparing Numbers

comparing numbers - use == comparing strings - use .equal()

if(secret.substring(i, i+guess.length()).equals(guess)) //in 2021 FRQ
Incomplete input:
|   if(secret.substring(i, i+guess.length()).equals(guess)) //in 2021 FRQ

Difference between Looping through Array, ArrayLists, String

String    str
for(int i=0; i<str.length(); i++)
    str.substring(i,i+1)       // means get every character in String 
 01234
"Linda".substring(0,1)      "Linda".substring(4)
.substring(start , end)     [start, end)     from start to end-1          


Array    arr
for(int i=0; i<arr.length; i++)
     arr[i]             //   means get every element in the arr


ArrayList  list 
for(int i=0; i<list.size(); i++) 
     list.get(i)          //  means get every item in the ArrayList

Show use case of access modifiers: Public, Private, Protected

Public Access Modifier - easily accessible from any part of the program. All data members and member functions of a class are public by default. A public class, method, or variable can be accessed from any other class at any time.

//declare a class as public
public class Animal{

}
//the Animal class can be accessed by any other class
//specifying a variable and a method as public
public int age;
public int getAge(){
}

Private Access Modifier - most restrictive access level (hides data from the outside world) Class and interfaces cannot be private. Variables that are declared private can be accessed outside the class, if public getter methods are present in the class.

public class Calculator {
    // Key instance variables
    private final String expression;
    private ArrayList<String> tokens;
    private ArrayList<String> reverse_polish;
    private Double result = 0.0;
...
}

Protected Access Modifier - attribute isn't affected by outside modifiers

public class Car {
    protected String brandName;
    protected double range;
    protected double doorNumber;
    protected double maxSpeed;
...
}

Inheritance, extends

extends (inherit the attributes and methods of the base class) - avoid having lots of repeated code (no need to redefine the methods)

```java
public class CpopArtist extends Artist { //subclass CpopArtist inherits attributes and methods of superclass Artist
...
}
```

Subclass constructor, super Keyword

constructor for the subclass uses the superclass constructor with the super keyword

super keyword - to use constructors and methods of superclass in a subclass

super class - have the generic methods all subclasses would have

public class KpopArtist extends Artist {
    // Constructor for Subclass
    public KpopArtist(String name, double age, String rapName) {
        // use the Superclass constructor for the shared attributes through the keyword "super"
        super(name, age);
        //not in Superclass, add this separately in the constructor
        this.rapName = rapName;
    }
    ...
}

Overloading a method, same name different parameters

Having two methods with the same name but different arguments and functionalities

public class CpopArtist extends Artist { //subclass
...

    @Override
...

    public void compose (boolean a) {  // input a boolean value instead of int
        System.out.println("Composing melody? " + a);
    }

    public void compose (boolean a, boolean b) {  //different arguments
        System.out.println("Composing melody? " + a + " Writing lyrics? " + b);
    }


    public static void main(String[] args) {
...
        // Using the overloaded method 
        jackson.compose(true);  
        jackson.compose(true, true);  

    }
}
CpopArtist.main(null);

Overriding a method, same signature of a method

Overriding allows a subclass or child class to provide a specific implementation of a method that has already been provided by a super-classes or parent classes. When a method in a subclass has the same name, same parameters or signature, and same return type (or sub-type) as a method in its super-class, then the method in the subclass will override the method in the super-class.

//existing method in superclass
    
public void sing () {
    System.out.println("Singing...");
}

public void dance () {
    System.out.println("Dancing...");
}

public void rap () {
    System.out.println("Rapping...");
}

// We use override to change the functionality in the subclass of an existing method in the superclass
@Override
public void sing () {
    System.out.println("Singing in Korean... Good boy gone bad..."); //title of song of their album
}
public static void main(String[] args) {
...
    // Using the overridden method
    yeonjun.sing();
...
}

//output: 
///Singing in Korean... Good boy gone bad...

Difference between Overridng and Overloading

Overriding occurs when the method signature is the same in the superclass and the subclass.

Overloading occurs when two or more methods in the same class have the same name but different parameters.

Polymorphism: any of overloading, overriding, late binding

Polymorphism - allow us to perform the same action in many different ways Happens when classes are related to each other by Inheritance Essentially it helps when you have to reuse attributes and methods of an already existing class in a new class

The above code example demonstrates Runtime Polymorphism. It is also called Dynamic Binding or Dynamic Method Dispatch. When you hear any of these things, think of method overriding.

Late binding of object, referencing superclass object, ie Animal a = new Chicken(); Animal b = new Goat();

Late binding has to do with when the method is decided at runtime. Relate this to Runtime Polymorphism or method overriding.

Late binding: In the late binding or dynamic binding, the compiler doesn't decide the method to be called.

Late binding in its book definition form means that the compiler should perform no argument checks, no type checks on a method call and should leave it all to the runtime.

public static void main(String[] args) {
    // 5 argument constructor
    KpopArtist yeonjun = new KpopArtist("Yeonjun", 23, "Lonely Boy"); 
    // Example of late binding
    Artist artist = new KpopArtist("Yeonjun", 23, "Puma");
    // can still use the methods from the child class, even though we didn't mention them in the subclass!
    yeonjun.dance();
    // Using the overridden method
    yeonjun.sing();
    // Using the method we added on to
    yeonjun.rap();
    artist.rap();
}

Abstract Class, Abstract Method

To achieve data abstraction (hiding certain details)

The abstract keyword is a non-access modifier, used for classes and methods

  • Abstract class: is a restricted class that cannot be used to create objects (to access it, it must be inherited from another class).
  • Abstract method: can only be used in an abstract class, and it does not have a body. The body is provided by the subclass (inherited from).

To access the abstract class, it must be inherited from another class.

Ternary Operator

the only conditional operator that takes three operands (condition, expression1, expression2)

can use the ternary operator in place of if-else conditions or even switch conditions using nested ternary operators

takes less space and helps to write the if-else statements in the shortest way possible

ternaryOperator

//use if-else statements
class Main {
    public static void main(String[] args) {
      
      // create a variable 
      int number = 24;
  
      if(number > 0) {
        System.out.println("Positive Number");
      }
      else {
        System.out.println("Negative Number");
      }
    }
  }

  Main.main(null);
//use ternary operator (shorten to one line of code)
class Main {
    public static void main(String[] args) {
      
      // create a variable 
      int number = 24;
  
      String result = (number > 0) ? "Positive Number" : "Negative Number"; //shorter
      System.out.println(result);
    }
  }
  
  Main.main(null);
//nested ternary operator
class Main {
    public static void main(String[] args) {
      
      // create a variable
      int n1 = 2, n2 = 9, n3 = -11;
  
      // nested ternary operator
      // to find the largest number
      int largest = (n1 >= n2) ? ((n1 >= n3) ? n1 : n3) : ((n2 >= n3) ? n2 : n3);
      System.out.println("Largest Number: " + largest);
    }
  }

Main.main(null);

//(n1 >= n2) - first test condition that checks if n1 is greater than n2
//(n1 >= n3) - second test condition that is executed if the first condition is true
//(n2 >= n3) - third test condition that is executed if the first condition is false
//However, it is not recommended to use nested ternary operators. This is because it makes our code more complex.

In FRQ 4 (nested for loops) for print print single character, except at midpoint print color code

String c = (i == (int) (ROWS / 2) && j == (int) (COLS / 2) ) 
? lights[row][col].getRGB()
: (j == (int) (COLS / 2))  // nested ternary
? " ".repeat(lights[row][col].getRGB().length())
: " ";