Arrays store a fixed number of elements of one declared type. Strings store text whose contents cannot change after creation. Both are reference types, but their mutation rules differ. Learning that difference prevents bugs in copying, equality and text processing. All examples target Java 21.
Array size, indexing and copying
new int[3] creates three integer elements initialized to zero. An initializer such as new int[] {4, 7, 9} supplies the elements directly. Valid indexes start at zero and end just before length. Access outside that range throws ArrayIndexOutOfBoundsException; Java does not let you read arbitrary neighboring memory.
An array's length never changes, although its elements can. Later you will use ArrayList when the number of elements must grow. Arrays expose a length field; strings expose a length() method. These similar spellings are easy to mix up.
Assigning one array variable to another creates an alias, another reference to the same array. Arrays.copyOf creates a separate array. For an array of objects that copy is shallow: both arrays still reference the same element objects. A two-dimensional Java array is an array of arrays, so rows may have different lengths and copying the outer array does not copy its rows.
A runnable example
Save as TextAndArrays.java, compile with javac --release 21 TextAndArrays.java, and run java TextAndArrays.
import java.util.Arrays;
import java.util.Locale;
public class TextAndArrays {
public static void main(String[] args) {
int[] scores = {4, 7, 9};
int[] alias = scores;
int[] copy = Arrays.copyOf(scores, scores.length);
alias[0] = 99;
System.out.println(Arrays.toString(scores));
System.out.println(Arrays.toString(copy));
String raw = " JAVA ";
String clean = raw.strip().toLowerCase(Locale.ROOT);
System.out.println("[" + raw + "] -> " + clean);
System.out.println(clean.equals(new String("java")));
String symbol = "A\uD83D\uDE00";
System.out.println(symbol.length());
System.out.println(symbol.codePointCount(0, symbol.length()));
StringBuilder report = new StringBuilder();
for (int score : copy) {
if (!report.isEmpty()) {
report.append(", ");
}
report.append(score);
}
System.out.println(report.toString());
}
}
Expected output:
[99, 7, 9]
[4, 7, 9]
[ JAVA ] -> java
true
3
2
4, 7, 9
The first two lines show that changing an alias changes the original, while the independent primitive-array copy retains its values. Arrays.toString formats elements; printing the array object directly does not produce this readable representation. For array contents, use Arrays.equals, not == or the array object's inherited equals.
Text equality and Unicode
strip and toLowerCase return strings; they do not edit raw. Always keep the return value if you need the transformed text. Locale.ROOT makes a machine-oriented conversion independent of the computer's default locale. Human-language matching may need a specific locale and more careful rules.
Use equals for string contents. == checks whether two references identify the same object. Some literals share objects, so incorrect identity comparisons can appear to work until the input comes from a file or network. If a value may be null, use Objects.equals(a, b) or check for null explicitly.
A Java string uses UTF-16. In the example, A takes one code unit and the smiley takes two, so length() is three while the code-point count is two. A code point is still not always a complete user-perceived character: combining marks and emoji sequences can contain several. Do not use charAt as a universal way to count displayed characters, or cut arbitrary text at an index that splits a surrogate pair.
Build and split text carefully
StringBuilder is mutable. Appending repeatedly builds text without expressing a new immutable string at every loop step. Convert the result to a string when finished. Ordinary + concatenation remains clear for a few values; you need not replace every greeting with a builder.
substring(start, end) includes the start and excludes the end. split takes a regular expression, so splitting on a literal dot needs split("\\."). By default, trailing empty fields are discarded; split("\\t", -1) keeps them. Splitting on commas is not a correct general CSV parser because quoted fields may themselves contain commas.
Exercise and solution guidance
Write joinNonBlank(String[] values) to strip each value, skip blanks, and join the rest with /. Define null elements as invalid. For " Java ", " ", "Go", expect Java / Go; for an empty array, expect an empty string.
Use a builder and append the separator only when it already contains text. Reject null before calling strip. Do not mutate the supplied array. Test repeated blanks, a single retained value and a Unicode value. As a follow-up, copy a nested array and explain why editing a shared row can still affect both outer arrays.
Official references
Previous: Control Flow and Methods. Next: Classes and Objects.

