Compañero de la entrevista, parte 3: Errores en los métodos comunes

propósito

  • Colección especial de algunos temas interesantes.
  • Estas preguntas serán fáciles de leer y erróneas.
  • Actualización continua, cada diez preguntas como un artículo

Tabla de contenido

Serie de artículos

[1] Acerca del operador ternario

  • ¿Cuál debería ser la salida del siguiente resultado de operación?
public static void main(String[] args) {
    
    
   Integer a = 1;
   Integer b = 2;
   Integer c = null;
   Integer d = a > b ? a + b : c;
   System.out.println(d);
}
  • Que esperas:
null
  • Realmente:
Exception in thread "main" java.lang.NullPointerException
	at DesignPattern.single.dfghj.main(dfghj.java:16)

Process finished with exit code 1
  • la razón

    • La línea 16 del error es esta oración: Entero d = a> b? A + b: c;
    • En primer lugar, lo dejamos claro: el operador condicional es asociativo por la derecha, es decir, agrupa los cálculos de derecha a izquierda. Por ejemplo, a? B: c? D: e se ejecutará como a? B: (c? D: e).
    • Cuando se convierten el tipo básico y el tipo de empaquetado, hay un proceso de empaquetado y desempaquetado automático, que llamará a .xxxxValue (), como .booleanValue (), .intValue (), .StringValue ().
    • El ":" del operador ternario se mantendrá automáticamente igual en los lados izquierdo y derecho. Si los tipos son inconsistentes, se producirá el proceso de desembalaje.
    • Si los tipos en los dos lados son inconsistentes, como en el título: el lado izquierdo se calcula como int3 en lugar de Integer3, y el lado derecho también se descomprimirá, entonces el propio nulo se suspenderá nuevamente usando .xxxxValue (), y ocurrirá NPE.
  • Solución: mantenga ambos lados de ":" consistentes,

    • O modificar a + b: Integer d = a> b? Integer.valueOf (a + b): c;
    • O modificar c: Entero d = a> b? A + b: nulo;
  • Blog de referencia: problema de puntero nulo del operador ternario

【2】 Acerca de la final efectiva

  • ¿Cuál debería ser la salida del siguiente resultado de operación?
public class ljtest{
    
    
    public static void main(String[] args) {
    
    
        for (int i = 0; i < 10; i++) {
    
    
            Thread t = new Thread(new Runnable() {
    
    
                @Override
                public void run() {
    
    
                    System.out.println("thread name:" + Thread.currentThread().getName() + ",i:" + i);
                }
            });
        }
    }
}
  • Que esperas:
thread name:Thread-0,i:0
thread name:Thread-1,i:1
thread name:Thread-2,i:2
thread name:Thread-4,i:4
thread name:Thread-6,i:6
thread name:Thread-8,i:8
thread name:Thread-9,i:9
thread name:Thread-3,i:3
thread name:Thread-5,i:5
thread name:Thread-7,i:7
  • Realmente:
编译期都过不了,会在输出语句哪一行的 i 哪里显示红线。
  • Análisis de causa
    • Porque cuando la clase interna accede a la variable miembro de la clase externa, la variable no se puede cambiar, debe ser estable, final o final efectiva.
    • Final significa inmutable, y final efectivo significa casi equivalente a inmutable Si una variable no ha sido asignada varias veces (dos veces) antes de ser utilizada, entonces por defecto es formalmente invariable.
  • Solución
    • Cambie la variable i a final, o final efectiva, por ejemplo, agregue una oración debajo del ciclo for: int temp = i; (tenga en cuenta que i en la declaración de salida también debe cambiarse a temp)
  • Ahora agregue int temp = i;, ¿el resultado será el que espera?
  • No, porque el hilo no se inicia en absoluto.
  • Solución:
    • Método 1: en el bucle for, agregue t.start (); después de cada hilo
    • Método 2: Entréguelo al grupo de subprocesos para que lo administre, no es necesario agregar t.start ();

[3] Acerca del estancamiento del hambre

  • ¿Cuál debería ser la salida del siguiente resultado de operación?
public class ljtest{
    
    

    private static ExecutorService executorService = Executors.newSingleThreadExecutor();

    static class t1 implements Callable<String> {
    
    

        @Override
        public String call() throws Exception {
    
    
            System.out.println("i am t1");
            return "t1===";
        }
    }

    static class t2 implements Callable<String> {
    
    

        @Override
        public String call() throws Exception {
    
    
            System.out.println("i am t2");
            Future<String> submit = executorService.submit(new t1());
            return "t2===" + submit.get();
        }
    }

    public static void main(String[] args) throws ExecutionException, InterruptedException {
    
    
        t2 t = new t2();
        Future<String> submit = executorService.submit(t);
        System.out.println(submit.get());
        System.out.println("la~la~la~");
        executorService.shutdown();
    }
}
  • Que esperas:
i am t2
i am t1
t2===t1===
la~la~la~
  • En realidad: solo esto
i am t2
  • Análisis de causa
    • El grupo de subprocesos que usamos es Executors.newSingleThreadExecutor (); es un grupo de subprocesos con solo un subproceso.
    • Cuando ponemos t2 para ejecución, t2 pone t1 de nuevo. En este momento, t1 está esperando el final de t2, y t2 está esperando el valor de retorno de t1, y hay hambre esperando.

[4] Intercambia los valores de a y b

  • Cómo intercambiar los valores de ayb sin usar otras variables
常规写法:
public static void main(String[] args) {
    
    
    int a = 5;
    int b = 6;
    a = a + b;
    b = a - b;
    a = a - b;
    System.out.println("a:" + a + "b:" + b);
}
异或写法
public static void main(String[] args) {
    
    
    int a = 8;
    int b = 8;
    a = a ^ b;
    b = a ^ b;
    a = a ^ b;
    System.out.println("new--->" + "a:" + a + ",b:" + b);

}
  • En respuesta a un blog que señaló que la escritura convencional tiene problemas de desbordamiento de memoria, teóricamente los hay, pero se puede optimizar después de jdk1.8, y no hay desbordamiento en el pro-test.
  • Algunos blogs señalaron que el método de escritura XOR tiene un error en el XOR de dos números idénticos, pero no hay un pro-test.
  • El método de escritura XOR puede ser relativo al método de escritura convencional, lo que reducirá el número de cálculos.

[5] Ataque de tiempo

  • Escribe un código que juzgue la igualdad de cadenas.
常规写法
public boolean equals(Object anObject) {
    
    
    if (this == anObject) {
    
    
        return true;
    }
    if (anObject instanceof String) {
    
    
        String anotherString = (String)anObject;
        int n = value.length;
        if (n == anotherString.value.length) {
    
    
            char v1[] = value;
            char v2[] = anotherString.value;
            int i = 0;
            while (n-- != 0) {
    
    
                if (v1[i] != v2[i])
                    return false;
                i++;
            }
            return true;
        }
    }
    return false;
}
  • El párrafo anterior se selecciona del método de igualdad de JDK, juzgue primero aproximadamente
    • Si la dirección de referencia es la misma
    • ¿Es el tipo de cadena?
    • Es la longitud consistente
    • Compare si cada personaje es el mismo uno por uno
  • Está bien escribirlo así, pero no es perfecto. Esto causará problemas de seguridad y expondrá una vulnerabilidad llamada ataque de tiempo (por favor, use el ataque de tiempo de Baidu).
  • De acuerdo con el siguiente método de escritura, se sacrificará la eficiencia para evitar ataques de tiempo.
防计时攻击写法
public boolean equals(String s1, String s2) {
    
    
    if (s1 == null || s2 == null) {
    
    
        return false;
    }
    if (s1 == s2) {
    
    
        return true;
    }
    if (s1.length() != s2.length()) {
    
    
        return false;
    }
    int res = 0;
    for (int i = 0; i < s1.length(); i++) {
    
    
        res |= s1.charAt(i) ^ s2.charAt(i);
    }
    return res == 0;
}

[6] Cuál es mi atributo

  • ¿Cuál debería ser la salida del siguiente resultado de operación?
public class ljtest {
    
    
    public final int value = 4;//5.注释掉本行
    public void dop(){
    
    
        int value = 6;//4.注释掉本行
        Runnable r = new Runnable() {
    
    
            public final int value = 9;//3.注释掉本行
            @Override
            public void run() {
    
    
                int value = 10;//2.注释掉本行
                System.out.println(this.value);//1.去掉this
            }
        };
        r.run();
    }

    public static void main(String[] args) {
    
    
        ljtest f = new  ljtest();
        f.dop();
    }
}
  • Salida
9
  • Mire los comentarios del código y considere los siguientes escenarios: ¿Cuáles son los resultados?

    • // 1. Eliminar esto
    • // 2. Comenta esta línea
    • // 3. Comenta esta línea
    • // 4. Comenta esta línea
    • // 5. Comenta esta línea
  • Resultado de salida

    • 1. Salida: 10
    • 2. Resultado: 9
    • 3. Salida: 6
    • 4. Resultado: 4
    • 5. Salida: error de compilación
  • En conclusión:

    • Distinguir los atributos y valores de las clases internas.

[7] Calcule el valor de 1 + 2 +… + n

  • Descripción del título: Seek 1 + 2 + 3 +… + n, y se requiere que las palabras clave y las sentencias de juicio condicional como multiplicación y división, for, while, if, else, switch, case no se pueden usar (A? B: C).
  • Ideas y código para la resolución de problemas:
public class Solution {
    
    
    private static int[] res = {
    
    0};
    public int Sum_Solution(int n) {
    
    
        /* 1、循环的写法
        int sum = 0;
        for(int i = 1;i <= n; i++){
            sum += i;
        }
        return sum; */
        
        /* 2、数学规律
        return (1 + n) * n / 2; */
        
        /* 3、递归
        return n == 0 ? 0 : n + Sum_Solution(n-1); */
        
        // 4、递归-满足题意
        try{
    
    
            return res[n];
        }catch(Exception e) {
    
    
            return n + Sum_Solution(n-1);
        }
    }
}

Supongo que te gusta

Origin blog.csdn.net/ljfirst/article/details/106376574
Recomendado
Clasificación