Os tipos primitivos são os dados mais "simples" presentes por toda computação.
Mais ou menos. Não existe uma definição única que é igual entre todas as linguagens, cada uma define isso de um jeito.
Em Java criou-se essa noção de que tipos primitivos são aqueles que não precisam de uma classe, e portanto não possuem métodos. Mas em outras linguagens pode ser diferente.
Por exemplo, em C# a lista de tipos primitivos é diferente, mas eles possuem métodos. Em JavaScript a lista também é diferente, incluindo até mesmo strings. Em Python não existe esta distinção, e por aí vai. Cada linguagem vai definir isso de um jeito diferente.
Vale lembrar que em Java o char
também é um tipo numérico. Segundo a própria especificação da linguagem:
The numeric types are the integral types and the floating-point types.
The integral types are byte, short, int, and long, whose values are 8-bit, 16-bit, 32-bit and 64-bit signed two's-complement integers, respectively, and char, whose values are 16-bit unsigned integers representing UTF-16 code units (§3.1).
O fato de um char
ser interpretado como um caractere é detalhe, pois no fundo o seu valor é guardado como um número. Inclusive, posso fazer coisas como:
char c = 97;
System.out.println(c); // "a"
c += 5;
System.out.println(c); // "f"
O que acontece é que este número é interpretado como o caractere Unicode correspondente, cujo codepoint é o valor numérico da variável.