Sabemos que pode em JavaScript .
Mas é possível imprimir a mensagem "Success" na condição fornecida abaixo em Java?
if (a==1 && a==2 && a==3) {
System.out.println("Success");
}
Alguém sugeriu:
int _a = 1;
int a = 2;
int a_ = 3;
if (_a == 1 && a == 2 && a_ == 3) {
System.out.println("Success");
}
Mas, ao fazer isso, estamos alterando a variável real. Existe alguma outra maneira?
&&
é umand
operador lógico , o que significa quea
deve ter os valores 1, 2 e 3 ao mesmo tempo, o que é logicamente impossível. A resposta é NÃO, não é possível. Deseja escrever umaif
declaração que verifique sea
possui um dos valores 1, 2 OU 3?yes
_
, exceto que você não pode vê-lo.if(a==1 && a==2 && a==3)
não é necessariamente avaliado ao mesmo tempo. E isso pode ser usado para fazer isso funcionar sem ter que recorrer a truques Unicode.Respostas:
Sim, é muito fácil conseguir isso com vários threads, se você declarar variável
a
como volátil.Um segmento altera constantemente a variável a de 1 para 3, e outro segmento constantemente testa isso
a == 1 && a == 2 && a == 3
. Isso acontece com frequência suficiente para que um fluxo contínuo de "Sucesso" seja impresso no console.(Observe que se você adicionar uma
else {System.out.println("Failure");}
cláusula, verá que o teste falha com muito mais frequência do que com êxito.)Na prática, ele também funciona sem se declarar
a
volátil, mas apenas 21 vezes no meu MacBook. Semvolatile
, o compilador ou o HotSpot pode armazenar em cachea
ou substituir aif
instrução porif (false)
. Provavelmente, o HotSpot entra em ação depois de um tempo e o compila com instruções de montagem que armazenam o valor em cachea
. Comvolatile
, ele continua imprimindo "Sucesso" para sempre.fonte
volatile
, mas, em princípio, isso pode acontecer sem avolatile
palavra-chave e pode acontecer um número arbitrário de vezes, enquanto, por outro lado, não há garantia de que isso aconteça, mesmo comvolatile
. Mas é claro, tê-lo acontecendo na prática, é silenciosamente impressionante ...volatile
. As barreiras de memória criadas para implementarvolatile
reduzem a velocidade dos encadeamentos e aumentam a probabilidade de eles operarem em sincronia por curtos períodos de tempo. Isso acontece com muito mais frequência do que eu esperava. É muito sensível ao tempo, mas vejo aproximadamente entre 0,2% e 0,8% das avaliações de(a == 1 && a == 2 && a == 3)
retornotrue
.Usando conceitos (e código) de uma brilhante resposta de código de golfe ,
Integer
valores podem ser alterados.Nesse caso, ele pode fazer
int
com queInteger
s seja igual a s quando normalmente não seriam:Infelizmente, não é tão elegante quanto a resposta multithread de Erwin Bolwidt (como esta exige
Integer
casting) , mas ainda existem algumas travessuras divertidas.fonte
Integer
. É uma pena o elenco, mas ainda é legal.a
sendo definida como 1/2/3 irá satisfazera == 1
, mas não ir por outro caminhoJava
. A versão menos feia que eu poderia encontrar era usara.equals(1) && a.equals(2) && a.equals(3)
, o que obriga1
,2
e3
para ser autoboxed comoInteger
s.a
uma aulaboolean equals(int i){return true;}
?Integer a = 1;
a linha anterior, ainda está claro quea
realmente é um número inteiro.Em esta questão @aioobe sugere (e aconselhar contra a) o uso de C pré-processador para classes Java.
Embora seja extremamente barato, essa é a minha solução:
Se executado usando os seguintes comandos, ele produzirá exatamente um
Success
:fonte
a
é uma variável, mas pode ser qualquer parte arbitrária de código em idiomas com um pré-processador.Como já sabemos que é possível fazer esse código ser avaliado como verdadeiro, graças às ótimas respostas de Erwin Bolwidt e phflack , eu queria mostrar que você precisa manter um alto nível de atenção ao lidar com uma condição semelhante à apresentada na pergunta, pois às vezes o que você vê pode não ser exatamente o que você pensa que é.
Esta é minha tentativa de mostrar que esse código é impresso
Success!
no console. Eu sei que trapacei um pouco , mas ainda acho que este é um bom lugar para apresentá-lo aqui.Não importa quais sejam os objetivos de escrever um código como este - é melhor saber como lidar com a situação a seguir e como verificar se você não está errado com o que acha que vê.
Usei o cirílico 'a', que é um caractere distinto do latim 'a'. Você pode inspecionar os caracteres usados na instrução if aqui .
Isso funciona porque os nomes das variáveis são obtidos de diferentes alfabetos. Eles são identificadores distintos, criando duas variáveis distintas com um valor diferente em cada uma.
Observe que, se você deseja que esse código funcione corretamente, a codificação de caracteres precisa ser alterada para uma que suporte os dois caracteres, por exemplo, todas as codificações Unicode (UTF-8, UTF-16 (em BE ou LE), UTF-32 e até UTF-7 ) ou Windows-1251, ISO 8859-5, KOI8-R (obrigado - Thomas Weller e Paŭlo Ebermann - por apontarem):
(Espero que você nunca precise lidar com esse tipo de problema em nenhum momento no futuro.)
fonte
а
ea
funcione, desde que você informe ao editor em que codificação está (e possivelmente também no compilador). Todas as codificações Unicode funcionam (UTF-8, UTF-16 (em BE ou LE), UTF-32 e até UTF-7), bem como, por exemplo, Windows-1251, ISO 8859-5, KOI8-R.Há outra maneira de abordar isso (além da abordagem volátil de corrida de dados que publiquei anteriormente), usando o poder do PowerMock. O PowerMock permite que os métodos sejam substituídos por outras implementações. Quando isso é combinado com o desempacotamento automático, a expressão original
(a == 1 && a == 2 && a == 3)
, sem modificação, pode ser verdadeira.A resposta do @ phflack depende da modificação do processo de boxe automático em Java que usa a
Integer.valueOf(...)
chamada. A abordagem abaixo depende da modificação do desbloqueio automático, alterando aInteger.intValue()
chamada.A vantagem da abordagem abaixo é que a declaração if original dada pelo OP na pergunta é usada inalterada, o que eu acho que é a mais elegante.
fonte
access$nnn
usados para lerprivate
campos de classes internas / externas? Isso permitiria que algumas outras variantes interessantes (que até mesmo o trabalho com umaint
variável) ...(Integer)2
) caixas o int. Olhando mais para a reflexão , parece que não é possível fazer isso com unboxing usando a reflexão, mas pode ser possível com Instrumentação vez (ou com PowerMock, como neste resposta)access$0
e a existência de um método seja verificada no registro. Mas a substituição nunca é invocada.Como esse parece ser um acompanhamento dessa pergunta sobre JavaScript , vale a pena notar que esse truque e similares também funcionam em Java:
Em Ideone
Mas observe que isso não é a pior coisa que você pode fazer com o Unicode. Usar espaços em branco ou caracteres de controle que sejam partes de identificadores válidos ou letras diferentes com a mesma aparência ainda cria identificadores diferentes e que podem ser identificados, por exemplo, ao fazer uma pesquisa de texto.
Mas esse programa
usa dois identificadores iguais, pelo menos do ponto de vista Unicode. Eles apenas usam maneiras diferentes de codificar o mesmo caractere
ä
, usandoU+00E4
eU+0061 U+0308
.Em Ideone
Portanto, dependendo da ferramenta que você está usando, elas podem não apenas parecer iguais, as ferramentas de texto habilitadas para Unicode podem até não reportar nenhuma diferença, sempre encontrando as duas ao pesquisar. Você pode até ter o problema de que as diferentes representações se percam ao copiar o código-fonte para outra pessoa, talvez tentando obter ajuda para o "comportamento estranho", tornando-o não reproduzível para o ajudante.
fonte
int ᅠ2 = 3;
é intencional? Porque, eu estou vendo código muito estranho todoa
), enquanto isso é sobre espaço em branco e, além disso, está dando crédito às respostas ainda mais antigas sobre a questão relacionada ao JavaScript. Note-se que o meu comentário não é ainda mais antiga do que a questão Java (por vários dias) ...Inspirado na excelente resposta do @ Erwin , escrevi um exemplo semelhante, mas usando a API Java Stream .
E uma coisa interessante é que minha solução funciona, mas em casos muito raros (porque o
just-in-time
compilador otimiza esse código).O truque é desativar as
JIT
otimizações usando a seguinteVM
opção:Nessa situação, o número de casos de sucesso aumenta significativamente. Aqui está o código:
Os fluxos paralelos PS são usados
ForkJoinPool
sob o capô, e a variável a é compartilhada entre vários threads sem nenhuma sincronização, por isso o resultado é não determinístico.fonte
Seguindo linhas semelhantes , forçando um flutuador (ou duplo) a estourar (ou estourar) através da divisão (ou multiplicação) por um grande número:
fonte