Этот фундамент Java, я не могу его испортить

Java задняя часть
Этот фундамент Java, я не могу его испортить

Привет, ребята, это программист cxuan. Добро пожаловать в мою последнюю статью. В этой статье я добавил некоторый контент о «Java Basic Core Summary», изменил некоторые опечатки и непонятные предложения, а также внес некоторые исправления во внутренние классы, дженерики. , и т.д., в определенной степени дополнены, и я дал некоторые ссылки в некоторых частях статьи.Эти ссылки являются хардкорными статьями, написанными мной, которые могут помочь вам лучше понять язык Java, так что бред без дальнейших адо, давайте начнем текст.

Обзор Java

Что такое Ява?

Java была впервые выпущена компанией Sun Microsystems в 1995 году.编程语言и вычислительные платформы. Язык программирования относительно прост для понимания, так что计算平台Шерстяная ткань?

Вычислительная платформа — это среда, в которой на компьютере выполняются приложения (программное обеспечение), в том числе硬件环境и软件环境. Общая системная платформа включает аппаратную архитектуру, операционную систему и библиотеку времени выполнения компьютера.

Java — это быстро, безопасно и надежно. От ноутбуков до центров обработки данных, от игровых приставок до научных суперкомпьютеров, от мобильных телефонов до Интернета — Java везде! Java в основном делится на три версии:

  • JavaSE (J2SE) (стандартная версия платформы Java2, стандартная версия платформы Java)

JavaSE является основой JavaEE и JavaME, JavaSE основана на JDK и JRE, а затем включает некоторые классы, поддерживающие разработку веб-сервисов Java.

  • JavaEE (J2EE) (платформа Java 2, Enterprise Edition, Java Platform Enterprise Edition)

Первоначально JavaEE назывался J2EE, а позже изменил свое название на JavaEE, которое является расширением JavaSE, версии, которую мы используем для корпоративной разработки, включая некоторые инструментальные средства Java Web.

  • JavaME (J2ME) (Java 2 Platform Micro Edition, микровыпуск платформы Java).

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

Особенности Java

  • Ява — это面向对象язык программирования

Что такое объектная ориентация?面向对象(Object Oriented)Это идея разработки программного обеспечения. Это абстракция реального мира, и объектно-ориентированная система организует связанные данные и методы как единое целое.

Другой идеей развития является процессно-ориентированная идея развития.面向过程(Procedure Oriented)Это процессно-ориентированная идея программирования.

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

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

class student {
		void student_wakeUp(){...}
  	void student_cloth(){...}
  	void student_wash(){...}
  	void student_eating(){...}
  	void student_gotoSchool(){...}
}

А объектно-ориентированный подход может абстрагировать учащихся, поэтому этот пример станет

class student(){
  	void wakeUp(){...}
  	void cloth(){...}
  	void wash(){...}
  	void eating(){...}
  	void gotoSchool(){...}
}

Каждое действие может выполняться не в строгом порядке. Это особенность номер один.

  • Java отказывается от концепций множественного наследования, указателей, управления памятью и т. д., которые трудно понять в C++, нет необходимости вручную управлять жизненным циклом объектов, что является второй особенностью.
  • Язык Java имеет две характеристики: мощные функции и простота использования.Сейчас разработка на уровне предприятия, быстрая и гибкая разработка, особенно появление различных фреймворков, делают Java все более и более популярным языком. Это особенность номер три.
  • Java — это статический язык.Статический язык относится к языку, который может знать тип данных во время компиляции и может проверять правильность типа перед запуском.Определенный тип не может быть изменен, как в следующем примере.
public void foo() {
    int x = 5;
    boolean b = x;
}

Статические языки в основномPascal, Perl, C/C++, JAVA, C#, ScalaЖдать.

Соответственно, в динамических языках нет конкретной ситуации, требующей указания типа переменной, типа данных, определяемого во время выполнения. Например, есть **Lisp, Perl, Python, Ruby, JavaScript** и так далее.

По замыслу все языки предназначены для преобразования удобочитаемого кода в машинные инструкции. Ниже представлена ​​схема классификации языков.

image-20210907222622439

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

  • Java является платформенно-независимой и переносимой.

У Java есть очень известный слоган:Write once, run anywhere, то есть пиши один раз, беги везде. Почему Java может использовать такой бредовый лозунг? ядроJVM. Мы знаем, что многие детали защищены между компьютерными приложениями и оборудованием, и они полагаются на операционную систему для завершения планирования и координации.Общая архитектура выглядит следующим образом.

image-20210907222642565

Тогда архитектура Java-приложения и JVM станет следующей

image-20210907222654021

Java является кроссплатформенной, и скомпилированные Java-программы могут работать на любой платформе с JVM. Вы можете написать код на платформе Windows, а затем запустить его на платформе Linux.Как это сделать?

Сначала вам нужно написать код Java в своем приложении;

использоватьEclipseилиjavacСкомпилируйте код Java для.classдокумент;

Затем введите файл .class как.jarдокумент;

Тогда ваш файл .jar может работать под Windows, Mac OS X, Linux. Различные операционные системы имеют разные реализации JVM, поэтому при смене платформы вам не нужно заново компилировать код Java. Это особенность пять.

  • Java может легко реализовать многопоточность

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

Реализация многопоточности в пользовательском пространстве

Реализация многопоточности в пространстве ядра

Смешанная реализация потоков в пространстве пользователя и ядра

И я думаю, что Java должна быть в用户空间Реализована многопоточность, ядро ​​не знает о существовании механизма многопоточности в Java. Это особенность шесть.

  • Java имеет высокую производительность

Код, который мы пишем, скомпилированный компилятором javac, называется字节码(bytecode), байт-код преобразуется в машинный код интерпретатором, встроенным в JVM, который интерпретируется и выполняется, и этот процесс преобразования менее эффективен. Но некоторые реализации JVM, такие какHotspot JVMпри условииJIT(Just-In-Time)Компилятор, также известный как динамический компилятор, JIT может компилировать горячий код в машинный код во время выполнения.Этот метод более эффективен, то есть выполнение компиляции. Итак, Java — это не просто интерпретируемый язык. Это особенность семь.

  • Язык Java надежен

Механизм строгого типа Java, обработка исключений, автоматическая сборка мусора и т. д. являются важными гарантиями надежности программ Java. Это также важное различие между языком Java и C. Это особенность восемь.

  • Java упрощает разработку распределенных проектов

Язык Java поддерживает разработку интернет-приложений.В Java есть net api, который предоставляет библиотеки классов для программирования сетевых приложений, включая URL, URLConnection, Socket, ServerSocket и т. д. ЯваRMI(远程方法激活)Механизм также является важным средством разработки распределенных приложений. Это функция девять.

Небольшой пример, иллюстрирующий разницу между процессом лицом к лицу и объектно-ориентированным процессом.

1. Ориентированность на процесс

Для того, чтобы упаковать слона в холодильник, требуется 3 процесса.

Идеи:

1. Откройте дверцу холодильника (получите холодильник с открытой дверцей).

2. Вставьте слона (открыв дверь, вы получите холодильник со слоном внутри).

3. Закройте дверцу холодильника (откройте дверцу и установите слона, чтобы получить холодильник с закрытой дверцей).

Согласно приведенному выше мышлению видно, что каждый процесс имеет поэтапную цель.Если эти процессы выполнять последовательно, то слона можно положить в холодильник.

2. Объектно-ориентированный

Чтобы поместить слона в холодильник, необходимы три действия (или поведения). У каждого действия есть исполнитель, который является объектом.

Идеи:

1. Холодильник, открой мне дверь.

2. Холодильник, ты засунь мне слона (или, слон, ты просверлишь мне холодильник).

3. Холодильник, закрой для меня дверь.

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

Среда разработки Java

JDK

JDK(Java Development Kit)Известный как Java Development Kit или Java Development Tool, это среда разработки программ для написания Java-апплетов и приложений. JDK — это ядро ​​всей Java, включаяJava运行环境(Java Runtime Environment),НемногоJava 工具иJava 的核心类库(Java API).

image-20210907222710633

Мы можем серьезно взглянуть на эту диаграмму, она включает в себя почти все концепции Java, которые я используюjdk1.8, вы можете нажатьDescription of Java Conceptual Diagram, вы можете обнаружить, что это включает все описания Java.

Oracle предоставляет две реализации платформы Java: одна — JDK, о которой мы упоминали выше, стандартный инструментарий разработки Java, а другая — JRE, называемая Java Runtime Environment, Java Runtime Environment. JDK намного функциональнее, чем JRE.

JRE

JRE — это среда выполнения, а JDK — среда разработки. Поэтому при написании программ на Java требуется JDK, а при запуске программ на Java требуется JRE. JDK уже содержит JRE, поэтому, пока JDK установлен, вы можете редактировать программу Java и запускать программу Java в обычном режиме. Однако, поскольку JDK содержит много контента, не связанного с запуском, он занимает много места, поэтому для запуска обычных Java-программ не требуется устанавливать JDK, а требуется только установка JRE.

Конфигурация среды развития Java

Вот несколько блогов, которые рекомендуют установку и настройку JDK:

Загрузка и установка версии JDK для Windows

Загрузка и установка версии JDK для Mac

Базовый синтаксис Java

После настройки среды разработки Java и загрузки инструментов разработки Java (Eclipse, IDEA и т. д.) вы можете писать программы Java.Поскольку данное руководство предназначено для изучения системы Java с нуля, необходимо начать с основных понятий.

тип данных

В Java типы данных только四类八种.

  • Целочисленный тип: byte, short, int, long

байт также является байтом, 1 байт = 8 бит, значение байта по умолчанию равно 0;

short занимает два байта, то есть 16 бит, 1 short = 16 бит, и его значение по умолчанию также равно 0;

int занимает четыре байта, то есть 32 бита, 1 int = 32 бита, значение по умолчанию 0;

long занимает восемь байт, то есть 64 бита, 1 long = 64 бита, значение по умолчанию 0L;

Таким образом, целочисленный тип размера посадочного места для long> int> short> byte

  • плавающая точка

Существует два типа данных с плавающей запятой: float и double.

float — тип с плавающей запятой одинарной точности, занимающий 4 бита, 1 float = 32 бита, значение по умолчанию — 0.0f;

double — тип с плавающей запятой двойной точности, занимающий 8 бит, 1 double = 64 бита, значение по умолчанию — 0.0d;

  • тип персонажа

Тип символа — char, тип char — одиночный 16-битный символ Unicode, а минимальное значение —\u0000 (也就是 0 ), максимальное значение\uffff (即为 65535), тип данных char может хранить любой символ, например char a = 'A'.

  • логический

Логическое значение относится к логическому значению. Логическое значение имеет только два значения, истинное или ложное, что соответствует только 1 биту. Значение по умолчанию — ложное.

вышеx 位Все ссылаются на занятость в памяти.

image-20210907222746854

Базовая грамматика

  • С учетом регистра: язык Java чувствителен к регистру.Например, Hello отличается от hello, который на самом деле является строковым представлением Java.
  • Имя класса: для всех классов первая буква должна быть заглавной, например.MyFirstClass.
  • Имя пакета: имя пакета должно быть как можно меньше в нижнем регистре, напримерmy.first.package.
  • Имя метода: первая буква имени метода должна быть строчной, а каждая буква следующего слова должна быть прописной, напримерmyFirstMethod().

оператор

Операторы есть не только в Java, но и в других языках.Операторы — это некоторые специальные символы, которые в основном используются в математических функциях, некоторых типах операторов присваивания и логических сравнений.Давайте возьмем Java в качестве примера, чтобы взглянуть на операторы.

  • оператор присваивания

Оператор присваивания использует оператор=чтобы указать, что это означает копирование значения справа от знака = влево Значение справа может быть любой константой, переменной или выражением, но значение слева должно быть явно определенной переменной. Напримерint a = 4.

Но для объектов копируется не значение объекта, а ссылка на объект, поэтому, если вы говорите копирование объекта в другой объект, вы на самом деле копируетеПрисвоение ссылки на объект другому объекту.

  • арифметические операторы

Арифметические операторы аналогичны числовым вычислениям в математике, в основном включая

image-20210907222804980

Следует обратить внимание на арифметические операторы.优先级问题, когда в выражении несколько операторов, приоритет операций определяет порядок вычислений.Самое простое правило — сначала умножить и разделить, а затем сложить и вычесть.()Приоритет самый высокий, нет необходимости запоминать весь порядок приоритетов, вы можете использовать () напрямую, если вы не уверены.

  • операторы инкремента и декремента

Это не объяснить на словах, объяснение лучше увидеть на примере напрямую

int a = 5;
b = ++a;
c = a++;
  • оператор сравнения

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

Результатом оператора сравнения является логическое значение. Когда отношение, соответствующее оператору, установлено, результат операции истинен, в противном случае он ложен. Существует 6 операторов сравнения, которые обычно используются в условных операторах в качестве основы для суждения.

image-20210907222824045

  • Логические операторы

Есть три основных логических оператора: И, ИЛИ, НЕ

image-20210907222837435

Ниже приведена таблица истинных/ложных символов, соответствующих логическим операторам.

image-20210907222850103

  • побитовые операторы

Побитовые операторы используются для работы с каждым из типов целочисленных примитивов.比特Биты, то есть двоичные биты. Побитовые операторы выполняют булеву алгебру над соответствующими битами в двух аргументах и ​​выдают результат.

image-20210907222905936

Если обе стороны сравнения являются числами, сравнение становится побитовой операцией.

Побитовое И: операция И выполняется побитовое (И), результат равен 1, если оба операнда равны 1, иначе результат равен 0. Вам нужно сначала преобразовать обе стороны сравнения в двоичные файлы, а затем сравнить каждый бит

Побитовое ИЛИ: Выполните операцию побитового ИЛИ (ИЛИ), пока один из двух битов равен 1, результат равен 1, в противном случае он равен 0.

Побитовое XOR: побитовая операция исключающее ИЛИ (XOR), если бит равен 0, результат равен 1, если бит равен 1, результат равен 0.

Побитовое НЕ: выполнить побитовое отрицание (НЕ), если биты двух операндов одинаковы, результат равен 0, а если они разные, результат равен 1.

  • оператор смены

Оператор сдвига используется для сдвига операнда в определенном направлении (влево или вправо) на указанное количество битов.

image-20210907222926218

  • Тернарный оператор

Тернарный оператор что-то вродеif...else...Этот оператор, синтаксис:Условное выражение? Выражение 1: Выражение 2. Позиция перед знаком вопроса является условием решения.Результат решения является логическим.Когда оно истинно, вызывается выражение 1, а когда ложно, вызывается выражение 2.

Java выполняет поток управления

Поток управления в Java фактически такой же, как и в C. В Java управление потоком включает в себя включениеесли-иначе, пока, делать-пока, для, вернуться, сломатьи выберите заявлениеswitch. Это проанализировано ниже.

Условные операторы

Условные операторы могут выполнять разные операторы на основе разных условий. Включая условные операторы if и операторы switch с несколькими ветвями.

если условное выражение

Оператор if может самостоятельно судить о результате выражения, указывая результат выполнения выражения, например:

int a = 10;
if(a > 10){
  return true;
}
return false;

if...else условное выражение

Оператор if также может использоваться в сочетании с оператором else, как правило, какЕсли выполняется определенное условие, выполните один вид обработки, в противном случае выполните другой вид обработки..

int a = 10;
int b = 11;
if(a >= b){
  System.out.println("a >= b");
}else{
  System.out.println("a < b");
}

Выражение внутри () после if должно быть логического типа. Если true, то выполнить составной оператор после if, если false, выполнить составной оператор после else.

if...else if многоветвевой оператор

Вышеупомянутое определяется, если ... еще одна ветвь и две ветви, если есть множество условий определения, необходимо использоватьif...else if.

int x = 40;
if(x > 60) {
  System.out.println("x的值大于60");
} else if (x > 30) {
  System.out.println("x的值大于30但小于60");
} else if (x > 0) {
  System.out.println("x的值大于0但小于30");
} else {
  System.out.println("x的值小于等于0");
}

оператор switch case с несколькими ветвями

Более элегантный способ, чем оператор **if...else if **, заключается в использованииswitchОператор с несколькими ответвлениями, пример которого выглядит следующим образом:

switch (week) {
  case 1:
    System.out.println("Monday");
    break;
  case 2:
    System.out.println("Tuesday");
    break;
  case 3:
    System.out.println("Wednesday");
    break;
  case 4:
    System.out.println("Thursday");
    break;
  case 5:
    System.out.println("Friday");
    break;
  case 6:
    System.out.println("Saturday");
    break;
  case 7:
    System.out.println("Sunday");
    break;
  default:
    System.out.println("No Else");
    break;
}

оператор цикла

Оператор цикла предназначен для многократного выполнения операции выражения при определенных условиях до тех пор, пока не будут выполнены требования оператора цикла. Используемые операторы цикла в основном включают **for, do...while(), а **.

оператор цикла

Оператор цикла while зацикливается, используя условие для управления повторным выполнением оператора. Формат оператора цикла while следующий:

while(布尔值){
  表达式
}

Это означает, что когда (логическое значение) истинно, выполняется следующее выражение, а когда логическое значение ложно, цикл завершается. Логическое значение на самом деле является выражением, например:

int a = 10;
while(a > 5){
  a--;
}

сделать... в то время как цикл

Единственная разница между циклом while и циклом do...while состоит в том, что оператор do...while выполняется хотя бы один раз, даже если в первый раз выражение ложно. В цикле while, если в первый раз условие ложно, то оператор в нем вообще не будет выполняться. На практике while используется более широко, чем do...while. Его общая форма выглядит следующим образом:

int b = 10;
// do···while循环语句
do {
  System.out.println("b == " + b);
  b--;
} while(b == 1);

оператор цикла for

Цикл for — это форма цикла, которую мы часто используем, эта форма будет инициализирована перед первой итерацией. Он имеет следующий вид:

for(初始化; 布尔表达式; 步进){}

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

оператор запятой

Одна вещь, которую нельзя здесь игнорировать, — это оператор запятой.Единственное, что использует оператор запятой в Java, — это оператор управления циклом for. В инициализирующей части выражения можно использовать ряд операторов, разделенных запятыми; с помощью оператора запятая можно определить несколько переменных в операторе for, но они должны иметь один и тот же тип.

for(int i = 1,j = i + 10;i < 5;i++, j = j * 2){}

для каждого оператора

В Java JDK 1.5 также представлен более лаконичный и удобный метод обхода массивов и коллекций, а именноfor-eachпредложения, например:

int array[] = {7, 8, 9};

for (int arr : array) {
     System.out.println(arr);
}

оператор перехода

В языке Java есть три оператора перехода:перерыв, продолжение и возврат.

оператор перерыва

Мы видели оператор break в операторе switch, который используется для завершения цикла, фактически, оператор break используется в операторах цикла for, while, do...while для принудительного выхода из текущего цикла, например:

for(int i = 0;i < 10;i++){
	if(i == 5){
    break;
  }
}

продолжить заявление

continue также может быть помещен в оператор цикла, который имеет эффект, противоположный оператору break. Его функция заключается в выполнении следующего цикла вместо выхода из текущего цикла. В основном используется приведенный выше пример:

for(int i = 0;i < 10;i++){
  
  System.out.printl(" i = " + i );
	if(i == 5){
    System.out.printl("continue ... ");
    continue;
  }
}

оператор возврата

Оператор return возвращает управление из метода и передает управление вызвавшему его оператору.

public void getName() {
    return name;
}

объектно-ориентированный

Объектно-ориентированный — очень важная идея разработки для изучения Java, но объектно-ориентированный — не уникальная идея Java, так что не запутайтесь.

Теперь давайте обсудим идею объектно-ориентированного, идея объектно-ориентированного постепенно вытеснила идею процедурного --- процессно-ориентированного, Java - это объектно-ориентированный язык программирования высокого уровня, объектно-ориентированный. ориентированный язык имеет следующие характеристики

  • Объектно-ориентированный — это распространенное мнение, которое больше соответствует привычкам мышления людей;

  • Объектно-ориентированный подход может упростить сложную бизнес-логику и улучшить повторное использование кода;

  • Объектно-ориентированный имеет характеристики абстракции, инкапсуляции, наследования, полиморфизма и так далее.

К объектно-ориентированным языкам программирования в основном относятся: C++, Java, C# и др.

Следовательно, вы должны быть знакомы с объектно-ориентированным мышлением, чтобы писать программы на Java.

Класс также является объектом

Теперь давайте познакомимся с новой концепцией объектно-ориентированного --- класса, что такое класс, он эквивалентен абстракции ряда объектов, точно так же, как книга, класс эквивалентен обложке книги, большинство объектно-ориентированных языков используютclassЧтобы определить класс, он сообщает вам, на что похожи объекты, определенные в нем, мы обычно используем следующее для определения класса

class ClassName {
	// body;
}

Во фрагменте кода задействована новая концепция//, о чем мы поговорим позже. Выше вы объявили класс class, теперь вы можете использовать new для создания этого объекта

ClassName classname = new ClassName();

В общем случае именование классов следует驼峰原则, который определяется следующим образом:

Camel-Case, также известный как CamelCase, представляет собой набор правил (соглашений) именования, используемых при написании компьютерных программ. Как видно из его названия, CamelCase относится к использованию комбинации прописных и строчных букв для формирования имен переменных и функций. Чтобы программистам было проще общаться со своими коллегами, программисты применяют унифицированный метод именования с лучшей читабельностью.

создание объекта

В Яве,все является объектом. Я полагаю, что вы знакомы с этим предложением.Хотя все рассматривается как объект, то, чем вы манипулируете, является объектом.引用(reference). Здесь есть очень яркая аналогия: вы можете думать о ключах от машины и о машине как о группе.Ссылки на объекты и объектыКомбинация. Если вы хотите сесть за руль, вам сначала нужно вынуть ключ от машины и нажать кнопку разблокировки.При парковке вам нужно нажать кнопку блокировки, чтобы запереть машину. Ключ от машины эквивалентен ссылке, автомобиль является объектом, а ключ от машины используется для управления запиранием и отпиранием автомобиля. И даже без существования автомобиля ключ от автомобиля является независимой сущностью, т. е.у вас есть ссылка на объект, но вам не обязательно нужен объект, связанный с ним, это,

Car carKey;

Здесь только ссылка, но не объекты, но если вы хотите использовать S., вы вернете исключение, говорящее вам, что объект необходим для связи с этой ссылкой. Безопасный подход состоит в том, чтобы присвоить ему объект при создании ссылки на объект.

Car carKey = new Car();

В Java, как только вы создаете ссылку, вы хотите, чтобы он был связан с новым объектом, обычно использующимnewоператора для достижения этой цели. новые средства, дай мне новый对象, если вы не хотите свидания вслепую, просто создайте объект самостоятельно. Желаю счастья в следующей жизни.

свойства и методы

Одним из самых основных элементов класса является то, что он имеет свойства и методы.

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

class A{
  int a;
  Apple apple;
}

Класс также должен включать методы, представляющиеспособ сделать что-то. Методы на самом деле являются функциями, но Java привыкла вызывать методы функций. Это название также отражает концепцию объектно-ориентированного.

К основным компонентам метода относятсяИмя метода, параметры, возвращаемое значение и тело метода, вот пример этого:

public int getResult(){
  // ...
  return 1;
}

в,getResultимя метода,()Он представляет параметры, полученные методом,returnПредставляет возвращаемое значение метода. Существует специальный тип параметра ---voidУказывает, что метод не имеет возвращаемого значения.{}Содержащийся сегмент кода называется телом метода.

Метод строительства

В Java есть специальный метод, называемый构造方法, также известные как конструкторы, конструкторы и т. д. В Java этот конструктор обеспечивает инициализацию каждого объекта. Конструктор может быть вызван только один раз во время создания объекта, что обеспечивает инициализацию объекта. Метод конструктора особенный. У него нет типа параметра и возвращаемого значения. Его имя должно совпадать с именем класса, а конструкторов может быть несколько. Ниже приведен пример конструктора:

class Apple {
  
  int sum;
  String color;
  
  public Apple(){}
  public Apple(int sum){}
  public Apple(String color){}
  public Apple(int sum,String color){}
  
}

Класс Apple определен выше. Вы обнаружите, что этот класс Apple не имеет типа параметра и возвращаемого значения и имеет несколько методов с тем же именем, что и Apple, и список параметров каждого Apple отличается. На самом деле это проявление полиморфизма. Мы поговорим об этом позже. После определения конструктора мы можем создать объект Apple.

class createApple {

    public static void main(String[] args) {
        Apple apple1 = new Apple();
        Apple apple2 = new Apple(1);
        Apple apple3 = new Apple("red");
        Apple apple4 = new Apple(2,"color");

    }
}

Как показано выше, мы определили четыре объекта Apple и вызвали четыре разных конструктора Apple, Среди них конструктор без каких-либо параметров называется конструктором по умолчанию, который

Apple apple1 = new Apple();

Если в классе не определен конструктор, JVM автоматически сгенерирует для вас конструктор следующим образом:

class Apple {    int sum;  String color;  }class createApple {    public static void main(String[] args) {        Apple apple1 = new Apple();    }}

Приведенный выше код не будет компилировать ошибки, поскольку объект Apple содержит конструктор по умолчанию.

Конструктор по умолчанию также известен как конструктор по умолчанию или конструктор без аргументов.

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

image-20210907222946943

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

перегрузка метода

Очень важной концепцией в Java является перегрузка методов, которая представляет собой другое представление имени класса. Мы упомянули конструктор выше, но конструктор также является своего рода перегрузкой. Другой - перегрузка метода

public class Apple {    int sum;    String color;    public Apple(){}    public Apple(int sum){}        public int getApple(int num){        return 1;    }        public String getApple(String color){        return "color";    }}

Как показано выше, существует два метода перегрузки: один — это перегрузка конструктора Apple, а другой — перегрузка метода getApple.

Но это связано с проблемой: если их несколько с одинаковым именем, как Java узнает, какой метод вы вызываете? Только помни здесь одну вещь,Каждый перегруженный метод имеет уникальный список параметров.. К ним относятся тип, порядок, количество параметров и т. д. Удовлетворение одному фактору является необходимым условием для перегрузки.

Помните приведенное ниже состояние перегрузки

  • Имена методов должны быть одинаковыми.

  • Списки параметров должны быть разными (разное количество, разные типы, разный порядок типов параметров и т. д.).

  • Типы возвращаемых данных методов могут совпадать, а могут и не совпадать.

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

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

переопределение метода

Переопределение и перегрузка методов имеют похожие названия, но это совершенно разные вещи. Описание переопределения метода верно子类和父类между. И перегрузка относится к тому же классу. Например следующий код

class Fruit { 	public void eat(){    System.out.printl('eat fruit');  }}class Apple extends Fruit{    @Override  public void eat(){    System.out.printl('eat apple');  }}

Приведенный выше код описывает переписанный код.Вы можете видеть, что метод в подклассе Apple имеет то же имя, что и метод в родительском классе Fruit, поэтому мы можем вывести принцип перезаписи

  • Переопределенный метод должен быть совместим с родительским классом, включаятип возвращаемого значения, имя метода, список параметровТо же самое.
  • Можно использовать переопределенные методы@OverrideАннотация для идентификации
  • Права доступа переопределенного метода в подклассе не могут быть ниже прав доступа метода в суперклассе.

инициализация

инициализация класса

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

class Car{  public Car(){}}

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

инициализация члена

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

  • Один из них — инициализация поля, заданная компилятором по умолчанию, инициализация базовых типов данных.

    image-20210907223003059

    Один из них — инициализация других типов объектов, String также является объектом, а начальное значение объекта равноnull, который также включает классы-оболочки для примитивных типов.

  • Один из них - инициализировать указанное значение, например:

int a = 11

То есть указать, что значение инициализации a равно не 0, а 11. То же самое относится и к другим примитивным типам и типам объектов.

Инициализация конструктора

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

public class Counter{
  int i;
  public Counter(){
    i = 11;
  }
}

С помощью конструктора значение i можно инициализировать равным 11.

порядок инициализации

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

  • Статические свойства: свойства, определенные в начале статического

  • Блок статического метода: блок кода, заключенный в статический {}

  • Обычные свойства: свойства, которые не определены статически

  • Обычный блок метода: {} обернутый блок кода

  • Конструктор: метод с тем же именем класса

  • метод: обычный метод

public class LifeCycle {
    // 静态属性
    private static String staticField = getStaticField();
    // 静态方法块
    static {
        System.out.println(staticField);
        System.out.println("静态方法块初始化");
    }
    // 普通属性
    private String field = getField();
    // 普通方法块
    {
        System.out.println(field);
    }
    // 构造函数
    public LifeCycle() {
        System.out.println("构造函数初始化");
    }

    public static String getStaticField() {
        String statiFiled = "Static Field Initial";
        return statiFiled;
    }

    public static String getField() {
        String filed = "Field Initial";
        return filed;
    }   
    // 主函数
    public static void main(String[] argc) {
        new LifeCycle();
    }
}

Результат выполнения этого кода отражает порядок его инициализации.

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

инициализация массива

Массив — это последовательность объектов или примитивных данных одного типа, инкапсулированных вместе с именем идентификатора. Доступ к массивам осуществляется с помощью оператора нижнего индекса в квадратных скобках.[]для определения использования.

Общий массив определяется следующим образом

int[] a1;

//或者

int a1[];

Смысл обоих форматов одинаков.

  • Назначьте каждый элемент напрямую: int array[4] = {1,2,3,4};
  • Присвойте значение части, все следующие равны 0 : int array[4] = {1,2};
  • Количество массивов определяется количеством параметров присваивания: int array[] = {1,2};

список переменных параметров

Непопулярное использование массивов в Java可变参数, переменные параметры определяются следующим образом

public int add(int... numbers){
  int sum = 0;
  for(int num : numbers){
    sum += num;
  }
  return sum;
}

Затем вы можете использовать следующие методы для выполнения вызовов с переменным числом аргументов.

add();  // 不传参数
add(1);  // 传递一个参数
add(2,1);  // 传递多个参数
add(new int[] {1, 3, 2});  // 传递数组

разрушение объектов

Хотя язык Java основан на C++, важной особенностью его и C/C++ является то, что нет необходимости вручную управлять уничтожением объектов. В известной книге "Глубокое понимание виртуальной машины Java" упоминается пункт

image-20210907223020842

В Java нам больше не нужно вручную управлять уничтожением объектов, оно управляется и уничтожается виртуальной машиной Java (JVM). Хотя нам не нужно управлять объектами вручную, вам нужно знать对象作用域это понятие.

сфера действия объекта

Многие языки имеют作用域(scope)это понятие. Область определяет видимость и время жизни имен переменных, определенных в ней. В C, C++ и Java область обычно определяется{}позиция для принятия решения, что также мы часто говорим代码块. Например:

{  int a = 11;  {    int b = 12;  }}

переменная будет в двух{}Область допустима, в то время как значение переменной b может быть только в ее собственном{}действует в течение.

Хоть и есть сфера, писать не разрешено

{
  int x = 11;
  {
    int x = 12;
  }
}

Такой способ написания допустим в C/C++, но не разрешен в Java, потому что разработчики Java считают, что это приведет к путанице в программе.

###это и супер

все это и ключевые слова super Java.

Текущий объект, представленный this, который может вызывать методы, вызывать свойства и указывать на сам объект. Обычно в Java это используется тремя способами: указание на текущий объект

public class Apple {

    int i = 0;

    Apple eatApple(){
        i++;
        return this;
    }

    public static void main(String[] args) {
        Apple apple = new Apple();
        apple.eatApple().eatApple();
    }
}

Этот код более тонкий, где тонкость? Мой метод eatApple() можно вызывать несколько раз, и вы можете продолжать вызывать его позже, что удивительно, почему? На самом деле это то, что на работе, яeatApple метод добавилreturn thisВозвращаемое значение , то есть любой объект, вызывающий метод eatApple, может вернуть сам объект.

это также может изменять свойства, чаще всего это используется в конструкторах, как показано ниже.

public class Apple {

    private int num;
    
    public Apple(int num){
        this.num = num;
    }

    public static void main(String[] args) {
        new Apple(10);
    }
}

В метод main передается параметр со значением int 10, который представляет количество яблок, и присваивает это число глобальной переменной num. Таким образом, значение num теперь равно 10.

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

public class Apple {

    private int num;
    private String color;

    public Apple(int num){
        this(num,"红色");
    }
    
    public Apple(String color){
        this(1,color);
    }

    public Apple(int num, String color) {
        this.num = num;
        this.color = color;
    }
    
}

Вы обнаружите, что приведенный выше код не использует это, аthis(参数). Это эквивалентно вызову других конструкторов и передаче параметров. Обратите внимание: this() необходимо поместить в первую строку конструктора, иначе компиляция завершится ошибкой.

image-20210907223035882

Если вы понимаете это как ссылку на самого себя, то super — это ссылка на суперкласс. Ключевое слово super такое же, как это, вы можете использоватьsuper.对象для обращения к членам родительского класса следующим образом:

public class Fruit {

    int num;
    String color;

    public void eat(){
        System.out.println("eat Fruit");
    }
}

public class Apple extends Fruit{

    @Override
    public void eat() {
        super.num = 10;
        System.out.println("eat " + num + " Apple");
    }

}

вы также можете использоватьsuper(参数)для вызова конструктора родительского класса, здесь больше нет примеров.

Ниже приводится сводка сравнения ключевого слова this и ключевого слова super.

image-20210907223047478

разрешения на управление доступом

разрешения на управление доступом封装, это одна из трех основных характеристик объектно-ориентированного.Я часто игнорировал инкапсуляцию в процессе обучения раньше, думая, что это не модификатор доступа, почему это необходимое условие для трех характеристик? Позже я узнал,Если подчиненный, которому вы доверяете, скрывает от вас ошибку, вы даже не знаете об этом.

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

В Java существует четыре типа разрешений доступа для членов, а именно:публичный, защищенный, по умолчанию, частный, их видимость следующая

image-20210907223100206

наследовать

Наследство это всеOOP(Object Oriented Programming)язык и язык Java являются неотъемлемыми частями. Пока мы создаем класс, он неявно наследуется отObjectРодительский класс, но не указан. Если вы явно указываете родительский класс, то вы наследуете от родительского класса, а ваш родительский класс наследуется от класса Object.

image-20210908223815666

Унаследованное ключевое словоextends, как показано на рисунке выше, если вы используете extends, чтобы показать, что указано наследование, то мы можем сказать, что Отец — это родительский класс, а Сын — подкласс, что выражается в коде следующим образом

class Father{}class Son extends Father{}

Наследование обеих сторон имеет некоторые общие характеристики

class Father{    public void feature(){    System.out.println("父亲的特征");  }}class Son extends Father {}

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

полиморфизм

Полиморфизм означает, что одно и то же поведение имеет несколько различных проявлений. Это означает, что один и тот же метод экземпляра класса (объекта) имеет разные проявления в разных ситуациях. Инкапсуляция и наследование — основа полиморфизма, то есть полиморфизм — это всего лишь форма выражения.

Как добиться полиморфизма? Реализация полиморфизма имеет три необходимых и достаточных условия

  • наследовать
  • Переопределить метод родительского класса
  • Ссылка родительского класса указывает на объект дочернего класса

Например следующий код

public class Fruit {

    int num;

    public void eat(){
        System.out.println("eat Fruit");
    }
}

public class Apple extends Fruit{

    @Override
    public void eat() {
        super.num = 10;
        System.out.println("eat " + num + " Apple");
    }

    public static void main(String[] args) {
        Fruit fruit = new Apple();
        fruit.eat();
    }
}

ты можешь найтиmainВ методе есть очень волшебное место,Fruit fruit = new Apple(), объект типа Fruit на самом деле указывает на ссылку объекта Apple, которая на самом деле является полиморфизмом -> ссылка родительского класса указывает на объект подкласса, потому что Apple наследует от Fruit и переписывает метод eat, поэтому он может отображать форму различные состояния.

комбинация

Композицию на самом деле понять не сложно, это поместить ссылки на объекты в новый класс. Композиция — это также способ улучшить возможность повторного использования классов. Если вы хотите, чтобы ваш класс имел более расширенную функциональность, вам нужно запомнить предложениеБольше композиции, меньше наследования.

public class SoccerPlayer {
    
    private String name;
    private Soccer soccer;
    
}

public class Soccer {
    
    private String soccerName;    
}

В коде SoccerPlayer ссылается на класс Soccer, а посредством ссылки на класс Soccer вызываются свойства и методы в футболе.

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

image-20210907223116239

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

играет роль

Помимо наследования и композиции, стоит изучить еще одну реляционную модель, которая называется代理. Общее описание прокси состоит в том, что A хочет вызвать метод класса B, но A не вызывает его напрямую.A создаст прокси объекта B в своем собственном классе, а затем прокси вызовет метод B . Например следующий код:

public class Destination {

    public void todo(){
        System.out.println("control...");
    }
}

public class Device {

    private String name;
    private Destination destination;
    private DeviceController deviceController;

    public void control(Destination destination){
        destination.todo();
    }

}

public class DeviceController {

    private Device name;
    private Destination destination;

    public void control(Destination destination){
        destination.todo();
    }
}

Статьи, посвященные более глубокому пониманию агентов, см.

Динамические прокси — это так просто!

Глубокое понимание агентства

Трансформация вверх

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

  • 向上转型: преобразование объекта подкласса (маленький диапазон) в объект родительского класса (большой диапазон), это преобразование выполняется автоматически, принудительно не требуется.
  • 向下转型: экземпляр объекта подкласса (маленький диапазон) через объект родительского класса (большой диапазон), это преобразование не выполняется автоматически и должно быть указано.

static

static — это ключевое слово в Java, оно означает静态的, static можно использовать для изменения переменных-членов и методов, а static используется для вызова методов/переменных без создания объекта.

  • Переменная-член, объявленная с помощью static, является статической переменной-членом, а также становится переменной класса. Переменные класса имеют тот же жизненный цикл, что и классы, и действуют на протяжении всего выполнения приложения.
static String name = "cxuan";
  • Метод, дополненный static, называется статическим методом, и статический метод можно использовать напрямую.имя класса.имя методапозвонить. Поскольку к статическим методам можно обращаться напрямую, не полагаясь на какой-либо объект, для статических методов ключевое слово this отсутствует, а переменные экземпляра будут иметь это ключевое слово. Нестатические переменные-члены и нестатические методы класса не могут быть доступны в статических методах,
static void printMessage(){  System.out.println("cxuan is writing the article");}

Помимо изменения свойств и методов, статические静态代码块функция, которую можно использовать для операций инициализации класса. Это повышает производительность программы.

public class StaicBlock {    static{        System.out.println("I'm A static code block");    }}

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

Для более глубокого понимания использования ключевого слова static вы можете обратиться к этой статье автора.Может ли статика быть сложной для меня?Настоятельно рекомендуется прочитать ее после изучения основ Java.

final

final означает окончательный, окончательный, он может быть измененКлассы, свойства и методы.

  • Когда final украшает класс, это указывает, что класс не может быть унаследован. Переменные-члены в конечных классах можно сделать окончательными по мере необходимости, но следует отметить, что все методы-члены в конечных классах неявно обозначаются как окончательные методы.
class Parent {}
final class Person extends Parent{} //可以继承Parent类
class Child extends Person{} //不能继承Person类
  • При оформлении метода final это указывает, что метод не может быть переопределен ни одним подклассом, поэтому делайте метод final только в том случае, если вы хотите явно запретить переопределение метода в подклассах.
class Parent {
	// final修饰的方法,不可以被覆盖,但可以继承使用
    public final void method1(){}  //这个方法不可以重写
    public void method2(){}
}
class Child extends Parent {
	//可以重写method2方法
	public final void method2(){}
}
  • Окончательная измененная переменная разделена на два случая: один — изменить базовый тип данных, указав, что значение типа данных не может быть изменено; другой — изменить ссылочный тип, указав, что он не может указывать на другой тип данных. объект после его инициализации.
final int i = 20;
i = 30; //赋值报错,final修饰的变量只能赋值一次

В Java с final , finally и finalize и статьпоследние три брата. Для подробного использования этих трех ключевых слов вы можете обратиться к этой статье автора.Прочитав этот финал, напоследок и доработав, поспорить с интервьюером не проблема

Интерфейсы и абстрактные классы

интерфейс

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

В языке Java интерфейс определяетсяinterfaceКлючевое слово для обозначения, например, мы можем определить интерфейс следующим образом

public interface CxuanGoodJob {}

Например, мы определяем интерфейс CxuanGoodJob, а затем вы можете определить хорошие вещи, которые cxuan делает внутри него, например, статьи, написанные cxuan, хороши.

public interface CxuanGoodJob {

    void writeWell();
}

Здесь подразумеваются некоторые особенности интерфейса:

  • interfaceИнтерфейс — это полностью абстрактный класс, который не предоставляет никакой реализации методов, а только определяет методы.
  • В интерфейсе можно использовать только два модификатора доступа, одинpublic, который виден всему проекту;defaultПо умолчанию он имеет только пакетный доступ.
  • Интерфейс предоставляет только определение метода, интерфейс не имеет реализации, но интерфейс может быть реализован другими классами. То есть класс, реализующий интерфейс, должен обеспечивать реализацию метода, а реализация интерфейса используетimplementsКлючевое слово, чтобы указать, что интерфейс может иметь несколько реализаций.
class CXuanWriteWell implements CxuanGoodJob{

    @Override
    public void writeWell() {
        System.out.println("Cxuan write Java is vary well");
    }
}
  • Интерфейсы не могут быть созданы, поэтому в интерфейсах не может быть никаких конструкторов.Если вы определите конструктор, компиляция завершится ошибкой.
  • Реализация интерфейса такова, что реализует все методы интерфейса, в противном случае он должен быть определен как抽象类, что мы собираемся сказать дальше

абстрактный класс

Абстрактный класс — это класс, чьи возможности абстракции слабее, чем у интерфейса.В Java абстрактные классы используютabstractключевое слово для указания. Если интерфейс описывается как вид собаки, то можно сказать, что абстрактный класс является породой с белой шерстью и маленьким телом, а класс реализации может быть конкретным классом, таким как шпиц, тедди и т. д. Вы можете определить абстрактный класс, как показано ниже

public interface Dog {

    void FurColor();

}

abstract class WhiteDog implements Dog{

    public void FurColor(){
        System.out.println("Fur is white");
    }

    abstract void SmallBody();
}

В абстрактном классе он имеет следующие характеристики

  • Если у класса есть абстрактные методы, то класс должен быть абстрактным, то есть использовать ключевое словоabstractИзмененный метод должен быть абстрактным методом, а класс с абстрактным методом должен быть абстрактным классом. Реализация методов класса имеет только специфичные для метода реализации.

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

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

  • Абстрактные классы не могут быть созданы, как интерфейсы, экземпляры могут быть созданы только具体的类.

аномальный

Исключения распространены в программах, и лучше всего искать ошибки на этапе компиляции, прежде чем вы попытаетесь запустить программу. Однако не все ошибки можно найти при компиляции, есть некоторыеNullPointerExceptionиClassNotFoundExceptionИсключения не обнаруживаются во время компиляции, эти исключения являются исключениями времени выполнения RuntimeException, и эти исключения часто обнаруживаются во время выполнения.

При написании программ на Java у нас часто возникают две проблемы: одна — java.lang.Exception, а другая — java.lang.Error, обе из которых используются для указания на возникновение исключения Ниже приводится понимание этих двух концепций.

Распознать исключение

Exceptionродыjava.langpackage, это интерфейс верхнего уровня, который наследуется отThrowableКласс, класс исключения и его подклассы — все это составляющие условия Throwable, которые являются разумными ситуациями для появления программы.

Прежде чем знать Exception, необходимо понять, что такоеThrowable.

Что можно бросать

Класс Throwable - это все错误(errors)и异常(exceptions)родительский класс. Только классы, которые унаследованы от Throwable или его подклассов, могут быть выброшены, и есть другой способ с Java.@throwАннотированные классы также могут бросать.

существуетСпецификация Java, определения непроверенных исключений и проверенных исключений следующие:

The unchecked exception classes are the run-time exception classes and the error classes.

The checked exception classes are all exception classes other than the unchecked exception classes. That is, the checked exception classes are Throwable and all its subclasses other than RuntimeException and its subclasses and Errorand its subclasses.

То есть кромеRuntimeExceptionи его подклассы, иerrorи его подклассы, все остальные исключенияcheckedException.

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

image-20210907223136780

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

// 返回抛出异常的详细信息
public string getMessage();
public string getLocalizedMessage();

//返回异常发生时的简要描述
public public String toString();
  
// 打印异常信息到标准输出流上
public void printStackTrace();
public void printStackTrace(PrintStream s);
public void printStackTrace(PrintWriter s)

// 记录栈帧的的当前状态
public synchronized Throwable fillInStackTrace();

Кроме того, поскольку родительский класс Throwable такжеObject, поэтому часто используемые методы также наследуются от родительского класса.getClass()иgetName()метод.

Общее исключение

Вернемся к обсуждению Exception.Теперь вы знаете, что родительским классом Exception является Throwable, а у Exception есть два типа исключений:RuntimeException; одинCheckedException, оба исключения должны перейти к捕获.

Ниже приведен список некоторых распространенных исключений в Java и их классификация. Этот интервьюер также может попросить вас назвать несколько распространенных исключений и классифицировать их.

RuntimeException

image-20210907223603308

UncheckedException

image-20210907223632991

Ключевые слова Java, связанные с исключением

Так как же обрабатываются эти исключения в Java? В Java есть несколько ключевых словкидает, бросает, старается, наконец, ловитдавайте обсудим отдельно

бросает и бросает

В Java исключение — это объект, который может быть создан программистом или приложением.throwsиthrowоператор для определения генерации исключений.

броски и бросок обычно парные, например.

static void cacheException() throws Exception{  throw new Exception();}

Оператор throw используется в теле метода, чтобы указать, что создается исключение, которое обрабатывается оператором в теле метода. Оператор throws используется после объявления метода, чтобы указать, что исключение генерируется снова, которое обрабатывается вызывающей стороной метода.

throws в основном для того, чтобы объявить, что этот метод будет генерировать исключение этого типа, чтобы вызывающая сторона знала, что нужно перехватить это исключение. Throw — это действие по выбрасыванию исключения, поэтому оно создает экземпляр исключения.

попробуй, наконец, поймай

Эти три ключевых слова в основном имеют следующие комбинациипопробуй... поймай, попробуй... наконец, попробуй... поймай... наконец.

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

static void cacheException() throws Exception{

  try {
    System.out.println("1");
  }catch (Exception e){
    e.printStackTrace();
  }

}

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

static void cacheException() throws Exception{
  for (int i = 0; i < 5; i++) {
    System.out.println("enter: i=" + i);
    try {
      System.out.println("execute: i=" + i);
      continue;
    } finally {
      System.out.println("leave: i=" + i);
    }
  }
}

То же самое верно и для try...catch...finally, что означает, что после перехвата исключения следует логика кода в finally.

Что такое ошибка

Ошибки — это ошибки, которые программа не может обработать и которые представляют собой более серьезные проблемы в работе приложения. Большинство ошибок не имеют ничего общего с действиями автора кода, а представляют собой проблему с JVM (виртуальная машина Java) во время выполнения кода. Эти ошибки невозможно проверить, потому что они находятся вне возможностей контроля и обработки приложения, и большинство из них являются условиями, которые не разрешены во время работы программы, напримерOutOfMemoryErrorиStackOverflowErrorЕсть несколько ситуаций, в которых возникают исключения.Здесь нам нужно представить модель памяти Java JDK1.7.

image-20210907223649891

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

Что такое частный поток: это означает, что каждый поток не влияет друг на друга и независимо хранится в области памяти.

Если приложение выполняет метод Java, то этот счетчик записывает虚拟机字节码адрес инструкции; если выполнениеNativeметод, значение счетчика равно空(Undefined).

В дополнение к счетчику программ, другие области:方法区(Method Area),虚拟机栈(VM Stack),本地方法栈(Native Method Stack)и堆(Heap)В обеих областях может возникнуть ошибка OutOfMemoryError.

  • Стек виртуальной машины: если глубина стека, запрошенная потоком, больше, чем глубина, разрешенная стеком виртуальной машины, она появитсяStackOverflowErrorИсключение; если динамическое расширение виртуальной машины не может применяться для достаточного количества памяти, оно появитсяOutOfMemoryError.

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

  • Куча: куча Java может быть физически прерывистой и логически непрерывной, как и наше дисковое пространство.Если в куче нет памяти для завершения выделения экземпляра, и куча не может расширяться, будет выброшена ошибка OutOfMemoryError.

  • Область метода: если область метода не может удовлетворить требования к выделению памяти, будет выдано исключение OutOfMemoryError.

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

внутренний класс

Пока все, что мы знаем, это определение общего класса, то есть создание нового класса непосредственно в IDEA.

image-20210907223703017

После того, как новое создание будет завершено, у вас будет определение файла класса.Эта операция слишком проста, и она будет скучной через долгое время.Нам, молодым людям, нужно обновить способ написания модных и наглых.Ну, так как вы упомянули об этом, затем используйте内部类Ну, это полезный и раздражающий способ определения класса.Определение внутреннего класса очень простое:Вы можете поместить определение одного класса внутри другого класса, это внутренний класс.

Внутренние классы — очень полезная функция. Класс, определенный внутри класса, содержит ссылку на внешний класс, но невидим для других внешних классов.弗兰奇将军Точно так же Фрэнки может общаться с генералом Фрэнки, но враг снаружи не может напрямую атаковать тело Фрэнки.

image-20210907223713681

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

Как определить внутренние классы

Ниже приведен самый простой способ определить внутренний класс:

public class Parcel1 {
    public class Contents{
        private int value = 0;
    
        public int getValue(){
            return value;
        }
    }
}

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

Итак, как показано в приведенном выше коде, как программисты могут получить доступ к контенту в Contents?

public class Parcel1 {

    public class Contents{
        private int value = 0;

        public int getValue(){
            return value;
        }
    }

    public Contents contents(){
        return new Contents();
    }

    public static void main(String[] args) {
        Parcel1 p1 = new Parcel1();
        Parcel1.Contents pc1 = p1.contents();
        System.out.println(pc1.getValue());
    }
}

Как видно из приведенного выше кода, вы можете написать метод для доступа к содержимому, что эквивалентно указанию ссылки на содержимое, доступ к которому можно получить с помощьювнешний класс внутренний классЭто определение создает ссылку на внутренний класс, как показано Parcel1.Contents pc1 = p1.contents() , а pc1 содержит доступ к внутреннему классу Contents .

Теперь у меня есть вопрос, если метод содержимого в приведенном выше коде станет статическим методом, сможет ли pc1 получить к нему доступ?

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

ссылка на внешний класс

Видя это, вы до сих пор не понимаете, почему вы хотите писать код таким образом, как будто это просто для установки B? Или вы думаете, что переопределить класс очень хлопотно, поэтому вы можете просто определить внутренний класс напрямую.Похоже, мы не видели преимуществ такого способа определения внутренних классов. См. пример ниже

public class Parcel2 {

    private static int i = 11;

    public class Parcel2Inner {

        public Parcel2Inner(){
            i++;
        }

        public int getValue(){
            return i;
        }

    }

    public Parcel2Inner parcel2Inner(){
        return new Parcel2Inner();
    }

    public static void main(String[] args) {
        Parcel2 p2 = new Parcel2();
        for(int i = 0;i < 5;i++){
            p2.parcel2Inner();
        }
        System.out.println("p2.i = " + p2.i);
    }
}

Выход: 16

Когда вы создаете объект внутреннего класса, этот объект имеет некоторую связь с окружающими его объектами.Как показано в приведенном выше коде, внутренний класс Parcel2Inner может получить доступ к значению i в Parcel2, а также может получить доступ к этому значению для изменения.

Итак, вопрос в том, как создать объект внутреннего класса? Программист не может написать метод, который каждый раз возвращает объект внешнего класса, верно? См. код ниже:

public class Parcel3 {

    public class Contents {

        public Parcel3 dotThis(){
            return Parcel3.this;
        }

        public String toString(){
            return "Contents";
        }
    }

    public Parcel3 contents(){
        return new Contents().dotThis();
    }

    public String toString(){
        return "Parcel3";
    }

    public static void main(String[] args) {
        Parcel3 pc3 = new Parcel3();
        Contents c = pc3.new Contents();
        Parcel3 parcel3 = pc3.contents();
        System.out.println(pc3);
        System.out.println(c);
        System.out.println(parcel3);
    }
}

вывод: Посылка3 Содержание Посылка3

Как показано в приведенном выше коде, внутренний класс Contents определен в Parcel3, а во внутреннем классе определен метод dotThis(). Возвращаемым значением этого метода является объект внешнего класса. Существует метод content() во внешнем классе Этот метод возвращает ссылку на внешний класс.

Внутренние классы и повышение класса

Пока эта статья показала, что этот класс имеет права доступа к внутренним классам, так как же классы, не связанные с этим классом, имеют права доступа к таким внутренним классам? И какое отношение внутренний класс имеет к восходящему приведению?

public interface Animal {

    void eat();
}

public class Parcel4 {

    private class Dog implements Animal {

        @Override
        public void eat() {
            System.out.println("啃骨头");
        }
    }

    public Animal getDog(){
        return new Dog();
    }

    public static void main(String[] args) {
        Parcel4 p4 = new Parcel4();
        //Animal dog = p4.new Dog();
        Animal dog = p4.getDog();
        dog.eat();
    }
}

Результат: грызть кости

Каждый должен знать этот вывод.Собака изменяется с помощью private.Говорят, что любой класс, кроме этого класса, недоступен, так почему же к нему можно получить доступ? Подумайте об этом внимательно, поскольку Parcel4 является общедоступным, а Parcel4 может получить доступ к своему собственному внутреннему классу, тогда Animal также может получить доступ к внутреннему классу Parcel4, который является классом Dog, а класс Dog реализует интерфейс Animal, поэтому метод getDog() также возвращает значение. подкласс класса Animal, тем самым достигая цели преобразования вверх и делая код более красивым.

Классы, определенные в методах и внутри произвольных областей

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

Вы можете рассмотреть следующие несколько определений:

  1. Я хотел бы определить внутренний класс, который реализует интерфейс, который я определяю внутренними классами, чтобы вернуть ссылочный интерфейс
  2. Я хочу решить некую задачу, а этот класс не хочет, чтобы он был в открытом доступе, как следует из названия, он инкапсулирован и не используется другими.
  3. из-за лени...

Вот несколько способов определения внутренних классов:

  • Класс, определенный в методе (локальный внутренний класс)
  • Класс, определенный в области, которая находится внутри метода (внутренний класс-член).
  • Анонимный класс, реализующий интерфейс (анонимный внутренний класс)
  • Анонимный класс, который расширяет класс с помощью конструктора не по умолчанию.
  • Анонимный класс, выполняющий операции инициализации полей.
  • Анонимный класс, который реализует конструкцию путем инициализации экземпляра.
  • Класс, определенный внутри метода, также называется локальным внутренним классом.
public class Parcel5 {  private Destination destination(String s){    class PDestination implements Destination{      String label;      public PDestination(String whereTo){        label = whereTo;      }      @Override      public String readLabel() {        return label;      }    }    return new PDestination(s);  }  public static void main(String[] args) {    Parcel5 p5 = new Parcel5();    Destination destination = p5.destination("China");    System.out.println(destination.readLabel());  }}

Выход : Китай

Как показано в приведенном выше коде, когда вы пишете метод, вы можете вставить определение класса в метод, и все свойства во внутреннем классе классифицируются. Мне было очень любопытно, когда я писал этот код. Каков процесс выполнения? Отладчик ходит вокруг и обнаруживает, что при выполнении p5.destination("China") он сначала выполнит return new PDestination(s), а затем перейдет к операции инициализации PDestination, которая аналогична нашему внешнему методу инициализации класс такой же, за исключением того, что этот метод предоставляет запись для доступа к внутреннему классу.

Определение локального внутреннего класса не может иметь модификаторов доступа.

  • Класс, определенный в области, которая находится внутри метода
public class Parcel6 {
  // 吃椰子的方法
  private void eatCoconut(boolean flag){
    // 如果可以吃椰子的话
    if(flag){
      class Coconut {
        private String pipe;

        public Coconut(String pipe){
          this.pipe = pipe;
        }

        // 喝椰子汁的方法
        String drinkCoconutJuice(){
          System.out.println("喝椰子汁");
          return pipe;
        }
      }
      // 提供一个吸管,可以喝椰子汁
      Coconut coconut = new Coconut("用吸管喝");
      coconut.drinkCoconutJuice();
    }

    /**
             * 如果可以吃椰子的话,你才可以用吸管喝椰子汁
             * 如果不能接到喝椰子汁的指令的话,那么你就不能喝椰子汁
             */
    // Coconut coconut = new Coconut("用吸管喝");
    // coconut.drinkCoconutJuice();
  }

  public static void main(String[] args) {
    Parcel6 p6 = new Parcel6();
    p6.eatCoconut(true);
  }
}

Выход: пить кокосовую воду.

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

  • Класс, реализующий анонимный интерфейс

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

public interface Contents {

    int getValue();
}

public class Parcel7 {

    private Contents contents(){
        return new Contents() {

            private int value = 11;

            @Override
            public int getValue() {
                return value;
            }
        };
    }

    public static void main(String[] args) {
        Parcel7 p7 = new Parcel7();
        System.out.println(p7.contents().getValue());
    }
}

Выход: 11

Почему можно вернуть определение интерфейса? И есть {}, что это за чертовщина? На самом деле это способ написания анонимного внутреннего класса, который похож на внутренний класс и преобразование, упомянутые выше. Другими словами, новый Contents(), возвращаемый анонимным внутренним классом, на самом деле является классом реализации Contents, но имя класса реализации скрыто и может быть преобразовано с помощью следующего примера кода:

public class Parcel7b {

    private class MyContents implements Contents {

        private int value = 11;

        @Override
        public int getValue() {
            return 11;
        }
    }

    public Contents contents(){
        return new MyContents();
    }

    public static void main(String[] args) {
        Parcel7b parcel7b = new Parcel7b();
        System.out.println(parcel7b.contents().getValue());
    }
}

Вы должны знать результат вывода~! Считаете ли вы, что этот код соответствует коду, представленному в Разделе 10.3?

  • Анонимный класс, который расширяет класс с помощью конструктора не по умолчанию.

Если вы хотите вернуть конструктор с параметрами (конструктор не по умолчанию), как вы его представляете?

public class WithArgsConstructor {

    private int sum;

    public WithArgsConstructor(int sum){
        this.sum = sum;
    }

    public int sumAll(){
        return sum;
    }
}

public class Parcel8 {

    private WithArgsConstructor withArgsConstructor(int x){

        // 返回WithArgsConstructor带参数的构造器,执行字段初始化
        return new WithArgsConstructor(x){

            // 重写sumAll方法,实现子类的执行逻辑
            @Override
            public int sumAll(){
                return super.sumAll() * 2;
            }
        };
    }

    public static void main(String[] args) {
        Parcel8 p8 = new Parcel8();
        System.out.println(p8.withArgsConstructor(10).sumAll());
    }
}

Код в приведенном выше WithArgsConstructor очень прост, поле суммы определено, конструктор инициализирован, метод sumAll возвращает значение суммы, а метод withArgsConstructor в Parcel8 напрямую возвращает значение x, но на данный момент вы хотите сделать что-то особенное в возвращаемом значении. Например, вы хотите определить класс и переопределить метод sumAll для реализации бизнес-логики подкласса. Java Programming Thought на странице 198 говорит, что ";" в коде означает не конец внутреннего класса, а конец выражения, но выражение содержит анонимный внутренний класс.

  • Анонимный класс, способный выполнять инициализацию поля

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

public class Parcel9 {

    private Destination destination(String dest){
        return new Destination() {

            // 初始化赋值操作
            private String label = dest;

            @Override
            public String readLabel() {
                return label;
            }
        };
    }

    public static void main(String[] args) {
        Parcel9 p9 = new Parcel9();
        System.out.println(p9.destination("pen").readLabel());
    }
}

Идеи программирования Java P198 говорит, что если поле инициализируется, то форма должна быть окончательной. Если это не окончательно, компилятор сообщит об ошибке, эта часть отображается вопросом, потому что я не определен для финала, компилятор имеет не сообщается об ошибке. Я считал, является ли она частной проблемой, когда я меняю частные для публики, проблем нет.

Я не знаю, то ли проблема с переводом автором китайской версии, то ли проблема устранена после стольких обновлений версии Java, я не проверял, как была написана оригинальная версия.

  • Анонимный класс, который реализует конструкцию путем инициализации экземпляра.
public abstract class Base {

    public Base(int i){
        System.out.println("Base Constructor = " + i);
    }

    abstract void f();
}

public class AnonymousConstructor {

    private static Base getBase(int i){

        return new Base(i){
            {
                System.out.println("Base Initialization" + i);
            }

            @Override
            public void f(){
                System.out.println("AnonymousConstructor.f()方法被调用了");
            }
        };
    }

    public static void main(String[] args) {
        Base base = getBase(57);
        base.f();
    }
}

вывод: Базовый конструктор = 57 Базовая инициализация 57 Вызывается метод AnonymousConstructor.f()

Этот код и «анонимный класс, который расширяет класс с помощью конструктора не по умолчанию» принадлежат к одной категории, и оба реализуют процесс инициализации через конструктор.

вложенный класс

Выше мы ввели 6 способов определения внутренних классов.Теперь давайте решим вопрос, который был поднят в начале, почему методcontents() становится статическим и вызывает ошибки компиляции:

На странице мыслей по программированию на Java p201 сказано: Если вам не нужны отношения между внутренним классом и окружающими его классами, объявите внутренний класс статическим. Это обычно называется вложенным классом, что означает, что внутренний класс вложенного класса не будет иметь какой-либо связи с окружающим его классом раньше, то есть, хотя внутренний класс определен во внешнем классе, он действительно может существовать независимо . Вложенные классы также известны как статические внутренние классы.

Статический внутренний класс означает:

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

см. код ниже

public class Parcel10 {

    private int value = 11;

    static int bValue = 12;

    // 静态内部类
    private static class PContents implements Contents {

        // 编译报错,静态内部类PContents中没有叫value的字段
        @Override
        public int getValue() {
            return value;
        }

        // 编译不报错,静态内部类PContents可以访问静态属性bValue
        public int f(){
            return bValue;
        }
    }

    // 普通内部类
    private class PDestination implements Destination {

        @Override
        public String readLabel() {
            return "label";
        }
    }

    // 编译不报错,因为静态方法可以访问静态内部类
    public static Contents contents(){
        return new PContents();
    }

    // 编译报错,因为非静态方法不能访问静态内部类
    public Contents contents2(){
        Parcel10 p10 = new Parcel10();
        return p10.new PContents();
    }

    // 编译不报错,静态方法可以访问非静态内部类
    public static Destination destination(){
        Parcel10 p10 = new Parcel10();
        return p10.new PDestination();
    }

    // 编译不报错,非静态方法可以访问非静态内部类
    public Destination destination2(){
        return new PDestination();
    }
}

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

класс внутри интерфейса

Нани? Внутри интерфейса могут быть определены только методы.Можно ли разместить класс внутри интерфейса? Может!

Обычно вы не можете поместить какой-либо код внутрь интерфейса, но поскольку вложенный класс является частью интерфейса, любой класс, который вы помещаете в интерфейс, по умолчанию является общедоступным и статическим. Так как класс статический, то он просто помещает вложенный класс в пространство имён интерфейса, что не нарушает правил интерфейса.Можно даже реализовать интерфейс внешнего класса во внутреннем классе, но вообще мы не рекомендуем писать так.

public interface InnerInterface {

    void f();

    class InnerClass implements InnerInterface {

        @Override
        public void f() {
            System.out.println("实现了接口的方法");
        }

        public static void main(String[] args) {
            new InnerClass().f();
        }
    }

    // 不能在接口中使用main方法,你必须把它定义在接口的内部类中
//    public static void main(String[] args) {}
}

Вывод: Методы интерфейса реализованы

Внутренние классы реализуют множественное наследование

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

Обратитесь к статье chenssyБлог Woohoo.cn on.com/Chen's College/Afraid/3…Это было написано очень хорошо.

public class Food {

    private class InnerFruit implements Fruit{
        void meakFruit(){
            System.out.println("种一个水果");
        }
    }

    private class InnerMeat implements Meat{
        void makeMeat(){
            System.out.println("煮一块肉");
        }
    }

    public Fruit fruit(){
        return new InnerFruit();
    }

    public Meat meat(){
        return new InnerMeat();
    }

    public static void main(String[] args) {
        Food food = new Food();
        InnerFruit innerFruit = (InnerFruit)food.fruit();
        innerFruit.meakFruit();
        InnerMeat innerMeat = (InnerMeat) food.meat();
        innerMeat.makeMeat();
    }
}

вывод: посадить плод приготовить кусок мяса

Наследование внутренних классов

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

public class BaseClass {

    class BaseInnerClass {

        public void f(){
            System.out.println("BaseInnerClass.f()");
        }
    }

    private void g(){
        System.out.println("BaseClass.g()");
    }
}
/**
 *  可以看到,InheritInner只是继承自内部类BaseInnerClass,而不是外围类
 *  但是默认的构造方式会报编译错误,
 *  必须使用类似enclosingClassReference.super()才能编译通过
 *  用来来说明内部类与外部类对象引用之间的关联。
 *
 */
public class InheritInner extends BaseClass.BaseInnerClass{

    // 编译出错
//    public InheritInner(){}

    public InheritInner(BaseClass bc){
        bc.super();
    }

    @Override
    public void f() {
        System.out.println("InheritInner.f()");
    }

    /*
    * 加上@Override 会报错,因为BaseInnerClass 中没有g()方法
    * 这也是为什么覆写一定要加上Override注解的原因,否则默认是本类
    * 中持有的方法,会造成误解,程序员以为g()方法是重写过后的。
    @Override
    public void g(){
        System.out.println("InheritInner.g()");
    }*/

    public static void main(String[] args) {
        BaseClass baseClass = new BaseClass();
        InheritInner inheritInner = new InheritInner(baseClass);
        inheritInner.f();
    }
}

Выход: InheritInner.f()

Переопределение внутреннего класса

Что касается покрытия внутренних классов, давайте сначала рассмотрим фрагмент кода:

public class Man {

    private ManWithKnowledge man;

    protected class ManWithKnowledge {

        public void haveKnowledge(){
            System.out.println("当今社会是需要知识的");
        }
    }

    // 我们想让它输出子类的haveKnowledge()方法
    public Man(){
        System.out.println("当我们有了一个孩子,我们更希望他可以当一个科学家,而不是网红");
        new ManWithKnowledge().haveKnowledge();
    }
}

// 网红
public class InternetCelebrity extends Man {

    protected class ManWithKnowledge {

        public void haveKnowledge(){
            System.out.println("网红是当今社会的一种病态");
        }
    }

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

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

Наш внутренний класс по умолчанию можно переопределить. Итак, мы хотим, чтобы он вывел InternetCelebrity.haveKnowledge() , чтобы реализовать нашу гипотезу, но вывел метод ManWithKnowledge.haveKnowledge().

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

Представление внутренних классов в исходном коде

Поскольку каждый класс создает файл .class, он содержит всю информацию для создания объекта этого типа.

Точно так же внутренний класс также сгенерирует файл .class, который представлен как: OneClass$OneInnerClass

Преимущества внутренних классов

Ниже приведены преимущества внутренних классов:

1. Инкапсулируйте часть кода Когда вы создаете внутренний класс, внутренний класс по умолчанию содержит ссылку на внешний класс;

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

3. Внутренние классы могут эффективно решить проблему множественного наследования.

собирать

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

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

Пришло время пожертвовать этим изображением бога

image-20210907223747116

Первое, что нужно представить, это интерфейс списка бабушек и дедушек.Iterator

Итерируемый интерфейс

Реализация этого интерфейса позволяет объекту быть целью цикла for-each, т. е. улучшить цикл for, который является语法糖.

List<Object> list = new ArrayList();
for (Object obj: list){}

В дополнение к объектам, реализующим этот интерфейс, массивы также могут быть пройдены с помощью цикла for-each следующим образом:

Object[] list = new Object[10];
for (Object obj: list){}

Другие методы обхода

До JDK 1.8IteratorСуществует только один метод итератора, который

Iterator<T> iterator();

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

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

Вы также можете использовать итераторы для обхода

for(Iterator it = coll.iterator(); it.hasNext(); ){
    System.out.println(it.next());
}

интерфейс верхнего уровня

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

Интерфейс List также является интерфейсом верхнего уровня, который наследует интерфейс Collection, а также является родительским классом элементов коллекции, таких как ArrayList и LinkedList.

Интерфейс Set находится на том же уровне, что и интерфейс List, и также наследует интерфейс Collection. Интерфейс Set предоставляет дополнительные возможности. Он предоставляет дополнительные критерии для методов add, equals, hashCode.

Queue — один из трех основных интерфейсов Collection наряду с интерфейсами List и Set. Очереди предназначены для поддержания порядка доступа к элементам перед обработкой. Очереди предоставляют дополнительные операции вставки, чтения и проверки в дополнение к основным операциям сбора.

Интерфейс SortedSet напрямую наследуется от интерфейса Set, используя Comparable для естественной сортировки элементов или Comparator для предоставления настраиваемых правил сортировки элементов во время создания. Итератор набора будет проходить по набору в порядке возрастания элементов.

Map – это объект, поддерживающий хранение ключей и значений. Карта не может содержать повторяющиеся ключи, и каждый ключ соответствует не более чем одному значению. Этот интерфейс заменяет класс Dictionary, который является абстрактным классом, а не интерфейсом.

ArrayList

ArrayList реализует интерфейс List可扩容数组(动态数组), который внутренне реализован на основе массивов. Его конкретное определение выглядит следующим образом:

public class ArrayList<E> extends AbstractList<E> implements List<E>, RandomAccess, Cloneable, java.io.Serializable {...}
  • ArrayList может реализовать все необязательные операции со списками, позволяя использовать все элементы, включая нулевые значения. ArrayList также предоставляет методы для внутреннего хранения списков, которые могут полностью заменить Vector, за одним исключением: ArrayList не является потокобезопасным контейнером.
  • ArrayList имеет концепцию емкости, емкость этого массива — это емкость списка, используемого для хранения элементов.
  • ArrayList не является потокобезопасным контейнером. Если по крайней мере два потока из нескольких потоков изменят структуру ArrayList, это вызовет проблемы с потокобезопасностью. В качестве альтернативы можно использовать потокобезопасный список.Collections.synchronizedList.
List list = Collections.synchronizedList(new ArrayList(...))
  • ArrayList имеет отказоустойчивый механизм быстрого отказа, который может обнаруживать отказ ArrayList. При изменении структуры коллекции в процессе итерации коллекции может произойти отказоустойчивость, то есть выбросConcurrentModificationException аномальный.

Vector

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

Другой момент заключается в том, что длина массива после расширения ArrayList увеличится на 50%, а длина Vector после расширения удвоится.

Класс LinkedList

LinkedList — это двусвязный список, позволяющий хранить любой элемент (включая null ). Его основные особенности заключаются в следующем:

  • Все операции LinkedList могут быть выражены как двунаправленные.Операции, проиндексированные к связанному списку, будут проходиться от начала до конца, в зависимости от того, какое расстояние ближе всего к порядку обхода.
  • Обратите внимание, что эта реализация также не является потокобезопасной.Если несколько потоков одновременно обращаются к связанному списку и хотя бы один из них изменяет структуру связанного списка, связанный список должен быть заблокирован извне. или использовать
List list = Collections.synchronizedList(new LinkedList(...))

Stack

стек - это то, что мы часто говорим后入先出(吃了吐)контейнер. Он расширяет класс Vector и предоставляет обычные операции push и pop, а также метод просмотра вершины стека, метод empty для проверки того, пуст ли стек, и метод поиска для нахождения расстояния от вершины стека. стек.

При первом создании стека он не содержит элементов. Более полная и надежная работа стека LIFO обеспечивается интерфейсом Deque и его реализацией, и этот класс следует использовать в первую очередь.

Deque<Integer> stack = new ArrayDeque<Integer>()

HashSet

HashSet — это класс реализации интерфейса Set, поддерживаемый хеш-таблицей (на самом деле HashSet — это экземпляр HashMap). Это не гарантирует порядок итерации коллекции. Этот класс допускает нулевые элементы.

  • Обратите внимание, что эта реализация не является потокобезопасной. Если несколько потоков одновременно обращаются к HashSet и хотя бы один поток изменяет набор, необходимо выполнить внешнюю блокировку. или использоватьCollections.synchronizedSet()переопределение метода.
  • Эта реализация поддерживает отказоустойчивый механизм.

TreeSet

TreeSet — это реализация NavigableSet, основанная на TreeMap. Элементы сортируются с использованием их естественного порядка или компаратора, предоставленного во время создания, в зависимости от используемого конструктора.

  • Эта реализация обеспечивает затраты времени log(n) для основных операций добавления, удаления и содержания.
  • Обратите внимание, что эта реализация не является потокобезопасной. Если несколько потоков одновременно обращаются к TreeSet и по крайней мере один поток изменяет набор, необходимо выполнить внешнюю блокировку. или использовать
SortedSet s = Collections.synchronizedSortedSet(new TreeSet(...))
  • Эта реализация содержит отказоустойчивый механизм.

Класс LinkedHashSet

LinkedHashSet наследуется от Set, давайте посмотрим на систему наследования LinkedHashSet:

image-20210907223758284

LinkedHashSet — это реализация хэш-таблицы и LinkedList интерфейса Set. Эта реализация отличается от HashSet тем, что поддерживает двусвязный список, который проходит через все записи. Этот связанный список определяет порядок, в котором элементы вставляются в коллекцию. Примечание. Если элемент вставлен повторно, порядок вставки не изменится.

  • LinkedHashSet имеет два параметра, влияющих на его состав: начальную емкость и коэффициент загрузки. Они определяются точно так же, как HashSet. Но обратите внимание: выбор чрезмерно высокого значения начальной емкости обходится дешевле для LinkedHashSet, чем для HashSet, поскольку емкость не влияет на количество итераций LinkedHashSet.
  • Обратите внимание, что LinkedHashSet также не является потокобезопасным.Если несколько потоков обращаются к LinkedHashSet одновременно, он должен быть заблокирован или с помощью
Collections.synchronizedSet
  • Этот класс также поддерживает отказоустойчивый механизм.

PriorityQueue

PriorityQueue — это класс реализации AbstractQueue.Элементы приоритетной очереди сортируются в соответствии с естественной сортировкой или путем предоставления компаратора во время конструктора, который определяется конструктором. PriorityQueue не допускает пустых элементов.

  • Голова очереди в некотором смысле является последним элементом в указанном порядке. Операции поиска в очереди опрашивают, удаляют, просматривают и получают доступ к элементу в начале очереди.
  • Очередь с приоритетом не ограничена, но имеет внутреннюю емкость, которая контролирует размер массива, используемого для хранения элементов в очереди.
  • Этот класс и итератор реализуют все необязательные методы интерфейсов Collection и Iterator. Этот итератор предоставляетiterator()Не гарантируется, что метод пройдет элементы приоритетной очереди в любом конкретном порядке. Если вам нужен обход по порядку, рассмотрите возможность использованияArrays.sort(pq.toArray()).
  • Обратите внимание, что эта реализация не является потокобезопасной, несколько потоков не должны одновременно обращаться к экземпляру PriorityQueue.Если поток изменяет очередь, используйте потокобезопасный класс.PriorityBlockingQueue.

HashMap

HashMap — это коллекция, которая использует принцип хеш-таблицы для хранения элементов и допускает пустые пары ключ-значение. HashMap не является потокобезопасным, а это значит, что в многопоточной среде могут возникнуть проблемы, тогда как Hashtable является потокобезопасным контейнером. HashMap также поддерживает отказоустойчивый механизм. Экземпляр HashMap имеет два параметра, влияющих на его производительность: начальную емкость и коэффициент загрузки. можно использоватьCollections.synchronizedMap(new HashMap(...))для создания потокобезопасного HashMap.

Класс TreeMap

Красно-черное дерево на основе реализации NavigableMap. Эта карта хранится с естественной сортировкой по ключу или с пользовательской сортировкой с помощью компаратора.

  • TreeMap обеспечивает log(n) накладных расходов для методов containsKey, get, put и remove.

  • Обратите внимание, что эта реализация не является потокобезопасной. Если несколько потоков одновременно обращаются к TreeMap и по крайней мере один поток изменяет карту, необходимо выполнить внешнюю блокировку. Обычно это достигается путем синхронизации с каким-либо объектом, который естественным образом инкапсулирует коллекцию, или с помощьюSortedMap m = Collections.synchronizedSortedMap(new TreeMap(...)).

  • Эта реализация содержит отказоустойчивый механизм.

Класс LinkedHashMap

LinkedHashMap — это хеш-таблица и реализация связанного списка интерфейса Map. Эта реализация отличается от HashMap тем, что поддерживает двусвязный список во всех своих записях. Этот связанный список определяет порядок обхода, обычно порядок вставки в карту.

  • Он предоставляет специальный конструктор LinkedHashMap(int,float,boolean) для создания LinkedHashMap, порядок обхода которого совпадает с порядком последнего посещения.

  • Метод removeEldestEntry(Map.Entry) можно переопределить, чтобы применить стратегию удаления карт с истекшим сроком действия при добавлении новой карты на карту.

  • Этот класс предоставляет все необязательные операции с картами и допускает нулевые элементы. Производительность может быть ниже, чем у HashMap, из-за дополнительных накладных расходов на поддержку связанных списков, за одним исключением: просмотр коллекций-представлений в LinkedHashMap должен быть пропорционален map.size, независимо от его емкости. Итерация по HashMap кажется более дорогой, поскольку она также требует времени, пропорционального ее емкости.

  • LinkedHashMap имеет два фактора, влияющих на его состав: начальная емкость и коэффициент загрузки.

  • Обратите внимание, что эта реализация не является потокобезопасной. Если несколько потоков одновременно обращаются к LinkedHashMap и хотя бы один поток изменяет карту, необходимо выполнить внешнюю блокировку. Обычно это достигается путем синхронизации с каким-либо объектом, естественным образом инкапсулирующим коллекцию.Map m = Collections.synchronizedMap(new LinkedHashMap(...)).

  • Эта реализация содержит отказоустойчивый механизм.

Класс хэш-таблицы

Класс Hashtable реализует хэш-таблицу, способную сопоставлять ключи со значениями. В качестве ключа или значения можно использовать любой ненулевой объект.

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

Класс IdentityHashMap

IdentityHashMap — относительно нишевая реализация карты.

  • Этот класс не является общей реализацией карты! Хотя этот класс реализует интерфейс Map, он намеренно нарушает контракт Map, который требует использования метода equals при сравнении объектов, и этот класс полезен только в редких случаях, когда требуется семантика равенства ссылок.
  • Как и HashMap, IdentityHashMap также неупорядочен, и этот класс не является потокобезопасным.Если вы хотите сделать его потокобезопасным, вы можете вызватьCollections.synchronizedMap(new IdentityHashMap(...))метод достижения.
  • Поддержка отказоустойчивого механизма

Класс WeakHashMap

Класс WeakHashMap — это базовая реализация Map на основе хэш-таблицы со слабыми ключами. Записи в WeakHashMap также автоматически удаляются, когда они больше не используются. Точнее, наличие карты для данного ключа не предотвратит отбрасывание ключа сборщиком мусора.

  • Судя по интерфейсу карты, это слабое ключевое соединение, и ключи в WeakHashMap будут автоматически переработаны.
  • Поддерживаются нулевые значения и нулевые ключи.
  • быстродействующий механизм
  • Дубликаты не допускаются
  • WeakHashMap часто используется в качестве кэша

Класс коллекций

Коллекции не относятся к содержимому дерева наследования платформы Java. Они относятся к отдельной ветви. Коллекции — это класс-оболочка. Его функция заключается в предоставлении определенных функциональных реализаций для структуры коллекций. Этот класс включает только операции статического метода или возвращает коллекции.

Синхронизированная упаковка

Оболочки синхронизации добавляют автоматическую синхронизацию (безопасность потоков) к произвольным коллекциям. Каждый из шести базовых интерфейсов коллекций (Collection, Set, List, Map, SortedSet и SortedMap) имеет статический фабричный метод.

public static  Collection synchronizedCollection(Collection c);
public static  Set synchronizedSet(Set s);
public static  List synchronizedList(List list);
public static <K,V> Map<K,V> synchronizedMap(Map<K,V> m);
public static  SortedSet synchronizedSortedSet(SortedSet s);
public static <K,V> SortedMap<K,V> synchronizedSortedMap(SortedMap<K,V> m);

немодифицируемая упаковка

Неизменяемые обертки путем перехвата операций, которые изменяют коллекцию и выбрасываютUnsupportedOperationException, в основном используется в следующих двух сценариях:

  • Сделайте коллекцию неизменной после ее создания. В этом случае лучше не получать ссылку на возвращаемую коллекцию, что хорошо для обеспечения неизменности
  • Разрешить доступ только для чтения к вашим структурам данных для определенных клиентов. Вы сохраняете ссылку на возвращенную коллекцию, но распространяете ссылку на оболочку. Таким образом, клиенты могут просматривать, но не изменять, сохраняя при этом полный доступ.

Эти методы:

public static  Collection unmodifiableCollection(Collection<? extends T> c);public static  Set unmodifiableSet(Set<? extends T> s);public static  List unmodifiableList(List<? extends T> list);public static <K,V> Map<K, V> unmodifiableMap(Map<? extends K, ? extends V> m);public static  SortedSet unmodifiableSortedSet(SortedSet<? extends T> s);public static <K,V> SortedMap<K, V> unmodifiableSortedMap(SortedMap<K, ? extends V> m);

Поточно-безопасные коллекции

Параллельный пакет Java1.5(java.util.concurrent)Предоставляет потокобезопасные коллекции, которые позволяют модифицировать во время обхода, за счет проектирования итератора, обеспечивающего отказоустойчивость и вызывающего исключение ConcurrentModificationException. Некоторые классы реализацииCopyOnWriteArrayList,ConcurrentHashMap,CopyOnWriteArraySet

Алгоритм коллекций

Этот класс содержит методы для алгоритмов набора фреймворков, таких как бинарный поиск, сортировка, перестановка, реверсирование и т. д.

Карта функций класса реализации коллекции

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

image-20210907223813609

Дженерики

В Jdk1.5 предлагается новая концепция:泛型, так что же такое дженерики?

Обобщения на самом деле представляют собой параметризованную коллекцию, которая ограничивает типы, которые вы можете добавить в коллекцию. Универсальные типы по сути являются параметризованным типом. Полиморфизм также можно рассматривать как механизм дженериков. Класс наследует родительский класс, тогда соответствующий подкласс можно найти через его родительский класс, но конкретный класс, который вы ищете, не может быть найден через другие классы. Обобщения предназначены для максимально широкой выразительности объектов или методов.

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

List arrayList = new ArrayList();
arrayList.add("cxuan");
arrayList.add(100);

for(int i = 0; i< arrayList.size();i++){
    String item = (String)arrayList.get(i);
		System.out.println("test === ", item);
}

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

java.lang.ClassCastException: java.lang.Integer cannot be cast to java.lang.String

Если мы перепишем его с помощью дженериков, пример кода будет следующим

List<String> arrayList = new ArrayList<String>();arrayList.add(100);

Этот код сообщит об ошибке во время компиляции, и компилятор сможет помочь нам найти подобные проблемы на этапе компиляции.

Использование дженериков

Есть три способа использования дженериков: универсальные классы, универсальные интерфейсы и универсальные методы. Давайте обсудим их вместе.

Представление классов с помощью дженериков

Обобщения могут быть добавлены к классу для представления типа класса.

//此处 T 可以随便写为任意标识,常见的如T、E、K、V等形式的参数常用于表示泛型
public class GenericDemo<T>{ 
    //value 这个成员变量的类型为T,T的类型由外部指定  
    private T value;

    public GenericDemo(T value) {
        this.value = value;
    }

    public T getValue(){ //泛型方法getKey的返回值类型为T,T的类型由外部指定
        return value;
    }
 
 		public void setValue(T value){
	      this.value = value
    }
}

Представление интерфейса с помощью дженериков

Определение и использование универсального интерфейса и универсального класса в основном одинаковы.

//定义一个泛型接口
public interface Generator<T> {
    public T next();
}

Универсальные интерфейсы обычно используются в生成器(generator)В , генератор эквивалентен фабрике объектов, классу, специально используемому для создания объектов.

общий метод

Вы можете использовать дженерики для представления методов

public class GenericMethods {
  public <T> void f(T x){
    System.out.println(x.getClass().getName());
  }
}

Общие подстановочные знаки

Неограниченное количество подстановочных знаков >

Список является универсальным классом. Чтобы представить родительский класс различных универсальных списков, можно использовать подстановочные знаки типов, а также можно использовать подстановочные знаки типов.问号(?)означает, что его тип элемента может соответствовать любому типу. Например

public static void main(String[] args) {
    List<String> name = new ArrayList<String>();
    List<Integer> age = new ArrayList<Integer>();
    List<Number> number = new ArrayList<Number>();
    name.add("cxuan");
    age.add(18);
    number.add(314);
    generic(name);
    generic(age);
    generic(number);   
}

public static void generic(List<?> data) {
    System.out.println("Test cxuan :" + data.get(0));
}

подстановочный знак верхней границы

Использование extensions в параметре типа указывает, что параметр в этом универсальном шаблоне должен быть E или подклассом E, что имеет два преимущества:

  • Если входящий тип не является E или подклассом E, редактирование не выполняется.
  • Метод E можно использовать в дженериках, в противном случае его необходимо привести к E, прежде чем его можно будет использовать.

Например:

private <K extends ChildBookBean, E extends BookBean> E test2(K arg1, E arg2){
    E result = arg2;
    arg2.compareTo(arg1);
    //.....
    return result;
}

Подстановочный знак Нижнего мира

Использование super в параметре типа означает, что параметр в этом универсальном должен быть E или надклассом E .

private <E> void add(List<? super E> dst, List<E> src){
    for (E e : src) {
        dst.add(e);
    }
}

Можно видеть, что приведенный выше тип dst "больше или равен" типу src. "Больше или равно" здесь означает, что диапазон, представленный dst, больше, чем диапазон src, поэтому контейнер, который может Hold dst также может содержать src.

сравнение с подстановочными знаками

Из приведенного выше примера мы можем узнать, что неограниченный подстановочный знак чем-то похож на Object и используется для представления сценариев с неограниченными или неопределенными диапазонами.

Две ограниченные формы подстановочных знаков super E> и extends E> также легко спутать, поэтому давайте сравним их.

Их цель — сделать интерфейс метода более гибким и принять более широкий диапазон типов.

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

Введите стирание для дженериков

Между дженериками в Java и шаблонами в C++ есть одно большое различие:

Создание экземпляров шаблонов в C++ создает разные наборы кода для каждого типа, что известно как раздувание кода. Эта проблема не возникает в Java. В виртуальной машине нет объектов универсального типа, все объекты являются обычными классами. (взято из:blog.CSDN.net/Service0124/Аретти…

В Java дженерики — это концепция компилятора Java.Программы Java, написанные с помощью дженериков, в основном такие же, как и обычные программы Java, за исключением того, что в них больше параметризованных типов и меньше преобразований типов.

На самом деле, универсальные программы сначала преобразуются в общие, необобщенные Java-программы перед обработкой. Компилятор автоматически завершает преобразование из универсальной Java в обычную Java. Среда выполнения виртуальной машины Java имеет базовое понимание универсальных программ. Я не знаю. .

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

На самом деле, используете вы дженерики или нет, тип данных объектов, хранящихся в фреймворке коллекции, — это Object, что видно не только из исходного кода, но и посредством отражения.

List<String> strings = new ArrayList<>();
List<Integer> integers = new ArrayList<>();
System.out.println(strings.getClass() == integers.getClass());//true

Вывод приведенного выше кода не является ожидаемым ложным, а истинным. Причиной этого является стирание дженериков.

отражение

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

Механизм отражения Java заключается в том, что во время выполнения программы для любого класса она может знать все его свойства и методы, для любого объекта она может знать любые свойства и методы, которые ее вызывают.Это динамическое получение информации и динамический вызов Функция объектного метода называется механизмом отражения языка Java..

Чтобы проанализировать класс, вы должны сначала получить объект файла байт-кода класса. Анатомия использует методы класса Class, поэтому сначала получите объект типа Class, соответствующий каждому файлу байт-кода.

Так называемое отражение на самом деле, чтобы получить классбайт-кодфайл, то есть файл .class, то мы можем получить его через объект Class.

Механизм отражения Java в основном предоставляет следующие функции.

  • Определить класс, к которому принадлежит любой объект во время выполнения
  • Создание объекта любого класса во время выполнения
  • Определить все переменные-члены и методы любого класса во время выполнения
  • Вызов метода для любого объекта во время выполнения

Глядя на это с этой точки зрения, отражение похоже на роль в управлении общей ситуацией.Независимо от того, как работает ваша программа, я могу знать, какие свойства и методы есть у вашего класса, и кто называет ваш объект, гм, очень крутым.

В Java используйтеJava.lang.reflectВ пакете реализован механизм отражения. Классы, разработанные Java.lang.reflect, следующие:

image-20210907223829738

Ниже приведен простой класс отражения

public class Person {
    public String name;// 姓名
    public int age;// 年龄
 
    public Person() {
        super();
    }
 
    public Person(String name, int age) {
        super();
        this.name = name;
        this.age = age;
    }
 
    public String showInfo() {
        return "name=" + name + ", age=" + age;
    }
}

public class Student extends Person implements Study {
    public String className;// 班级
    private String address;// 住址
 
    public Student() {
        super();
    }
 
    public Student(String name, int age, String className, String address) {
        super(name, age);
        this.className = className;
        this.address = address;
    }
 
    public Student(String className) {
        this.className = className;
    }
 
    public String toString() {
        return "姓名:" + name + ",年龄:" + age + ",班级:" + className + ",住址:"
                + address;
    }
 
    public String getAddress() {
        return address;
    }
 
    public void setAddress(String address) {
        this.address = address;
    }
}

public class TestRelect {
 
    public static void main(String[] args) {
        Class student = null;
        try {
            student = Class.forName("com.cxuan.reflection.Student");
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }
 
        // 获取对象的所有公有属性。
        Field[] fields = student.getFields();
        for (Field f : fields) {
            System.out.println(f);
        }
        System.out.println("---------------------");
        // 获取对象所有属性,但不包含继承的。
        Field[] declaredFields = student.getDeclaredFields();
        for (Field df : declaredFields) {
            System.out.println(df);
        }
      
      	// 获取对象的所有公共方法
        Method[] methods = student.getMethods();
        for (Method m : methods) {
            System.out.println(m);
        }
        System.out.println("---------------------");
        // 获取对象所有方法,但不包含继承的
        Method[] declaredMethods = student.getDeclaredMethods();
        for (Method dm : declaredMethods) {
            System.out.println(dm);
        }
				
      	// 获取对象所有的公共构造方法
        Constructor[] constructors = student.getConstructors();
        for (Constructor c : constructors) {
            System.out.println(c);
        }
        System.out.println("---------------------");
        // 获取对象所有的构造方法
        Constructor[] declaredConstructors = student.getDeclaredConstructors();
        for (Constructor dc : declaredConstructors) {
            System.out.println(dc);
        }
      
      	Class c = Class.forName("com.cxuan.reflection.Student");
      	Student stu1 = (Student) c.newInstance();
      	// 第一种方法,实例化默认构造方法,调用set赋值
        stu1.setAddress("河北石家庄");
        System.out.println(stu1);

        // 第二种方法 取得全部的构造函数 使用构造函数赋值
        Constructor<Student> constructor = c.getConstructor(String.class, 
                                                            int.class, String.class, String.class);
        Student student2 = (Student) constructor.newInstance("cxuan", 24, "六班", "石家庄");
        System.out.println(student2);

        /**
        * 獲取方法并执行方法
        */
        Method show = c.getMethod("showInfo");//获取showInfo()方法
        Object object = show.invoke(stu2);//调用showInfo()方法
      	
 
    }
}

Некоторые из них используются чаще, некоторые из них я до сих пор не видел, как их использовать.Ниже приводится классификация.

Классы, связанные с отражением Java, в основном

класс класс

В Java каждый раз, когда вы определяете объект класса Java, будет генерироваться объект класса. То есть, когда мы пишем класс после завершения компиляции, в сгенерированном.classВ файле будет сгенерирован объект класса, который используется для представления информации о типе этого класса. В классе нет общедоступного конструктора, что означает, что объекты класса не могут быть созданы. Давайте кратко рассмотрим, какие методы включены в класс Class.

toString()

public String toString() {
  return (isInterface() ? "interface " : (isPrimitive() ? "" : "class "))
    + getName();
}

Метод toString() может преобразовать объект в строку. toString() сначала определит, является ли тип Class типом интерфейса, то есть обычные классы и интерфейсы могут быть представлены объектом Class, а затем определит, является ли он типом класса. базовый тип данных. Здесь оцениваются базовые типы данных и классы-оболочки, а такжеvoid тип.

Все типы следующие

  • java.lang.Boolean : класс-оболочка, представляющий логический тип данных.
  • java.lang.Character: класс-оболочка, представляющий тип данных char.
  • java.lang.Byte: класс-оболочка, представляющий тип данных byte.
  • java.lang.Short: класс-оболочка, представляющий короткий тип данных.
  • java.lang.Integer: класс-оболочка, представляющий тип данных int.
  • java.lang.Long: класс-оболочка, представляющий тип данных long.
  • java.lang.Float: класс-оболочка, представляющий тип данных float.
  • java.lang.Double: класс-оболочка, представляющий тип данных double.
  • java.lang.Void: класс-оболочка, представляющий тип данных void.

ПослеgetName()метод, который возвращает полное имя класса.

  • Если это ссылочный тип, например String.class.getName() ->java.lang.String
  • Если это базовый тип данных, byte.class.getName() ->byte
  • Если это тип массива, new Object[3]).getClass().getName() ->[Ljava.lang.Object

toGenericString()

Этот метод возвращает полное имя класса, включая модификаторы класса и сведения о параметрах типа.

forName()

Получите ссылку на объект класса по имени класса, этот метод инициализирует объект класса.

НапримерClass t = Class.forName("java.lang.Thread")может инициализировать объект потока Thread

В Java есть три способа получить экземпляр класса.

  • Class.forName(java.lang.Thread)
  • Thread.class
  • thread.getClass()

newInstance()

Создает экземпляр класса, который представляет объект этого класса. Приведенный выше метод forName() инициализирует класс, а метод newInstance создает экземпляр класса.

getClassLoader()

Получите объект загрузчика классов.

getTypeParameters()

Получите информацию о типе параметра объекта в порядке объявления.

getPackage()

пакет, который возвращает класс

getInterfaces()

Получить класс или интерфейс, реализованный текущим классом, их может быть несколько, поэтому возвращаемым является массив классов.

Cast

Преобразование объекта в объект, представляющий класс или интерфейс

asSubclass(Class clazz)

Преобразует объект переданного класса в объект, представляющий его подкласс

getClasses()

Возвращает массив, содержащий объекты всех общедоступных и интерфейсных классов в классе

getDeclaredClasses()

Возвращает массив, содержащий объекты всех классов и классов интерфейса в этом классе

getSimpleName()

получить имя класса

getFields()

Получить все объекты публичной собственности

getField(String name)

Получить объект публичной собственности

getDeclaredField(String name)

получить объект недвижимости

getDeclaredFields()

получить все объекты недвижимости

getAnnotation(Class annotationClass)

Возвращает общедоступный объект аннотации в этом классе, соответствующий типу параметра.

getAnnotations()

Возвращает все общедоступные объекты аннотаций этого класса.

getDeclaredAnnotation(Class annotationClass)

Возвращает все объекты аннотаций в этом классе, которые соответствуют типу параметра

getDeclaredAnnotations()

Возвращает все объекты аннотации этого класса

getConstructor(Class...<?> parameterTypes)

Получить общедоступный конструктор в этом классе, который соответствует типу параметра

getConstructors()

Получить все общедоступные конструкторы этого класса

getDeclaredConstructor(Class...<?> parameterTypes)

Получите конструктор в этом классе, который соответствует типу параметра

getDeclaredConstructors()

Получить все конструкторы этого класса

getMethod(String name, Class...<?> parameterTypes)

Получить публичный метод этого класса

getMethods()

Получить все общедоступные методы этого класса

getDeclaredMethod(String name, Class...<?> parameterTypes)

получить метод этого класса

getDeclaredMethods()

Получить все методы этого класса

Класс поля

Класс Field предоставляет информацию и динамический доступ к отдельным полям в классе или интерфейсе.

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

Вот лишь несколько часто используемых методов

equals(Object obj)

Возвращает true, если свойство равно obj

get(Object obj)

Получить соответствующее значение свойства в obj

set(Object obj, Object value)

Установите соответствующее значение свойства в obj

Класс метода

invoke(Object obj, Object... args)

Передайте объект объекта и параметры для вызова метода, соответствующего объекту

Класс ClassLoader

При отражении другим очень важным классом является класс ClassLoader.Загрузчик классов используется для类(class)загружен вJVM из. ClassLoader использует родительскую модель делегирования для поиска загруженных классов, которая также является родительской моделью делегирования. Схема наследования классов ClassLoader выглядит следующим образом.

image-20210907223844550

Для более глубокого понимания рефлексии вы можете прочитать эту статью автораНаучившись размышлять, я был принят! (галантерея)

перечислить

Перечисление может быть функцией, которую мы используем реже.enumключевое слово, чтобы указать, что перечисления на самом деле очень полезная функция, и вы можете думать о них как о классах с определенными свойствами. Enum — это не только Java, C и C++ также имеют концепцию перечисления. Ниже приведен пример перечисления.

public enum Family {

    FATHER,
    MOTHER,
    SON,
    Daughter;

}

Выше мы создалиFamilyКласс перечисления, который имеет 4 значения, представлен прописными буквами, поскольку типы перечисления являются константами. Затем создается перечисление, как на него сослаться?

public class EnumUse {

    public static void main(String[] args) {
        Family s = Family.FATHER;
    }
}

свойства перечисления

Класс перечисления enum интересен, когда вы создаете перечисление, компилятор автоматически добавит его в ваше перечисление.toString()метод, который позволяет удобно отображать конкретное имя экземпляра перечисления. В дополнение к методу toString() компилятор добавляетordinal()метод, который используется для указания порядка объявления констант перечисления, иvalues()Метод отображает стоимость заказа.

public static void main(String[] args) {

  for(Family family : Family.values()){
    System.out.println(family + ", ordinal" + family.ordinal());
  }
}

enum может статически импортировать пакеты, а статически импортировать пакеты можно без ввода枚举类名.常量, вы можете использовать константы напрямую, магия?Используйте ennum иstaticКлючевое слово может делать статический пакет импорта

image-20210907223907374

Приведенный выше код импортирует все константы в Family, и вы также можете указать константы по отдельности.

Перечисления такие же, как обычные классы

Перечисления аналогичны обычным классам, за исключением того, что их можно легко и быстро определить в перечислениях.常量, которые мы используем в нашей повседневной разработкеpublic static final xxxНа самом деле его можно определить перечислением. Атрибуты и методы также могут быть определены в перечислении, не думайте об этом как о разнородном, это то же самое, что и тысячи классов.

public enum OrdinalEnum {

    WEST("live in west"),
    EAST("live in east"),
    SOUTH("live in south"),
    NORTH("live in north");

    String description;

    OrdinalEnum(String description){
        this.description = description;
    }

    public String getDescription() {
        return description;
    }

    public void setDescription(String description) {
        this.description = description;
    }

    public static void main(String[] args) {
        for(OrdinalEnum ordinalEnum : OrdinalEnum.values()){
            System.out.println(ordinalEnum.getDescription());
        }
    }
}

Как правило, switch можно использовать вместе с enum для создания небольшой машины перехода между состояниями.

enum Signal {
  GREEN, YELLOW, RED
}

public class TrafficLight {
    Signal color = Signal.RED;

    public void change() {
        switch (color) {
        case RED:
            color = Signal.GREEN;
            break;
        case YELLOW:
            color = Signal.RED;
            break;
        case GREEN:
            color = Signal.YELLOW;
            break;
        }
    }
}

Стал ли код вдруг более элегантным и аккуратным?

перечислять тайны

В Java все является объектом.Хотя enum является ключевым словом, оно неявно наследуется отEnumсвоего рода. Давайте взглянем на класс Enum, который находится вjava.langПод пакетом на него можно автоматически сослаться.

image-20210907223923592

Этот класс имеет меньше свойств и методов. Вы заметите, что нашего метода значений нет в этом классе. Я только что сказал раньше,values()Методы — это статические методы, добавляемые компилятором при использовании перечислений.Вы можете использовать отражение для проверки.

Кроме того, у enum также есть пересечение с классом Class, и в классе Class есть три метода для Enum.

image-20210907223931510

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

перечисляемый класс

В дополнение к Enum вам также необходимо знать два класса инструментов для перечисления, один из которыхEnumSet,одинEnumMap

EnumSet и EnumMap

EnumSet был представлен в JDK1.5. Дизайн EnumSet полностью учитывает фактор скорости. Использование EnumSet можно использовать в качестве альтернативы Enum, поскольку он более эффективен.

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

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

I/O

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

Класс IO определенно предназначен для решения операций, связанных с вводом-выводом.Наиболее распространенными операциями чтения и записи ввода-вывода являются сеть, диск и т. д. В Java операция с файлом является типичной операцией ввода-вывода. Далее мы классифицируем ввод-вывод.

image-20210907223943720

Ввод/вывод также можно различать в зависимости от объекта операции: в основном делится на

image-20210907224000191

Кроме того, в вводе-выводе есть и другие более важные классы.

Класс файла

Класс File — это класс, который работает с файлами и папками в файловой системе.Он может работать с файлами и папками посредством объектно-ориентированного мышления.Разве это не удивительно?

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

class FileDemo{
   public static void main(String[] args) {
       File file = new File("D:\\file.txt");
       try{
         f.createNewFile(); // 创建一个文件
         
         // File类的两个常量
         //路径分隔符(与系统有关的)<windows里面是 ; linux里面是 : >
        System.out.println(File.pathSeparator);  //   ;
        //与系统有关的路径名称分隔符<windows里面是 \ linux里面是/ >
        System.out.println(File.separator);      //  \
         
         // 删除文件
         /*
         File file = new File(fileName);
         if(f.exists()){
             f.delete();
         }else{
             System.out.println("文件不存在");
         }   
         */

         
       }catch (Exception e) {
           e.printStackTrace();
       }
    }
}

Вы также можете работать с папками

class FileDemo{
  public static void main(String[] args) {
    String fileName = "D:"+ File.separator + "filepackage";
    File file = new File(fileName);
    f.mkdir();
    
		// 列出所有文件
    /*
    String[] str = file.list();
    for (int i = 0; i < str.length; i++) {
      System.out.println(str[i]);
    }
    */
    
    // 使用 file.listFiles(); 列出所有文件,包括隐藏文件
    
    // 使用 file.isDirectory() 判断指定路径是否是目录
  }
}

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

File(String directoryPath);
File(String directoryPath, String filename);
File(File dirObj, String filename);

directoryPath — это путь к файлу, filename — это имя файла, а dirObj — это объект File. Например

File file = new File("D:\\java\\file1.txt");  //双\\是转义
System.out.println(file);
File file2 = new File("D:\\java","file2.txt");//父路径、子路径--可以适用于多个文件的!
System.out.println(file2);
File parent = new File("D:\\java");
File file3 = new File(parent,"file3.txt");//File类的父路径、子路径
System.out.println(file3);

Теперь подведем итоги класса File

image-20210907224017172

Основные классы ввода-вывода и связанные с ними методы

Хотя классов .IO много, самыми основными являются четыре абстрактных класса,InputStream, OutputStream, Reader, Writer. Самый основной метод этоread()иwrite()метод, другие потоки являются подклассами вышеупомянутых четырех типов потоков, и методы также являются производными от этих двух типов методов. И большая часть исходного кода IOnativeПодписанный, то есть исходный код написан на C/C++. Здесь мы сначала рассмотрим эти потоковые классы и их методы.

InputStream

InputStream — это абстрактный класс, определяющий схему ввода байтов потока Java. Все методы этого класса вызывают исключение IOException при возникновении ошибки. Его основной метод определяется следующим образом

image-20210907224027459

OutputStream

OutputStream — это абстрактный класс, определяющий схему потокового вывода байтов. Все методы этого класса возвращают пустое значение и вызывают исключение IOException в случае ошибки. Его основной метод определяется следующим образом

image-20210907224038211

Читательский класс

Reader — это абстрактный класс для режима потокового ввода символов, определенного в Java. Метод в классе выдает ошибкуIOExceptionаномальный.

image-20210907224047953

Класс писателя

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

image-20210907224100871

InputStream и его подклассы

Входной поток файла FileInputStream: класс FileInputStream создает класс InputStream, который может считывать байты из файла.

Входной поток массива байтов ByteArrayInputStream: использовать буфер в памяти как InputStream

Конвейерный входной поток PipedInputStream: Реализует концепцию трубы, в основном используемую в потоках.

Последовательный входной поток SequenceInputStream: объединить несколько InputStreams в один InputStream.

FilterOutputStream фильтрует входной поток: оболочка для других входных потоков.

ObjectInputStream десериализует входной поток: восстановить исходные данные, сериализованные с помощью ObjectOutputStream, как объект и прочитать объект в потоке.

DataInputStream: потоки ввода данных позволяют приложениям считывать основные типы данных Java из основного потока ввода машинно-независимым способом.

PushbackInputStream отталкивает входной поток: новое использование буферизации заключается в реализации推回 (pushback). Pushback используется во входном потоке, чтобы байты могли быть прочитаны, а затем возвращены в поток.

OutputStream и его подклассы

Выходной поток файла FileOutputStream: этот класс реализует поток вывода, данные которого записываются в файл.

Выходной поток массива байтов ByteArrayOutputStream: этот класс реализует поток вывода, данные которого записываются в буфер, управляемый массивом байтов, который автоматически увеличивается по мере записи данных.

Выходной поток конвейера PipedOutputStream: выходной поток конвейера, который является отправляющим концом конвейера.

Выходной поток примитивного типа ObjectOutputStream: этот класс сериализует сериализованный объект и записывает его в указанное место.

FilterOutputStream фильтровать выходной поток: оболочка для других выходных потоков.

Поток печати PrintStreamТекст можно распечатать в файл или в сеть через PrintStream.

DataOutputStream: Потоки вывода данных позволяют приложениям записывать базовые типы данных Java в базовый поток вывода машинно-независимым способом.

Читатель и его подклассы

Входной поток символов файла FileReader: преобразовать файл в поток символов и прочитать его.

Входной поток массива символов CharArrayReader: это реализация входного потока, который принимает массив символов в качестве источника

Входной поток буфера BufferedReader: класс BufferedReader считывает текст из потока ввода символов и буферизует символы для эффективного чтения символов, массивов и строк.

PushbackReader: класс PushbackReader позволяет вернуть один или несколько символов обратно во входной поток.

Входной поток канала PipedReader: Основная цель также состоит в том, чтобы общаться между потоками, но это может быть использовано для передачи символов.

Writer и его подклассы

Поток вывода символов FileWriter: FileWriter создает класс Writer, который может записывать в файл.

Поток вывода массива символов CharArrayWriter: CharArrayWriter реализует выходной поток, нацеленный на массив.

Выходной поток буфера BufferedWriter: BufferedWriter добавленflush( )Метод Писателя. Метод flush() можно использовать для гарантии того, что буфер данных действительно записывается в фактический выходной поток.

**PrintWriter ** : PrintWriter по сути является символьной версией PrintStream.

Выходной поток канала PipedWriter: Основная цель также состоит в том, чтобы общаться между потоками, но это может быть использовано для передачи символов.

Потоковый интерфейс Java для ввода и вывода обеспечивает аккуратную абстракцию для сложных и тяжелых задач. Комбинация классов отфильтрованных потоков позволяет динамически создавать интерфейсы потоковой передачи на стороне клиента в соответствии с требованиями к передаче данных. Java-программы, наследующие потоковые классы более высокого уровня InputStream, InputStreamReader, Reader и Writer, можно разумно использовать в будущем (даже если будут созданы новые и улучшенные конкретные классы).

Для более глубокого понимания Java IO вы можете прочитать эту статью автораГлубокое понимание Java IO

аннотация

Java 注解(Annotation)Также известен как元数据, который предоставляет нам формальный способ добавления информации в наш код. Он был представлен JDK1.5, Java определяет набор аннотаций, всего 7, 3 вjava.lang, остальные 4 находятся вjava.lang.annotationсередина.

Есть три аннотации, которые действуют на код:

  • @Override: тег перезаписи обычно используется после того, как подкласс наследует родительский класс, и помечается в переопределенном методе подкласса. Если обнаружится, что его родительский класс или указанный интерфейс не имеют этого метода, будет сообщено об ошибке компиляции.
  • @Deprecated: код, аннотированный этой аннотацией, устарел и объявлен устаревшим.
  • @SuppressWarnings: Эта аннотация играет роль игнорирования предупреждений компилятора.

Существует четыре мета-аннотации, а мета-аннотации — это аннотации, используемые для обозначения аннотаций. они соответственно

  • @Retention: как хранится удостоверение, находится ли оно только в коде, скомпилировано в файл класса или может быть доступно через отражение во время выполнения.

RetentionPolicy.SOURCE: аннотация сохраняется только в исходном файле.Когда файл Java компилируется в файл класса, аннотация отбрасывается;

RetentionPolicy.CLASS: аннотации сохраняются в файле класса, но отбрасываются, когда jvm загружает файл класса, это默认的жизненный цикл;

RetentionPolicy.RUNTIME: аннотация не только сохраняется в файле класса, но и существует после того, как JVM загрузит файл класса;

  • @Documented: Отмечает, включены ли эти аннотации в JavaDoc.
  • @Target: Отметьте эту аннотацию, чтобы описать область действия объекта, измененного аннотацией.Аннотацию можно использовать для пакетов, типов (классы, интерфейсы, перечисления, типы аннотаций), членов типа (методы, конструкторы, переменные-члены, значения перечисления), методы Параметры и локальные переменные (например, переменные цикла, параметры захвата). Значения следующие
public enum ElementType {
    TYPE, 						// 类、接口、注解、枚举
    FIELD,						// 字段
    METHOD,						// 方法
    PARAMETER,				// 参数
    CONSTRUCTOR,			// 构造方法
    LOCAL_VARIABLE,		// 本地变量
    ANNOTATION_TYPE,	// 注解
    PACKAGE,					// 包
    TYPE_PARAMETER,		// 类型参数
    TYPE_USE					// 类型使用
  • @Inherited: Отметьте, от какого класса аннотаций унаследована эта аннотация.

Начиная с JDK1.7, были добавлены три дополнительные аннотации:

  • @SafeVarargs: Компилятор Java выдает непроверенное предупреждение при объявлении конструктора или метода с переменным числом аргументов. Используйте @SafeVarargs, чтобы игнорировать эти предупреждения.

  • @FunctionalInterface: указывает, что метод является функциональным интерфейсом

  • @Repeatable: указывает, что аннотацию можно использовать несколько раз в одном и том же объявлении.

Примечание. Аннотации не поддерживают наследование.

Жизненный цикл аннотации

У аннотации также есть соответствующий цикл объявления, и она также инкапсулирована в класс перечисления: RetentionPolicy:

  • ИСТОЧНИК: Во время исходного кода он удаляется во время компиляции, так что это все для компилятора.
  • КЛАСС: он останется в файле класса, но JVM не нужно сохранять его во время выполнения, жизненный цикл по умолчанию.
  • ВРЕМЯ ВЫПОЛНЕНИЯ: он будет сохранен во время выполнения JVM и может быть получен путем отражения.

Цикл объявления используется в сочетании с @Retention следующими способами:

@Retention(RetentionPolicy.RUNTIME)

Вообще говоря, жизненный цикл аннотаций, используемых для написания фреймворков, — это ВРЕМЯ ВЫПОЛНЕНИЯ.

Несколько способов борьбы с нулем

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

Итак, что касается null , вы должны знать следующие вещи, чтобы эффективно понимать null и избегать многих ошибок, вызванных null .

image-20210908220944817

Деликатный случай

Во-первых, null есть в Java.关键字, например **public, static, final. ** Это чувствительно к регистру, вы не можете написать null как Null или NULL, редактор не распознает их и сообщит об ошибке.

image-20210908221001686

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

null — начальное значение любого ссылочного типа

Null — это значение по умолчанию для всех ссылочных типов.Любая ссылочная переменная в Java принимает null в качестве значения по умолчанию, что означает, что значение по умолчанию для всех ссылочных типов в классе Object равно null. Это относится ко всем ссылочным переменным. Так же, как и значения по умолчанию для примитивных типов, например, значение по умолчанию для int равно 0, а значение по умолчанию для логического значения — false.

Ниже приведены начальные значения примитивных типов данных.

image-20210908221018989

null - это просто специальное значение

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

public static void main(String[] args) {
  String str = null;
  Integer itr = null;
  Double dou = null;

  Integer integer = (Integer) null;
  String string = (String)null;

  System.out.println("integer = " + integer);
  System.out.println("string = " + string);
}

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

null может быть присвоен только ссылочным переменным, а не переменным примитивного типа.

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

public static void main(String[] args) {
  int i = 0;
  Integer itr = null;
  System.out.println(itr == i);
}

используется переменная ссылочного типа с нулевым значением,instanceofОперация вернет false

public static void main(String[] args) {
  Integer isNull = null;
  // instanceof = isInstance 方法
  if(isNull instanceof Integer){
    System.out.println("isNull is instanceof Integer");
  }else{
    System.out.println("isNull is not instanceof Integer");
  }
}

Это важная особенность оператора instanceof, которая делает его полезным для проверки приведения типов.

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

Используйте нулевой безопасный метод

Вы должны использовать нулевые безопасные методы.В библиотеке классов java есть много классов инструментов, которые предоставляют статические методы, такие как классы-оболочки для базовых типов данных, Integer , Double и так далее. Например

public class NullSafeMethod {

    private static String number;

    public static void main(String[] args) {
        String s = String.valueOf(number);
        String string = number.toString();
        System.out.println("s = " + s);
        System.out.println("string = " + string);
    }
}

номер не имеет назначения, поэтому по умолчанию он равен нулю, используйтеString.value(number)Статические методы не генерируют исключения нулевого указателя, а используютtoString() Он генерирует исключение нулевого указателя. Поэтому попробуйте использовать статические методы объектов.

нулевое решение

ты можешь использовать==или!=операции для сравнения нулевых значений, но не могут использовать другие арифметические или логические операции, такие как меньше или больше. В отличие от SQL, в Java null == null вернет true, например:

public class CompareNull {

    private static String str1;
    private static String str2;

    public static void main(String[] args) {
        System.out.println("str1 == str2 ? " + str1 == str2);
        System.out.println(null == null);
    }
}

Наконец

Если статья была вам полезна, надеюсь, вы поставите мне лайк! ! !