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:

Low-level mechanisms - part 2 | Go ↔ Java
In this article, we gathered the key low-level mechanisms of Go that most often raise questions for developers coming from Java. We will consider: unsafe.Pointer, struct alignment, pointer arithmetic,...
Go vs Java - comparison of memory models: happens-before, visibility, reorder, synchronization events, write/read barriers
Memory model is a layer between the program and the processor. Modern CPUs aggressively optimize execution: instructions may be reordered, data may be stored in core caches, and operations may be perf...
Map internals from random order to bucket evacuation | Go ↔ Java
In this article, we will examine the internal structure of maps / hash tables in Go and Java. If you are a Java developer used to HashMap, you will be interested in how differently Go thinks. If you a...

New Articles:

Concurrency is not about “starting many threads”. It’s about agreements between them. Imagine a restaurant kitchen: — cooks (threads / goroutines) — orders (tasks) — and the main question: how do th...
When HashMap starts killing production: the engineering story of ConcurrentHashMap
Imagine a typical production service. 32 CPU hundreds of threads configuration / session / rate limits cache tens of thousands of operations per second And somewhere inside — a regular Map. At first...
Zero Allocation in Java: what it is and why it matters
Zero Allocation — is an approach to writing code in which no unnecessary objects are created in heap memory during runtime. The main idea: fewer objects → less GC → higher stability and performance. ...
Fullscreen image