In addition to the overhead from dyn alloc and the GC as someone else mentioned, there is also the size overhead that comes with every object in an OO language. The obj overhead for Java is JVM-dependent, but I believe it to be somewhere around 16 bytes.
A mostly unrelated stackoverflow post I found[0] states that an empty standard string in Java occupies 40 bytes due to the normal object overhead and overhead related to the internal byte array for the char storage. Obviously what you gain in return is convenience in programming as well as runtime-enforced safety from buffer overflows. Whether this is worth it depends on what you're doing.
In general, you're definitely absorbing overhead with any managed lang, although it need not be hidden. The specifics should be documented somewhere for whatever platform you're using, and most GCs are pretty tuneable nowadays.
In cases where perfomance actually matters, you usually have other tools, like StringBuilder in C#. But in my experience, 99% of code that works with dynamic strings is not perfomance-sensitive, but is often very correctness-sensitive and readibility-sensitive.
A mostly unrelated stackoverflow post I found[0] states that an empty standard string in Java occupies 40 bytes due to the normal object overhead and overhead related to the internal byte array for the char storage. Obviously what you gain in return is convenience in programming as well as runtime-enforced safety from buffer overflows. Whether this is worth it depends on what you're doing.
In general, you're definitely absorbing overhead with any managed lang, although it need not be hidden. The specifics should be documented somewhere for whatever platform you're using, and most GCs are pretty tuneable nowadays.
[0] https://stackoverflow.com/questions/56827569/what-is-an-over...