Featured image of post Generics vs Templates: Java vs C# vs C++

Generics vs Templates: Java vs C# vs C++

Generics vs Templates: Java vs C# vs C++

Generics vs Templates: Java vs C# vs C++


Generics vs Templates: The Key Differences

How They Work at Compile-Time & Runtime

One of the biggest differences between Java, C#, and C++ generics/templates is how they compile:

FeatureC++ TemplatesJava GenericsC# Generics
Compile-Time vs RuntimeCompile-TimeCompile-Time (Erased at Runtime)Full Runtime Support
OutputCompiles directly to machine codeCompiles to Java BytecodeCompiles to .NET IL (Intermediate Language)
Performance🚀 Fast (No runtime overhead)🐢 Slower (Type Erasure)⚡ Fast (Optimized in CLR)
Reflection Support?❌ No❌ No (Because erased)✅ Yes
Can Work with Primitives?✅ Yes❌ No (Must box to Integer, Double, etc.)✅ Yes
Metaprogramming?✅ Yes (Template Metaprogramming)❌ No❌ No

Java Generics: Backward Compatibility at the Cost of Performance

Java generics were added in Java 5 (2004), but the JVM was designed in 1995—before generics existed. To maintain backward compatibility with older JVMs, Java removes generic type information at runtime (aka Type Erasure).

This means generic types don’t actually exist in the compiled Java bytecode! So, while you write:

1
List<String> list = new ArrayList<>();

At runtime, Java only sees:

1
List list = new ArrayList();

Which means type safety is only enforced at compile time. Once compiled, it’s wild west time.


C# Generics: Microsoft Didn’t Care About Old Code

Unlike Java, Microsoft designed .NET to support generics from the start (2005), meaning no type erasure.

C# generics exist at runtime, are stored in metadata, and can be reflected upon:

1
Console.WriteLine(typeof(List<string>)); // System.Collections.Generic.List`1[System.String]

This makes C# generics more efficient and safer than Java’s.


C++ Templates: The Ultimate Metaprogramming Beast

C++ templates were introduced in C++98, and unlike Java/C#, they don’t use a virtual machine—they generate actual assembly code at compile-time.

This means:

  1. Each template instantiation generates new machine code.
  2. There’s zero runtime overhead.
  3. Templates can be used for metaprogramming (yes, you can run code at compile time!).

For example, this C++ template:

1
2
3
4
template <typename T>
T add(T a, T b) {
    return a + b;
}

Will generate different assembly code for add<int>, add<double>, etc.


Generics in Action: Java vs C# vs C++

Let’s compare how you’d write the same generic class in Java, C#, and C++.

Java Generic Class (Type Erased)

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
class Box<T> {
    private T value;

    public Box(T value) {
        this.value = value;
    }

    public T getValue() {
        return value;
    }

    public static void main(String[] args) {
        Box<Integer> intBox = new Box<>(42);
        System.out.println("Java Box: " + intBox.getValue());
    }
}

C# Generic Class (Preserves Type at Runtime)

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
using System;

class Box<T> {
    private T value;

    public Box(T value) {
        this.value = value;
    }

    public T GetValue() {
        return value;
    }

    public static void Main() {
        Box<int> intBox = new Box<int>(42);
        Console.WriteLine("C# Box: " + intBox.GetValue());
    }
}

C++ Template Class (Compiles to Machine Code)

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
#include <iostream>

template <typename T>
class Box {
    private:
        T value;
    public:
        Box(T v) : value(v) {}
        T getValue() { return value; }
};

int main() {
    Box<int> intBox(42);
    std::cout << "C++ Box: " << intBox.getValue() << std::endl;
    return 0;
}

Assembly vs Bytecode vs IL: What Actually Gets Compiled?

LanguageWhat it compiles to
C++Machine Code (Assembly)
JavaJava Bytecode (Type Erased Generics)
C#.NET Intermediate Language (Preserves Generics)

This means:

  • C++ is fastest, but generates tons of machine code.
  • C# is efficient, because the CLR optimizes generics.
  • Java is slower, because boxing happens for primitive types, and generics don’t exist at runtime.

Final Thoughts: Which One is Best?

LanguageProsCons
C++Super fast, no runtime overhead, metaprogrammingCompiles to separate copies for each type (code bloat)
JavaBackward compatible, works everywhereType erasure, can be slow due to boxing
C#Preserves types, better performance than JavaNeeds .NET ecosystem

Concepts

  • If you care about performanceC++
  • If you need Java compatibilityJava
  • If you want a good balanceC#

Key Ideas Table

ConceptExplanation
Type ErasureJava removes generic types at runtime for backward compatibility
Runtime GenericsC# stores generic type info, making reflection possible
Compile-Time TemplatesC++ generates machine code for each template instantiation
Performance ImpactC++ → Fastest, C# → Optimized, Java → Slower due to type erasure

References