Основы Java — как много вы не знаете?

1. && и ||

1. Угадайте, что напечатает следующая программа?
вставьте сюда описание изображения

Результат следующий:
вставьте сюда описание изображения

2. Объясните
символ &&.Когда левая сторона ложна, суждение справа больше не будет выполняться, потому что программа уже может быть определена как ложная, поэтому b++ не выполняется

Когда символ || истинен, решение слева не выполняется, потому что программа может быть определена как истинная, поэтому выполняется d++

3. Использование этого механизма оценки
может решить проблему последовательной оценки. Например, следующая программа
вставьте сюда описание изображения
сначала оценивает, не является ли она пустой, а затем оценивает длину строки. Это правильно, потому что, когда s пусто, она не будет выполняться s.length()== 5

И наоборот, если сначала оценивается длина строки, немедленно будет выдано исключение нулевого указателя.
вставьте сюда описание изображения

Два, целое и целое

1. Сможете ли вы правильно ответить на следующие вопросы? Каков результат?
вставьте сюда описание изображения

результат:
вставьте сюда описание изображения

2. Объясните, что
Integer является классом-оболочкой для int, Integer относится к вновь созданному объекту в куче памяти, а int относится к данным в пуле констант Java.

Integer и int будут иметь механизм распаковки и упаковки
. При сравнении int и Integer Integer будет автоматически распакован для int
. При назначении данных Integer для int
Integer будет автоматически распакован
. При сравнении int с == сравнение представляет собой размер значения.
При сравнении int и Integer с ==, Integer будет автоматически распакован в int, и сравнение будет размером значения.
При сравнении Integer и Integer с == сравнение равно двум Являются ли объекты ссылками на одинаковый

Небольшие детали автоупаковки int: для данных -128~127 int будет судить, есть ли в кеше целочисленный объект с соответствующим значением, если да, вернуть объект напрямую, в противном случае создать новый объект и поместить объект в середине кеша. Это сделано для того, чтобы сохранить только одну копию часто используемых данных и уменьшить потери памяти.

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. Разница между String, StringBuffer и StringBuilder

1. Разница

Нить Строковый буфер StringBuilder
ячейка памяти Постоянный пул / куча Java куча пространства куча пространства
вопросы безопасности потоков потокобезопасность потокобезопасность поток небезопасен
Это переменная Неизменный переменная переменная
эффективность самый медленный в целом самый быстрый
сцены, которые будут использоваться Используйте, когда не требуется никаких изменений Многопоточность один поток

2. Что означает, что String неизменяем?
Например, строка s="abc", если вы хотите s="adc", вы не можете напрямую изменить символ 'b' на 'd', но создадите новый объект "adc" и позвольте s ссылаться на него.

3. Почему String самый медленный?
Поскольку объект String является неизменяемым, каждый раз при его изменении необходимо создавать новый объект,
например, при сращивании строк: "abc"+"d", необходимо создавать новый объект строки "abcd", а StringBuffer и StringBuilder могут непосредственно изменять текущий объект

4. Какой поток небезопасен?
В случае многопоточности возникнут ошибки, например: несколько потоков модифицируют объект StringBuilder одновременно

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());
    }
}

вставьте сюда описание изображения

Было сообщено об исключении, и логически оно должно выводить 10000. Из-за проблемы с многопоточностью результат был неверным, что означает, что поток небезопасен.

5. Причина, по которой поток StringBuilder небезопасен

Поскольку несколько потоков работают с одним и тем же объектом StringBuilder, а метод StringBuilder не заблокирован, несколько потоков вводят метод одновременно, что приводит к несоответствиям.Например, поток 1 получает данные после входа в метод, а поток 2 изменяет string , то поток 1 получает грязные данные

И каждый метод StringBuffer синхронизирован, так что многопоточность не проблема.

вставьте сюда описание изображения

6. Точно так же HashMap и HashSet не являются потокобезопасными, в многопоточной среде вместо них можно использовать ConcurrentHashMap и ConcurrentHashSet, конечно, эффективность будет снижена

4. Верно ли i+1<i?

1. Письменный контрольный вопрос: Существует ли число i+1<i? существовать?
Он есть в компьютере, число типа Int занимает 32 бита, когда int будет максимальным значением, прибавьте 1, тогда оно станет минимальным значением

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);
    }
}

вставьте сюда описание изображения

5. Проблема невежественного нуля

1. Сначала посмотрите программу

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. Что это за штука? Может ли эта программа действительно работать? настоящий!
вставьте сюда описание изображения

3. Объяснение
На самом деле NULL — это имя класса, в java null можно преобразовать в любой объект. После переноса это эквивалентно следующей программе:

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();
    }
}

Так что, наверное, ты понял! haha() — это статический метод, и также можно вызывать нулевые объекты! Конечно, если это не статический метод, будет сообщено об исключении нулевого указателя.

вставьте сюда описание изображения

6. Сколько раундов целочисленного деления вы знаете?

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);

    }
}


вставьте сюда описание изображения

Наиболее часто используется округление в большую сторону — метод 3.

7. Это тоже будет работать?

1. Сначала посмотрите программу

package com.wu.hello.main;

public class Main {
    
    

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

2. Как вы думаете, эта программа может работать?
ответ да
вставьте сюда описание изображения

3. Объяснение
Фактическая программа выглядит следующим образом:

package com.wu.hello.main;

public class Main {
    
    

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

На самом деле, https: — это способ написания оператора goto, от этого способа написания почти отказались, потому что оператор goto сделает программу запутанной и трудной в сопровождении.

Вы можете увидеть следующую программу, чтобы понять использование 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 оптимизировала синтаксис goto C++, за которым может следовать только прерывание и продолжение выхода из цикла или повторное выполнение цикла.

Восемь, многопоточная ошибка?

1. Посмотрите внимательно на следующую программу. И поток 1, и поток 3 могут доказать, что остановка верна. Почему поток 2 не может остановиться?

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();

    }
}


вставьте сюда описание изображения

2. Объясните

Во-первых, давайте посмотрим на объяснение Baidu:
(1), JIT

Компиляция «точно в срок» (JIT) — это метод, который повышает производительность языков, компилируемых с помощью байт-кода, путем преобразования байт-кода в машинный код во время выполнения.

(2), горячий код

В системе компиляции Java в процессе преобразования файла исходного кода Java в исполняемую компьютером машинную инструкцию требуются два этапа компиляции: первый этап — преобразование файла .java в файл .class. Второй этап компиляции — это процесс преобразования .class в машинные инструкции.

Когда JVM обнаруживает, что определенный метод или блок кода запускается особенно часто, он будет считать это «кодом горячей точки». JIT преобразует некоторые классы «горячего кода» в локальные машинные коды, оптимизирует их, а затем кэширует переведенные машинные коды для следующего использования.

Именно из-за проблемы jit цикл while оптимизируется jit после многократного выполнения, и программа была изменена.

3. Доказательство
Добавив в ВМ параметр -Xint, используя значение интерпретации выполнения,
вставьте сюда описание изображения
вставьте сюда описание изображения
мы можем увидеть, что программа выполнилась 22428641 раз, и наконец остановилась, что решило эту проблему, но неиспользование jit сильно снизит производительность программы , потому что виртуальная машина у нас не оптимизируется, так что оптимизированная без ошибок программа не будет оптимизирована

4. Хорошее решение
Для многопоточных общих ресурсов вы можете использовать volatile для изменения переменных, Volatile может помочь нам обеспечить видимость и порядок программы, но все же не может гарантировать атомарность

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();

    }
}

вставьте сюда описание изображения

5. Подробно
безопасность изменчивых потоков должна учитывать три аспекта: видимость, порядок и атомарность.

Видимость: один поток изменяет общие переменные, а другой поток может видеть последние результаты.

Упорядоченность: код в потоке выполняется в том порядке, в котором он написан.

Атомарность: несколько строк кода в одном потоке выполняются как единое целое, во время которого код другого потока не может перейти в очередь.

Видимость программы аналогична этому примеру, который решает проблему, связанную с тем, что поток 2 не может прочитать последнее значение остановки.

Атомарность - это, например, следующая программа, одна пара потоков a+=5, другая нить a-=5, тогда результат a должен быть 0? Ответ — нет, также могут появиться 5 и -5, потому что, хотя a+=5 — это одна строка кода, это несколько инструкций после компиляции, включая выборку данных, вычисление, сохранение обратно и т. д. Нельзя гарантировать, что эти операции являются атомарными. Да, после того, как поток 1 получает данные, поток 2 изменяет данные, а поток 1 считывает грязные данные.

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);
    }

}

Упорядоченность означает, что в следующей программе, очевидно, могут быть три ситуации печати:
x=0
y=0

х=1
у=1

х=0
у=1

Итак, возможно ли, что x=1 и y=0? Ответ возможен, потому что программа будет оптимизировать программу при компиляции, а порядок выполнения кода можно изменить без изменения результата ни одного потока, а это значит, что поток 1 может сначала выполнить x=1, а затем выполнить y =1;, в результате чего x=1 и 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();
    }

}

volatile модифицированные переменные могут решить эту проблему

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();
    }

}

Таким образом, volatile может гарантировать видимость и порядок, в то время как атомарность должна решаться с помощью механизма блокировки.

Если вы считаете, что текст хороший, ставьте лайк!

Je suppose que tu aimes

Origine blog.csdn.net/weixin_52115456/article/details/131227316
conseillé
Classement