OOP Dispatch: Dynamic Binding, Single & Double Dispatch
Dispatch refers to the selection of the actual method to be executed during a method call. This selection can occur statically at compile time or dynamically at runtime and is the foundation for polymorphism.
What is Dispatch?
Dispatch is the mechanism that resolves a method call to a concrete implementation. The type of dispatch resolution influences the flexibility and performance of the software.
Types of Dispatch
- Static Dispatch: Decision at compile time
- Dynamic Dispatch: Decision at runtime
- Single Dispatch: Selection based on receiver object
- Double Dispatch: Selection based on two object types
- Multiple Dispatch: Selection based on multiple object types
Static vs Dynamic Dispatch
Static Dispatch (Overloading)
public class StaticDispatchDemo {
// Overloaded methods - static dispatch
public static class Printer {
public void print(Object obj) {
System.out.println("Printing Object: " + obj.toString());
}
public void print(String str) {
System.out.println("Printing String: " + str);
}
public void print(Integer num) {
System.out.println("Printing Integer: " + num);
}
public void print(String str, int count) {
for (int i = 0; i < count; i++) {
System.out.println("String " + (i + 1) + ": " + str);
}
}
}
public static void demonstrateStaticDispatch() {
Printer printer = new Printer();
// Direct calls - unambiguous selection
printer.print("Hello"); // print(String)
printer.print(42); // print(Integer)
printer.print("Test", 3); // print(String, int)
// Important case: Static types decide!
Object obj1 = "Hello";
Object obj2 = 42;
printer.print(obj1); // print(Object) - Compiler knows only Object type!
printer.print(obj2); // print(Object) - Compiler knows only Object type!
// Cast to select the right overload
printer.print((String) obj1); // print(String)
// printer.print((Integer) obj2); // ClassCastException at runtime!
}
}
Dynamic Dispatch (Overriding)
public class DynamicDispatchDemo {
// Base class with virtual methods
public static abstract class Animal {
protected String name;
public Animal(String name) {
this.name = name;
}
// Virtual method - dynamically bound
public String makeSound() {
return name + " makes a sound";
}
// Another virtual method
public String move() {
return name + " moves";
}
// Final method - cannot be overridden
public final String getName() {
return name;
}
// Abstract method - must be overridden
public abstract String getType();
}
// Concrete subclasses
public static class Dog extends Animal {
public Dog(String name) {
super(name);
}
@Override
public String makeSound() {
return name + " barks: Woof!";
}
@Override
public String move() {
return name + " runs happily";
}
@Override
public String getType() {
return "Dog";
}
// Additional method
public String wagTail() {
return name + " wags tail excitedly";
}
}
public static class Cat extends Animal {
public Cat(String name) {
super(name);
}
@Override
public String makeSound() {
return name + " meows: Meow!";
}
@Override
public String move() {
return name + " sneaks silently";
}
@Override
public String getType() {
return "Cat";
}
public String purr() {
return name + " purrs contentedly";
}
}
public static class Bird extends Animal {
public Bird(String name) {
super(name);
}
@Override
public String makeSound() {
return name + " chirps: Tweet!";
}
@Override
public String move() {
return name + " flies gracefully";
}
@Override
public String getType() {
return "Bird";
}
public String sing() {
return name + " sings a beautiful song";
}
}
// Demonstration of dynamic dispatch
public static void demonstrateDynamicDispatch() {
List<Animal> animals = new ArrayList<>();
animals.add(new Dog("Buddy"));
animals.add(new Cat("Whiskers"));
animals.add(new Bird("Tweety"));
System.out.println("=== Dynamic Dispatch ===");
for (Animal animal : animals) {
// Dynamic binding - runtime decides!
System.out.println(animal.getType() + ": " + animal.makeSound());
System.out.println(animal.getType() + ": " + animal.move());
System.out.println();
}
// Polymorphic processing
processAnimal(animals.get(0)); // Dog
processAnimal(animals.get(1)); // Cat
processAnimal(animals.get(2)); // Bird
}
// Polymorphic method
public static void processAnimal(Animal animal) {
System.out.println("Processing " + animal.getType());
// Dynamic dispatch
String sound = animal.makeSound();
String movement = animal.move();
System.out.println(" Sound: " + sound);
System.out.println(" Movement: " + movement);
// Type-specific operations (with instanceof)
if (animal instanceof Dog) {
Dog dog = (Dog) animal;
System.out.println(" Special: " + dog.wagTail());
} else if (animal instanceof Cat) {
Cat cat = (Cat) animal;
System.out.println(" Special: " + cat.purr());
} else if (animal instanceof Bird) {
Bird bird = (Bird) animal;
System.out.println(" Special: " + bird.sing());
}
}
}
Single Dispatch
How Single Dispatch Works
public class SingleDispatchDemo {
// Single Dispatch - only the receiver type decides
public interface Shape {
double area();
double perimeter();
String getType();
void accept(ShapeVisitor visitor);
}
public static class Circle implements Shape {
private double radius;
public Circle(double radius) {
this.radius = radius;
}
@Override
public double area() {
return Math.PI * radius * radius;
}
@Override
public double perimeter() {
return 2 * Math.PI * radius;
}
@Override
public String getType() {
return "Circle";
}
@Override
public void accept(ShapeVisitor visitor) {
visitor.visitCircle(this); // Single Dispatch
}
public double getRadius() { return radius; }
}
public static class Rectangle implements Shape {
private double width, height;
public Rectangle(double width, double height) {
this.width = width;
this.height = height;
}
@Override
public double area() {
return width * height;
}
@Override
public double perimeter() {
return 2 * (width + height);
}
@Override
public String getType() {
return "Rectangle";
}
@Override
public void accept(ShapeVisitor visitor) {
visitor.visitRectangle(this); // Single Dispatch
}
public double getWidth() { return width; }
public double getHeight() { return height; }
}
public static class Triangle implements Shape {
private double base, height;
public Triangle(double base, double height) {
this.base = base;
this.height = height;
}
@Override
public double area() {
return 0.5 * base * height;
}
@Override
public double perimeter() {
// Simplified: equilateral triangle
double side = base;
return 3 * side;
}
@Override
public String getType() {
return "Triangle";
}
@Override
public void accept(ShapeVisitor visitor) {
visitor.visitTriangle(this); // Single Dispatch
}
public double getBase() { return base; }
public double getHeight() { return height; }
}
// Demonstration
public static void demonstrateSingleDispatch() {
List<Shape> shapes = new ArrayList<>();
shapes.add(new Circle(2.0));
shapes.add(new Rectangle(3.0, 4.0));
shapes.add(new Triangle(5.0, 3.0));
System.out.println("=== Single Dispatch ===");
for (Shape shape : shapes) {
System.out.println(shape.getType());
System.out.println(" Area: " + String.format("%.2f", shape.area()));
System.out.println(" Perimeter: " + String.format("%.2f", shape.perimeter()));
System.out.println();
}
}
}
Double Dispatch with Visitor Pattern
Visitor Pattern for Double Dispatch
public class DoubleDispatchDemo {
// Visitor Interface
public interface ShapeVisitor {
void visitCircle(Circle circle);
void visitRectangle(Rectangle rectangle);
void visitTriangle(Triangle triangle);
double getResult();
}
// Konkreter Visitor für Flächenberechnung
public static class AreaVisitor implements ShapeVisitor {
private double totalArea = 0.0;
@Override
public void visitCircle(Circle circle) {
double area = Math.PI * circle.getRadius() * circle.getRadius();
totalArea += area;
System.out.println("Circle area: " + String.format("%.2f", area));
}
@Override
public void visitRectangle(Rectangle rectangle) {
double area = rectangle.getWidth() * rectangle.getHeight();
totalArea += area;
System.out.println("Rectangle area: " + String.format("%.2f", area));
}
@Override
public void visitTriangle(Triangle triangle) {
double area = 0.5 * triangle.getBase() * triangle.getHeight();
totalArea += area;
System.out.println("Triangle area: " + String.format("%.2f", area));
}
@Override
public double getResult() {
return totalArea;
}
}
// Visitor für Umfangberechnung
public static class PerimeterVisitor implements ShapeVisitor {
private double totalPerimeter = 0.0;
@Override
public void visitCircle(Circle circle) {
double perimeter = 2 * Math.PI * circle.getRadius();
totalPerimeter += perimeter;
System.out.println("Circle perimeter: " + String.format("%.2f", perimeter));
}
@Override
public void visitRectangle(Rectangle rectangle) {
double perimeter = 2 * (rectangle.getWidth() + rectangle.getHeight());
totalPerimeter += perimeter;
System.out.println("Rectangle perimeter: " + String.format("%.2f", perimeter));
}
@Override
public void visitTriangle(Triangle triangle) {
double perimeter = 3 * triangle.getBase(); // Vereinfacht
totalPerimeter += perimeter;
System.out.println("Triangle perimeter: " + String.format("%.2f", perimeter));
}
@Override
public double getResult() {
return totalPerimeter;
}
}
// Visitor für XML-Export
public static class XMLExportVisitor implements ShapeVisitor {
private StringBuilder xml = new StringBuilder();
@Override
public void visitCircle(Circle circle) {
xml.append("<shape type=\"circle\">\n");
xml.append(" <radius>").append(circle.getRadius()).append("</radius>\n");
xml.append(" <area>").append(String.format("%.2f", Math.PI * circle.getRadius() * circle.getRadius())).append("</area>\n");
xml.append("</shape>\n");
}
@Override
public void visitRectangle(Rectangle rectangle) {
xml.append("<shape type=\"rectangle\">\n");
xml.append(" <width>").append(rectangle.getWidth()).append("</width>\n");
xml.append(" <height>").append(rectangle.getHeight()).append("</height>\n");
xml.append(" <area>").append(String.format("%.2f", rectangle.getWidth() * rectangle.getHeight())).append("</area>\n");
xml.append("</shape>\n");
}
@Override
public void visitTriangle(Triangle triangle) {
xml.append("<shape type=\"triangle\">\n");
xml.append(" <base>").append(triangle.getBase()).append("</base>\n");
xml.append(" <height>").append(triangle.getHeight()).append("</height>\n");
xml.append(" <area>").append(String.format("%.2f", 0.5 * triangle.getBase() * triangle.getHeight())).append("</area>\n");
xml.append("</shape>\n");
}
@Override
public double getResult() {
return 0; // Nicht relevant für diesen Visitor
}
public String getXML() {
return "<shapes>\n" + xml.toString() + "</shapes>";
}
}
// Demonstration von Double Dispatch
public static void demonstrateDoubleDispatch() {
List<Shape> shapes = new ArrayList<>();
shapes.add(new Circle(2.0));
shapes.add(new Rectangle(3.0, 4.0));
shapes.add(new Triangle(5.0, 3.0));
System.out.println("=== Double Dispatch mit Visitor Pattern ===");
// Area Visitor
System.out.println("Area calculation:");
AreaVisitor areaVisitor = new AreaVisitor();
for (Shape shape : shapes) {
shape.accept(areaVisitor); // Double Dispatch!
}
System.out.println("Total area: " + String.format("%.2f", areaVisitor.getResult()));
System.out.println();
// Perimeter Visitor
System.out.println("Perimeter calculation:");
PerimeterVisitor perimeterVisitor = new PerimeterVisitor();
for (Shape shape : shapes) {
shape.accept(perimeterVisitor); // Double Dispatch!
}
System.out.println("Total perimeter: " + String.format("%.2f", perimeterVisitor.getResult()));
System.out.println();
// XML Export Visitor
System.out.println("XML Export:");
XMLExportVisitor xmlVisitor = new XMLExportVisitor();
for (Shape shape : shapes) {
shape.accept(xmlVisitor); // Double Dispatch!
}
System.out.println(xmlVisitor.getXML());
}
}
Multiple Dispatch
Simulation of Multiple Dispatch
public class MultipleDispatchDemo {
// Problem: Operations that depend on two types
public interface Collider {
void collideWith(Collider other);
String getType();
}
public static class Asteroid implements Collider {
private String name;
private double mass;
public Asteroid(String name, double mass) {
this.name = name;
this.mass = mass;
}
@Override
public void collideWith(Collider other) {
// Single Dispatch - only the other type matters
System.out.println(name + " collides with " + other.getType());
}
@Override
public String getType() {
return "Asteroid";
}
public double getMass() { return mass; }
public String getName() { return name; }
}
public static class Spaceship implements Collider {
private String name;
private double shield;
public Spaceship(String name, double shield) {
this.name = name;
this.shield = shield;
}
@Override
public void collideWith(Collider other) {
// Single Dispatch - Problem: we don't know which type we have
System.out.println(name + " collides with " + other.getType());
}
@Override
public String getType() {
return "Spaceship";
}
public double getShield() { return shield; }
public String getName() { return name; }
}
public static class SpaceStation implements Collider {
private String name;
private double hull;
public SpaceStation(String name, double hull) {
this.name = name;
this.hull = hull;
}
@Override
public void collideWith(Collider other) {
System.out.println(name + " collides with " + other.getType());
}
@Override
public String getType() {
return "SpaceStation";
}
public double getHull() { return hull; }
public String getName() { return name; }
}
// Solution with Double Dispatch Pattern
public interface CollisionHandler {
void handleAsteroidAsteroid(Asteroid a1, Asteroid a2);
void handleAsteroidSpaceship(Asteroid asteroid, Spaceship spaceship);
void handleAsteroidStation(Asteroid asteroid, SpaceStation station);
void handleSpaceshipSpaceship(Spaceship s1, Spaceship s2);
void handleSpaceshipStation(Spaceship spaceship, SpaceStation station);
void handleStationStation(SpaceStation s1, SpaceStation s2);
}
public static class DefaultCollisionHandler implements CollisionHandler {
@Override
public void handleAsteroidAsteroid(Asteroid a1, Asteroid a2) {
double totalMass = a1.getMass() + a2.getMass();
System.out.println("Asteroid collision: " + a1.getName() + " + " + a2.getName() +
" (total mass: " + String.format("%.1f", totalMass) + ")");
}
@Override
public void handleAsteroidSpaceship(Asteroid asteroid, Spaceship spaceship) {
double damage = asteroid.getMass() * 0.1;
spaceship.setShield(spaceship.getShield() - damage);
System.out.println("Asteroid-Spaceship collision: " + asteroid.getName() +
" hits " + spaceship.getName() + " (damage: " +
String.format("%.1f", damage) + ")");
}
@Override
public void handleAsteroidStation(Asteroid asteroid, SpaceStation station) {
double damage = asteroid.getMass() * 0.05;
station.setHull(station.getHull() - damage);
System.out.println("Asteroid-Station collision: " + asteroid.getName() +
" hits " + station.getName() + " (damage: " +
String.format("%.1f", damage) + ")");
}
@Override
public void handleSpaceshipSpaceship(Spaceship s1, Spaceship s2) {
System.out.println("Spaceship collision: " + s1.getName() + " + " + s2.getName());
}
@Override
public void handleSpaceshipStation(Spaceship spaceship, SpaceStation station) {
System.out.println("Spaceship-Station collision: " + spaceship.getName() +
" docks at " + station.getName());
}
@Override
public void handleStationStation(SpaceStation s1, SpaceStation s2) {
System.out.println("Station collision: " + s1.getName() + " + " + s2.getName());
}
}
// Improved Collider with Double Dispatch
public static class ImprovedAsteroid extends Asteroid {
public ImprovedAsteroid(String name, double mass) {
super(name, mass);
}
@Override
public void collideWith(Collider other) {
other.collideWithAsteroid(this); // Reversal for Double Dispatch
}
public void collideWithAsteroid(Asteroid other) {
CollisionHandler handler = new DefaultCollisionHandler();
handler.handleAsteroidAsteroid(this, other);
}
public void collideWithSpaceship(Spaceship spaceship) {
CollisionHandler handler = new DefaultCollisionHandler();
handler.handleAsteroidSpaceship(this, spaceship);
}
public void collideWithStation(SpaceStation station) {
CollisionHandler handler = new DefaultCollisionHandler();
handler.handleAsteroidStation(this, station);
}
}
public static class ImprovedSpaceship extends Spaceship {
public ImprovedSpaceship(String name, double shield) {
super(name, shield);
}
@Override
public void collideWith(Collider other) {
other.collideWithSpaceship(this);
}
public void collideWithAsteroid(Asteroid asteroid) {
CollisionHandler handler = new DefaultCollisionHandler();
handler.handleAsteroidSpaceship(asteroid, this);
}
public void collideWithSpaceship(Spaceship other) {
CollisionHandler handler = new DefaultCollisionHandler();
handler.handleSpaceshipSpaceship(this, other);
}
public void collideWithStation(SpaceStation station) {
CollisionHandler handler = new DefaultCollisionHandler();
handler.handleSpaceshipStation(this, station);
}
}
// Demonstration
public static void demonstrateMultipleDispatch() {
System.out.println("=== Multiple Dispatch Simulation ===");
// Simple Single Dispatch (Problem)
System.out.println("Single Dispatch (Problem):");
Collider asteroid1 = new Asteroid("Rocky", 100.0);
Collider spaceship1 = new Spaceship("Explorer", 50.0);
asteroid1.collideWith(spaceship1); // Only type of spaceship1 known
System.out.println();
// Double Dispatch Solution
System.out.println("Double Dispatch Solution:");
ImprovedAsteroid asteroid2 = new ImprovedAsteroid("Rocky", 100.0);
ImprovedSpaceship spaceship2 = new ImprovedSpaceship("Explorer", 50.0);
asteroid2.collideWith(spaceship2); // Both types known!
System.out.println();
// More complex collisions
List<Collider> objects = Arrays.asList(
new ImprovedAsteroid("Rocky", 100.0),
new ImprovedSpaceship("Explorer", 50.0),
new ImprovedSpaceship("Voyager", 60.0),
new SpaceStation("Alpha", 200.0)
);
System.out.println("Complex collisions:");
for (int i = 0; i < objects.size(); i++) {
for (int j = i + 1; j < objects.size(); j++) {
objects.get(i).collideWith(objects.get(j));
}
}
}
}
Virtual Method Tables (vtable)
How vtables work
public class VTableDemo {
// Simplified representation of a vtable
public static class VTableVisualization {
// Base class
public static class Base {
// Virtual methods
public virtual void method1() { System.out.println("Base.method1"); }
public virtual void method2() { System.out.println("Base.method2"); }
// Concrete method
public void concreteMethod() { System.out.println("Base.concreteMethod"); }
}
// Derived class 1
public static class Derived1 extends Base {
@Override
public void method1() { System.out.println("Derived1.method1"); }
// method2 inherited
@Override
public void method2() { System.out.println("Derived1.method2"); }
}
// Derived class 2
public static class Derived2 extends Base {
// method1 inherited
@Override
public void method2() { System.out.println("Derived2.method2"); }
public void method3() { System.out.println("Derived2.method3"); }
}
// Demonstration of vtable
public static void demonstrateVTable() {
System.out.println("=== VTable Demonstration ===");
Base base = new Base();
Base derived1 = new Derived1();
Base derived2 = new Derived2();
// Vtable for Base:
// [Base.method1, Base.method2]
System.out.println("Base object:");
base.method1(); // Base.method1
base.method2(); // Base.method2
// Vtable for Derived1:
// [Derived1.method1, Derived1.method2]
System.out.println("\nDerived1 object:");
derived1.method1(); // Derived1.method1
derived1.method2(); // Derived1.method2
// Vtable for Derived2:
// [Base.method1, Derived2.method2]
System.out.println("\nDerived2 object:");
derived2.method1(); // Base.method1 (inherited)
derived2.method2(); // Derived2.method2
// Concrete method - not in vtable
System.out.println("\nConcrete method:");
base.concreteMethod();
derived1.concreteMethod();
derived2.concreteMethod();
}
}
// Performance comparison
public static class PerformanceComparison {
// Final method - no virtual call
public static class FinalClass {
public final void finalMethod() {
// No vtable lookup
}
}
// Virtual method - vtable lookup
public static class VirtualClass {
public void virtualMethod() {
// vtable lookup required
}
}
public static void performanceTest() {
FinalClass finalObj = new FinalClass();
VirtualClass virtualObj = new VirtualClass();
int iterations = 100_000_000;
// Test final method
long start = System.nanoTime();
for (int i = 0; i < iterations; i++) {
finalObj.finalMethod();
}
long finalTime = System.nanoTime() - start;
// Test virtual method
start = System.nanoTime();
for (int i = 0; i < iterations; i++) {
virtualObj.virtualMethod();
}
long virtualTime = System.nanoTime() - start;
System.out.println("Performance Comparison:");
System.out.println("Final method: " + (finalTime / 1_000_000) + " ms");
System.out.println("Virtual method: " + (virtualTime / 1_000_000) + " ms");
System.out.println("Difference: " + ((virtualTime - finalTime) / 1_000_000) + " ms");
}
}
}
Dispatch in Practice
Framework Example: Plugin System
public class PluginDispatchDemo {
// Plugin Interface
public interface Plugin {
void initialize();
void execute();
void shutdown();
String getName();
String getVersion();
}
// Abstract base class for plugins
public abstract class AbstractPlugin implements Plugin {
protected String name;
protected String version;
public AbstractPlugin(String name, String version) {
this.name = name;
this.version = version;
}
@Override
public final String getName() {
return name;
}
@Override
public final String getVersion() {
return version;
}
// Template Method Pattern
@Override
public final void execute() {
System.out.println("Executing plugin: " + name);
try {
doExecute();
System.out.println("Plugin execution completed: " + name);
} catch (Exception e) {
System.err.println("Plugin execution failed: " + name + " - " + e.getMessage());
}
}
// Abstract method for concrete implementation
protected abstract void doExecute();
// Default implementations
@Override
public void initialize() {
System.out.println("Initializing plugin: " + name);
}
@Override
public void shutdown() {
System.out.println("Shutting down plugin: " + name);
}
}
// Concrete plugins
public static class DatabasePlugin extends AbstractPlugin {
public DatabasePlugin() {
super("DatabasePlugin", "1.0.0");
}
@Override
protected void doExecute() {
System.out.println(" Connecting to database...");
System.out.println(" Executing database operations...");
System.out.println(" Closing database connection...");
}
@Override
public void initialize() {
super.initialize();
System.out.println(" Loading database driver...");
}
}
public static class LoggingPlugin extends AbstractPlugin {
public LoggingPlugin() {
super("LoggingPlugin", "2.1.0");
}
@Override
protected void doExecute() {
System.out.println(" Setting up loggers...");
System.out.println(" Configuring log levels...");
System.out.println(" Starting log rotation...");
}
@Override
public void shutdown() {
System.out.println(" Flushing log buffers...");
super.shutdown();
}
}
public static class SecurityPlugin extends AbstractPlugin {
public SecurityPlugin() {
super("SecurityPlugin", "1.5.2");
}
@Override
protected void doExecute() {
System.out.println(" Initializing security manager...");
System.out.println(" Setting up authentication...");
System.out.println(" Configuring authorization rules...");
}
}
// Plugin Manager with dispatch
public static class PluginManager {
private List<Plugin> plugins = new ArrayList<>();
public void registerPlugin(Plugin plugin) {
plugins.add(plugin);
plugin.initialize();
}
public void executeAllPlugins() {
System.out.println("=== Executing all plugins ===");
for (Plugin plugin : plugins) {
plugin.execute(); // Dynamic dispatch
}
}
public void shutdownAllPlugins() {
System.out.println("\n=== Shutting down all plugins ===");
for (Plugin plugin : plugins) {
plugin.shutdown(); // Dynamic dispatch
}
}
public void executePluginByName(String name) {
for (Plugin plugin : plugins) {
if (plugin.getName().equals(name)) {
plugin.execute(); // Dynamic dispatch
return;
}
}
System.out.println("Plugin not found: " + name);
}
public void listPlugins() {
System.out.println("=== Registered Plugins ===");
for (Plugin plugin : plugins) {
System.out.println(plugin.getName() + " v" + plugin.getVersion());
}
}
}
// Demonstration
public static void demonstratePluginSystem() {
PluginManager manager = new PluginManager();
// Register plugins
manager.registerPlugin(new DatabasePlugin());
manager.registerPlugin(new LoggingPlugin());
manager.registerPlugin(new SecurityPlugin());
// Execute all plugins
manager.listPlugins();
manager.executeAllPlugins();
// Execute specific plugin
System.out.println("\n=== Executing specific plugin ===");
manager.executePluginByName("LoggingPlugin");
// Clean up
manager.shutdownAllPlugins();
}
}
Best Practices for Dispatch
1. Final for Performance
public class DispatchBestPractices {
// Finale Methoden für Performance
public static class PerformanceOptimized {
// Finale Methode - kein virtueller Aufruf
public final void criticalMethod() {
// Hot Path Code
}
// Finale Klasse - keine Vererbung möglich
public static final class ImmutableData {
private final int value;
public ImmutableData(int value) {
this.value = value;
}
public final int getValue() {
return value;
}
}
}
// Interface für Flexibilität
public interface Processor {
void process();
}
// Konkrete Implementierung
public static class FastProcessor implements Processor {
@Override
public void process() {
// Implementierung
}
}
}
2. Avoiding Dispatch Problems
public class DispatchProblems {
// Problem: Überladung mit Referenztypen
public static class ProblematicOverloading {
public void process(Object obj) {
System.out.println("Processing Object");
}
public void process(String str) {
System.out.println("Processing String");
}
public void demonstrateProblem() {
Object obj = "Hello";
process(obj); // Ruft process(Object) auf!
}
}
// Lösung: Klare Methodennamen
public static class Solution {
public void processObject(Object obj) {
System.out.println("Processing Object");
}
public void processString(String str) {
System.out.println("Processing String");
}
public void demonstrateSolution() {
Object obj = "Hello";
if (obj instanceof String) {
processString((String) obj);
} else {
processObject(obj);
}
}
}
}
Exam-Relevant Concepts
Important Distinctions
-
Static vs Dynamic
- Static: Compile-time (Overloading)
- Dynamic: Runtime (Overriding)
-
Single vs Double Dispatch
- Single: One object type decides
- Double: Two object types decide
-
vtable vs Early Binding
- vtable: Virtual methods
- Early Binding: Final methods
Typical Exam Tasks
- Explain Single vs Double Dispatch
- Implement Visitor Pattern
- Compare static and dynamic binding
- Describe vtable functionality
- Solve dispatch problems
Summary
Dispatch is fundamental to object-oriented programming:
- Static Dispatch: Predictable, performant (Overloading)
- Dynamic Dispatch: Flexible, extensible (Overriding)
- Single Dispatch: Standard in most OOP languages
- Double Dispatch: Realizable via Visitor Pattern
- vtables: Efficient implementation of dynamic dispatch
The correct application of dispatch enables flexible, maintainable, and performant software architectures.