The restrictions about names are fixed in the JVM specification:
Class and interface names that appear in class file structures are always represented in a fully qualified form known as binary names (JLS §13.1). Such names are always represented as CONSTANT_Utf8_info
structures (§4.4.7) and thus may be drawn, where not further constrained, from the entire Unicode codespace…
For historical reasons, the syntax of binary names that appear in class file structures differs from the syntax of binary names documented in JLS §13.1. In this internal form, the ASCII periods (.
) that normally separate the identifiers which make up the binary name are replaced by ASCII forward slashes (/
). The identifiers themselves must be unqualified names (§4.2.2).
Names of methods, fields, local variables, and formal parameters are stored as unqualified names. An unqualified name must contain at least one Unicode code point and must not contain any of the ASCII characters .
;
[
/
(that is, period or semicolon or left square bracket or forward slash).
Method names are further constrained so that, with the exception of the special method names <init>
and <clinit>
(§2.9), they must not contain the ASCII characters <
or >
(that is, left angle bracket or right angle bracket).
So the answer is, there are only a few characters you can’t use on the binary level. First, /
is the package separator. Then, ;
and [
can’t be used because the have special meaning in field signatures and method signatures which may contain type names. In these signatures, [
starts an array type and ;
marks the end of a reference type name.
There is no clear reason why .
is forbidden. It isn’t used within the JVM and only has a meaning within generic signatures but if you are using generic signatures, the type names are further restricted by not being allowed to contain <
, >
, :
as well as these characters have a special meaning within generic signatures too.
Consequently, violating the specification by using .
within identifiers has no impact on the primary function of the JVM. There are obfuscators doing so. The resulting code works but you may encounter problems with Reflection when asking for Generic type signatures. Also, converting binary names to source name by replacing all /
s with .
s will become irreversible if the binary name contains .
s.
It might be interesting that there was a proposal to support all possible identifiers within Java syntax (see point 3, “exotic identifiers”), but it didn’t make it into the final Java 7. And it seems, no-one is currently making a new attempt to bring it in.
There is the additional technical limitation that the names can’t have a Modified UTF-8 representation being longer than 65535 bytes because the number of bytes is stored as unsigned short value.