Java Note
目录
-
Introduction of Java
-
Terminology
-
Basic concepts' definition of Java
-
Preconditions. Object interaction.
-
Collections and iteration. While loops.
-
Javac Postconditions Invariants Exceptions Equality vs Identity
-
Implementation vs interface Visibility Class members Constants Generic classes
-
Testing and debugging
-
Interfaces, Function/method overloading, Advance generics
-
Inheritance Abstract classes Inheritance-based polymorphism, encapsulation.
-
Comparable Anonymous classes Functional interfaces Streams Lambda functions
1. Introduction of Java
Features
- Platform Independent: Java is famous for its Write Once, Run Anywhere (WORA) feature. This means we can write our Java code once, and it will run on any device or operating system without changing anything.
- Object-Oriented: Java follows the object-oriented programming. This makes code clean and reusable.
- Security: Java does not support pointers, it includes built-in protections to keep our programs secure from common problems like memory leakage
Java is a strongly typed language; variables must be declared before use.. - Multithreading: Java programs can do many things at the same time using multiple threads. This is useful for handling complex tasks like processing transactions.
- Just-In-Time (JIT) Compiler: Java uses a JIT compiler. It improves performance by converting the bytecode into machine readable code at the time of execution.
- Automatic Memory Management (Garbage Collection) : Java automatically manages memory allocation and deallocation through its garbage collector. Developers don't need to manually free memory, which prevents memory leaks and reduces programming errors.
- Rich Standard Library: Java comes with an extensive collection of pre-built classes and APIs (Java Standard Edition API) covering everything from data structures, networking, file I/O, database connectivity, to GUI development, reducing development time significantly.
- Robust Exception Handling: Java provides a comprehensive exception handling mechanism with try-catch-finally blocks and checked/unchecked exceptions. This forces developers to handle potential errors explicitly, making applications more reliable and fault-tolerant.
- Dynamic Loading and Linking: Java supports dynamic class loading at runtime, allowing applications to load classes on-demand. This enables flexible architecture patterns and plugin-based systems without recompiling the entire application.
- Generics: Java's generic programming feature allows developers to write type-safe code by parameterizing types. This eliminates the need for casting and catches type errors at compile-time rather than runtime.
- Reflection: Java provides powerful reflection capabilities that allow programs to examine and modify their own structure and behavior at runtime. This enables frameworks, serialization, and dynamic programming techniques.
- Distributed Computing Support: Java has built-in support for distributed computing through technologies like RMI (Remote Method Invocation), CORBA, and web services, making it easy to build networked and distributed applications.
- Bytecode Portability: Java source code compiles to platform-neutral bytecode that runs on the Java Virtual Machine (JVM), enabling true cross-platform compatibility without performance penalties of pure interpretation.
JDK vs JRE vs JVM
Aspect | JDK | JRE | JVM |
---|---|---|---|
Purpose | Used to develop Java applications | Used to run Java applications | Executes Java bytecode |
Platform Dependency | Platform-dependent (OS specific) | Platform-dependent (OS specific) | JVM is OS-specific, but bytecode is platform-independent |
Includes | JRE + Development tools (javac, debugger, etc.) | JVM + Libraries (e.g., rt.jar) | ClassLoader, JIT Compiler, Garbage Collector |
Use Case | Writing and compiling Java code | Running a Java application on a system | Convert bytecode into native machine code |
2. Terminology
- Program:
Definition: A set of instructions that can be executed, i.e., the code you write.
Example: A simple C program file namedhello.c
that prints “Hello, world!” when compiled and run. - Algorithm:
Definition: A finite set of instructions that can be executed.
Example: Binary search, which finds an element’s position in a sorted array by repeatedly dividing the search interval in half. - Executable:
Definition: A file with a specific format, e.g., ELF, which contains a compiled program that can be executed.
Example: On Windows,calculator.exe
; on Linux,a.out
produced after runninggcc hello.c -o a.out
. - Process:
Definition: An instance of an executable that is being executed.
Example: When you double-clickcalculator.exe
, the operating system creates a “Calculator” process that runs until you close it.
3. Basic concepts' definition of Java
-
Classes and Objects:
-
Object:
-
An instance of a particular class, representing a value (with related operations) for a specific problem domain.
- A software notion: a "machine" known through the operations it supports.
-
Can represent:
- Physical objects: Material things (e.g., a bicycle, a book).
- Abstract objects: Conceptual notions (e.g., a schedule, an appointment).
- Software objects: Internal software abstractions (e.g., an iterator, an array).
- OOP's modeling ability allows connecting software objects to real-world or problem-domain entities.
- Class:
-
Defines all possible objects of a specific kind, specifying their common structure and behavior.
-
Defines:
- Data (Fields): Determine the state space of all the class's objects.
- Methods/Operations: Define the operations that can be invoked on an object.
- Constructors: Define how new objects are created and initialized.
- Structure (Java code):
- Features: The object's data (fields) and operations (methods) are collectively called its features. Each object belongs to a specific class that defines these features.public class ClassName { // CLASS MEMBERS (Fields, Constructors, Methods) }
-
-
Fields (Instance Variables / Attributes):
- Definition: Variables declared within a class (outside any method or constructor) that hold the data for each object.
- Purpose: Store data that persists throughout the life of an object, defining the object's state. Fields determine the state space (the set of all possible states) of the class's objects.
- Structure (Java code):
- Lifetime: Lasts as long as the object exists. - Scope: Accessible throughout the entire class (ifprivate Type fieldName; // Example: private int price;
private
, only within the class). -
Constructors:
- Purpose: Special methods responsible for creating and initializing new objects. They define how new objects are created.
-
Characteristics:
-
Have the exact same name as the class.
- Have no return type (not even
void
). - Structure (Java code):
public ClassName(/* ARGUMENTS (Parameters) */) { // BODY (Statements to initialize the object) } // Example: public TicketMachine(int ticketCost) { price = ticketCost; }
-
Methods:
- Definition: Operations that can be invoked on a particular object, implementing the object's behavior.
- Structure (Java code):
- Return Type: (public Type methodName(/* ARGUMENTS (Parameters) */) { // BODY (Statements to perform the operation) } // Example: public int getPrice() { return price; } // Example: public void insertMoney(int amount) { balance = balance + amount; }
Type
in the structure) Specified before the method name. Indicates the type of data the method sends back.void
means no value is returned. Non-void
methods must have areturn expression;
statement. - Accessor Methods (Queries): Retrieve or compute information about an object's state without changing it. They typically return a value. (e.g.,getPrice()
). - Mutator Methods (Commands): Modify the state of an object. (e.g.,insertMoney()
). - Command-Query Separation Principle: A method should either be a command (modify state, no return value) or a query (return value, no state modification), but not both. -
Arguments (Parameters):
- Definition: A list (possibly empty) of elements in a constructor or method header used to pass data into it.
- Format:
Type name
(e.g.,int amount
,String author
), separated by commas if more than one. - Purpose: Act as temporary variables, initialized by the values passed during the call. Their scope is limited to the constructor/method.
-
Body (of Constructors and Methods):
- Definition: The part enclosed in curly braces
{}
containing statements. - Structure: Can be a single
statement;
, or multiplestatement;
s, or a block{ body }
. -
Statement Types:
-
Assignment:
variable = expression;
(e.g.,balance = 0;
) - Variable Declaration:
Type variableName = expression;
orType variableName;
(for local variables, e.g.,int amountToRefund = balance;
) - Return:
return expression;
(used in methods that return a value) - Method Call:
objectReference.methodName(/*arguments*/);
(e.g.,System.out.println("Hello");
) - (Conditional statements, loops, etc., are also types of statements)
- Definition: The part enclosed in curly braces
-
Expressions:
- Definition: A "string" of Java code that can be evaluated to produce a value.
-
Examples:
-
A literal value (e.g.,
"Hello"
,100
,true
). - A variable (e.g.,
price
,name
). - A unary expression (e.g.,
!isVali
d,count++
,--i
). - A binary expression (e.g.,
3 + 1
,balance + amount
,"Hello" + "World!"
,4 * 3
). - A method call that returns a value (e.g.,
student.getName()
,name.substring(0,4)
). - A constructor call (which creates an object, e.g.,
new TicketMachine(500)
).
-
Data Types:
- Definition: Defines a set of possible values and the operations applicable to them.
-
Categories:
-
Primitive Types:
byte
,short
,int
,long
,float
,double
,char
,boolean
. - Reference Types:
String
, Arrays, Classes, Interfaces, Enums.
-
Variables (General Types and Characteristics):
- Fields (Instance Variables): Store object's persistent state. Defined at class level. Lifetime of the object.
- Parameters: Pass data into methods/constructors. Defined in headers. Temporary lifetime (during method/constructor execution).
- Local Variables: Temporary storage within a method/constructor body. Defined inside methods/constructors. Must be explicitly initialized before use if their value is read. Lifetime limited to method/constructor execution.
-
Conditional Statements (
if-else
): (Covered by "statement" type within method bodies)- Allow different code paths based on a boolean expression's result.
-
Source Code and Bytecode:
- Java code (source) is compiled into Bytecode for execution by the Java Virtual Machine (JVM).
4. Preconditions. Object interaction.
Precondition
- Definition: A condition that must be true before a method or constructor is executed.
-
Note:
-
The caller (client) is responsible for ensuring the precondition holds.
- If a precondition is not met, the method or object may behave incorrectly.
- Enforcing preconditions helps protect object state and supports encapsulation.
2. Assertions
- Definition: A Java feature for implementing precondition checking. If an assertion's condition is false, the program stops and shows an error message.
- Note: Assertions are typically used during development and testing and can be enabled or disabled at runtime.
3. Abstraction
- Definition: The ability to ignore the details of parts to focus on a higher level of a problem.
- Note: It helps in managing complexity by hiding implementation details and exposing only essential features.
- Example: When using a
ClockDisplay
object, you interact with methods likesetTime()
orgetTime()
without needing to know how it internally managesNumberDisplay
objects for hours and minutes.
4. Modularization
- Definition: The process of dividing a whole system into well-defined parts (modules) that can be built and analyzed separately, and whose interactions are clearly defined.
- Note: This promotes reusability and makes complex systems easier to manage and develop.
- Example: Creating a
ClockDisplay
class by combining two instances of aNumberDisplay
class.NumberDisplay
is a module for handling a two-digit number, andClockDisplay
uses these modules to represent time.
5. Object Reference
- Definition: When a variable is declared to be of an object type, it does not store the object itself but rather stores a reference (or address) to where the object is located in memory.
- Note: If two variables reference the same object, changes made to the object through one variable will be visible through the other variable.
- Example:
// Assuming a Person class with a setName(String name) method
Person personA = new Person("Alex");
Person personB = personA; // personB now references the same object as personA
personA.setName("John");
// Now, if you print personB.getName(), it will also be "John"
// System.out.println(personB.getName()); // Output: John
6. Classes Define Types
- Definition: A class name can be used as a type for a variable.
- Note: Variables of a class type can store references to objects of that class.
7. Java Comments
- Definition: Text in source code that is ignored by the compiler, used to provide explanations or annotations for human readers.
- Note: Javadoc comments (
/** ... */
) can be processed by the Javadoc tool to generate API documentation.
8. Logic Operators in Java
- Definition: Operators used to perform logical operations, typically on boolean values, resulting in a boolean value.
- Note: They are fundamental for controlling program flow in conditional statements and loops.
AND ( &&
), OR ( ||
), NOT ( !
)
9. Invoking Methods on Objects (External Method Call)
- Definition: The process of calling a method that belongs to an object. This is how you ask an object to perform an action or provide information.
- Note: The syntax involves the object reference, a dot (
.
), the method name, and parentheses (with arguments if required). - Example:
In the ClockDisplay
class: minutes.increment();
calls the increment
method on the minutes
object (which is of type NumberDisplay
).
10. Internal Method Call
- Definition: Calling a method from within another method of the same class.
- Note: You do not need to specify an object reference; the call is implicitly made on the current object (
this
)
11. Multiple Constructors
- Definition: A class can have more than one constructor, provided each has a different parameter list (i.e., different number or types of parameters).
- Note: This allows objects of the class to be created in various ways, with different initializations.
12. this
Keyword
- Definition: In Java,
this
is a reference variable that refers to the current object instance. -
Note:
-
It is commonly used to distinguish between instance variables (fields) and parameters when they have the same name (name overloading/shadowing).
- It can also be used to call another constructor in the same class (constructor chaining) or to pass the current object as an argument to another method.
13. Debugger Breakpoints
- Definition: A flag set in the source code at a specific line that instructs the debugger to pause the program's execution at that point.
- Note: When execution is paused, developers can inspect the state of variables, the call stack, and step through code line by line to understand program behavior and diagnose issues.
5. Collections and iteration. While loops.
1. Variable Declaration Scope
- Definition: Refers to the rules governing where variables can be declared and accessed in Java.
-
Note:
-
A class cannot have two fields (instance variables) with the same name.
- A local variable declared within a method or a block can have the same name as a class field. In this case, the local variable "shadows" the field within its scope. Use
this.fieldName
to access the field. - You cannot declare two local variables with the same name within the same scope (e.g., within the same method or the same block of code).
- You can declare variables with the same name in different, non-overlapping scopes (e.g., in two different methods, or in two separate
if
blocks) because their existence is confined to their respective scopes. - Example:
public class ScopeExample {
private int x = 10; // Field
public void methodOne() {
int x = 20; // Local variable, shadows the field 'x'
System.out.println(x); // Prints 20
System.out.println(this.x); // Prints 10 (accessing the field)
// int x = 30; // Error: Variable 'x' is already defined in this scope
}
public void methodTwo() {
int x = 30; // Different local variable 'x', valid because it's in a different scope
System.out.println(x); // Prints 30
if (true) {
int y = 5;
}
// int y = 10; // Error: 'y' was in the if-block scope only
}
}
2. Collection
- Definition: An object that groups multiple other objects and stores them as a single unit.
- Note: Collections provide ways to store, retrieve, manipulate, and communicate aggregate data.
- Example: An
ArrayList
can store an arbitrary number ofString
objects, orPerson
objects, etc.
3. Java Libraries
- Definition: Collections of pre-written, useful classes and interfaces grouped together, often to perform common programming tasks.
-
Note:
-
They allow developers to reuse code instead of writing everything from scratch.
- Java organizes libraries into packages (e.g.,
java.util
,java.io
). - Using collections is a common need, and libraries provide implementations.
- Example: The
java.util
package is a Java library that contains utility classes, including collection classes likeArrayList
.
4. ArrayList
- Definition: A resizable array implementation of the
List
interface in Java, which stores an ordered collection of elements. -
Note:
-
It's an unsorted (elements are stored in the order they are added, not necessarily sorted by value) but ordered (elements have specific indices) list with a flexible size.
- It belongs to the
java.util
package, so you need to importjava.util.ArrayList;
to use it. - Example: Declaring an
ArrayList
to storeString
objects:
import java.util.ArrayList;
public class MusicOrganizer {
private ArrayList<String> files; // "files" is an ArrayList that holds String objects
public MusicOrganizer() {
files = new ArrayList<String>(); // Or new ArrayList<>();
}
}
5. Generic Classes (using ArrayList
as an example)
- Definition: Classes that can work with different types of objects, where the specific type is specified as a parameter when an instance of the generic class is created or declared.
ArrayList
is an example of a generic class. -
Note:
-
The type parameter (e.g.,
<String>
,<Person>
) specifies the type of elements the collection will hold. - You must specify two types: the type of the collection itself (e.g.,
ArrayList
) and the type of its elements (e.g.,String
). -
ArrayList
provides methods likeadd
,get
,size
,remove
. - When an element at index
i
is removed, subsequent elements shift to fill the gap (e.g., element ati+1
moves toi
). - Example:
private ArrayList<String> songTitles; // An ArrayList to store String objects
private ArrayList<Integer> trackNumbers; // An ArrayList to store Integer objects
// private ArrayList<Person> members;
6. Diamond Notation
- Definition: A shorthand syntax introduced in Java 7 for invoking the constructor of a generic class, where the type arguments for the constructor can be inferred by the compiler.
- Note: Instead of writing
new ArrayList<String>()
, you can writenew ArrayList<>()
if the compiler can infer the typeString
from the context (e.g., the variable declaration). The<>
is called the diamond operator. - Example:
// Full form
ArrayList<String> namesListFull = new ArrayList<String>();
// Using Diamond Notation
ArrayList<String> namesListDiamond = new ArrayList<>();
7. ArrayList Structure and Characteristics
- Definition:
ArrayList
internally manages an array to store its elements and can dynamically resize this array. -
Note:
-
It can increase its internal capacity as required when more items are added.
- It maintains a private counter for its size, accessible via the
size()
method. - It keeps elements in a sequential order, and each element has a specific index.
- Inserting or deleting elements can affect the indices of other elements in the list.
- The internal implementation details (like how resizing happens) are hidden (encapsulation).
- Example: Conceptually, an
ArrayList
starts with a certain capacity. If you add more elements than its current capacity, it automatically creates a new, larger array and copies the old elements to it.
8. Iteration
- Definition: The process of repeating a set of instructions or actions multiple times, often to process each element within a collection or to continue until a certain condition is met.
- Note: Java provides several types of iteration statements (loops) to control this repetition.
- Example: To print every song title stored in an
ArrayList
of songs, you would use iteration.
9. For-each Loop (Enhanced For Loop)
- Definition: A type of loop in Java designed to iterate through elements of collections (like
ArrayList
) or arrays without using an explicit index. -
Note:
-
The syntax is
for (ElementType element : collection)
. - It's considered "definite iteration" as it iterates once for each element.
- You generally cannot modify the structure of the collection (e.g., add/remove elements) inside a for-each loop without risking a
ConcurrentModificationException
. - It's syntactically simple and makes code more readable for full collection traversal.
10. While-Loop
- Definition: A control flow statement that allows code to be executed repeatedly based on a given boolean condition. The loop body is executed as long as the condition evaluates to
true
. -
Note:
-
Provides more flexibility than a for-each loop, as the continuation condition is explicit.
- It's not limited to iterating over collections.
- Requires careful management of the loop condition and variables involved to prevent infinite loops.
11. For-Each vs. While Loop (Comparison)
-
Note:
-
For-Each:
- Simpler syntax, easier to write and read for iterating over all elements of a collection.
- Safer regarding termination (guaranteed to terminate after processing all elements).
- Less flexible; generally used for "definite iteration."
- No explicit index available.
-
While:
-
More flexible; can be used for "indefinite iteration" and when not iterating over a collection.
- Requires careful loop control to avoid infinite loops.
- Allows for early exit and more complex iteration logic (e.g., modifying loop variables or accessing elements by index if applicable).
12. Search in a Collection (using while-loop)
- Definition: Implementing a search algorithm within a collection using a
while
loop, typically to find if an element exists or to find its position. -
Note:
-
The loop continues as long as there are elements to check AND the target has not yet been found.
- Must correctly handle both cases: element found (success) and element not found after checking all items (failure).
- It's important to consider empty collections.
- Example:
public int findFileIndex(String searchString, ArrayList<String> files) {
int index = 0;
boolean found = false;
int foundAtIndex = -1; // To store the index if found, -1 if not found
while (index < files.size() && !found) {
String file = files.get(index);
if (file.contains(searchString)) {
found = true;
foundAtIndex = index; // Store the index
} else {
index++;
}
}
return foundAtIndex; // Returns index or -1
}
6. Javac Postconditions Invariants Exceptions Equality vs Identity
1. The main
Method
- Definition: The entry point for any Java application. The Java Virtual Machine (JVM) starts execution by invoking this method.
- Signature:
public static void main(String[] args)
-
Note:
-
public
: Accessible from anywhere. -
static
: It's a class method, meaning it can be called without creating an object of the class. It's associated with the class itself. -
void
: It does not return any value. -
String[] args
: It accepts an array ofString
objects, which are the command-line arguments passed to the program.
2. static
Keyword
- Definition: A Java keyword used to declare members (fields or methods) that belong to the class itself, rather than to instances (objects) of the class.
-
Note:
-
Static Method (Class Method) : Can be called using the class name directly, without needing an object instance (e.g.,
Math.random()
). Themain
method is static. - Static Field (Class Field/Variable) : There is only one copy of a static field shared among all instances of the class. If one object changes the value of a static field, the change is reflected for all other objects.
3. Packages
- Definition: A mechanism in Java to organize classes and interfaces into namespaces or logical groups, preventing naming conflicts and making code more manageable.
-
Note:
-
From an OS perspective, a package corresponds to a directory structure.
- In Java, package names are sequences of identifiers separated by dots (e.g.,
java.util
,com.example.myapp
). - The
package
statement at the top of a Java file declares the package the class belongs to. - The
import
statement is used to access classes from other packages.
4. Compilation and Execution (Java)
- Definition: The two-step process of transforming Java source code into an executable program.
-
Note:
-
Compilation: Java source code (
.java
files) is compiled by the Java Compiler (javac
) into Java bytecode (.class
files). Bytecode is a platform-independent intermediate representation. - Execution: The Java Virtual Machine (JVM) interprets (or JIT-compiles) and executes the Java bytecode. The
java
command is used to launch the JVM and run a specific class file containing amain
method. - If a main Java file imports classes from other
.java
files (in the same package or specified correctly),javac
will typically compile these dependencies automatically. - To run a class within a package:
java packageName.ClassName
. -
Example:
-
Compile:
javac MyProgram.java
(createsMyProgram.class
) - Execute:
java MyProgram
(JVM runsMyProgram.class
) - Compile
Main.java
which importspackageA.A
:javac Main.java
(might also compileA.java
) - Execute
Main.java
which usespackageA.A
:java Main
(assuming Main is not in a package) - Execute a class
B
inpackageB
:java packageB.B
5. Preconditions and Postconditions (Full Contracts)
-
Definition:
-
Precondition: A condition that must be true before a method is called. The responsibility of the client (caller).
- Postcondition: A condition that must be true after a method completes successfully, assuming the preconditions were met. The responsibility of the implementer (method).
-
Note:
-
Together, preconditions and postconditions form a "contract" for a method.
- Preconditions protect the method from misuse.
- Postconditions provide guarantees to the client about the outcome or state change if preconditions are met.
6. Class Invariants
- Definition: Conditions or properties related to the state of an object that must always be true for any valid instance of a class, except during the execution of a method that might temporarily violate them (but must restore them before completion).
-
Note:
-
Class invariants define what constitutes a "correct" or "consistent" state for an object.
- They should hold true after a constructor finishes and before and after any public method call (assuming preconditions of the method were met).
- A
repOk()
(representation okay) method is often used to check if an object's state satisfies its class invariants. - Example: For a
Student
class:
public boolean repOk() {
if (minutes == null || hours == null) {
return false;
}
if (minutes.getLimit() != 60 || hours.getLimit() != 24) {
return false;
}
return minutes.repOk() && hours.repOk();
}
7. Exceptions
- Definition: Events that occur during the execution of a program that disrupt the normal flow of instructions. Java uses an exception handling mechanism to deal with runtime errors.
-
Note:
-
Checked Exceptions: Must be declared in a method's
throws
clause or handled using atry-catch
block. The compiler enforces this. - Unchecked Exceptions (RuntimeExceptions) : Do not need to be declared or caught, though they can be. Often indicate programming errors (e.g.,
NullPointerException
,IllegalArgumentException
). -
Common unchecked exceptions:
-
ArithmeticException
(e.g., division by zero). -
NullPointerException
(using anull
reference). -
IllegalArgumentException
(invalid argument passed to a method). -
IllegalStateException
(object is in an inappropriate state for the requested operation). - Exceptions can be
thrown
(to signal an error) andcaught
(to handle an error).
-
8. Catching and Rethrowing Exceptions
- Definition: A
try-catch
block allows you to attempt code that might throw an exception. If an exception occurs within thetry
block, the correspondingcatch
block can handle it. Rethrowing means catching an exception and then throwing a new (or the same) exception, often to wrap it in a more specific or application-relevant exception type. -
Note:
-
try
: Contains the code that might throw an exception. -
catch
: Catches a specific type of exception. You can have multiplecatch
blocks. - Checked exceptions caught might need to be rethrown (or handled) if the current method cannot fully resolve the issue but also declares it in its
throws
clause. - Example (Catching an unchecked exception and returning a default):
public int parseInteger(String text, int defaultValue) {
if (text == null) {
throw new IllegalArgumentException("Input string cannot be null.");
}
try {
return Integer.parseInt(text);
} catch (NumberFormatException e) {
return defaultValue; // Handle by returning default
}
}
9. Equality of Primitive Types
- Definition: For primitive data types (like
int
,char
,boolean
,double
), the equality operator==
compares their actual values. - Note: The
!=
operator checks for inequality of values.
10. Equality of Non-Primitive Types (Objects/References)
- Definition: For non-primitive types (objects), the equality operator
==
compares the memory addresses (references) of the objects, not their contents or states. -
Note:
-
obj1 == obj2
istrue
if and only ifobj1
andobj2
refer to the exact same object in memory. - This is usually not what is desired for "logical" equality (i.e., whether two objects represent the same conceptual entity).
- Every object has a unique identifier (hashcode), but
==
directly compares references. - Example:
String s1 = new String("hello");
String s2 = new String("hello");
String s3 = s1;
// s1 == s2 is false (s1 and s2 are different objects in memory, even if their content is the same)
// s1 == s3 is true (s3 refers to the same object as s1)
11. equals()
Method
- Definition: A method inherited by all classes from the
Object
class, intended to compare the "logical" equality of two objects (i.e., whether their states or contents are considered equivalent), rather than just their memory addresses. -
Note:
-
The default implementation of
equals()
in theObject
class behaves like==
(compares references). - Classes should override
equals()
(andhashCode()
) to provide a meaningful comparison based on their fields. - The
equals(Object other)
method takes an argument of typeObject
to be compatible with any class. -
Implementation usually involves:
- check whether it is null.
- check whether it is an instance of that class
- convert the class type and check whether they are equal.
- check each field
- Example
@Override
public boolean equals(Object other) {
if (other == null) {
return false;
}
if (!(other instanceof Clock)) {
return false;
}
Clock otherAsClock = (Clock) other;
if (amPm != otherAsClock.amPm) {
return false;
}
return minutes.equals(otherAsClock.minutes) && hours.equals(otherAsClock.hours);
}
12. Instance / Generating Class
-
Definition:
-
An instance of a class is an object created from that class's blueprint.
- The generating class (or simply "class") of an object is the class from which the object was instantiated.
- Note: The
instanceof
operator can be used to check if an object is an instance of a particular class or interface. - Example:
String myString = new String("Hello");
// myString is an instance of the String class.
// String is the generating class of the myString object.
7. Implementation vs interface Visibility Class members Constants Generic classes
1. Java Class Structure Review
- Definition: A typical organization of a Java class file.
-
Note:
-
Starts with an optional
package
declaration. - Followed by
import
statements to use classes from other packages.import laboratory.data.*
would import all public classes from thelaboratory.data
package. - Class documentation (using Javadoc
/** ... */
) precedes the class declaration. - The class declaration includes visibility modifiers (e.g.,
public
), theclass
keyword, and the class name. -
Inside the class:
- Fields (instance variables) are declared, typically with
private
visibility. - Constructors are defined, with Javadoc.
- Methods are defined, with Javadoc and their implementations.
- Conventionally, Java source files are placed in a
src/main/java
directory structure within a project. - Example:
- Fields (instance variables) are declared, typically with
package com.example.school; // Package declaration
import java.util.List; // Import statement
import com.example.people.Student; // Import specific class
/**
* Represents a classroom with students.
*/
public class Classroom {
private String roomNumber;
private List<Student> students; // Fields
/**
* Constructs a new Classroom.
* @param roomNumber The number of the classroom.
*/
public Classroom(String roomNumber) { // Constructor
this.roomNumber = roomNumber;
// this.students = new ArrayList<>(); // Implementation detail
}
/**
* Adds a student to the classroom.
* @param student The student to add.
*/
public void addStudent(Student student) { // Method
// this.students.add(student); // Implementation detail
}
}
2. Java import
Statement
- Definition: A statement in Java that allows you to use classes and interfaces defined in other packages without referring to them by their fully qualified names.
- Note: Unlike C's
#include
, Java'simport
does not insert the code of the imported class into the current file. It simply tells the compiler where to find the definition of the class or interface being used, making the type available by its simple name. - Example:
// Without import:
// java.util.ArrayList<String> myList = new java.util.ArrayList<>();
// With import:
import java.util.ArrayList;
// ArrayList<String> myList = new ArrayList<>();
3. Class Interface
- Definition: The public-facing part of a class, consisting of its public constructors, methods (signatures and documentation), and public constants. It defines how other classes can interact with it.
- Note: The implementation details (private fields and method bodies) are hidden from the client. This promotes encapsulation.
- Example: From the
Laboratory
class example, the interface would include:
package laboratory;
import java.util.ArrayList;
import laboratory.data.Student;
import laboratory.data.Teacher;
/**
* <Class documentation>
*/
public class Laboratory {
/**
* <Constructor documentation>
*/
public Laboratory(String name, Teacher teacher);
/**
* <Method documentation>
*/
public int numberOfStudents();
}
(Actual implementation of constructors and methods is hidden from the interface view).
4. Visibility Modifiers
- Definition: Keywords in Java that control the accessibility of classes, interfaces, fields, and methods.
-
Note:
-
private
: Accessible only within the same class. -
package
(default, no keyword): Accessible only within the same package. -
protected
: Accessible within the same package, and by subclasses in other packages. -
public
: Accessible from any class, anywhere.
5. static
Keyword (Class Members)
- Definition: A keyword used to declare members (fields or methods) that belong to the class itself, rather than to a specific instance (object) of the class.
-
Note:
-
Static fields (class variables) : Shared among all instances of the class. Only one copy exists.
- Static methods (class methods) : Can be called using the class name directly (e.g.,
ClassName.staticMethod()
) without creating an object. They cannot directly access instance (non-static) members. - Think "class-level" vs. "object-level."
6. final
Keyword (Constants)
- Definition: A keyword used to declare entities that cannot be changed after initialization.
-
Note:
-
Final variable: Its value cannot be reassigned once initialized. Must be initialized at declaration or in the constructor (for instance variables).
- Often used with
static
to create class constants (e.g.,public static final int MAX_USERS = 100;
).
7. Generic/Parameterized Classes (Concept)
- Definition: Classes that are designed to work with one or more types, where the specific type(s) are provided as parameters when an instance of the generic class is created or declared.
-
Note:
-
Allows for type safety and code reusability.
-
ArrayList<T>
is a common example, whereT
is a type parameter representing the type of elements the list will hold (e.g.,ArrayList<String>
,ArrayList<Student>
).
8. Software Evolution and Maintainability
- Definition: The idea that software is not static but changes over time due to new requirements, bug fixes, or environmental changes. Maintainability refers to the ease with which software can be modified.
-
Note:
-
Software that is hard to maintain is likely to become obsolete.
- Good design practices aim to increase maintainability.
9. Code Quality
- Definition: A set of characteristics that determine the overall goodness of source code.
-
Note: Key aspects include:
-
Self-documenting code: Code that is clear and easy to understand on its own.
- Proper documentation: Javadoc comments and other explanations.
- Testability: Ease of writing tests for the code.
- Low coupling: Minimizing dependencies between different parts of the code.
- High cohesion: Ensuring that each unit (class, method) has a single, well-defined responsibility.
10. Coupling
- Definition: The degree of interdependence between software modules (e.g., classes).
-
Note:
-
Tight coupling: Classes depend heavily on each other's internal details. Changes in one class often require changes in others.
- Loose coupling (Goal) : Classes are independent. Changes in one class have minimal impact on others. This improves maintainability, as classes can be understood and modified in isolation.
- Example: If
ClassA
directly accesses and manipulates many private fields ofClassB
, they are tightly coupled. IfClassA
only interacts withClassB
through its well-defined public methods, they are more loosely coupled.
11. Cohesion
- Definition: The degree to which the elements within a single module (e.g., a class or a method) belong together and are focused on a single, well-defined task or purpose.
-
Note:
-
Low cohesion: A class or method does many unrelated things.
- High cohesion (Goal) : A class represents a single logical entity, and a method performs a single logical task. This makes code easier to understand, name, and reuse.
-
Example:
-
A class
UserManagerAndReportGenerator
likely has low cohesion. - Separate classes
UserManager
andReportGenerator
would have higher cohesion. - A method
getUserDetailsAndSendEmailAndLogAccess()
has low cohesion.
12. Code Duplication
- Definition: The occurrence of the same or very similar blocks of code in multiple places within a software system.
-
Note:
-
It's an indicator of poor design.
- Makes maintenance harder (a change needs to be applied in all duplicated places).
- Increases the risk of errors if one instance of the duplicated code is updated but others are missed.
- Example: Copying and pasting a 10-line algorithm into three different methods instead of extracting it into a single, reusable helper method.
13. Responsibility-Driven Design (RDD)
- Definition: A design approach that focuses on assigning clear responsibilities to objects (classes). Each class should be responsible for managing its own data and operations related to that data.
-
Note:
-
Emphasizes the "contract" between a client (user of a class's features) and a provider (the class offering features).
- Leads to lower coupling because classes manage their own affairs rather than other classes directly manipulating their internal state.
- Example: Instead of a
ShoppingCartManager
directly modifying theprice
field of anItem
object, theItem
class itself should have a method likeupdatePrice(newPrice)
, makingItem
responsible for its own price.
14. Localizing Change
- Definition: A design goal aiming to ensure that when a modification to the software is required, the changes are confined to as few modules (classes) as possible.
- Note: This is a benefit of low coupling and good responsibility assignment. It makes the system more robust and easier to maintain because changes in one area are less likely to have unintended side effects elsewhere.
- Example: If the way user authentication is handled needs to change, ideally, only an
Authenticator
class should be affected, not every class that needs user authentication.
15. Thinking Ahead (Design)
- Definition: The practice of considering potential future changes and requirements during the initial design phase of a class or system.
-
Note:
-
The aim is to design software that is flexible enough to accommodate likely future modifications easily.
- However, this should be balanced against the risk of "over-engineering" – creating overly complex solutions for hypothetical future problems that may never materialize.
- Example: When designing a
ReportGenerator
, one might consider that future reports might need different output formats (PDF, CSV, HTML) and design the class in a way that makes adding new formats relatively simple, perhaps using a strategy pattern.
16. Refactoring
- Definition: The process of restructuring existing computer code—changing the factoring—without changing its external behavior.
-
Note:
-
Aimed at improving non-functional attributes of the software, such as readability, reducing complexity, improving maintainability, and increasing extensibility.
- Often done when classes or methods become too long or complex, to restore high cohesion and low coupling.
- Example: Extracting a complex block of code from a long method into a new, separate private method with a descriptive name.
17. Refactoring and Testing
- Definition: The practice of ensuring code quality and correctness during refactoring by using tests.
-
Note:
-
Refactoring should be done separately from adding new features or fixing bugs.
- Regression testing (running existing tests) is crucial before and after refactoring to ensure that no existing functionality was broken by the changes.
- Example: Before refactoring a
calculateDiscount
method, ensure there are comprehensive unit tests covering its current behavior. After refactoring, run the same tests to verify it still works correctly.
18. Design Guidelines (Method/Class Complexity)
- Definition: General principles to help in designing well-structured classes and methods.
-
Note:
-
Method length: A method might be too long if it performs more than one distinct logical task.
- Class complexity: A class might be too complex (low cohesion) if it represents more than one logical entity or concept.
- These are guidelines, not strict rules, and require designer judgment.
-
Example:
-
A method
loadUserDataAndValidateAndSaveToDatabase()
is likely doing too much. It could be split intoloadUserData()
,validateUserData()
, andsaveUserDataToDatabase()
. - A class
UserOrderProductInventoryManager
is likely too complex.
8. Testing and debugging
1. Testing Fundamentals
- Definition: The core principles involved in verifying that a unit of software (e.g., a method or a class) behaves as expected according to its contract or specification.
-
Note:
-
Requires understanding the unit's contract (what it's supposed to do).
- Aims to find violations of this contract.
- Involves both positive tests (testing correct behavior with valid inputs/scenarios) and negative tests (testing incorrect behavior, such as error handling or graceful failure, with invalid inputs/scenarios).
-
Example:
-
Positive Test: For a method
sum(int a, int b)
, testsum(2, 3)
and expect5
. - Negative Test: For a method
divide(int a, int b)
, testdivide(5, 0)
and expect anArithmeticException
or a specific error code.
2. Components of a Unit Test (Arrange, Act, Assert)
- Definition: A common structure for writing unit tests, breaking them down into three distinct phases.
-
Note:
-
Arrange: Set up the necessary preconditions and inputs. This includes creating objects, initializing variables, and preparing the environment for the test.
- Act: Execute the specific unit of code (e.g., call the method) being tested with the arranged inputs.
- Assert: Verify that the outcome of the action matches the expected behavior. This involves checking return values, object states, or whether specific exceptions were thrown.
- Example:
// Assume a Calculator class with an add(int, int) method
@Test // Annotation for JUnit
public void testAddition() {
// Arrange
Calculator calc = new Calculator();
int num1 = 5;
int num2 = 10;
int expectedSum = 15;
// Act
int actualSum = calc.add(num1, num2);
// Assert
assertEquals(expectedSum, actualSum); // JUnit assertion
}
3. Ad hoc Unit Testing
- Definition: Informal testing performed as needed, often manually within an IDE or by temporarily adding print statements, without a structured testing framework.
- Note: The example image shows using BlueJ's object bench to manually create objects, call methods, and inspect results.
-
Drawbacks:
-
Not easily repeatable for future runs.
- Can become complex and error-prone to set up for more intricate scenarios.
- Requires manual verification of results, which can be subjective or lead to missed errors.
4. Testing Framework (e.g., JUnit)
- Definition: A set of tools, libraries, and conventions that provides a standardized way to write, organize, and run automated tests. JUnit is a popular testing framework for Java.
-
Note:
-
Automates the execution of tests and reporting of results.
- Allows tests to be easily re-run (e.g., for regression testing).
- Provides assertions to programmatically check expected outcomes.
- Supports features like test fixtures for setting up common test environments.
- Example: The image shows a JUnit test class with
@Test
annotated methods, usingassertEquals
for assertions.
5. Test Automation
- Definition: The use of software tools and frameworks to execute tests and verify their outcomes automatically, without manual intervention.
-
Note:
-
While designing good tests is a creative process, running them repeatedly can be tedious.
- Crucial for regression testing (re-running tests to ensure recent changes haven't broken existing functionality).
- A test rig or test harness (like JUnit) helps automate this process.
6. JUnit
- Definition: A widely used open-source unit testing framework for the Java programming language.
-
Note:
-
Test Cases: Individual tests, typically implemented as methods within a test class.
- Test Classes: Classes that group related test methods.
- Assertions: Methods (e.g.,
assertEquals
,assertTrue
,assertNull
) used within test methods to check if the actual outcome matches the expected outcome. - Fixtures: A fixed state of a set of objects used as a baseline for running tests. JUnit provides mechanisms (e.g.,
@BeforeEach
,@BeforeAll
) to set up fixtures.
7. Modularization and Interfaces
-
Definition:
-
Modularization: The process of dividing a software system into separate, independent, and interchangeable modules.
- Interfaces (between modules) : Clearly defined contracts that specify how modules interact with each other, without exposing their internal implementation details.
-
Note:
-
Increases software quality by providing abstraction.
- Supports independent and concurrent development of modules.
- Increases the likelihood of successful integration of modules.
- In the calculator example, the UI (User Controls) and the calculation logic (Engine) are separate modules communicating through a defined interface.
- Example: A
PaymentProcessor
module might have an interface likeprocessPayment(OrderDetails details, PaymentInfo info)
which other modules (e.g.,OrderService
) can use without knowing if the payment is processed via Credit Card, PayPal, etc.
8. Method Headers as an Interface
- Definition: The collection of public method signatures (including method name, parameters, and return type, often with Javadoc) of a class defines its primary interface for interaction.
- Note: These headers specify what a class can do, not how it does it. Clients of the class use this interface to interact with its objects.
-
Example: The calculator engine methods:
-
public int getDisplayValue();
-
public void numberPressed(int number);
-
public void plus();
- etc.
These define how an external component (like a UI) interacts with the calculator engine.
9. Debugging
- Definition: The process of finding and resolving defects or problems (bugs) within a computer program that prevent correct operation.
-
Note:
-
Requires good code reading skills, especially when debugging others' code.
- Various techniques and tools (like debuggers in IDEs) exist to aid this process.
10. Manual Walkthroughs (Debugging)
- Definition: A debugging technique where a developer manually simulates the execution of code, line by line or step by step, often away from the computer.
-
Note:
-
A low-tech but potentially powerful approach.
- Can be done at a high level (stepping over methods) or low level (stepping into methods).
- Helps in understanding program flow and identifying logical errors.
- Example: Taking a piece of code on paper and manually tracking variable values and execution paths for a given input.
11. Tabulating Object State (Debugging)
- Definition: A debugging technique involving systematically recording the values of an object's key fields (its state) at various points during execution, especially before and after method calls.
-
Note:
-
Incorrect object behavior is often due to an incorrect state.
- Helps identify when and how an object's state becomes corrupted.
- Example: For a
BankAccount
object, tracking itsbalance
field after eachdeposit
andwithdraw
call.
12. Verbal Walkthroughs (Rubber Ducking)
- Definition: A debugging technique where a developer explains their code, line by line, to someone else (who may or may not be a developer) or even to an inanimate object (like a rubber duck).
-
Note:
-
The act of articulating the code's logic can help the developer spot their own errors.
- The listener might also identify issues.
- Formal group-based processes for code review like inspections are more structured versions.
- Example: Explaining to a colleague: "First, I initialize the counter to zero, then in this loop, I increment it if the condition X is met..." and suddenly realizing the condition X is flawed.
13. Print Statements (Debugging)
- Definition: A common debugging technique that involves inserting statements into the code to print the values of variables or messages to the console at various points of execution.
-
Note:
-
Simple to implement and supported by all languages.
- Effectiveness depends on placing print statements strategically.
- Can lead to a large volume of output, making it hard to find relevant information.
- Manually adding/removing them can be labor-intensive and error-prone.
9. Interfaces, Function/method overloading, Advance generics
1. Type (General Concept)
- Definition: A type defines a set of values and specifies which operations can be applied to those values.
- Attention Point: The type itself doesn't define the implementation of the operations, only which operations are permissible.
2. Type (in Object-Oriented Programming - OOP)
- Definition: In OOP, a type (often represented by a class) defines a set of values, their representation (how data is stored), and also the operations (methods) that can be applied to those values, including their implementations.
- Attention Point: It bundles data (values and representation) with behavior (operations and their implementations).
3. Abstract Data Type (ADT)
- Definition: An ADT is a description of a set of values and the operations on those values, without specifying the technical details of how those values are represented internally or how the operations are implemented. It focuses on what it does, not how it does it.
- Attention Point: It's a conceptual model, focusing on behavior from the user's perspective, hiding implementation details.
4. List (as an ADT)
- Definition: A linearly organized collection of values.
- Operations: Creation, Insertion, Deletion, Retrieval, and properties like checking if it's empty, getting its size, or checking if it contains a value.
5. Set (as an ADT)
- Definition: An unordered collection of different (unique) elements.
- Operations: Creation, Insertion, Deletion, Union, Intersection, and properties like checking if it's empty, getting its size, checking if it contains a value, or if it's a subset of another set.
- Attention Point: Elements are unique, and order doesn't matter.
6. Stack (as an ADT)
- Definition: A linearly organized collection of values that follows the FILO (First-In, Last-Out) principle. The last element added is the first one to be removed.
- Operations: Creation, Push (add an element to the top), Pop (remove an element from the top), and properties like checking if it's empty or getting its size.
- Attention Point: Access is restricted to the "top" of the stack.
7. Queue (as an ADT)
- Definition: A linearly organized collection of values that follows the FIFO (First-In, First-Out) principle. The first element added is the first one to be removed.
- Operations: Creation, Enqueue (add an element to the rear), Dequeue (remove an element from the front), and properties like checking if it's empty or getting its size.
- Attention Point: Elements are added at one end and removed from the other.
8. Data Abstractions in Object-Oriented Languages (Classes and Objects)
- Definition: A class defines a new type. It specifies the data (attributes) and the operations (methods) that can be performed on instances of that class. Objects are instances of a class.
- Attention Point: Data and operations are encapsulated together within an object. Memory management for objects is often automatic (e.g., via garbage collection).
9. Interface (in Java)
- Definition: An interface in Java defines a new abstract type by describing a set of operations (method signatures) without providing their implementation or a specific data representation. It acts as a contract for classes that implement it.
-
Attention Points:
-
Cannot be instantiated directly (cannot create objects of an interface type).
- Cannot have constructors.
- Traditionally, cannot define or declare instance fields (constants are allowed:
public static final
). - Traditionally, cannot define method implementations (only declare public abstract methods).
- (Note: Some of these restrictions have been relaxed in Java 9+ with default and static methods, and private methods, but the core concept for basic understanding focuses on abstract methods).
- Implementing classes are considered subtypes of the interface type, enabling polymorphism.
- Promotes strong separation of functionality (what to do) from implementation (how to do it).
- Example
interface Playable {
void playSound();
void stopSound();
}
class MP3Player implements Playable {
public void playSound() { /* code to play MP3 */ }
public void stopSound() { /* code to stop MP3 */ }
}
class VideoPlayer implements Playable {
public void playSound() { /* code to play video sound */ }
public void stopSound() { /* code to stop video sound */ }
}
10. Function Overloading
- Definition: The ability to define multiple functions (or methods within a class) with the same name but different parameter lists. The difference can be in the number of arguments, the types of arguments, or both.
- Attention Point: The compiler distinguishes which version of the function to call based on the arguments provided during the function call (this is called signature matching). The return type alone is not sufficient to overload a function.
10. Inheritance Abstract classes Inheritance-based polymorphism, encapsulation
1. Class Extension (Inheritance)
- Definition: In Object-Oriented Programming, class extension is a mechanism where a new class (subclass or derived class) inherits properties (fields) and behaviors (methods) from an existing class (superclass or base class). In Java, all classes implicitly or explicitly extend the
Object
class, which is the root of the class hierarchy. -
Attention Points:
-
A subclass (e.g., class
A
) has access topublic
,package-private
(if in the same package), andprotected
members of its superclass (e.g., classB
). - A subclass can redefine (override) inherited methods. The access permission of an overridden method in the subclass must be the same or more permissive (e.g., a
protected
method in the superclass can beprotected
orpublic
in the subclass, but notprivate
). - The relationship is often described as an "is-a" relationship (e.g., if
Dog
extendsAnimal
, then aDog
is anAnimal
). - Simple Example:
class Animal {
public String sound = "Generic Sound";
public void makeSound() {
System.out.println(sound);
}
}
class Dog extends Animal {
// Dog inherits 'sound' field and 'makeSound()' method
// Dog can also have its own specific members
public void fetch() {
System.out.println("Dog is fetching.");
}
}
// Usage:
// Dog myDog = new Dog();
// myDog.makeSound(); // Output: Generic Sound
// myDog.fetch(); // Output: Dog is fetching.
2. Superclass Constructor Call (super()
)
- Definition: A call from a subclass constructor to a constructor of its direct superclass.
-
Attention Points:
-
It must be the very first statement in the subclass constructor.
- If no explicit
super()
call is written, the compiler automatically inserts asuper()
call (a call to the superclass's no-argument constructor). This only works if the superclass has an accessible no-argument constructor. - If the superclass does not have a no-argument constructor, you must explicitly call one of its other constructors using
super(arguments)
. - Simple Example:
class Vehicle {
String type;
Vehicle(String type) {
this.type = type;
System.out.println("Vehicle constructor called: " + type);
}
}
class Car extends Vehicle {
String model;
Car(String modelName) {
super("Land Vehicle"); // Explicit call to Vehicle constructor
this.model = modelName;
System.out.println("Car constructor called: " + modelName);
}
}
// Usage:
// Car myCar = new Car("Sedan");
// Output:
// Vehicle constructor called: Land Vehicle
// Car constructor called: Sedan
3. Extending Interfaces
- Definition: An interface can extend one or more other interfaces. This means the extending interface inherits all the abstract method declarations from the super-interfaces. A class implementing the extending interface must provide implementations for all methods from the entire interface hierarchy.
- Attention Point: This is different from a class implementing an interface. "Interface A extends Interface B" means A gets all methods of B. "Class C implements Interface A" means C must define all methods in A (and transitively B).
- Simple Example:
interface Runnable {
void run();
}
interface Stoppable extends Runnable { // Stoppable inherits run()
void stop();
}
class MyProcess implements Stoppable {
public void run() { System.out.println("Process running..."); }
public void stop() { System.out.println("Process stopping..."); }
}
4. Abstract Class
- Definition: A class that is declared with the
abstract
keyword. It cannot be instantiated directly (you cannot create objects of an abstract class). It is designed to be subclassed. Abstract classes can contain abstract methods (methods without a body) and concrete methods (methods with an implementation). -
Attention Points:
-
If a class contains one or more abstract methods, it must be declared abstract.
- A subclass of an abstract class must either implement all inherited abstract methods or be declared abstract itself.
- Simple Example:
abstract class Shape {
String color;
abstract void draw(); // Abstract method - no implementation
public Shape(String color) { this.color = color; }
public String getColor() { return color; } // Concrete method
}
class Circle extends Shape {
double radius;
public Circle(String color, double radius) {
super(color);
this.radius = radius;
}
@Override
void draw() { // Implementation of abstract method
System.out.println("Drawing a " + getColor() + " circle with radius " + radius);
}
}
// Shape myShape = new Shape("Red"); // ERROR! Cannot instantiate abstract class.
// Shape myCircle = new Circle("Blue", 5.0); // OK
// myCircle.draw();
5. Subtyping (and Substitution)
- Definition: If class
B
is a subclass of classA
, then typeB
is a subtype of typeA
. This means an object of a subclass (B
) can be used wherever an object of its superclass (A
) is expected. This principle is also known as the Liskov Substitution Principle. - Attention Point: The reverse is not true without an explicit cast (and runtime type check). You cannot directly use a superclass object where a subclass object is expected.
- Simple Example:
// (Using Animal and Dog from example 1)
Animal myPet;
myPet = new Dog(); // OK: Dog is a subtype of Animal (Dog "is an" Animal)
myPet.makeSound(); // Calls Dog's makeSound if overridden, else Animal's
// Dog specificDog = new Animal(); // ERROR! Animal is not necessarily a Dog.
6. Polymorphism (with Subclasses and Parameter Passing)
- Definition: Polymorphism ("many forms") allows objects of different classes (that share a common superclass or interface) to be treated as objects of the common supertype. When a method is called on such an object, the version of the method specific to the object's actual runtime type is executed (this is dynamic method dispatch).
- Attention Point: This is evident when passing subclass objects to methods expecting superclass parameters.
- Simple Example:
// (Using Animal, Dog, and a new Cat class)
class Cat extends Animal {
@Override
public void makeSound() { System.out.println("Meow"); }
}
public class Zoo {
public void introduceAnimal(Animal animal) {
System.out.print("This animal says: ");
animal.makeSound(); // Actual method called depends on animal's runtime type
}
public static void main(String[] args) {
Zoo myZoo = new Zoo();
Animal genericAnimal = new Animal();
Dog myDog = new Dog();
Cat myCat = new Cat();
myZoo.introduceAnimal(genericAnimal); // Output: This animal says: Generic Sound
myZoo.introduceAnimal(myDog); // Output: This animal says: Generic Sound (or "Woof" if overridden in Dog)
myZoo.introduceAnimal(myCat); // Output: This animal says: Meow
}
}
7. Object
Class
- Definition: The root of the class hierarchy in Java. Every class is a descendant (directly or indirectly) of
Object
. - Attention Point: A variable of type
Object
can hold a reference to an instance of any non-primitive type (any class, interface implementation, or array). - Simple Example:
Object obj1 = "Hello World"; // String is an Object
Object obj2 = new Dog(); // Dog is an Object
Object obj3 = new int[]{1, 2, 3}; // Array is an Object
8. Method Overriding
- Definition: A feature where a subclass provides a specific implementation for a method that is already defined in its superclass. The overridden method in the subclass must have the same name, return type (or a subtype, known as covariant return type), and parameter list as the method in the superclass.
-
Attention Point:
-
The
@Override
annotation is recommended to ensure the method is indeed overriding a superclass method. - Access level of the overriding method cannot be more restrictive than the overridden method.
-
final
methods cannot be overridden.static
methods cannot be overridden (they can be hidden). - Simple Example:
class Vehicle {
void startEngine() {
System.out.println("Vehicle engine starting.");
}
}
class ElectricCar extends Vehicle {
@Override
void startEngine() { // Overriding the method
System.out.println("Electric car motor engaged silently.");
}
}
// Vehicle myVehicle = new ElectricCar();
// myVehicle.startEngine(); // Output: Electric car motor engaged silently.
9. Dynamic Method Dispatch (Runtime Polymorphism)
- Definition: The process of determining which specific implementation of an overridden method to call at runtime, based on the actual type of the object being referenced, rather than the type of the reference variable.
- Attention Point: This is a core mechanism behind polymorphism. It applies to instance methods that are overridden. It does not apply to static methods, private methods, or final methods.
- Simple Example:
class A {
void m1() { System.out.println("A's m1"); }
void m2() { System.out.println("A's m2"); }
void m3() { System.out.println("A's m3"); }
}
class B extends A {
@Override void m1() { System.out.println("B's m1"); }
@Override void m2() { System.out.println("B's m2"); }
}
class C extends A {
@Override void m1() { System.out.println("C's m1"); }
@Override void m2() { System.out.println("C's m2"); }
}
// A x = new B(); // x is type A, but points to an object of type B
// x.m1(); // Calls B's m1() - Dynamic dispatch
// x.m2(); // Calls B's m2() - Dynamic dispatch
// x.m3(); // Calls A's m3() - m3 is not overridden in B
10. Encapsulation
- Definition: Bundling data (fields) and the methods that operate on that data within a single unit (a class), and hiding the internal data from direct outside access.
- How: Make class fields
private
and providepublic
methods (getters and setters) to access and modify them.
Example:
public class Account {
private double balance; // Data is hidden
public double getBalance() { // Public getter
return balance;
}
public void deposit(double amount) { // Public method to modify data
if (amount > 0) {
balance += amount;
}
}
}
// Usage:
// Account myAccount = new Account();
// myAccount.deposit(100);
// System.out.println(myAccount.getBalance()); // Access via getter
// // myAccount.balance = -50; // ERROR! Cannot access private field directly
Attention Point:
The main goal is control. By using setters, you can add validation logic to ensure data remains in a valid state, preventing direct, uncontrolled modification of an object's internal fields.
11. Comparable Anonymous classes Functional interfaces Streams Lambda functions
1. Anonymous Class
- Definition: A class that is defined and instantiated at the same time, without being given a specific name. It's typically used for a one-time implementation of an interface or an extension of an abstract (or concrete) class.
-
Attention Points:
-
It's a way to create an instance of an object with a "one-off" class implementation, often for concise code when a full named class is overkill.
- It's syntactic sugar; the compiler generates a named class behind the scenes (e.g.,
ContainingClass$1
). - You are not creating an instance of the interface/abstract class itself, but an instance of an unnamed class that implements/extends it.
- Overuse or complex anonymous classes can make code unreadable.
- Simple Example:
interface Greeter {
void greet();
}
public class Main {
public static void main(String[] args) {
// Anonymous class implementing the Greeter interface
Greeter spanishGreeter = new Greeter() {
@Override
public void greet() {
System.out.println("Hola!");
}
};
spanishGreeter.greet(); // Output: Hola!
}
}
2. Functional Interface
- Definition: An interface that contains exactly one abstract method. It can be optionally annotated with
@FunctionalInterface
which helps the compiler verify this condition. -
Attention Points:
-
It forms the basis for lambda expressions, method references, and constructor references in Java.
- It allows for more concise ways to represent single-method interfaces.
- Simple Example:
@FunctionalInterface
interface StringOperation {
String operate(String input);
}
public class TestFunctionalInterface {
public static void main(String[] args) {
// Using an anonymous class to implement the Functional Interface
StringOperation toUpperCase = new StringOperation() {
@Override
public String operate(String input) {
return input.toUpperCase();
}
};
System.out.println(toUpperCase.operate("hello")); // Output: HELLO
}
}
(The slide also mentions that (String s) -> {return s;}
could be used for a FunctionalInterface taking and returning a String, or Integer::valueOf
for one taking a String and returning Integer.)
3. Lambda Expression
- Definition: An anonymous function (a function without a name) that can be used to implement a method defined by a functional interface. It provides a concise way to represent a block of code that can be passed around.
-
Attention Points:
-
Format:
(list-arguments) -> {body}
or(list-arguments) -> expression
. - Argument types can often be inferred by the compiler.
- If the body is a single expression, curly braces
{}
and thereturn
keyword are often optional. If the body is a block,return
is needed for non-void functions. - Very useful for short, single-purpose functions.
- Overuse or overly complex lambdas can reduce code readability.
- Simple Example:
@FunctionalInterface
interface StringOperation {
String operate(String input);
}
public class TestFunctionalInterface {
public static void main(String[] args) {
// Using a lambda expression for the Functional Interface
StringOperation toUpperCase = (s) -> s.toUpperCase();
System.out.println(toUpperCase.operate("hello")); // Output: HELLO
}
}
4. Stream (Java Streams API)
- Definition: A sequence of elements from a source (like a collection) that supports various aggregate operations (e.g., filter, map, reduce) which can be executed sequentially or in parallel. Streams don't store data; they convey elements from a source through a pipeline of operations.
-
Attention Points:
-
Operations on collections to produce new collections typically require iterating over all elements.
- Stream operations can be "lazy," meaning computations might only happen when a terminal operation (one that produces a result or side-effect) is invoked.
- Streams work in a Producer-Consumer fashion; the resulting stream can be used while not all elements in the source stream are consumed.
- Allow for parallel processing of elements, though this incurs overhead and isn't always faster.
- Order of evaluation/generation can be important, especially with parallel streams.
- Overuse or complex stream pipelines can make code hard to read.
- Simple Example:
import java.util.List;
import java.util.stream.Collectors;
public class StreamDemo {
public static void main(String[] args) {
List<String> names = List.of("Alice", "Bob", "Anna", "Charles");
List<String> namesStartingWithA = names.stream() // 1. Get a stream from the list
.filter(name -> name.startsWith("A")) // 2. Intermediate operation: filter
.collect(Collectors.toList()); // 3. Terminal operation: collect results
System.out.println(namesStartingWithA); // Output: [Alice, Anna]
}
}
5. Method Reference
- Definition: A shorthand syntax for a lambda expression that executes a single existing method. They are used to refer to methods without invoking them.
-
Attention Points:
-
Can refer to static methods, instance methods of a particular object, instance methods of an arbitrary object of a particular type, or constructors.
- Makes code more readable by clearly indicating the method being called.
- Simple Example (from slide context, and a common use):
import java.util.Arrays;
import java.util.List;
@FunctionalInterface
interface StringConverter<F, T> { // A generic functional interface
T convert(F from);
}
public class MethodReferenceDemo {
public static void main(String[] args) {
// Lambda: (String s) -> Integer.valueOf(s)
// Method Reference for a static method: Integer::valueOf
StringConverter<String, Integer> stringToInt = Integer::valueOf;
System.out.println(stringToInt.convert("123") + 7); // Output: 130
List<String> words = Arrays.asList("hello", "world");
// Lambda: words.forEach(s -> System.out.println(s))
// Method Reference for an instance method of a particular object (System.out):
words.forEach(System.out::println);
// Output:
// hello
// world
}
}
6. Constructor Reference
- Definition: A special type of method reference used to refer to a constructor. It allows you to create new objects. The syntax is
ClassName::new
. -
Attention Points:
-
Used with functional interfaces whose abstract method returns an instance of the class.
- Simple Example (from slide context):
import java.util.function.Function; // A standard Functional Interface
class MyString {
private String value;
public MyString(String value) {
this.value = value;
System.out.println("MyString created with: " + value);
}
public String getValue() { return value; }
}
public class ConstructorReferenceDemo {
public static void main(String[] args) {
// Functional interface whose method takes a String and returns a MyString
// The signature matches the MyString(String) constructor
Function<String, MyString> myStringFactory = MyString::new;
MyString ms1 = myStringFactory.apply("Test1"); // Calls new MyString("Test1")
MyString ms2 = myStringFactory.apply("Test2"); // Calls new MyString("Test2")
System.out.println(ms1.getValue());
}
}
// Output:
// MyString created with: Test1
// MyString created with: Test2
// Test1