All declared variables are associated with a particular location in memory that serves to hold their value.
All primitive types are Value types, except Strings. This means that their location in memory actually holds their value. When passed to a procedure by value a copy of the contents of their memory location are passed.
Strings, Arrays and other Objects, are actually Reference types. This means that their location in memory actually contains a reference (pointer) to another location in memory where their actual value is located. For Strings this is a sequence of characters, for Arrays this is a sequence of values of the declared types, for Objects it is a structure holding the object data.
When a Reference type is passed by value the contents of their memory location are also passed but in this case it is a pointer to where the actual data for the type is stored. Normally this would mean the passed value could be to be used to modify the actual value and the caller would see any changes to that value, and in fact this is true for Arrays and other Objects.
However in B4x/Java (and C#, Python and many other languages) Strings are given special treatment by the language compiler to give them "value semantics". What this means is that Strings behave like they are value, rather than reference types. The compiler achieves this by ensuring that String values are immutable - they cannot be changed. Any change to a String results in a new String being built rather than the existing String being modified. The pointer to the location of the new String is then stored as the reference to the String. This means that in the case of a passed String reference the passed reference is changed in the memory location of the passed parameter variable but the original String variable location still contains a pointer to the original String value.