1. введение
Система типов Java – это тема, часто поднимаемая на технических собеседованиях для разработчиков Java. В этой статье рассматриваются некоторые важные вопросы, которые задаются чаще всего и могут быть сложными для правильного ответа.
2. Вопросы
Q1. Опишите Место класса объектов в Иерархии типов. Какие типы наследуются от объекта, а какие нет? Наследуют ли массивы от объекта? Можно ли назначить Лямбда-выражение объектной переменной?
java.lang.Объект находится в верхней части иерархии классов в Java. Все классы наследуются от него либо явно, либо неявно (когда ключевое слово extends опущено в определении класса), либо транзитивно через цепочку наследования.
Однако существует восемь примитивных типов , которые не наследуются от Object , а именно boolean , byte , short , char , int , float , long и double .
Согласно спецификации языка Java, массивы также являются объектами. Они могут быть назначены ссылке Object , и на них могут быть вызваны все методы Object .
Лямбда-выражения не могут быть назначены непосредственно переменной Object , поскольку Object не является функциональным интерфейсом. Но вы можете назначить лямбду переменной функционального интерфейса, а затем назначить ее переменной Object (или просто назначить ее переменной объекта, одновременно приведя ее к функциональному интерфейсу).
Q2. Объясните Разницу Между Примитивными и ссылочными Типами.
Ссылочные типы наследуются от верхнего java.lang.Объект класс и сами являются наследуемыми (за исключением final классов). Примитивные типы не наследуются и не могут быть подклассами.
Примитивно типизированные значения аргументов всегда передаются через стек, что означает, что они передаются по значению, а не по ссылке. Это имеет следующее значение: изменения, внесенные в значение примитивного аргумента внутри метода, не распространяются на фактическое значение аргумента.
Примитивные типы обычно хранятся с использованием базовых типов аппаратных значений.
Например, для хранения значения int можно использовать 32-разрядную ячейку памяти. Ссылочные типы вводят накладные расходы заголовка объекта, который присутствует в каждом экземпляре ссылочного типа.
Размер заголовка объекта может быть довольно значительным по сравнению с размером простого числового значения. Вот почему примитивные типы были введены в первую очередь — для экономии места на накладных расходах объектов. Недостатком является то, что не все в Java технически является объектом — примитивные значения не наследуются от Object class.
Q3. Опишите Различные типы примитивов и объем памяти, который они занимают.
Java имеет 8 примитивных типов:
- логическое — логическое true |/false значение. Размер boolean не определяется спецификацией JVM и может варьироваться в разных реализациях. байт
- — знаковое 8-битное значение, короткое
- — 16-битное значение со знаком, char
- — 16-битное значение без знака, int
- — 32-разрядное значение со знаком, long
- — 64-разрядное значение со знаком, поплавок
- — 32-битовое значение с плавающей запятой с одинарной точностью, соответствующее стандарту IEEE 754, двойной
- — 64-битовое значение с плавающей запятой двойной точности, соответствующее стандарту IEEE 754.
Q4. В чем разница между абстрактным классом и интерфейсом? Каковы варианты использования одного и другого?
Абстрактный класс-это класс с модификатором abstract в его определении. Он не может быть создан, но его можно подклассировать. Интерфейс-это тип, описываемый с помощью ключевого слова interface . Он также не может быть создан, но может быть реализован.
Основное различие между абстрактным классом и интерфейсом заключается в том, что класс может реализовывать несколько интерфейсов, но расширять только один абстрактный класс.
Класс abstract обычно используется в качестве базового типа в некоторой иерархии классов, и это означает основное намерение всех классов, которые наследуют от него.
Класс abstract также может реализовать некоторые основные методы, необходимые во всех подклассах. Например, большинство коллекций карт в JDK наследуются от класса AbstractMap , который реализует множество методов, используемых подклассами (например, метод equals ).
Интерфейс определяет некоторый контракт, с которым соглашается класс. Реализованный интерфейс может означать не только основное намерение класса, но и некоторые дополнительные контракты.
Например, если класс реализует интерфейс Comparable , это означает, что экземпляры этого класса могут сравниваться, независимо от основной цели этого класса.
Q5. Каковы ограничения на элементы (Поля и методы) Типа интерфейса?
Интерфейс может объявлять поля, но они неявно объявляются как public , static и final , даже если вы не указываете эти модификаторы. Следовательно, вы не можете явно определить поле интерфейса как private . По сути, интерфейс может содержать только постоянные поля, а не поля экземпляра.
Все методы интерфейса также неявно public . Они также могут быть либо (неявно) абстрактными , либо по умолчанию .
Q6. В чем разница между Внутренним классом и Статическим вложенным классом?
Проще говоря, вложенный класс – это в основном класс, определенный внутри другого класса.
Вложенные классы делятся на две категории с очень разными свойствами. Внутренний класс-это класс, который не может быть создан без создания экземпляра заключающего класса в первую очередь, т. Е. Любой экземпляр внутреннего класса неявно привязан к некоторому экземпляру заключающего класса.
Вот пример внутреннего класса – вы можете видеть, что он может получить доступ к ссылке на экземпляр внешнего класса в виде OuterClass1.this construct:
public class OuterClass1 { public class InnerClass { public OuterClass1 getOuterInstance() { return OuterClass1.this; } } }
Чтобы создать экземпляр такого внутреннего класса, вам необходимо иметь экземпляр внешнего класса:
OuterClass1 outerClass1 = new OuterClass1(); OuterClass1.InnerClass innerClass = outerClass1.new InnerClass();
Статический вложенный класс совсем другой. Синтаксически это просто вложенный класс с модификатором static в его определении.
На практике это означает, что этот класс может быть создан как любой другой класс, без привязки его к какому-либо экземпляру заключающего класса:
public class OuterClass2 { public static class StaticNestedClass { } }
Чтобы создать экземпляр такого класса, вам не нужен экземпляр внешнего класса:
OuterClass2.StaticNestedClass staticNestedClass = new OuterClass2.StaticNestedClass();
Q7. Имеет Ли Java Множественное Наследование?
Java не поддерживает множественное наследование классов, что означает, что класс может наследовать только от одного суперкласса.
Но вы можете реализовать несколько интерфейсов с одним классом, и некоторые методы этих интерфейсов могут быть определены как default и иметь реализацию. Это позволяет вам иметь более безопасный способ смешивания различных функций в одном классе.
Q8. Каковы классы обертки? Что Такое Автобоксинг?
Для каждого из восьми типов примитивов в Java существует класс-оболочка, который можно использовать для обертывания значения примитива и использования его как объекта. Эти классы, соответственно, Boolean , Byte , Short , Character , Integer , Float , Long и Double . Эти обертки могут быть полезны, например, когда вам нужно поместить примитивное значение в общую коллекцию, которая принимает только ссылочные объекты.
Listlist = new ArrayList<>(); list.add(new Integer(5));
Чтобы избежать проблем с ручным преобразованием примитивов туда и обратно, компилятор Java обеспечивает автоматическое преобразование, известное как автобокс/автоматическая распаковка.
Listlist = new ArrayList<>(); list.add(5); int value = list.get(0);
Q9. Опишите разницу между equals() и ==
Это позволяет сравнить два объекта для “одинаковости” (т. Е. Чтобы обе переменные ссылались на один и тот же объект в памяти). Важно помнить, что ключевое слово new всегда создает новый объект, который не будет передавать равенство == с любым другим объектом, даже если они, кажется, имеют одинаковое значение:
String string1 = new String("Hello"); String string2 = new String("Hello"); assertFalse(string1 == string2);
Кроме того, позволяет сравнивать примитивные значения:
int i1 = 5; int i2 = 5; assertTrue(i1 == i2);
Метод equals() определен в java.lang.Объект класс и, следовательно, доступен для любого ссылочного типа. По умолчанию он просто проверяет, является ли объект тем же самым с помощью. Но обычно он переопределяется в подклассах, чтобы обеспечить определенную семантику сравнения для класса.
Например, для класса String этот метод проверяет, содержат ли строки одинаковые символы:
String string1 = new String("Hello"); String string2 = new String("Hello"); assertTrue(string1.equals(string2));
Q10. Предположим, У Вас Есть Переменная, которая ссылается на экземпляр типа класса. Как проверить, что Объект Является Экземпляром Этого класса?
В этом случае вы не можете использовать ключевое слово instanceof , потому что оно работает только в том случае, если вы указываете фактическое имя класса в качестве литерала.
К счастью, класс Class имеет метод isInstance , который позволяет проверить, является ли объект экземпляром этого класса:
Class> integerClass = new Integer(5).getClass(); assertTrue(integerClass.isInstance(new Integer(4)));
Q11. Что такое Анонимный класс? Опишите Его Вариант Использования.
Анонимный класс-это одноразовый класс, который определяется в том же месте, где необходим его экземпляр. Этот класс определен и создан в одном и том же месте, поэтому ему не нужно имя.
До Java 8 вы часто использовали анонимный класс для определения реализации одного интерфейса метода, например Runnable . В Java 8 вместо отдельных интерфейсов абстрактных методов используются лямбды. Но анонимные классы все еще имеют варианты использования, например, когда вам нужен экземпляр интерфейса с несколькими методами или экземпляр класса с некоторыми дополнительными функциями.
Вот как вы можете создать и заполнить карту:
Mapages = new HashMap (){{ put("David", 30); put("John", 25); put("Mary", 29); put("Sophie", 22); }};