Noções básicas de Java - quanto você não sabe?

1. && e ||

1. Adivinhe o que o seguinte programa irá imprimir?
insira a descrição da imagem aqui

O resultado é o seguinte:
insira a descrição da imagem aqui

2. Explique
o símbolo &&. Quando o lado esquerdo for falso, o julgamento à direita não será mais executado, porque o programa já pode ser determinado como falso, então b++ não é executado

Quando o símbolo || é verdadeiro, o julgamento à esquerda não é executado, porque o programa pode ser determinado como verdadeiro, então d++ é executado

3. O uso deste mecanismo de julgamento
pode resolver o problema de julgamento sequencial. Por exemplo, o seguinte programa
insira a descrição da imagem aqui
primeiro julga se não está vazio e depois julga o comprimento da string. Não está errado, porque quando s está vazio, ele não executará s.length()== 5

Por outro lado, se o comprimento da string for julgado primeiro, uma exceção de ponteiro nulo será lançada imediatamente
insira a descrição da imagem aqui

Dois, inteiro e int

1. Você consegue fazer as seguintes perguntas corretamente? Qual é a saída?
insira a descrição da imagem aqui

resultado:
insira a descrição da imagem aqui

2. Explique que
Integer é a classe wrapper de int, Integer refere-se ao objeto recém-criado na memória heap e int refere-se aos dados no conjunto de constantes java

Integer e int terão um mecanismo de unboxing e boxing
. Ao comparar int e Integer, Integer será automaticamente unboxed para int
. Ao atribuir dados Integer a int
, Integer será automaticamente unboxed
. Ao comparar int com ==, a comparação é o tamanho do valor.
Ao comparar int e Integer com ==, Integer será automaticamente desmarcado para int, e a comparação é o tamanho do valor.
Ao comparar Integer e Integer com ==, a comparação é dois Se os objetos são referências a o mesmo

Os pequenos detalhes do int autoboxing: para os dados de -128~127, int julgará se existe um objeto Integer com o valor correspondente no cache, se houver, retorne o objeto diretamente, caso contrário, crie um novo objeto e coloque o objeto no meio do cache. Isso é feito para salvar apenas uma cópia dos dados usados ​​com frequência e reduzir o desperdício de memória

package com.wu.hello.main;

public class Main {
    
    
    public static void main(String[] args) {
    
    
        int a=0;
        int b=0;
//        true,int和Integer用==比较时,Integer会自动拆箱为int,比较的是值的大小
        System.out.println(a==b);

        Integer c=new Integer(1);
        Integer d=new Integer(1);
//        false,Integer和Integer用==比较时,比较的是两个对象是否是同一个的引用
        System.out.println(c==d);

        Integer e=2;
        Integer f=2;
//        true,int自动装箱的小细节:对于-128~127的数据,int会判断缓存里有没有相对应值的Integer对象,
//        如果有,直接返回该对象,否则新创建一个对象,并把对象放到缓存中。
        System.out.println(e==f);

        Integer g=200;
        Integer h=200;
//        false,int自动装箱的小细节:对于-128~127的数据,int会判断缓存里有没有相对应值的Integer对象,
//        如果有,直接返回该对象,否则新创建一个对象,并把对象放到缓存中。
        System.out.println(g==h);

        Integer i=new Integer(200);
        int j=new Integer(200);
//        true,int和Integer用\=\=比较时,Integer会自动拆箱为int,比较的是值的大小
        System.out.println(i==j);
    }
}

3. A diferença entre String, StringBuffer e StringBuilder

1. Diferença

Corda StringBuffer StringBuilder
local de memória java pool constante/espaço de heap espaço de pilha espaço de pilha
problemas de segurança de thread segurança do fio segurança do fio tópico inseguro
é variável Imutável variável variável
eficiência mais lento geralmente o mais rápido
cenas a serem usadas Use quando nenhuma alteração for necessária Multithreading fio único

2. O que significa que String é imutável?
Por exemplo, a string s="abc", se você quiser s="adc", você não pode alterar diretamente o caractere 'b' para 'd', mas crie um novo objeto "adc" e vamos nos referir a ele

3. Por que o String é o mais lento?
Como o objeto String é imutável, um novo objeto precisa ser gerado toda vez que ele é modificado,
como emenda de string: "abc"+"d", um novo objeto string "abcd" precisa ser criado e StringBuffer e StringBuilder podem modificar diretamente o objeto atual

4. Qual thread não é seguro?
No caso de multi-threading, ocorrerão erros, por exemplo: vários threads modificam o objeto StringBuilder ao mesmo tempo

package com.wu.hello.main;

public class Main {
    
    
    public static void main(String[] args) throws InterruptedException {
    
    
        StringBuilder s=new StringBuilder();
        for (int i = 0; i < 10; i++){
    
    
            new Thread(new Runnable() {
    
    
                @Override
                public void run() {
    
    
                    for (int j = 0; j < 1000; j++){
    
    
                        s.append("a");
                    }
                }
            }).start();
        }
        Thread.sleep(1000);
        System.out.println(s.length());
    }
}

insira a descrição da imagem aqui

Uma exceção foi relatada e deve gerar logicamente 10000. Devido ao problema de multiencadeamento, o resultado estava errado, o que significa que o encadeamento não é seguro.

5. A razão pela qual o thread StringBuilder não é seguro

Como vários threads operam no mesmo objeto StringBuilder e o método de StringBuilder não está bloqueado, vários threads inserem o método ao mesmo tempo, resultando em inconsistências. Por exemplo, o thread 1 obtém dados após inserir o método e o thread 2 modifica o string , então o que o thread 1 obtém são dados sujos

E cada método de StringBuffer é sincronizado, então multi-threading não é problema

insira a descrição da imagem aqui

6. Da mesma forma, HashMap e HashSet não são thread-safe. Em um ambiente multi-threaded, ConcurrentHashMap e ConcurrentHashSet podem ser usados, é claro, a eficiência será reduzida

4. i+1<i é realmente verdadeiro?

1. Questão da prova escrita: Existe um número i+1<i? existir?
Existe no computador, o número do tipo Int ocupa 32 bits, quando o int for o valor máximo, adicione 1, então ele se tornará o valor mínimo

package com.wu.hello.main;

public class Main {
    
    
    public static void main(String[] args) throws InterruptedException {
    
    
        int maxValue = Integer.MAX_VALUE;
        System.out.println(maxValue);

        System.out.println(maxValue+1<maxValue);
    }
}

insira a descrição da imagem aqui

5. O problema nulo ignorante

1. Veja o programa primeiro

package com.wu.hello.main;

public class NULL {
    
    

    public static void haha(){
    
    
        System.out.println("haha");
    }

    public static void main(String[] args) throws InterruptedException {
    
    
        ((NULL)null).haha();
    }
}

2. O que é isso? Este programa pode realmente executar? real!
insira a descrição da imagem aqui

3. Explicação
Na verdade, NULL é o nome de uma classe.Em java, null pode ser convertido em qualquer objeto. Após a transferência, é equivalente ao seguinte programa:

package com.wu.hello.main;

public class NULL {
    
    

    public static void haha(){
    
    
        System.out.println("haha");
    }

    public static void main(String[] args) throws InterruptedException {
    
    
        NULL n=null;
        n.haha();
    }
}

Então, você provavelmente entendeu! haha() é um método estático, e objetos nulos também podem ser chamados! Obviamente, se não for um método estático, uma exceção de ponteiro nulo será relatada.

insira a descrição da imagem aqui

6. Quantas rodadas você conhece sobre divisão inteira?

package com.wu.hello.main;

public class Main {
    
    

    public static void main(String[] args) {
    
    
        int a=20;
        int b=6;

        //方法1
        System.out.println((int)Math.ceil((double) a/b));

        //方法2
        System.out.println(a/b+(((a%b)!=0)?1:0));

        //方法3
        System.out.println((a+b-1)/b);

    }
}


insira a descrição da imagem aqui

O arredondamento para cima mais comumente usado é o método 3.

7. Isso também funcionará?

1. Veja o programa primeiro

package com.wu.hello.main;

public class Main {
    
    

    public static void main(String[] args) {
    
    
        https://www.baidu.com/;
        System.out.println("haha");
    }
}

2. Você acha que este programa pode ser executado?
A resposta é sim
insira a descrição da imagem aqui

3. Explicação
O programa atual é o seguinte:

package com.wu.hello.main;

public class Main {
    
    

    public static void main(String[] args) {
    
    
        https:
        System.out.println("haha");
    }
}

Na verdade, https: é a maneira de escrever a instrução goto. Essa forma de escrever está quase abandonada, porque a instrução goto tornará o programa confuso e difícil de manter.

Você pode ver o seguinte programa para entender o uso de goto:

package com.wu.hello.main;

public class Main {
    
    

    public static void main(String[] args) {
    
    
        https:
        while (true){
    
    
            break https;
        }
        System.out.println("haha");
    }
}

Java otimizou a sintaxe goto de C++, que só pode ser seguida por break e continue para sair do loop ou reexecutar o loop

Oito, bug multiencadeado?

1. Observe atentamente o seguinte programa. Tanto a thread 1 quanto a thread 3 podem provar que a parada é verdadeira. Por que a thread 2 não pode parar?

package com.wu.hello.main;


public class Main {
    
    

    static boolean stop = false;

    public static void main(String[] args) {
    
    


//        线程1
        new Thread(()->{
    
    
            try {
    
    
                Thread.sleep(100);
            } catch (InterruptedException e) {
    
    
                throw new RuntimeException(e);
            }
            stop=true;
            System.out.println("线程1执行完毕,stop="+stop);
        }).start();

//        线程2
        new Thread(()->{
    
    
            int i=0;
            while (!stop){
    
    
                i++;
            }
            System.out.println("线程2执行完毕,i="+i);
        }).start();

//        线程3
        new Thread(()->{
    
    
            try {
    
    
                Thread.sleep(200);
            } catch (InterruptedException e) {
    
    
                throw new RuntimeException(e);
            }
            System.out.println("线程3执行完毕,stop="+stop);
        }).start();

    }
}


insira a descrição da imagem aqui

2. Explique

Primeiro, vejamos a explicação do Baidu:
(1), JIT

A compilação just-in-time (JIT) é uma técnica que melhora o desempenho de linguagens compiladas por bytecode, traduzindo bytecode em código de máquina em tempo de execução.

(2), código quente

No sistema de compilação Java, no processo de transformar um arquivo de código-fonte Java em uma instrução de máquina executável por computador, são necessários dois estágios de compilação: o primeiro estágio é converter o arquivo .java em um arquivo .class. A segunda etapa da compilação é o processo de conversão de .class em instruções de máquina.

Quando a JVM descobre que um determinado método ou bloco de código é executado com frequência, ela o considera um "código de ponto de acesso". O JIT traduzirá algumas classes de "código quente" em códigos de máquina relacionados à máquina local, os otimizará e, em seguida, armazenará em cache os códigos de máquina traduzidos para o próximo uso.

É justamente por causa do problema do jit que o loop while é otimizado pelo jit após ser executado várias vezes, e o programa ter sido modificado

3. Prova
Adicionando o parâmetro -Xint à VM, usando o significado de interpretar a execução,
insira a descrição da imagem aqui
insira a descrição da imagem aqui
podemos ver que o programa executou 22428641 vezes e finalmente parou, o que resolveu esse problema, mas não usar o jit reduzirá muito o desempenho do programa , porque a máquina virtual não vai otimizar para nós, então o programa otimizado sem erro não será otimizado

4. Uma boa solução
Para recursos compartilhados multiencadeados, você pode usar volátil para modificar variáveis. Volátil pode nos ajudar a garantir a visibilidade e ordem do programa, mas ainda não pode garantir atomicidade

package com.wu.hello.main;


public class Main {
    
    

    static volatile boolean stop = false;

    public static void main(String[] args) {
    
    


//        线程1
        new Thread(()->{
    
    
            try {
    
    
                Thread.sleep(100);
            } catch (InterruptedException e) {
    
    
                throw new RuntimeException(e);
            }
            stop=true;
            System.out.println("线程1执行完毕,stop="+stop);
        }).start();

//        线程2
        new Thread(()->{
    
    
            int i=0;
            while (!stop){
    
    
                i++;
            }
            System.out.println("线程2执行完毕,i="+i);
        }).start();

//        线程3
        new Thread(()->{
    
    
            try {
    
    
                Thread.sleep(200);
            } catch (InterruptedException e) {
    
    
                throw new RuntimeException(e);
            }
            System.out.println("线程3执行完毕,stop="+stop);
        }).start();

    }
}

insira a descrição da imagem aqui

5. Em detalhes, a segurança de thread volátil
deve considerar três aspectos: visibilidade, ordem e atomicidade

Visibilidade: um thread modifica variáveis ​​compartilhadas e outro thread pode ver os resultados mais recentes

Ordenação: o código em uma thread é executado na ordem em que foi escrito

Atomicidade: Múltiplas linhas de código em um thread executado como um todo, durante o qual nenhum outro código de thread pode pular na fila

A visibilidade do programa é como este exemplo, que resolve o problema de que a thread 2 não consegue ler o valor mais recente de stop

Atomicity é, por exemplo, o seguinte programa, um par de threads a+=5, outro thread a-=5, então o resultado de a deve ser 0? A resposta é não, 5 e -5 também podem aparecer, porque embora a+=5 seja uma linha de código, são várias instruções após a compilação, incluindo busca de dados, cálculo, armazenamento de volta, etc. Essas operações não podem ser garantidas como atômicas Sim, depois que o thread 1 obtém os dados, o thread 2 modifica os dados e o thread 1 lê os dados sujos

package com.wu.hello.main;


import java.util.concurrent.CountDownLatch;

public class Main {
    
    
    
    static int a=0;

    public static void main(String[] args) throws InterruptedException {
    
    
        
        CountDownLatch latch = new CountDownLatch(2);

        //        线程1
        new Thread(() -> {
    
    
            a += 5;
            latch.countDown();
        }).start();

        //        线程2
        new Thread(() -> {
    
    
            a -= 5;
            latch.countDown();
        }).start();

        latch.await();

        System.out.println("a=" + a);
    }

}

Ordenação significa que no programa a seguir, é óbvio que pode haver três situações de impressão:
x=0
y=0

x=1
y=1

x=0
y=1

Então, é possível que x=1 e y=0? A resposta é possível, porque o programa otimizará o programa ao compilar, e a ordem de execução do código pode ser alterada sem alterar o resultado de um único thread, o que significa que o thread 1 pode primeiro executar x=1; e depois executar y =1;, resultando em x=1 e y=0

package com.wu.hello.main;


import java.util.concurrent.CountDownLatch;

public class Main {
    
    

    static int x=0;
    static int y=0;

    public static void main(String[] args) throws InterruptedException {
    
    

        CountDownLatch latch = new CountDownLatch(2);

        //        线程1
        new Thread(() -> {
    
    
            y=1;
            x=1;
        }).start();

        //        线程2
        new Thread(() -> {
    
    
            System.out.println("x="+x);
            System.out.println("y="+y);
        }).start();
    }

}

variáveis ​​modificadas voláteis podem resolver este problema

package com.wu.hello.main;


import java.util.concurrent.CountDownLatch;

public class Main {
    
    

    static volatile int x=0;
    static volatile int y=0;

    public static void main(String[] args) throws InterruptedException {
    
    

        CountDownLatch latch = new CountDownLatch(2);

        //        线程1
        new Thread(() -> {
    
    
            y=1;
            x=1;
        }).start();

        //        线程2
        new Thread(() -> {
    
    
            System.out.println("x="+x);
            System.out.println("y="+y);
        }).start();
    }

}

Então, em resumo, o volátil pode garantir visibilidade e ordem, enquanto a atomicidade precisa ser resolvida pelo mecanismo de bloqueio

Se você acha que a escrita é boa, dê um joinha!

Acho que você gosta

Origin blog.csdn.net/weixin_52115456/article/details/131227316
Recomendado
Clasificación