Java

Expressions

Precedence (highest to lowest):

  1. Postfix: i++, i--
  2. Unary: (int) a, !b, ++i, --i
  3. Multiplicative: *, /, %
  4. Additive: +, -
  5. Relational: >, >=, <=, <, instanceof
  6. Equality: ==, !=
  7. And: &&
  8. Or: ||
  9. Assignment: =, +=-=, *=, /=, %=

== vs .equals()**

==: two primitives (int, boolean, etc.) have the same value OR two variables point to the same object in memory. .equals(): Checks if two objects have the same contents if they implement the equals() method, otherwise still reference.

Watch out that methods like .toLowerCase() create a new object in memory!

Weird Java quirk: When calling .equals() on two arrays, it still compares references, not contents!

Inheritance

Static type: the type of the variable reference Dynamic type: the type of the actual object

FieldType
Static methodStatic type
Regular methodDynamic type
Fields (Attributes)Static type

Error: If only the dynamic type has a static method or attribute and not the static type, we cannot access it. Trying causes a compile error.

Casting only changes the static type, not the dynamic type.

Example

class Animal {
  int energy = 10;
}
 
class Dog extends Animal {
  int energy = 50// hides Animal.energy
 
  void eat() {
	energy += 5;   // modifies Dog.energy
  }
}
 
Animal a = new Dog();
Dog d = (Dog) a;
 
d.eat();
 
System.out.println(a.energy);  // 10
System.out.println(d.energy);  // 55

In this example, we have the following memory layout:

Reference a (Animal) ---> Dog object:
-------------------------------
| Animal.energy = 10          |  <-- a.energy
| Dog.energy    = 55          |  <-- modified by Dog.eat()
-------------------------------
Reference d (Dog) ---> same object

Explanation:

  • If a class inherits from another class, its objects contain both the fields of the actual type and of all the parents, even if they have the same names.
  • Inside a method, field access resolves to the nearest field in that class. Here, Dog.energy is the nearest. If Dog didn’t have an energy field, then it would resolve to Animal.energy.
  • The static type hides the fields that don’t belong to it. It acts as a filter. The other fields are still there and can be modified by methods belonging to the same class.
  • Casting changes which fields are hidden and which ones aren’t. It changes the filter

Errors

Compile Errors

  • Syntax errors (missing semicolons, type definitions)
  • Incompatible types (assigning a boolean to an int, dividing a string)
  • Undefined variables or methods, including because they belong to the dynamic type and not the static one
  • Casting a variable where the static type has no inheritance relationship to the type to cast.
    • The compiler can already know for sure that this cannot work.
    • You can cast upwards and downwards the inheritance chain, but never sideways
    • Important: This compiles fine because Integer inherits from Object: Object o = "hello"; Integer i = (Integer) o; It would not compile if we exchange Object for String.

Runtime Exceptions

  • Division by zero
  • Null reference / null pointer access
  • Array or index out of bounds
  • Casting a variable where the dynamic type has no inheritance relationship

Tips

  • a % 0 throws an ArithmeticException
  • Pay close attention to whether a method is truly overridden (same signature) or merely overloaded (different parameters)
    • If an exam shows a call obj.calculate(5), and 5 is an int, Java will look for a version specifically for int before trying to “widen” it to a double.
  • Assignment are expressions that returns the assigned value
  • final classes cannot be inherited from; abstract classes cannot be initialized.
  • abstract classes define behavior and state (via fields); interfaces define only behavior (and constants). For that reason, we can implement multiple interfaces but only one class.
    • If we implement two interfaces that have the same default methods, we must overwrite them
  • Only possible to increment on variables, not values