Java Basics


This is the debut article from a series that I created for myself. Maybe this will help somebody even if some information that I felt I already know by heart are not present. Good luck at your interview experiences.
JDK (Java Development Kit)
compile, archive (jar, war...)
debug
JRE (Java Runtime Environment)
- run java apps
JVM (Java Virtual Machine)
- just in time compiler (JIT)
ClassLoader
System -> CLASSPATH (jar, war etc..)
Extension -> /ext folder
Bootstrap -> java core files (base classes)
Wrapper Classes (Integer, Boolean, Long, Short, etc..)
accept null value (as opposed to primitives)
can be used in Collections
creation of wrapper classes objects
ex:
Integer i = new Integer(10);
or
Integer val = Integer.valueOf(10);
- autoboxing, static, uses cached values so it saves space
Autoboxing (when java converts automatically primitives to wrapper class objects)
Casting
- Implicit Autoboxing (Compiler does the conversion automatically):
int primitiveInt = 42;
Integer wrappedInt = primitiveInt;
- Explicit Autoboxing (Programmer explicitly performs the conversion):
int primitiveInt = 100;
Integer wrappedInt = Integer.valueOf(primitiveInt);
Strings
immutable
stored in the "String constant pool" in the Heap memory
StringBuffer - mutable, better performance and synchronized
StringBuilder - mutable, better performance not thread safe
more here: https://javainterviewprep.hashnode.dev/java-strings
OOP
Class (is a template)
state: class values at a particular time
behavior: methods
Object - instance of a class
Object class - the class that is inherited by all Java classes
\== (compares references but not the content of a class)
equals() - compares references and contents
hashCode() - object with the same hashcode are, by definition, equal
object that are not equal can have the same hashcode (collision)
Methods
Overloading - the same method but with different signature
ex:
Object(int n){}
and
Object(String s){}
Overriding - creating the same method with same signature but different implementation in a subclass
Inheritance
ex:
class Actor{} / class Hero extends Actor{}
Actor a1 = new Actor();
Actor a2 = new Hero();
← can only execute the methods present in Actor
Interfaces
Implemented
Contract for a class to implement methods
All defined methods must be implemented
Can contain default implementation
Public and abstract by default
Variables are always public, static, and final
Methods are public by default
Can be extended by another interface
A class can implement multiple interfaces
Abstract classes
https://docs.oracle.com/javase/tutorial/java/IandI/abstract.html
An abstract class is a class that is declared abstract, it may or may not include abstract methods. Abstract classes cannot be instantiated, but they can be subclassed.
An abstract method is a method that is declared without an implementation (without braces, and followed by a semicolon), like this:
Extended
Can be fully or partially implemented
Extended by classes with common functionality
A concrete class can extend only one abstract class
A child class can define abstract methods but with less or equal visibility
@MappedSuperclass
public abstract class AbstractBaseEntity {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
public AbstractBaseEntity() {
}
public AbstractBaseEntity(Long id) {
this.id = id;
}
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
}
Constructors
default:
public Class(){}
any argument constructor overrides the default constructor
this()
ex:
public Animal(){ this("Some Name"));}
calls
public Animal(String name){}
- calling a child class constructor automatically calls constructors from the inheritance chain
ex: Animal <<< Dog extends Animal <<< Labrador extends Dog
so Labrador calls Dog that calls Animal
Polymorphism (same code, different behavior)
The power of polymorphism lies in the ability to treat different objects with a common interface (Shape in this case) in a unified manner, making the code more flexible and maintainable.
ex:
interface Shape {
double calculateArea();
}
class Circle implements Shape {
private double radius;
public Circle(double radius) {
this.radius = radius;
}
@Override
public double calculateArea() {
return Math.PI * radius * radius;
}
}
class Rectangle implements Shape {
private double length;
private double width;
public Rectangle(double length, double width) {
this.length = length;
this.width = width;
}
@Override
public double calculateArea() {
return length * width;
}
}
class Triangle implements Shape {
private double base;
private double height;
public Triangle(double base, double height) {
this.base = base;
this.height = height;
}
@Override
public double calculateArea() {
return 0.5 * base * height;
}
}
import java.util.ArrayList;
import java.util.List;
public class AreaCalculator {
public static void main(String[] args) {
List<Shape> shapes = new ArrayList<>();
shapes.add(new Circle(5));
shapes.add(new Rectangle(4, 6));
shapes.add(new Triangle(3, 7));
double totalArea = calculateTotalArea(shapes);
System.out.println("Total Area: " + totalArea);
}
public static double calculateTotalArea(List<Shape> shapes) {
double totalArea = 0;
for (Shape shape : shapes) {
totalArea += shape.calculateArea();
}
return totalArea;
}
}
instanceOf()
- works with classes and interfaces
Coupling
defines how much a class is dependent of other classes
the objective is loose coupling
Cohesion
- defines how related the responsibilities of a class are
ex:
class InternetDownloader {
public void downloadFromInternet() {}
}
class DataParser {
public void parseData() {}
}
class StoreIntoDB {
public void storeInDB() {}
}
- in the example above the responsibilities are separated
Encapsulation
Hide the implementation of a class
Internal modification of a class should not require changes to other code
Use getters and setters, and create methods that limit the setting of private variables
Inner Class
- created inside another class or inside methods
ex:
OuterClass ex = new OuterClass();
OuterClass.InnerClass in =
ex.new
InnerClass();
for Static Nested Classes there is no need to instantiate the OuterClass to access the Inner
static cannot access values of OuterClass
ex:
OuterClass.StaticInnerClass = new OuterClass.StaticInnerClass();
Anonymous classes have no name and help you create a class and it's implementation inside another class
- used for single usage classes and methods
ex: creating a Comparator and it's implementation inside another class
Collections.sort(people, new Comparator<Person>() {
@Override
public int compare(Person person1, Person person2) {
return Integer.compare(person1.getAge(), person2.getAge());
}
});
Modifiers
default
Package access
Visibility only inside the package
private
Only available in the class they are declared in
Not available in subclasses
protected
Visibility inside the package
Available to subclasses
public
- Access from anywhere
Final Modifier
Class: A final class cannot be extended and becomes immutable.
Method: A final method cannot be overridden.
Variable: A constant variable cannot change (e.g., pi).
Static Modifier
Variables and methods become class-level members.
Static variables are shared by all instances of the class and can be accessed without instantiating.
Static methods cannot access instance variables or
this()
.Non-static methods and variables can access static methods and variables defined in the class.
Conditions and Loops
if (n > 10)
n = 1; // Without the {} only the first line is considered part of the if
n++; // This is executed outside of the if
// int n = 2;
switch(n) { // switch works only for String, char, byte, short, int, and ENUM
case 1:
System.out.println(1);
break;
case 2:
System.out.println(2);
break;
case 3:
System.out.println(3);
break;
default:
System.out.println("default");
// without a break, the output will be 2 3 default
}
// default can be anywhere in the switch but it will act the same
for (int n : numbers) { // numbers is an array[]
System.out.println(n);
}
Exception handling
- Chain of responsibility
ex:
main() >calls> method1() >calls> method2()
if method2() has no try catch it sends the responsibility to method1()
if method1() has no try catch it sends the responsibility to main()
if main also does not have a try catch it will throw the full stack trace
- finally keyword -> good for closing connections or context
it will always execute except if it throws exception or a JVM crash
- accepted forms:
try catch
try finally
try catch finally
Exception hierarchy
All exceptions inherit Throwable.
Error extends Throwable: Represents issues a programmer cannot handle (e.g., out of memory, stack overflow).
Exception extends Throwable: Can and should be handled by the programmer.
CheckedException extends Exception: Must be handled by the code calling this method.
UncheckedException extends RuntimeException: Thrown when the calling code is not expected or able to handle the exception.
When a method throws a CheckedException, it should handle it or declare that it throws an exception (e.g.,
throws Exception
) so the calling method can handle it or pass it up the chain of responsibility.
Try with resources:
ex:
try(BufferedReader b = new BufferedReader()){code}
it should close automatically the BufferedReader as long as it extends AutoClosable
Arrays
- default values:
byte, short, int, long: 0
float, double: 0.0
boolean: false
object: null
- array
.toString() -> for 1D arrays
.deepToString -> for 2D, 3D... arrays
. equals()
Enum
- works in switch statements
enum Seasons { WINTER(1), SPRING(2), SUMMER(3), FALL(4); private int code; public int getCode() { return code; } Seasons(int code) { this.code = code; } }
Variable arguments
ex:
public int sum(int...numbers){
for(int number: numbers){code...}}
Initializers
Static - runs when a class is loaded (ex: static {...} from a class)
Instance - runs when a new object is created
ex: class X {
int n;
{...}
}
Serialization
ex: Class implements serializable
converting an object in its current state to some internal representation (to File etc...)
deserialization is the reverse process
transient keyword for element we do not want to serialize
Subscribe to my newsletter
Read articles from Mihai Popescu directly inside your inbox. Subscribe to the newsletter, and don't miss out.
Written by
