Skip to content
ASCII World

ASCII in Java

char, int Casting, and Character Class Methods

By the ASCII World team

1. char and int: Direct Casting

In Java, char is a 16-bit unsigned integer type that stores a UTF-16 code unit. Casting between char and int is implicit in one direction and explicit in the other:

char letter = 'A';
int code = letter;      // implicit widening: 65
char back = (char) 65;  // explicit narrowing: 'A'

System.out.println((int) 'A');  // 65
System.out.println((int) 'a');  // 97
System.out.println((int) '0');  // 48
System.out.println((char) 10);  // newline

For ASCII characters (0 through 127), the cast value matches the decimal column in the ASCII table exactly. 65 is uppercase A, 97 is lowercase a, 48 is the digit 0. Arithmetic on chars works because Java treats them as numbers: 'A' + 1 evaluates to 66 (an int), and (char)('A' + 1) gives 'B'.

Watch out: char is unsigned, so it ranges from 0 to 65535. Casting a negative int to char wraps around: (char)(-1) gives 65535, not an error.

2. Character Class Methods

java.lang.Character provides static methods for classifying and converting characters by their code point values:

Character.isLetter('A')     // true
Character.isDigit('5')      // true
Character.isWhitespace(' ') // true
Character.isUpperCase('A')  // true
Character.toLowerCase('A')  // 'a'
Character.toUpperCase('z')  // 'Z'
Character.getNumericValue('7') // 7
Character.getNumericValue('A') // 10 (hex digit)

These methods handle the full Unicode range, not just ASCII. Character.isLetter() returns true for Chinese characters, Arabic letters, and Cyrillic. To restrict checks to the ASCII range, combine with a range test:

public static boolean isAsciiLetter(char c) {
    return (c >= 'A' && c <= 'Z') || (c >= 'a' && c <= 'z');
}

public static boolean isAsciiPrintable(char c) {
    return c >= 32 && c <= 126;
}

The 95 printable ASCII characters span positions 32 (space) through 126 (tilde). The letter positions follow the original 1963 arrangement.

3. String to ASCII Codes

Java strings are sequences of chars. Access individual code points with charAt() or iterate with chars() (returns an IntStream since Java 9):

String text = "Hello";

// charAt approach
for (int i = 0; i < text.length(); i++) {
    System.out.printf("%c = %d%n", text.charAt(i), (int) text.charAt(i));
}

// IntStream approach (Java 9+)
int[] codes = text.chars().toArray();
// [72, 101, 108, 108, 111]

Both produce the same values you would see in the text to ASCII converter. Note that chars() returns UTF-16 code units. For characters outside the BMP (emojis, rare CJK), use codePoints() instead to get actual Unicode code points.

4. Byte Arrays and Charset

Converting between String and byte[] requires specifying a character encoding. The US-ASCII charset maps each character to a single byte in the range 0 through 127.

import java.nio.charset.StandardCharsets;

// String to bytes
byte[] bytes = "Hello".getBytes(StandardCharsets.US_ASCII);
// [72, 101, 108, 108, 111]

// Bytes to String
String text = new String(bytes, StandardCharsets.US_ASCII);
// "Hello"

Always use StandardCharsets.US_ASCII or StandardCharsets.UTF_8 instead of the string name "ASCII". Using the constant is type-safe and avoids the checked UnsupportedEncodingException that the string overload forces you to catch.

Before JDK 18, String.getBytes() without an argument used the platform default encoding. On Windows with a Japanese locale, that could be Shift_JIS. On Linux, usually UTF-8. JDK 18 (JEP 400) changed the default to UTF-8 everywhere. If your code must run on older JDKs, always specify the charset explicitly.

5. Building an ASCII Table

public class AsciiTable {
    public static void main(String[] args) {
        System.out.printf("%5s  %4s  %8s  %s%n",
            "Dec", "Hex", "Binary", "Char");
        for (int i = 0; i < 128; i++) {
            String ch = (i >= 32 && i <= 126)
                ? String.valueOf((char) i)
                : String.format("(ctrl-%d)", i);
            System.out.printf("%5d  0x%02X  %s  %s%n",
                i, i,
                String.format("%7s",
                    Integer.toBinaryString(i)).replace(' ', '0'),
                ch);
        }
    }
}

This generates all 128 positions with decimal, hexadecimal, and binary columns. Compare the output against the ASCII chart view to verify. The base converter handles interactive conversions between number bases.

6. Common Pitfalls

char arithmetic returns int

Adding two chars or a char and an int produces an int, not a char. This compiles fine: int sum = 'A' + 'B'; (131). But char sum = 'A' + 'B'; fails with a compiler error because the result is wider than char. Cast explicitly: char sum = (char)('A' + 1);.

byte is signed

Java's byte type is signed, ranging from -128 to 127. ASCII values 0 through 127 fit, but the byte for value 127 is the maximum. If you process Extended ASCII or raw binary data with values 128 through 255, bytes become negative. Use Byte.toUnsignedInt(b) or b & 0xFF to get the correct unsigned value.

Default encoding surprises

Reading a file with new FileReader(path) (pre-JDK 18) uses the platform default encoding. On a developer's macOS machine, this is UTF-8. On the CI server running Windows, it could be cp1252. Everything reads fine in development and produces corrupted text in production. Always wrap with an explicit charset: new InputStreamReader(new FileInputStream(path), StandardCharsets.UTF_8).

7. Practical Recipes

Strip non-ASCII from a string

public static String stripNonAscii(String input) {
    return input.replaceAll("[^\\x00-\\x7F]", "");
}

Case conversion via bit manipulation

char lower = (char) ('A' | 32);   // 'a'
char upper = (char) ('a' & ~32);  // 'A'

This works because ASCII letters are arranged with exactly 32 between upper and lower pairs. Bit 5 (decimal value 32) is the only difference. Setting it with OR gives lowercase. Clearing it with AND gives uppercase.

Validate ASCII input

public static boolean isAscii(String s) {
    return s.chars().allMatch(c -> c >= 0 && c <= 127);
}

public static boolean isPrintableAscii(String s) {
    return s.chars().allMatch(c -> c >= 32 && c <= 126);
}

Use isPrintableAscii() to reject control characters from user input in form fields, filenames, or API payloads. The control characters article explains which ones still have active meaning in modern systems.

References

  1. Java SE Documentation: Character (java.lang.Character)
  2. Java SE Documentation: StandardCharsets
  3. JEP 400: UTF-8 by Default
  4. Java Language Specification: 4.2.1. Integral Types and Values