
Java интервю: въпроси за ООП
1. Какви са характеристиките на Java?
Отговор:-
ООП концепции:
- обектна ориентация
- наследство
- капсулиране
- полиморфизъм
- абстракция
-
Междуплатформен: Java програма може да се изпълнява на всяка платформа без ниHowви промени. Разбира се, това изисква инсталиран JVM (Java виртуална машина).
-
Висока производителност: Компилаторът Just-In-Time (JIT) прави възможна висока производителност. JIT компилаторът преобразува byte codeа в машинен code и след това JVM започва изпълнението.
- Многопоточност: JVM създава нишка за изпълнение, наречена
main thread
. Програмистът може да създаде множество нишки, като извлече от класа Thread or имплементираRunnable
интерфейса.
2. Какво е наследство?
Наследяването означава, че един клас може да наследи друг клас (с помощта на ключовата дума extends ). Това означава, че можете да използвате повторно code от класа, който наследявате. Съществуващият клас е известен като,superclass
а новосъздаденият клас е subclass
. Хората също казват да използват термините родител и child
.
public class Animal {
private int age;
}
public class Dog extends Animal {
}
къде Animal
е parent
и Dog
е child
.
3. Какво е капсулиране?
Този въпрос често се задава в интервюта за позиции на Java разработчици. Капсулирането крие изпълнението чрез използване на модификатори за достъп, гетери и сетери. Това се прави, за да се предотврати външен достъп, където разработчиците смятат, че е необходимо. Прост пример от реалния живот е колата. Нямаме пряк достъп до работата на двигателя. Всичко, което трябва да направим, е да поставим ключа в запалването и да включим двигателя. Процесите, които протичат под капака, не са наша работа. Освен това, ако трябва да се намесим в дейността на двигателя, това може да доведе до непредсказуема ситуация, евентуално да повреди колата и да доведе до телесна повреда. Абсолютно същото се случва в програмирането. Това е добре описано в Уикипедия. Има и статия за капсулирането в CodeGym .4. Какво е полиморфизъм?
Полиморфизмът е способността на програмата да третира обекти със същия интерфейс по един и същи начин, без информация за конкретния тип на обекта. Както се казва, "един интерфейс - много реализации". С полиморфизма можете да комбинирате и използвате различни типове обекти въз основа на споделено поведение. Например, имаме клас Animal, който има два наследника: Dog и Cat. Общият клас Animal има поведение, споделяно от всички, способността да издава звук. Ние използваме полиморфни възможности, когато трябва да съберем всичко, което наследява класа Animal и да изпълним метода „издаване на звук“. Ето How изглежда:
List<Animal> animals = Arrays.asList(new Cat(), new Dog(), new Cat());
animals.forEach(animal -> animal.makeSound());
С други думи, полиморфизмът е полезен. И това се отнася и за полиморфните (претоварени) методи. Как да използваме полиморфизъм
Въпроси за интервю за синтаксиса на Java
5. Какво е конструктор в Java?
Конструкторите имат следните характеристики:- Когато се създаде нов обект, програмата използва подходящия конструктор, за да го създаде.
- Конструкторът е като метод. Неговите отличителни черти се състоят във факта, че няма върната стойност (включително void) и че името му е същото като името на класа.
- Ако не е създаден изрично конструктор, автоматично се създава празен конструктор.
- Конструкторът може да бъде заменен.
- Ако декларирате конструктор с параметри, но имате нужда и от такъв без параметри, тогава трябва да го създадете отделно, тъй като няма да бъде създаден автоматично.
6. Кои два класа не наследяват Object?
Не се заблуждавайте от трикови въпроси - няма такива класове. Всички класове наследяват класа Object директно or чрез предци!7. Какво е локална променлива?
Това е друг популярен въпрос за интервю за Java разработчици. Локална променлива е променлива, която е дефинирана вътре в метод и съществува, докато методът се изпълнява. Веднага щом изпълнението приключи, локалната променлива престава да съществува. Ето една програма, която използва локална променлива с име helloMessage в метода main():
public static void main(String[] args) {
String helloMessage;
helloMessage = "Hello, World!";
System.out.println(helloMessage);
}
8. Какво е променлива на екземпляр?
Променлива на екземпляр е променлива, която е декларирана вътре в клас. Съществува, докато съществува един обект. Например, имаме клас Bee, който има две екземплярни променливи — nectarLoad и maxNectarLoad:
public class Bee {
/**
* Current nectar load
*/
private double nectarLoad;
/**
* Maximum nectar that can the bee can collect.
*/
private double maxNectarLoad = 20.0;
...
}
9. Какво представляват модификаторите за достъп?
Модификаторите за достъп са механизъм за персонализиране на достъпа до класове, методи и променливи. Съществуват следните модификатори, изброени по ред на увеличаване на достъпа:private
— Този модификатор за достъп се използва за методи, полета и конструктори. Достъпът е ограничен до класа, в който са декларирани.package-private (default)
— Това е нивото на достъп по подразбиране за класове. Достъпът е ограничен до конкретния пакет, в който е деклариран клас, метод, променлива or конструктор.protected
— Този модификатор на достъп предлага същото ниво на достъп, Howтоpackage-private
при добавянето на достъп за класове, които наследяват клас сprotected
модификатора.public
— Това ниво на достъп се използва и за класове. Това ниво на достъп означава, че има пълен достъп в цялото приложение.

10. Какво е отмяна на метода?
Ние отменяме методите, когато дъщерен клас иска да промени поведението на своя родителски клас. Ако също трябва да направим това, което е в родителския метод, можем да използваме super.methodName() в дъщерния, който ще изпълни родителския метод. След това можем да добавим нашата допълнителна логика. Изисквания, които трябва да се спазват:- сигнатурата на метода трябва да е същата
- върнатата стойност трябва да е същата
11. Какво представляват сигнатурите на метода?

12. Какво е претоварване на метода?
Претоварването на метода е характеристика на полиморфизма, при която променяме сигнатурата на метода, за да създадем множество методи, които изпълняват едно и също действие:- същото име
- различни аргументи
- може да има различни видове връщане
ArrayList
на класа add()
може да бъде претоварен, което ни позволява да добавяме по различни начини в зависимост от входните аргументи:
add(Object o)
— Този метод просто добавя обектadd(int index, Object o)
— Този метод добавя обект към конкретен индексadd(Collection<Object> c)
— Този метод добавя списък с обектиadd(int index, Collection<Object> c)
— Този метод добавя списък с обекти, започвайки от определен индекс.
13. Какво е интерфейс?
Java не поддържа множествено наследяване. За да се преодолее това ограничение, бяха добавени интерфейси във форма, която познаваме и обичаме ;) Дълго време интерфейсите имаха само методи без ниHowва реализация. В контекста на този отговор нека поговорим за тях. Например:
public interface Animal {
void makeSound();
void eat();
void sleep();
}
Някои подробности следват от това:
- Всички методи в интерфейса са публични и абстрактни
- Всички променливи са публични статични финални
- Класовете не наследяват интерфейси (т.е. не използваме ключовата дума extends). Вместо това класовете ги имплементират (т.е. използваме ключовата дума implements). Освен това можете да внедрите толкова интерфейси, колкото искате.
- Класовете, които имплементират интерфейс, трябва да предоставят реализация на всички методи, които са в интерфейса.
public class Cat implements Animal {
public void makeSound() {
// Method implementation
}
public void eat() {
// Implementation
}
public void sleep() {
// Implementation
}
}
14. Какво е метод по подразбиране в интерфейс?
Сега нека поговорим за методите по подразбиране. За Howво са те? За кого са те? Тези методи бяха добавени, за да обслужват "и двете ръце". за Howво говоря Е, от една страна, имаше нужда от добавяне на нова функционалност: ламбда и API на потока. От друга страна, беше необходимо да се запази това, с което Java е известна - обратна съвместимост. За да направят това, интерфейсите се нуждаеха от някои нови готови решения. Ето How методите по подразбиране дойдоха при нас. Методът по подразбиране е внедрен метод в интерфейс, маркиран сdefault
ключовата дума. Например, добре познатият stream()
метод в Collection
интерфейса. Повярвайте ми, този интерфейс не е толкова прост, колкото изглежда. Или също толкова известния forEach()
метод вIterable
интерфейс. Освен това не съществуваше, докато не бяха добавени методите по подразбиране. Между другото, можете също да прочетете за това в CodeGym тук .
15. Как тогава да наследим два идентични метода по подразбиране?
Предишният отговор за това Howво е метод по подразбиране повдига друг въпрос. Ако можете да имплементирате методи в интерфейси, тогава теоретично можете да имплементирате два интерфейса с един и същ метод. Как да направим това? Ето два различни интерфейса със същия метод:
interface A {
default void foo() {
System.out.println("Foo A");
}
}
interface B {
default void foo() {
System.out.println("Foo B");
}
}
И имаме клас, който имплементира тези два интерфейса. Но How точно да изберем конкретен метод в интерфейс A or B? Следната специална конструкция позволява това: A.super.foo()
:
public class C implements A, B {
public void fooA() {
A.super.foo();
}
public void fooB() {
B.super.foo();
}
}
По този начин fooA()
методът ще използва foo()
метода по подразбиране на A
интерфейса, докато fooB()
методът ще използва foo()
метода на B
интерфейса.
16. Какво представляват абстрактните методи и класове?
В Javaabstract
е запазена дума. Използва се за обозначаване на абстрактни класове и методи. Първо, имаме нужда от определения. Абстрактен метод е метод, който се декларира с помощта на abstract
ключовата дума без реализация в абстрактен клас. Тоест, това е метод като в интерфейс, но с добавяне на ключова дума, например:
public abstract void foo();
Абстрактен клас е клас, също маркиран с abstract
ключовата дума:
public abstract class A {
}
Абстрактният клас има няколко характеристики:
- не можете да създадете обект от абстрактен клас
- може да има абстрактни методи
- може също да няма абстрактни методи
17. Каква е разликата между String, StringBuilder и StringBuffer?
String
стойностите се съхраняват в постоянен набор от низове. Веднага щом бъде създаден низ, той се появява в този пул. И не можете да го изтриете. Например:
String name = "book";
Променливата ще сочи към постоянния набор от низове. 
name = "pen";
Константният набор от низове изглежда така: 
String
стойностите се съхраняват в стек. Ако дадена стойност бъде променена, тогава новата стойност ще замени старата.String Buffer
е синхронизиран и следователно е безопасен за нишки.- Поради безопасността на конеца, работата му е лоша.
StringBuffer name = “book”;


StringBuffer
, само че не е безопасен за нишки. В резултат на това е значително по-бърз от StringBuffer
.
18. Каква е разликата между абстрактен клас и интерфейс?
Абстрактен клас:- Абстрактните класове имат конструктор по подразбиране. Извиква се всеки път, когато се създава наследник на абстрактния клас.
- Те могат да включват Howто абстрактни методи, така и неабстрактни. Като цяло, абстрактен клас не трябва да има абстрактни методи.
- Клас, който наследява абстрактен, трябва да прилага само абстрактни методи.
- Абстрактен клас може да има променливи на екземпляр (вижте въпрос #5).
- Интерфейсът няма конструктор и не може да бъде инициализиран.
- Могат да се добавят само абстрактни методи (с изключение на методите по подразбиране).
- Класовете, които имплементират интерфейса, трябва да имплементират всички методи (с изключение на методите по подразбиране).
- Интерфейсите могат да имат само константи.
19. Защо достъпът до елемент в масив е O(1)?
Този въпрос беше буквално зададен в последното ми интервю. Както разбрах по-късно, целта на този въпрос е да се види How мисли човек. Ясно е, че има малка практическа стойност в това знание. Самото знание е достатъчно. Първо, трябва да изясним, че O(1) е нотация за времевата сложност на алгоритъм за "постоянно време". С други думи, това обоmeaning показва най-бързото време за изпълнение. За да отговорим на този въпрос, трябва да разгледаме Howво знаем за масивите. За да създадемint
масив, трябва да напишем следното:
int[] intArray = new int[100];
От този синтаксис могат да се направят няколко заключения:
- Когато масивът е деклариран, неговият тип е известен. Ако типът е известен, тогава е известен размерът на всяка клетка в масива.
- Размерът на целия масив е известен.
И така, How да стигнем до O(1) при достъп до обекти в ArrayList?
Този въпрос следва непосредствено предишния. Истината е, че когато работим с масив, който съдържа примитиви, знаем предварително (в момента на създаване) размера на типа елемент. Но Howво да правим, ако имаме този вид йерархия на наследяване и
List<A> list = new ArrayList();
list.add(new B());
list.add(new C());
list.add(new D());
list.add(new B());
В тази ситуация, How да изчислим размера на всяка клетка? В края на краищата всеки обект ще бъде различен, евентуално с различни допълнителни полета. Какво да правя? Тук въпросът е поставен по начин, който има за цел да ви обърка. Знаем, че колекцията не съхранява директно обекти. Той съхранява само препратки към обекти. И всички препратки имат еднакъв размер и това е известно. В резултат на това изчисляваме addressите тук по същия начин, Howто в предишния въпрос.
21. Автобоксиране и разопаковане
Исторически контекст: автоматичното поставяне в кутия и разопаковане са някои от основните нововъведения в JDK 5. Автоматичното поставяне в кутия е процесът на автоматично преобразуване от примитивен тип в съответен клас обвивка. Unboxing е точно обратното на autoboxing. Това е процес на преобразуване на обвиващ клас в примитивен. Но ако стойността на обвивката еnull
, тогава NullPointerException
ще бъде хвърлено по време на разопаковане.
Примитиви и съответните им обвивки
Примитивен | Клас обвивка |
---|---|
булево | Булева стойност |
вътр | Цяло число |
byte | Байт |
въглен | Характер |
плавам | Поплавък |
дълго | Дълги |
къс | Къс |
двойно | Двойна |
// Autoboxing се случва:
-
когато присвоявате примитив на препратка към клас обвивка:
ПРЕДИ Java 5:
// Manual boxing (the way it was BEFORE Java 5). public void boxingBeforeJava5() { Boolean booleanBox = new Boolean(true); Integer intBox = new Integer(3); // And so on for other types } After Java 5: // Automatic boxing (the way it became in Java 5). public void boxingJava5() { Boolean booleanBox = true; Integer intBox = 3; // And so on for other types }
-
когато примитив се предава като аргумент на метод, който очаква обвивка:
public void exampleOfAutoboxing() { long age = 3; setAge(age); } public void setAge(Long age) { this.age = age; }
// Разопаковането се случва:
-
когато присвоим екземпляр на клас обвивка на примитивна променлива:
// BEFORE Java 5: int intValue = new Integer(4).intValue(); double doubleValue = new Double(2.3).doubleValue(); char c = new Character((char) 3).charValue(); boolean b = Boolean.TRUE.booleanValue(); // And after JDK 5: int intValue = new Integer(4); double doubleValue = new Double(2.3); char c = new Character((char) 3); boolean b = Boolean.TRUE;
-
По време на аритметични операции. Операциите се прилагат само за примитивни типове, така че е необходимо разопаковане на примитиви.
// BEFORE Java 5: Integer integerBox1 = new Integer(1); Integer integerBox2 = new Integer(2); // A comparison used to require this: integerBox1.intValue() > integerBox2.intValue() // In Java 5 integerBox1 > integerBox2
-
при предаване на екземпляр на клас обвивка към метод, който приема съответния примитив:
public void exampleOfAutoboxing() { Long age = new Long(3); setAge(age); } public void setAge(long age) { this.age = age; }
22. Коя е крайната ключова дума и къде се използва?
Ключоватаfinal
дума може да се използва за променливи, методи и класове.
- Стойността на крайната променлива не може да бъде променена, след като е инициализирана.
- Последен клас е стерилен :) Не може да има деца.
- Последният метод не може да бъде заменен от наследник.
Крайни променливи
Java ни дава два начина да декларираме променлива и да й присвоим стойност:- Можете да декларирате променлива и да я инициализирате по-късно.
- Можете да декларирате променлива и да присвоите стойност веднага.
public class FinalExample {
// A static final variable that is immediately initialized:
final static String FINAL_EXAMPLE_NAME = "I'm likely the final one";
// A final variable that is not initialized, but will only work if you
// initialize it in the constructor:
final long creationTime;
public FinalExample() {
this.creationTime = System.currentTimeMillis();
}
public static void main(String[] args) {
FinalExample finalExample = new FinalExample();
System.out.println(finalExample.creationTime);
// The final FinalExample.FINAL_EXAMPLE_NAME field cannot be accessed
// FinalExample.FINAL_EXAMPLE_NAME = "Not you're not!";
// The final Config.creationTime field cannot be accessed
// finalExample.creationTime = 1L;
}
}
Може ли крайната променлива да се счита за константа?
Тъй като не можем да присвоим нови стойности на крайните променливи, изглежда, че това са постоянни променливи. Но само на пръв поглед: ако типът данни на променливата еimmutable
, тогава, да, това е константа. Но ако типът данни е mutable
, тоест променлив, тогава ще бъде възможно да се използват методи и променливи за промяна на стойността на обекта, към който се отнася променливата final
. Поради това не може да се нарече константа. Следващият пример показва, че някои крайни променливи са наистина константи, докато други не са, тъй като могат да бъдат променяни.
public class FinalExample {
// Immutable final variables
final static String FINAL_EXAMPLE_NAME = "I'm likely the final one";
final static Integer FINAL_EXAMPLE_COUNT = 10;
// Mutable final variables
final List<String> addresses = new ArrayList();
final StringBuilder finalStringBuilder = new StringBuilder("Constant?");
}
Локални крайни променливи
Когатоfinal
променлива е създадена в рамките на метод, тя се нарича променлива local final
:
public class FinalExample {
public static void main(String[] args) {
// You can do this
final int minAgeForDriveCar = 18;
// Or you can do this, in a for-each loop:
for (final String arg : args) {
System.out.println(arg);
}
}
}
Можем да използваме ключовата дума final в подобрен for цикъл, тъй като след всяка итерация на цикъла се създава нова променлива. Имайте предвид, че това не се отнася за нормален for цикъл, така че ще получим грешка по време на компorране.
// The final local j variable cannot be assigned
for (final int i = 0; i < args.length; i ++) {
System.out.println(args[i]);
}
Заключителен клас
Клас, деклариран като,final
не може да бъде разширен. Казано по-просто, никой друг клас не може да го наследи. Отличен пример за final
клас в JDK е String. Първата стъпка към създаването на неизменен клас е да го маркирате като final
, като по този начин предотвратите разширяването му:
public final class FinalExample {
}
// Compilation error!
class WantsToInheritFinalClass extends FinalExample {
}
Крайни методи
Когато даден метод е маркиран като окончателен, той се нарича окончателен метод (има смисъл, нали?). Краен метод не може да бъде заменен в дъщерен клас. Между другото, методите wait() и notify() на класа Object са окончателни, така че нямаме възможност да ги заменим.
public class FinalExample {
public final String generateAddress() {
return "Some address";
}
}
class ChildOfFinalExample extends FinalExample {
// Compilation error!
@Override
public String generateAddress() {
return "My OWN Address";
}
}
Как и къде да използвате final в Java
- Използвайте ключовата дума final, за да дефинирате някои константи на ниво клас;
- Създайте крайни променливи за обекти, които не искате да бъдат променяни. Например, специфични за обекта свойства, които можем да използваме за целите на регистриране.
- Ако не искате класът да бъде удължен, тогава го маркирайте като окончателен.
- Ако трябва да създадете неизменен клас, трябва да го направите окончателен.
- Ако искате изпълнението на даден метод да не се променя в неговите наследници, тогава маркирайте метода като
final
. Това е много важно, за да сте сигурни, че изпълнението няма да се промени.
23. Какво представляват изменяемите и неизменяемите типове?
Променлив
Променливите обекти са обекти, чието състояние и променливи могат да бъдат променяни след създаването. Примери за променливи класове включват StringBuilder и StringBuffer. Пример:
public class MutableExample {
private String address;
public MutableExample(String address) {
this.address = address;
}
public String getAddress() {
return address;
}
// This setter can change the name field
public void setAddress(String address) {
this.address = address;
}
public static void main(String[] args) {
MutableExample obj = new MutableExample("First address");
System.out.println(obj.getAddress());
// We are updating the name field, so this is a mutable object
obj.setAddress("Updated address");
System.out.println(obj.getAddress());
}
}
Неизменна
Неизменните обекти са обекти, чието състояние и променливи не могат да бъдат променяни след създаването на обекта. Страхотен ключ за HashMap, не мислите ли? :) Например String, Integer, Double и т.н. Пример:
// We'll make this class final so no one can change it
public final class ImmutableExample {
private String address;
ImmutableExample(String address) {
this.address = address;
}
public String getAddress() {
return address;
}
// We remove the setter
public static void main(String[] args) {
ImmutableExample obj = new ImmutableExample("Old address");
System.out.println(obj.getAddress());
// There is no way to change this field, so it is an immutable object
// obj.setName("new address");
// System.out.println(obj.getName());
}
}
В следващата част разглеждаме въпроси и отговори относно колекциите. Моят профил в GitHub Топ 50 въпроса и отговори за интервю за работа за Java Core. Част 2
GO TO FULL VERSION