Generics, Reflection and Channels - Go vs Java | Types - Language

In this article we will analyze advanced type system features in Go: generics (type parameters), reflection, and channel types for concurrency. We will compare Go and Java approaches, so Java developers can more easily learn Go, and experienced Go developers — understand how these concepts are implemented in Java.

1. Generics (type parameters)

Generics in Go allow writing functions and structures that work with different data types without code duplication. In Java this is similar to , and other generics.

Example of addition function in Go:

package main

import "fmt"

// Sum - function that adds two values of the same type: int or float64
func Sum[T int | float64](a, b T) T {
    return a + b
}

func main() {
    fmt.Println(Sum(10, 20))       // int
    fmt.Println(Sum(3.5, 2.5))     // float64
}
  

The same in Java:

import java.util.function.BinaryOperator;

public class Main {
    // Function with generics for numbers
    public static <T extends Number> double sum(T a, T b) {
        return a.doubleValue() + b.doubleValue();
    }

    public static void main(String[] args) {
        System.out.println(sum(10, 20));     // int → double
        System.out.println(sum(3.5, 2.5));   // double
    }
}
  
Tip: In Go you are limited to the types specified via | (union), while Java allows using upper bounds (<T extends Number>), giving more flexibility with inheritance.

2. Reflection

Reflection allows programs to inspect types and values at runtime. In Java this is similar to the java.lang.reflect class.

Example in Go:

package main

import (
    "fmt"
    "reflect"
)

func main() {
    var x float64 = 3.4
    fmt.Println("Variable type x:", reflect.TypeOf(x))
}
  

The same in Java:

public class Main {
    public static void main(String[] args) {
        Double x = 3.4;
        System.out.println("Variable type x: " + x.getClass().getName());
    }
}
  
Tip: Reflection is powerful, but in Go it should only be used for tasks like serialization, logging, or dynamic constructors. For regular code, generics are preferable.

3. Channel types (types of channels for concurrency)

Channels in Go are the main way to safely exchange data between goroutines. In Java, similar mechanisms use queues and blocking structures.

Channel types in Go:

ch := make(chan int)    // bidirectional channel
var chSend chan<- int   // send only
var chRecv <-chan int   // receive only
  

Example of using a channel (Go):

package main

import "fmt"

func worker(ch chan int) {
    ch <- 42 // send to channel
}

func main() {
    ch := make(chan int)
    go worker(ch)
    result := <-ch // receive from channel
    fmt.Println("Result:", result)
}
  

Analog in Java (using BlockingQueue):

import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.BlockingQueue;

public class Main {
    public static void main(String[] args) throws InterruptedException {
        BlockingQueue<Integer> queue = new ArrayBlockingQueue<>(1);

        Thread worker = new Thread(() -> {
            try {
                queue.put(42); // send
            } catch (InterruptedException e) {
                Thread.currentThread().interrupt();
            }
        });
        worker.start();

        int result = queue.take(); // receive
        System.out.println("Result: " + result);
    }
}
  
Tip: In Go, channels are built into the language, which simplifies building concurrency patterns like worker pool, while in Java you need additional libraries and synchronization.

4. Comparison Generics Go ↔ Java

Feature Go Java Comment
Type constraints union types: int | float64 upper bounds: <T extends Number> Java is more flexible with inheritance
Runtime performance no type erasure, works like regular type type erasure, generic info lost at runtime Go generics simpler at runtime
Reflection reflect.TypeOf(v) v.getClass() For dynamic scenarios
Concurrency goroutine + chan Thread + BlockingQueue / Executor Go is shorter and safer

5. Examples of thread schemes (ASCII)

Worker Pool in Go:
+------------+      +--------+
|  Producer  | ---> | Channel| ---> [Worker1]
+------------+      +--------+ ---> [Worker2]
                               ---> [Worker3]

In Java:
Producer Thread --> BlockingQueue --> Worker Threads
  

6. Conclusion and practical tips

Go provides powerful tools for working with types and concurrency:

  • Generics: use union types for constraints and code simplification. Java uses upper bounds and a more flexible inheritance system.
  • Reflection: useful for dynamic tasks, but in Go generics often make it unnecessary.
  • Channels: built-in concurrency support makes patterns like worker pool simple and safe. In Java, more code and synchronization are required.
Tip: Java developers should focus on the difference in generics implementation and Go's built-in concurrency model, while Go developers — understand how these concepts look in Java for knowledge portability.

🌐 На русском
Total Likes:0
My social media channel
By sending an email, you agree to the terms of the privacy policy

Useful Articles:

Asynchrony and Reactivity in Java: CompletableFuture, Flow, and Virtual Threads
In modern Java development, there are three main approaches to asynchrony and concurrency: CompletableFuture — for single asynchronous tasks. Flow / Reactive Streams — for data flows with backpressur...
Understanding Multithreading in Java Through Collections and Atomics
1️⃣ HashMap / TreeMap / TreeSet (not thread-safe) HashMap: Structure: array of buckets + linked lists / trees (for collisions). Under the hood: put/remove modifies the bucket array and possibly reord...
Let's Break It Down: Rate Limiter, Non-Blocking Operations, and Scheduler: Go vs. Java | Concurrency Part 4
This article is dedicated to understanding the principles of concurrency and synchronization in Go and Java. We ll cover key approaches such as rate-limiter, non-blocking operations, and task scheduli...

New Articles:

Generics, Reflection and Channels - Go vs Java | Types - Language
In this article we will analyze advanced type system features in Go: generics (type parameters), reflection, and channel types for concurrency. We will compare Go and Java approaches, so Java develope...
Let's look at: Trace, Profiling, Integration Testing, Code Coverage, Mocking, Deadlock Detection in Go vs Java | Testing, Debugging and Profiling
Series: Go for Java Developers — analysis of trace, profiling and testing In this article we will analyze tools and practices for testing, debugging and profiling in Go. For a Java developer this wil...
Let's Break It Down: Rate Limiter, Non-Blocking Operations, and Scheduler: Go vs. Java | Concurrency Part 4
This article is dedicated to understanding the principles of concurrency and synchronization in Go and Java. We ll cover key approaches such as rate-limiter, non-blocking operations, and task scheduli...
Fullscreen image