Прочитав этот финал, напоследок и доработав, поспорить с интервьюером не проблема

Java задняя часть

Я скомпилировал свои предыдущие статьи на Github, приветствую всех в звездахGitHub.com/Next Day Picks/Не голоден…Отправила эту статью

final001

finalэто ключевое слово в Java, а также очень важное ключевое слово в Java Final модифицированные классы, методы и переменные имеют разные значения;finallyЭто также ключевое слово, но мы можем использовать finally в сочетании с другими ключевыми словами для выполнения некоторых операций композиции;finalizeэто нежелательный метод, это предок объектаObjectМетод в , механизм finalize теперь устарел. В этой статье cxuan поможет вам начать с этих трех ключевых слов и поможет вам понять эти три ключевых слова простым способом с точки зрения использования, применения и принципа.

окончательный, наконец, и завершить

Я считаю, что все здесь — старшие программисты, поэтому нет необходимости говорить больше о базовом ключевом слове final. Тем не менее, мы все еще должны заботиться о читателях Xiaobai, ведь все мы пришли из Xiaobai.

final украшает классы, свойства и методы

finalМожет использоваться для модификации классов, окончательные измененные классы не позволяют наследовать другие классы, то есть окончательные измененные классы уникальны. Следующее

final002

Сначала мы определяем класс FinalUsage, который украшен final, и в то же время мы определяем класс FinalUsageExtend, который хочет继承(extend)FinalUsage, после того, как мы наследуем как выше, компилятор не дает нам играть так, он подсказывает намНе могу получить от FinalUsageНаследование классов, почему? Не волнуйтесь, это соглашение Java, и есть несколько причин, по которым это не обязательно, просто следуйте ему.

finalЕго можно использовать для изменения методов. Методы Final Modified не могут быть переопределены. Давайте сначала продемонстрируем ситуацию без изменения ключевого слова final.

final003

Как показано выше, мы расширяем класс FinalUsage классом FinalUsageExtend и предоставляемwriteArticleпереопределение метода. С компиляцией таким образом проблем нет, ключевым моментом переписывания является@OverrideСогласованность аннотаций и модификаторов методов, имен и возвращаемых значений.

Примечание. Многие программисты игнорируют @Override при переопределении методов, что, несомненно, усложнит чтение кода, что не рекомендуется.

Когда мы используем окончательный модифицированный метод, этот метод нельзя переопределить, как показано ниже.

final004

Когда мы объявляем метод writeArticle недействительным, переопределенный метод сообщит об ошибке и не сможет переопределить метод writeArticle.

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

final005

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

Мы используем строку String выше, и String по умолчанию является final.На самом деле, нет смысла использовать final модификацию, потому что строка не может быть перезаписана в первую очередь, что не объясняет проблему.

Давайте перепишем его, используя базовые типы данных, чтобы продемонстрировать

final006

Также видно, что компилятор все же дает подсказку о том, что age нельзя перезаписать, поэтому можно доказать, что финальную измененную переменную нельзя переписать.

В Java есть не только базовые типы данных, но и ссылочные типы данных, так что же происходит, когда ссылочный тип финализируется? Давайте посмотрим на код ниже

Сначала постройтеPersonсвоего рода

public class Person {
    int id;
    String name;
    get() and set() ...
    toString()...
}

Затем мы определяем последнюю переменную Person.

static final Person person = new Person(25,"cxuan");

public static void main(String[] args) {

  System.out.println(person);
  person.setId(26);
  person.setName("cxuan001");
  System.out.println(person);
}

Вывод, вы обнаружите странное явление, почему мы явно сменили id и имя лично, но компилятор не сообщил об ошибке?

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

наконец гарантирует, что программа должна быть выполнена

finallyЭто механизм, гарантирующий, что программа должна быть выполнена. Это также ключевое слово в Java. Вообще говоря, finally обычно не используется сам по себе. Обычно он используется с блоками try. Например, ниже приведена попытка... наконец кодовый блок

try{
  lock.lock();
}finally {
  lock.unlock();
}

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

Также работает с lock.lock() при возникновении исключенияtry...catch...finallyиспользовать вместе

try{
  lock.lock();
}catch(Exception e){
  e.printStackTrace();
}finally {
  lock.unlock();
}

try...finally Этот способ записи подходит для JDK1.7 до того, как в JDK1.7 была введена новая операция закрытого потока, то естьtry...with...resources, в Java появился оператор try-with-resources, упрощающий try-catch-finally до try-catch, который на самом деле является синтаксическим сахаром, а не дополнительным синтаксисом. try...with...resources по-прежнему преобразуются в операторы try-catch-finally во время компиляции.

语法糖(Syntactic sugar), также переводится как «подслащенная грамматика», относится к определенной грамматике, добавленной к компьютерному языку.Эта грамматика не влияет на функции языка, но более удобна для использования программистами. Вообще говоря, использование синтаксического сахара может повысить читабельность программы, тем самым уменьшив вероятность ошибки в программном коде.

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

Роль доработки

finalize — класс-предокObjectМетод класса, предназначенный для обеспечения того, чтобы объект завершил освобождение определенного ресурса перед сборкой мусора. finalize теперь устарела и была явно помечена какdeprecated.

Глубокое понимание final, final и finalize

окончательный дизайн

Многие языки программирования каким-то образом сообщают компилятору, что определенный фрагмент данных является константой. Иногда полезны постоянные данные, например

  • Постоянная времени компиляции, которая никогда не меняется. Напримерstatic final int num = 1024
  • значение, которое инициализируется во время выполнения, и вы не хотите его менять

окончательный дизайн будет иabstractконфликты в дизайне, потому что ключевое слово abstract в первую очередь изменяет抽象类, в то время как абстрактные классы должны быть реализованы конкретными классами. final означает, что наследование запрещено, и проблем с реализацией не будет. Потому что только после наследования подкласс может реализовать метод родительского класса.

все в классеprivateнеявно указаны какfinalДа, нет никакого дополнительного смысла в использовании final в приватно оформленном коде.

пустой финал

Java разрешен空白 finalПустой final указывает на объявление как final , но не присваивает ему значение для его инициализации. Но в любом случае компилятору нужно инициализировать final, поэтому задача этой инициализации передается构造器для завершения пустой финал дает больше гибкости для финала. Следующий код

public class FinalTest {

   final Integer finalNum;
   
   public FinalTest(){
       finalNum = 11;
   }
   
   public FinalTest(int num){
       finalNum = num;
   }

    public static void main(String[] args) {
        new FinalTest();
        new FinalTest(25);
    }
}

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

Существует два основных способа использования final:不可变и效率

  • Immutable: Immutable означает блокировку метода (обратите внимание, что он не заблокирован), и основное внимание уделяется предотвращению перезаписи других методов.
  • Эффективность: Это в основном для ранней версии Java.В ранней реализации Java, если метод объявлен final, это означает, что компилятор изменит вызов этого метода на内嵌调用, но не принесли существенной оптимизации производительности. Этот вид вызова довольно безвкусен.В Java5/6 виртуальная машина точки доступа автоматически обнаруживает встроенные вызовы и оптимизирует их, поэтому есть один основной способ использования окончательной модификации: неизменяемый.

Примечание: final не является Immutable, Immutable действительно неизменяем.

финал не соответствует действительностиImmutable, потому что объект, на который ссылается ключевое слово final, может быть изменен. Если мы действительно хотим, чтобы объект был неизменным, нам обычно нужен соответствующий класс для поддержки неизменного поведения, например следующий код

final List<String> fList = new ArrayList();
fList.add("Hello");
fList.add("World");
List unmodfiableList = List.of("hello","world");
unmodfiableList.add("again");

List.ofМетод создает неизменяемый список. Immutable Immutable — хороший выбор во многих случаях, в целом при реализации Immutable необходимо обратить внимание на следующие моменты.

  • Объявите класс как final, чтобы другие классы не расширялись.
  • Объявляйте переменные-члены внутри класса (включая переменные экземпляра и переменные класса) какprivateилиfinalДа, не предоставляйте методы, которые могут изменять переменные-члены, то есть методы установки.
  • При создании объекта вы обычно используетеdeep-clone, что помогает предотвратить изменение входного объекта другими пользователями при непосредственном назначении объекта.
  • настаиватьcopy-on-writeВ принципе, создайте приватную копию.

Улучшает ли final производительность?

Вопрос о том, может ли final повысить производительность, всегда был предметом споров в отрасли. Во многих книгах упоминается, что производительность можно повысить в определенных сценариях. Например, final можно использовать для поддержки встроенных методов JVM, которые могут быть изменены компилятором. Возможность компилировать и т.д., но многие из этих выводов основаны на предположениях.

Может быть, ответ R даст нам некоторые выводыУуху. Call.com/question/21…

грубо говоряНезависимо от того, объявлена ​​ли локальная переменная с модификацией ключевого слова final или без нее, эффективность доступа к ней одинакова..

Например, следующий код (версия без final)

static int foo() {
  int a = someValueA();
  int b = someValueB();
  return a + b; // 这里访问局部变量
}

версия с финалом

static int foo() {
  final int a = someValueA();
  final int b = someValueB();
  return a + b; // 这里访问局部变量
}

использоватьjavacРезультат после компиляции точно такой же.

invokestatic someValueA:()I
istore_0 // 设置a的值
invokestatic someValueB:()I
istore_1 // 设置b的值
iload_0  // 读取a的值
iload_1  // 读取b的值
iadd
ireturn

Поскольку выше используется ссылочный тип, байт-код тот же.

Если это постоянный тип, давайте посмотрим

// 带 final
static int foo(){

  final int a = 11;
  final int b = 12;

  return a + b;

}

// 不带 final
static int foo(){

  int a = 11;
  int b = 12;

  return a + b;

}

Давайте скомпилируем два отдельноfooметод, вы найдете следующий байт-код

final007

Слева код, модифицированный ключевым словом non-final, а справа код, измененный ключевым словом final Сравнивая два байт-кода, можно сделать следующие выводы.

  • Int a = 11 или int a = 12 обрабатываются как константы с модификаторами final или без них.
  • При возврате a + b без final будет рассматриваться как переменная; a + b с модификацией final будет рассматриваться как константа напрямую.

На самом деле, этот уровень различий оказывает большее влияние только на более простую JVM, потому что такая VM в значительной степени зависит от интерпретатора, а байт-код в исходном файле класса выполняется как есть; для высокопроизводительной JVM (например, HotSpot, J9 и т. д.) не действуют.

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

Глубокое понимание наконец

Мы говорили об использовании finally выше, и его роль заключается в том, чтобы гарантировать, что после выполнения кода в блоке try будет выполнено выражение в finally. Независимо от того, выбрасывается ли исключение в блоке try.

Итак, давайте подробнее рассмотрим finally, что такое байт-код finally и природу выполнения finally.

  • Прежде всего, мы знаем, что блок finally будет выполняться только тогда, когда выполняется блок try, и finally не будет существовать сам по себе..

Это не требует дополнительных пояснений, это правило известно всем. finally должен использоваться с блоком try или блоком try catch.

  • Во-вторых, блок finally выполняется перед оператором передачи управления после выхода из блока try или когда блок try не завершен, но следует оператор передачи управления (return/continue/break).

Это на самом деле объясняет время выполнения finally Давайте возьмем return в качестве примера, чтобы увидеть, так ли это.

Следующий код

static int mayThrowException(){
  try{
    return 1;
  }finally {
    System.out.println("finally");
  }
}

public static void main(String[] args) {
  System.out.println(FinallyTest.mayThrowException());
}

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

Когда наконец будет возвращено значение, он вернется напрямую. Больше никаких возвращаемых значений из try или catch.

static int mayThrowException(){
  try{
    return 1;
  }finally {
    return 2;
  }
}

public static void main(String[] args) {
  System.out.println(FinallyTest.mayThrowException());
}
  • Оператор передачи управления сохраняет возвращаемое значение в локальной переменной перед выполнением оператора finally.

Посмотрите на код ниже

static int mayThrowException(){
  int i = 100;
  try {
    return i;
  }finally {
    ++i;
  }
}

public static void main(String[] args) {
  System.out.println(FinallyTest.mayThrowException());
}

Приведенный выше код может показать, что return i выполняется до ++i, а return i временно сохраняет значение i и возвращается с finally.

Суть, наконец,

Давайте посмотрим на кусок кода

public static void main(String[] args) {

  int a1 = 0;
  try {
    a1 = 1;
  }catch (Exception e){
    a1 = 2;
  }finally {
    a1 = 3;
  }

  System.out.println(a1);
}

Каков результат этого кода? Ответ 3, почему?

Сомневаетесь, давайте сначала посмотрим на байткод этого кода

final008

Я для вас отметил китайские комментарии байткода, тут нужно обратить внимание на следующееException table, Таблица исключений — это таблица исключений, каждая запись в таблице исключений представляет собой генератор исключений, а генератор исключений состоит из указателя From, указателя To, указателя Target и типа исключения, которое должно быть перехвачено.

Таким образом, для приведенного выше кода есть три пути выполнения.

  • Если в блоке операторов try возникает исключение, относящееся к exception и его подклассам, переходите к обработке catch.
  • Если в блоке оператора try возникает исключение, не принадлежащее к исключению и его подклассам, перейдите к окончательной обработке.
  • Если в блоке catch возникает новое исключение, перейдите к окончательной обработке

До сих пор мы не говорили, в чем суть finally, если вы внимательно посмотрите на приведенный выше байт-код, вы обнаружите, что finally на самом деле поместитa1 = 3байт-кодiconst_3 и istore_1Поместите его после блока try и блока catch, чтобы приведенный выше код был эквивалентен

public static void main(String[] args) {

  int a1 = 0;
  try {
    a1 = 1;
		// finally a1 = 3
  }catch (Exception e){
    a1 = 2;
    // finally a1 = 3
  }finally {
    a1 = 3;
  }
  System.out.println(a1);
}

Таблица исключений выше толькоThrowableподклассисключение и ошибкаБудет выполнена таблица исключений для обхода исключений. В нормальных условиях без блока try не существует таблицы исключений. Давайте проверим это.

public static void main(String[] args) {
  int a1 = 1;
  System.out.println(a1);
}

Например, мы использовали очень простую программу выше для проверки, и после компиляции давайте посмотрим на ее байт-код

final009

Как видите, таблицы исключений действительно нет.

наконец, он будет выполнен?

То, что мы обсуждали выше, — это случаи, когда finally обязательно будет выполнено, значит, наконец будет выполнено? Я не боюсь.

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

  • перечислитьSystem.exitметод

  • перечислитьRuntime.getRuntime().halt(exitStatus)метод

  • Сбой JVM (забавное лицо)

  • Если JVM достигает бесконечного цикла (или другого непрерывного, не завершающего оператора) в блоке try или catch

  • Уничтожила ли операционная система процесс JVM принудительно; например, kill -9 pid в UNIX.

  • не будет выполняться в случае сбоя хост-системы, такого как сбой питания, аппаратная ошибка, сбой ОС и т. д.

  • Если блок finally выполняется потоком демона, то все потоки, не являющиеся демонами, завершаются до вызова finally.

Finalize действительно бесполезен?

Мы кратко представили метод finalize выше и объяснили, что это плохая практика. Итак, каковы сроки завершения вызова? Почему финализация бесполезна?

Мы знаем, что существенная разница между Java и C++ заключается в том, что Java может自动管理内存, в Java из-за автоматического механизма сбора GC нет гарантииfinalizeМетоды будут выполнены своевременно (время сборки мусора неизвестно), и нет никакой гарантии, что они будут выполнены.

Другими словами, период выполнения finalize неизвестен, и мы не можем полагаться на метод finalize, чтобы помочь нам выполнить сборку мусора.Может случиться так, что сборщик мусора не сработает до того, как мы исчерпаем ресурсы, поэтому рекомендуется использовать метод finalize. отображение, когда ресурсы исчерпаны.Способ освобождения, например метод закрытия. В дополнение к этому, метод finalize также проглатывает исключения.

Финализация работает следующим образом: как только сборщик мусора готов освободить место, занимаемое объектом, он сначала вызываетfinalizeметод, и память, занимаемая объектом, не будет освобождена, пока не произойдет следующее действие по сборке мусора.Сборка мусора касается только памяти.

Мы не поддерживаем использование методов finalize в повседневной разработке.

Здравствуйте, я cxuan, техник. Всего я написал шесть PDF-файлов

«Краткое описание технологии Java Core» «Сводка ядра HTTP» «Базовые знания, которые должен знать программист» «Сводка ядра операционной системы» «Ядро ядра 2.0» Резюме вопросов для собеседования по Java

Теперь я предоставил вам ссылку на Baidu, вы можете щелкнуть ссылку ниже, чтобы получить ее.

Ссылка на сайт:disk.baidu.com/is/1my AES9Hi…Пароль: p9rs