Prefácio
Este artigo apresenta principalmente conteúdo relevante sobre o número inteiro em Java e o compartilha para sua referência e aprendizado. Não vou dizer muito abaixo, vamos dar uma olhada na introdução detalhada juntos.
Parasitas reais
Alguns dias atrás, vi um artigo compartilhado por meus momentos "o mecanismo de transmissão de parâmetros das funções Java - você realmente entende?》
Alguns gatilhos já foram estudados no número inteiro de Java antes, então escrevi este artigo, esperando que seja útil para você.
intercâmbio
Vamos primeiro olhar para um exemplo.
Use Java para concluir a função de troca e trocar valores de dois tipos inteiros.
public static void test () lança exceção {inteiro a = 1, b = 2; troca (a, b); System.out.println ("a =" + a + ", b =" + b);} troca de vazio estático (número inteiro a, número inteiro b) {// partes que precisam ser implementadas} A primeira vez
Se você não entender como os objetos Java são alocados na memória e como os métodos passam os parâmetros, você poderá escrever o seguinte código.
Public Static Void Swpone (Inteiro A, Inteiro B) lança exceção {Inteiro ATEMPVALUE = A; a = b; B = ATEMPVALUE;} Os resultados da execução mostram que os valores A e B não são trocados.
Então, vamos dar uma olhada em como os objetos Java são alocados na memória quando o programa acima é executado:
Atribuição de endereço de objeto
A partir disso, podemos ver que as tabelas variáveis locais dos dois métodos mantêm referências aos endereços de dados reais dos objetos a e b.
A função SWAP implementada acima apenas troca referências à variável local A e variável local B na função Swap e não troca os dados reais na pilha JVM.
Portanto, os dados referenciados por A e B na função principal não são trocados; portanto, os A e B das variáveis locais na função principal não mudarão.
Então, como você opera ao trocar os dados na função principal?
A segunda vez
De acordo com a prática acima, podemos considerar a troca de valores de dados de A e B na pilha JVM?
Vamos aprender brevemente sobre o objeto inteiro. Ele possui apenas um valor de tipo de tipo de objeto para representar o valor do objeto.
Por isso, usamos a reflexão para modificar o valor, o código é o seguinte:
public static void swaptwo (número inteiro A1, número inteiro b1) lança a exceção {field ValueField = Integer.class.getDecaredfield ("value"); valuefield.setAccessible (true); int tempavalue = valuefield.getint (a1); valuefield.setInt (A1, B1.IntValue ()); valuefield.setInt (B1, Tempavalue);}Os resultados da operação estão alinhados com as expectativas.
Surpresa
Após a execução do programa acima, o que acontecerá se eu declarar um Integer c = 1, d = 2;
O programa de amostra é o seguinte:
public static void swaptwo (número inteiro A1, número inteiro b1) lança a exceção {field ValueField = Integer.class.getDecaredfield ("value"); valuefield.setAccessible (true); int tempavalue = valuefield.getint (a1); valuefield.setInt (A1, B1.IntValue ()); valuefield.setInt (b1, tempavalue);} public static void testThree () lança exceção {número inteiro a = 1, b = 2; swaptwo (a, b); System.out.println ("a =" + a + "; b =" + b); Número inteiro c = 1, d = 2; System.out.println ("c =" + c + "; d =" + d);}Os resultados da saída são os seguintes:
a = 2; b = 1c = 2; d = 1
Surpresa ou não! Acidente ou não! Estimulante ou não!
Aprofundado
O que exatamente aconteceu? Vamos dar uma olhada no código descompilado:
O autor usou a ferramenta IDE para descompilar diretamente este arquivo .class
public static void testThree () lança exceção {Inteiro a = Integer.valueof (1); Inteiro B = Inteiro.ValueOf (2); swaptwo (a, b); System.out.println ("a =" + a + "; b =" + b); Inteiro c = Inteiro.ValueOf (1); Número inteiro d = inteiro.valueof (2); System.out.println ("c =" + c + "; d =" + d);} No processo de Java, boxe automaticamente o tipo original int para o tipo inteiro Integer.valueOf(int) é usado.
Deve ser que esse método encapsule algumas operações internamente, o que nos leva a ter um impacto global após a modificação Integer.value .
Tudo isso envolve o código nesta parte do código é colado de uma só vez (PS: o autor que não arrasta é um bom codificador):
classe pública Inteiro { / ** * @since 1.5 * / public estático Inteiro Valueof (int i) {if (i> = Integercache.low && i <= Integercache.high) Retorne Integercache.cache [i + (-Integercache.low)]; devolver novo número inteiro (i); } classe estática privada Integercache {estático final int baixo = -128; estático final int alto; Cache inteiro final estático []; estático {// Alto valor pode ser configurado pela propriedade int h = 127; String integegercacheHighPropValue = Sun.misc.vm.getSavedProperty ("java.lang.integer.integercache.high"); if (integercacheHighPropValue! = null) {try {int i = parseInt (integercacheHighPropValue); i = math.max (i, 127); // O tamanho máximo da matriz é inteiro.max_value h = math.min (i, integer.max_value -(-low) -1); } catch (númeroFormatexception nfe) {// Se a propriedade não puder ser analisada em um int, ignore -o. }} alta = h; cache = novo número inteiro [(alto - baixo) + 1]; int j = baixo; for (int k = 0; k <cache.length; k ++) cache [k] = novo número inteiro (j ++); // intervalo [-128, 127] deve ser internado (JLS7 5.1.7) assert integercache.high> = 127; } private integercache () {}} Como mostrado acima, o número inteiro possui uma classe estática privada inteira dentro, que inicializa estaticamente uma matriz inteira contendo Integer.IntegerCache.low para java.lang.Integer.IntegerCache.high .
A faixa de valor de java.lang.Integer.IntegerCache.high está entre [127~Integer.MAX_VALUE - (-low) -1] .
Todos os objetos retornados pela função Integer.valueOf(int) nesse intervalo são compensados calculados com base no valor int e são obtidos do Integer.IntegerCache.cache da matriz.Integercache.cache. O objeto é o mesmo e nenhum novo objeto é criado.
Portanto Integer.IntegerCache.cache[ 1 - IntegerCache.low ] quando modificamos o valor do Integer.valueOf(1) .
Eu acredito que seu QI deve ser entendido. Se você não entende, ligue para 10086 na seção de comentários.
OK, e a parte que não está em [IntegerCache.low~IntegerCache.high) ?
Obviamente, eles têm sorte, não em cache por integração e toda vez que chegam, alocam um pedaço de terra (interior) (distribuição) na JVM.
Devaneio
E se eu alterar o parâmetro convertido para digitar para int?
public static void testone () lança exceção {int a = 1, b = 2; Swapone (A, B); System.out.println ("a =" + a + ", b =" + b);} Swpone estático de vazio (int a, int b) {// partes que precisam ser implementadas} Com as habilidades atuais do autor, não há solução. Especialistas podem deixar mensagens na conta oficial, muito obrigado!
Até agora, a parte da troca foi concluída.
1 + 1
Primeiro, vejamos o código:
public static void testone () {int one = 1; int dois = um + um; System.out.printf ("dois =%d", dois);} Qual é a saída?
Se você disser 2, com certeza, aprendeu em vão, ligue diretamente para 95169.
Posso dizer com certeza que pode ser qualquer valor no intervalo [Integer.MIN_VALUE~Integer.MAX_VALUE] .
Surpresa ou não! Acidente ou não! Estimulante ou não!
Vamos acariciar o código assado um por um.
O autor usou a ferramenta IDE para descompilar diretamente este arquivo .class
public static void testone () {int one = 1; int dois = um + um; System.out.printf ("dois =%d", dois);} A variável dois aqui não chamou de teger.valueOf(int) , que é diferente do que eu imaginava. Eu suspeito que este é o pote do IDE.
Portanto, verifique o bytecode compilado decisivamente. A seguir, alguns dos bytecodes do trecho:
Ldc "dois =%d" iconst_1anewArray java/lang/objectDupiconst_0ILOAD 2invokestatic Java/lang/integer.valueof (i) ljava/lang/integro; Aastoreinvokevirtual (Ljava/lang/string; [ljava/lang/objeto;) ljava/io/printStream; pop
Pode -se observar que é realmente o pote do IDE. Não é apenas Integer.valueOf(int) .
O código Java completo deve ficar assim:
public static void testone () {int one = 1; int dois = um + um; Objeto [] params = {Integer.valueof (dois)}; System.out.printf ("dois =%d", params);} Portanto, basta modificar o valor do Integer.IntegerCache.cache[2+128] antes que o método seja chamado, então adicione algum código à parte de inicialização estática da classe.
classe pública OnePlusone {static {try {class <?> Cacheclazz = class.ForName ("java.lang.integer $ integercache"); Cachefield de campo = CacheClazz.getDecLaredField ("cache"); Cachefield.setAccessible (true); Inteiro [] cache = (Inteiro []) Cachefield.get (null); // mude aqui para 1 + 1 = 3 cache [2 + 128] = novo número inteiro (3); } catch (Exceção e) {e.printStackTrace (); }} public static void testone () {int one = 1; int dois = um + um; System.out.printf ("dois =%d", dois); }}dois == 2?
Depois de modificar o valor de Integer.IntegerCache.cache[2 + 128] , a variável é dois iguais a 2?
public static void testtwo () {int one = 1; int dois = um + um; System.out.println (dois == 2); System.out.println (Integer.valueof (dois) == 2);}A saída de código acima é a seguinte
truefalse
Como dois == 2 não envolve a conversão do boxe inteiro ou uma comparação do tipo original, o 2 do tipo original é sempre igual a 2.
A forma real de Integer.valueOf(two)==2 é Integer.valueOf(two).intValue == 2 , ou seja, 3 == 2, por isso é falso.
Aqui podemos ver que, se você comparar um valor de nulo com uma variável inteira com uma variável int com um sinal de igualdade duplo, uma NullpointException será lançada.
Que tipo de saída será se o método aqui for substituído pelo System.out.println("Two=" + two) ? Você pode tentar.
PostScript
Xcache
| tipo | Existe um cache | Valor mínimo | Valor máximo |
|---|---|---|---|
| Booleano | nenhum | - | - |
| Byte | Bytecache | -128 | 127 (fixo) |
| Curto | Shortcache | -128 | 127 (fixo) |
| Personagem | CaracterCache | 0 | 127 (fixo) |
| Inteiro | Integercache | -128 | java.lang.integer.integercache.high |
| Longo | Longcache | -128 | 127 (fixo) |
| Flutuar | Nenhum | - | - |
| Dobro | Nenhum | - | - |
java.lang.integer.integercache.high
Depois de ler o método de obter alta sun.misc.VM.getSavedProperty classe Integercache, você pode ter as seguintes perguntas. Não atrasaremos e usaremos um método de uma pergunta-one-Answer.
1. Como passar esse valor para a JVM?
Como as propriedades do sistema, quando a JVM é iniciada, ela é passada por configuração -Djava.lang.Integer.IntegerCache.high=xxx .
2. Qual é a diferença entre esse método e System.getProperty ?
Para distinguir os parâmetros exigidos pelo sistema JVM dos parâmetros usados pelo usuário,
Quando java.lang.System.initializeSystemClass for iniciado, os parâmetros de inicialização serão salvos em dois lugares:
2.1 Os parâmetros do sistema recebidos por todos os JVMs são salvos no sol.misc.vm.sAvedProps.
Quando a JVM é iniciada, ele chama o método java.lang.System.initializeSystemClass para inicializar a propriedade.
Ao mesmo tempo, o método sun.misc.VM.saveAndRemoveProperties também será chamado para excluir as seguintes propriedades de java.lang.System.props :
As propriedades listadas acima são todos os parâmetros do sistema que precisam ser definidos para inicialização da JVM; portanto, para considerações de segurança e considerações de isolamento, separam-as do sistema acessível pelo usuário.
2.2 Salvar outros parâmetros, exceto os seguintes parâmetros necessários para a inicialização da JVM em java.lang.system.props.
PS: JDK 1.8.0_91 usado pelo autor
Integercache para Java 9
Imagine se a jogabilidade Naugada acima aparecer no pacote de dependência de terceiros, definitivamente haverá um grupo de programadores que ficarão loucos (por favor, não tente uma jogabilidade tão ruim, as consequências são muito graves).
Felizmente, o Java 9 restringiu isso. Você pode gravar o arquivo módulo-info.java no módulo correspondente, que restringe o uso da reflexão para acessar membros, etc. Após a declaração, conforme necessário, o código pode acessar apenas campos, métodos e outras informações que podem ser acessadas por reflexão. Somente quando a classe está no mesmo módulo, ou o módulo abriu um pacote para acesso a reflexão. Para detalhes, consulte o artigo:
Modificar o IntegerCache em Java 9?
Obrigado a Lydia e Asuka por seus valiosos conselhos e trabalho duro na revisão.
Por fim, gostaria de compartilhar com você um problema que não presto atenção ao valor inteiro em Java:
Vamos primeiro olhar para um trecho de código:
public static void main (String [] args) {Inteiro A1 = Integer.Valueof (60); // Danielinbiti inteiro b1 = 60; System.out.println ("1: ="+(a1 == b1)); Inteiro A2 = 60; Inteiro B2 = 60; System.out.println ("2: ="+(a2 == b2)); Número inteiro A3 = novo número inteiro (60); Número inteiro b3 = 60; System.out.println ("3: ="+(a3 == b3)); Número inteiro A3 = novo número inteiro (60); Número inteiro b3 = 60; System.out.println ("3: ="+(a3 == b3)); Inteiro A4 = 129; Número inteiro b4 = 129; System.out.println ("4: ="+(a4 == b4)); } Se o resultado da comparação desse código não for executado, não sei quais estão as respostas em sua mente.
Para saber esta resposta, envolve os problemas de buffer e heap java.
Em Java, o tipo inteiro é um buffer para números entre -128-127, por isso é consistente com o sinal igual. Mas para números não nesse intervalo, eles são novos na pilha. Portanto, o espaço de endereço é diferente, por isso não é igual.
Integer b3=60 , este é um processo de embalagem, ou seja, Integer b3=Integer.valueOf(60)
Portanto, no futuro, quando você encontra o número inteiro, você precisa usar intValue() para comparar se os valores são iguais.
Não há buffer para o dobro.
Resposta
1: = true
2: = verdadeiro
3: = false
4: = false
Resumir
O acima é o conteúdo inteiro deste artigo. Espero que o conteúdo deste artigo tenha certo valor de referência para o estudo ou trabalho de todos. Se você tiver alguma dúvida, pode deixar uma mensagem para se comunicar. Obrigado pelo seu apoio ao wulin.com.