Como detectar se String.substring copia os dados de caractere
Eu sei que para o Oracle Java 1.7 atualização 6 e mais recente, ao usarString.substring
, a matriz de caracteres internos da String é copiada e, para versões mais antigas, é compartilhada. Mas eu não encontrei nenhuma API oficial que me dissesse o comportamento atual.
Meu caso de uso é: em um analisador, gosto de detectar seString.substring
copia ou compartilha o array de caracteres subjacente. O problema é que, se a matriz de caracteres é compartilhada, então meu analisador precisa explicitamente "não compartilhar" usandonew String(s)
para evitar problemas de memória. No entanto, seString.substring
de qualquer maneira copia os dados, então isso não é necessário, e copiar explicitamente os dados no analisador pode ser evitado. Caso de uso:
// possibly the query is very very large
String query = "select * from test ...";
// the identifier is used outside of the parser
String identifier = query.substring(14, 18);
// avoid if possible for speed,
// but needed if identifier internally
// references the large query char array
identifier = new String(identifier);
O que eu precisoBasicamente, eu gostaria de ter um método estáticoboolean isSubstringCopyingForSure()
que detectaria senew String(..)
Não é necessário. Eu estou bem se a detecção não funcionar se houverSecurityManager
. Basicamente, a detecção deve ser conservadora (para evitar problemas de memória, prefiro usarnew String(..)
mesmo que não seja necessário).
Eu tenho algumas opções, mas não tenho certeza se elas são confiáveis, especialmente para JVMs não-Oracle:
Verificando o campo String.offset
/**
* @return true if substring is copying, false if not or if it is not clear
*/
static boolean isSubstringCopyingForSure() {
if (System.getSecurityManager() != null) {
// we can not reliably check it
return false;
}
try {
for (Field f : String.class.getDeclaredFields()) {
if ("offset".equals(f.getName())) {
return false;
}
}
return true;
} catch (Exception e) {
// weird, we do have a security manager?
}
return false;
}
Verificando a versão da JVM
static boolean isSubstringCopyingForSure() {
// but what about non-Oracle JREs?
return System.getProperty("java.vendor").startsWith("Oracle") &&
System.getProperty("java.version").compareTo("1.7.0_45") >= 0;
}
Verificando o comportamento Existem duas opções, ambas são bastante complicadas. Uma é criar uma string usando charset customizado, depois criar uma nova string b usando substring, depoismodificar a string original e verifique se b também é alterado. A segunda opção é criar uma cadeia enorme, depois algumas substrings e verificar o uso da memória.