-
Notifications
You must be signed in to change notification settings - Fork 5
/
content.txt
5343 lines (4471 loc) · 665 KB
/
content.txt
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
! Java interview Q&A
** Java interview questions and answers
* Исключения, роль наследования в обработке исключений. Что знаешь о try, final/finally/finalize. Секция throws в сигнатуре метода
Ключевое слово final означает, что final-класс не может быть расширен, метод – переопределен, значение переменной – изменено.
В блок try помещается критический блок кода, который может бросать исключения. Обработка исключений ведется в блоке catch. Блок finally выполняется всегда, кроме случая потоков-демонов и вызова System.exit(0).
Инструкция throws в сигнатуре метода означает, что метод может бросить указанное исключение. Тот, кто вызывает метод должен обработать его или передать выше. Throws в классах-потомках – см. п.Полиморфизм.
При перечислении блоков catch вначале следует указывать исключения-потомки, потом – предки. В обратном случае будет обработано исключение более общего класса и следующий блок catch не вызовется.
Метод finalize() вызывается сборщиком мусора до освобождения памяти, занимаемой объектом. Это означает, что неизвестно, когда объект будет финализирован. Поэтому надо избегать освобождать в нем такие ресурсы, как дескрипторы файлов, сокеты, соединения с БД и т.д., т.к. Java имеет конечное кол-во таких ресурсов и неизвестно, когда сборщик освободит эти ресурсы вызовом finalize-метода.
* Назвать и описать J2EE-паттерны: Factory, Builder, Command, MVC, Front Controller, Controller, Decorator, DTO, DAO и т.д.
* Fundamental patterns:
= Delegation (Делегирование) - объект внешне выражает некоторое поведение, но в реальности передаёт ответственность за выполнение этого поведения связанному объекту.
= Functional design (Функциональный дизайн) - гарантирует, что каждый модуль компьютерной программы имеет только одну обязанность и исполняет её с минимумом побочных эффектов на другие части программы.
= Immutable (Неизменяемый) – объект, который не может быть изменён после своего создания.
= Interface (Интерфейс) - общий метод для структурирования компьютерных программ для того, чтобы их было проще понять.
* Creational (порождающие) patterns:
= Abstract Factory (абстрактная фабрика) – класс, который представляет интерфейс для создания компонентов системы.
= Builder (строитель) – класс, который представляет интерфейс для создания сложного объекта.
= Factory method (фабричный метод) – определяет интерфейс для создания объекта, но оставляет подклассам решение о том, какой класс инстанциировать.
= Lazy initialization (отложенная инициализация) – объект, инициализируемый во время первого обращения к нему.
= Object pool (объектный пул) – класс, который представляет собой интерфейс для работы с набором инициализированных и готовых к использованию объектов.
= Singleton (одиночка) – класс, который может иметь только один экземпляр.
* Structural (структурные) patterns:
= Adapter/Wrapper (Адаптер) – Объект, обеспечивающий взаимодействие двух других объектов, один из которых использует, а другой предоставляет несовместимый с первым интерфейс.
= Bridge (Мост) - Структура, позволяющая изменять интерфейс обращения и интерфейс реализации класса независимо.
= Composite (Компоновщик) - Объект, который объединяет в себе объекты, подобные ему самому (объект может быть представлен одиночным объектом или набором (коллекцией) объектов).
= Decorator (Декоратор) - добавление/ограничение функциональности объекта во время выполнения, без наследования (наследование добавляет функциональность к классам во время компиляции). Этот паттерн реализуют классы пакета java.io.*. Пример:
= File file = new File(“file-name”);
= FileInputStream fis = new FileInputStream(file);
= BufferedInputStream fis = new BufferedInputStream(fis);
= Facade (Фасад) – объект, который абстрагирует работу с несколькими классами, объединяя их в единое целое.
= Flyweight (Приспособленец) – объект, представляющий себя как уникальный экземпляр в разных местах программы, но по факту не являющийся таковым. Цель – оптимизация работы с памятью путем предотвращения создания экземпляров эл-тов, имеющих общую сущность. Св-ва приспособленца делятся на внешние и внутренние; внутренние – всегда неизменны, внешние могут отличаться в зависимости от места и контекста применения и должны быть вынесены за пределы приспособленца. Дополняет Factory, которая создает новый объект только, если нет уже созданного с нужными параметрами. Пример: String.
= Proxy (Заместитель) - объект, который является посредником между двумя другими объектами, и который реализовывает/ограничивает доступ к объекту, к которому обращаются через него.
* Behavioral (поведенческие) patterns:
= Command (Команда) - представляет действие. Объект команды заключает в себе само действие и его параметры.
= Iterator/Cursor (Итератор) – поведенческий паттерн, обеспечивает путь получения эл-тов коллекции последовательно без открытия ее внутреннего представления.
= Memento/Token (Хранитель) - позволяет не нарушая инкапсуляцию зафиксировать и сохранить внутреннее состояния объекта так, чтобы позднее восстановить его в этом состоянии.
= Null object – предотвращает нулевые указатели, предоставляя объект “по умолчанию”.
= Observer (Наблюдатель) - определяет зависимость типа «один ко многим» между объектами таким образом, что при изменении состояния одного объекта все зависящие от него оповещаются об этом событии.
= Reactor (Реактор) – демультиплексирует сообщения, разделяя один поток сообщений на несколько потоков, и передает их обработчиками. Похож на Observer (Publisher) паттерн, но у того только один источник сообщений, тогда как реактор перехватывает сообщения от нескольких источников.
= Chain of responsibility (цепочка обязанностей) – сообщения в системе обрабатываются по схеме “обработай сам, либо перешли другому”; в системе имеется группа объектов, которые могут обрабатывать сообщения определенного типа.
= Mediator (Посредник) – обеспечивает взаимодействие множества объектов, формируя при этом слабую связанность и избавляя объекты от необходимости явно ссылаться друг на друга (частный случай Mediator-а - Front Controller – обеспечивает централизованную входную точку для обработки запросов).
* Написать Singleton
1. Неленивые Singleton-ы
```
public class Singleton { // Static field
public static final Singleton INSTANCE = new Singleton();
}
public enum Singleton { // Enum Singleton
INSTANCE;
}
```
2. Ленивые Singleton-ы
```
public class Singleton { // Synchronized Accessor
private static Singleton instance;
public static synchronized Singleton getInstance() {
if (instance == null) {
instance = new Singleton();
}
return instance;
}
}
public class Singleton { // Double Checked Locking & volatile
private static volatile Singleton instance;
public static Singleton getInstance() {
Singleton localInstance = instance;
if (localInstance == null) {
synchronized (Singleton.class) {
localInstance = instance;
if (localInstance == null) {
instance = localInstance = new Singleton();
}
}
}
return localInstance;
}
}
public class Singleton { // On Demand Holder idiom
public static class SingletonHolder {
public static final Singleton HOLDER_INSTANCE = new Singleton();
}
public static Singleton getInstance() {
return SingletonHolder.HOLDER_INSTANCE;
}
}
```
Советы по использованию Singleton:
1) Использовать нормальную (не ленивую) инициализацию везде где это возможно (п.2)
2) Для статических полей использовать On Demand Holder idiom (п.2.3)
3) Для простых полей использовать Double Checked Lock & volatile idiom (п.2.2)
4) Во всех остальных случаях использовать Synchronized accessor (п.2.1)
* Struts
Struts framework – среда для разработки Java EE web-приложений с помощью технологий Java Servlet и JSP. Способствует разработке приложений с архитектурой, соответствующей паттерну MVC, Model2. Включает следующие основные ф-ции:
1. Controller servlet, который координирует запросы к соответствующим Action классам, созданным разработчиком. Те обращаются к модели; модель возвращает строку “ActionForward”, сообщая контроллеру, какую страницу отправить клиенту. Класс ActionForm помогает передавать данные между моделью и представлением.
2. Библиотеки JSP-тегов и их поддержка в сервлете-контроллере для создания интерактивных приложений, основанных на веб-формах
3. Вспомогательные классы для парсинга XML, автоматического наполнения JavaBeans, i18n сообщений, валидации входных данных, создания шаблонов (tiles)
Разработчик пишет код модели (представляющей обычно набор JavaBeans) и создает конф. файл struts-config.xml, который связывает воедино модель, представление и контроллер.
* Что такое JSF? Чем JSF лучше Struts?
JSF – фреймворк для веб-приложений, написанный на Java. Служит для того, чтобы облегчить разработку пользовательских интерфейсов для Java EE приложений. В отличие от прочих MVC фреймворков, управляемых запросами, JSF основывается на использовании компонентов. Для отображения используются JSP, Facelets.
JSF включает:
• Набор API для представления компонент пользовательского интерфейса и управления их состоянием, обработкой событий и валидацией вводимой информации, определения навигации, а также поддержку i18n и доступности
• Специальная библиотека JSP тегов для выражения интерфейса JSF на JSP странице
Технология JSF усиливает существующие концепции пользовательского интерфейса и концепции web-уровня без привязки разработчика к конкретному языку разметки, протоколу или клиентскому устройству. Возможно настраивать рендеринг JSF-компонент на различных клиентских устройствах (библиотека JSP-тегов для рендеринга на HTML-клиенте).
Чем JSF лучше Struts для меня: произвожу описание только вида и модели, без контроллера. Автоматически: данные отображаются из вида в модель, происходит валидация. Возможно визуальная настройка переходов между страницами вида. Можно использовать шаблоны, вкладывая их один в другой.
* Spring. Spring IoC. AoP.
= Spring Framework – универсальный фреймворк с открытым исходным кодом на Java. Может быть рассмотрен как коллекция меньших фреймворков или фреймворков во фреймворке. Большинство из них может работать независимо друг от друга. Spring делится на структурные эл-ты:
• Inversion of Control контейнер: конфигурирование компонент приложений и управление жизненным циклом Java-объектов
• Фреймворк аспектно-ориентированного программирования: работает с функциональностью, которая не может быть реализована возможностями объектно-ориентированного программирования на Java без потерь
• Фреймворк доступа к данным: работает с системами управления реляционными БД на Java платформе используя JDBC и Object-relational mapping средства обеспечивая решения задач, которые повторяются в большом числе Java-based environments
• Фреймворк управления транзакциями: координация различных API управления транзакциями и инструментарий настраиваемого управления транзакциями для объектов Java
• Фреймворк MVC: каркас, основанный на HTTP и сервлетах предоставляющий множество возможностей для расширения и настройки (customization)
• Фреймворк удалённого доступа: конфигурируемая передача Java-объектов через сеть в стиле RPC, поддерживающая RMI, CORBA, HTTP-based протоколы, включая web-сервисы (SOAP)
• Фреймворк аутентификации и авторизации
• Фреймворк удалённого управления: конфигурируемое представление и управление Java объектами для локальной или удалённой конфигурации с помощью JMX
• Фреймворк работы с сообщениями: конфигурируемая регистрация объектов-слушателей сообщений для прозрачной обработки сообщений из очереди сообщений с помощью JMS, улучшенная отправка сообщений по стандарту JMS API
• Тестирование: каркас, поддерживающий классы для написания модульных и интеграционных тестов
Центральной частью Spring является IoC контейнер, предоставляющий ср-ва конфигурирования и управления объектами Java при помощи рефлексии. Контейнер отвечает за управление жизненным циклом объекта: создание, вызов методов инициализации и конфигурирование объектов путем связывания между собой.
Объекты, создаваемые контейнером, называются Beans. Обычно конфигурирование контейнера осуществляется посредством XML-файлов, содержащих определение Bean-ов и предоставляющих информацию, необходимую для создания Bean-ов. Объекты могут быть получены либо с помощью поиска зависимости, либо внедрения зависимости.
Поиск зависимости – шаблон проектирования, когда вызывающий объект запрашивает у объекта-контейнера экземпляр объекта с определенным именем или определенного типа.
Внедрение зависимости (Dependency injection) - шаблон проектирования, когда контейнер передает экземпляры объектов по их имени другим объектам либо с помощью конструктора, либо свойства, либо фабричного метода. Является специфичной формой обращения контроля (IoC), где изменение порядка связи является путем получения необходимой зависимости.
= AoP (АОП, аспектно-ориентированно программирование) – парадигма программирования, основанная на идее разделения функциональности для улучшения разбиения программы на модули.
Аспект – модуль или класс, реализующий сквозную функциональность.
Сквозная функциональность – функциональность, которую нельзя выделить в отдельные сущности, ее реализация рассыпана по различным модулям программы. СФ приводит к рассредоточенному и запутанному коду, сложному для понимания и сопровождения.
Примеры сквозной функциональности: ведение лога, обработка ошибок, трассировка, авторизация. Для программы, написанное в парадигме ООП, любая функциональность, по которой не была проведена декомпозиция, является сквозной.
* Что такое сервер приложений? Что такое веб-сервер, в чём его отличие от сервера приложений? Привести примеры веб-сервера и сервера приложений. Минимальные требования для веб-приложения.
Сервер – ПО, выполняющееся на некотором аппаратном обеспечении, и исполняющее сервисные (т.е. обслуживающие) функции по запросу клиента, предоставляя ему доступ к определенным ресурсам.
Веб-сервер – сервер, принимающий HTTP-запросы от клиентов (обычно веб-браузеров), и выдающий им HTTP-ответы. Веб-сервером могут называть как ПО с такими функциями, так и сам компьютер, на котором оно выполняется.
Примеры веб-серверов: Apache, IIS, nginx, lighttpd.
Веб-приложение – клиент-серверное приложение, в котором клиент – браузер, а сервер – веб-сервер. Клиенты не зависят от ОС пользователя, поэтому веб-приложения являются межплатформенными сервисами. Состоит из клиентской и серверной части.
Минимальные требования для веб-приложения:
• веб-сервер с запущенным на нем сервлетом
• mapping в конфигурационном файле сервлета, чтобы клиент мог получить доступ к сервлету
• наличие браузера у клиента
Сервер приложений – программная платформа (software framework), предназначенная для исполнения процедур (программ, скриптов), которые поддерживают построение приложений. Действует как набор компонентов, доступных разработчику через API, который определен самой платформой. Термин сервер приложений часто используется для веб-серверов, которые поддерживают Java EE, хотя он не ограничивается только Java.
Преимущества сервера приложений:
• Целостность – гарантированные обновления и улучшения приложений для всех пользователей
• Централизованная настройка и управление – изменения настроек (сервера БД или системных) могут производиться централизованно
• Безопасность – можно управлять доступом к данным и частям приложений
• Поддержка транзакций – единицы активности, во время которой большое число изменений ресурсов может быть выполнено атомарно
Современные серверы приложений не только генерируют страницы, но и выполняют такие сервисы, как кластеризация, отказоустойчивость, балансировка нагрузки, позволяя разработчикам сфокусироваться на реализации бизнес-логики.
Термин сервер приложений обычно относится к Java-серверам приложений. В этом случае сервер приложений ведет себя как расширенная виртуальная машина для запуска приложений, прозрачно управляя соединениями с БД с одной стороны и соединениями с веб-клиентом с другой.
Примеры серверов приложений: GlassFish, WebSphere, JBoss, Zope.
* Контейнер сервлетов. Сервлет, его методы, жизненный цикл.
Контейнер сервлетов (Web-контейнер) (КС) – компонент веб-сервера для взаимодействия с сервлетами. КС отвечает за управление жизненным циклом сервлетов, мэпингом URL к конкретному сервлету, идентификацию и авторизацию клиента, запрашивающего URL, организацию сессии для клиента. Может работать как самостоятельный веб-сервер или интегрироваться в Java EE сервер приложений.
Примеры КС: Apache Tomcat, JBoss, GlassFish, WebSphere.
Сервлет – Java-программа, выполняющаяся на стороне сервера и расширяющая его функциональные возможности. Взаимодействует с клиентами посредством принципа запрос-ответ. Реализует Servlet интерфейс, который определяет методы жизненного цикла.
Жизненный цикл сервлета состоит из следующих шагов:
1. В случае отсутствия сервлета в контейнере:
• Класс сервлета загружается контейнером
• Контейнер создает экземпляр класса сервлета
• Контейнер вызывает метод init(). Он инициализирует сервлет и вызывается в первую очередь, до того, как сервлет сможет обслуживать запросы. За весь жизненный цикл метод init() вызывается только однажды
2. Обслуживание клиентского запроса. Каждый запрос обрабатывается в своем отдельном потоке. Контейнер вызывает метод service() для каждого запроса. Этот метод определяет тип пришедшего запроса и распределяет его в соответствующий этому типу метод для обработки запроса (doGet(), doPost(), doPut(), doDelete() и т.д.). Разработчик сервлета должен предоставить реализацию для этих методов. Если поступил запрос, метод для которого не реализован, вызывается метод родительского класса и обычно завершается возвращением ошибки инициатору запроса.
3. В случае, если контейнеру необходимо удалить сервлет, он вызывает метод destroy(). Подобно методу init(), этот метод тоже вызывается единожды за весь цикл сервлета.
API сервлета определяют взаимодействие КС и сервлета, содержатся в Java пакете javax.servlet. Классы для HTTP – в пакете javax.servlet.http.
* Отличие getParameter от getAttribute в сервлете.
getParameter возвращает (в виде String) значение параметра, который был отправлен HTML-формой или был включен в строку запроса. getAttribute возвращает Java-объект, который был сохранен в текущем контексте (по сути – в сессии).
* Можно ли в web.xml определить сервлет без указания url паттерна и как к нему обратиться?
В файле <Tomcat directory>/conf/web.xml можно раскомментировать invoker servlet, который может запускать анонимные сервлеты (mapping которых не указан). Синтаксис следующий:
http://<host>:<port>/<appname>/servlet/<full qualified class name (т.е. пакет+имя.класса)>
В данный момент invoker считается deprecated.
* Что такое сессия?
Сессия – информационный диалог между двумя и более коммуникационными устройствами или компьютером и юзером. Длится какой-то промежуток времени. Могут отправляться сообщения в обоих направлениях. Чаще всего хотя бы одно из взаимодействующих устройств сохраняет информацию о сессии, реже – взаимодействие состоит из независимых request-ов с response-ами.
Для сервлета сессия – файл, создаваемый на сервере, куда сохраняются данные, присланные пользователем. Клиенту выдается “ключ сессии” (Session ID) – уникальный указатель на этот файл.
* Что нужно сделать пользователю, чтобы зайти на сайт и что происходит при этом?
Пользователь должен иметь подключение к Интернету, браузер и знать url сайта. При этом прописанные в его системе DNS преобразуют url в ip-адрес, к которому браузер и осуществляет запрос. DNS-сервер кэширует запросы. По заданному адресу должен располагаться веб-сервер, который передаст браузеру свою стартовую страницу.
* Что нужно написать в браузерной строке, чтобы обратиться к сервлету? Как обратиться к конкретному сервлету? Можно ли из браузерной строки напрямую вызвать метод сервлета?
Для обращения к сервлету используется запись: http://<host>:<port>/<context path>/<servlet name (in web.xml)>. Для обращения к конкретному сервлету надо использовать соответствующее имя в web.xml.
Напрямую вызвать метод сервлета нельзя; контейнер вызывает метод service() для каждого запроса. Метод service() определяет тип пришедшего запроса и распределяет его в соответствующий этому типу метод для обработки запроса (doGet(), doPost(), doPut(), doDelete() и т.д.).
* HTTP. Описать структуру HTTP-протокола.
HTTP – протокол прикладного уровня передачи данных. Его основой является технология “клиент-сервер”, т.е. предполагается существования потребителей (клиентов) и поставщиков (серверов), которые ожидают соединения для получения запроса, производят необходимые действия и возвращают обратно сообщение с результатом. Используется в качестве “транспорта” для других протоколов прикладного уровня (SOAP, XML-RPC). Основным объектом манипуляции в HTTP является ресурс, на который указывает URI в запросе клиента. Ресурсами могут быть файлы, логические объекты или что-то абстрактное. Особенностью является возможность указания в запросе и ответе способа представления одного и того же ресурса по различным параметрам (формату, кодировке, языку) (указывается в заголовке HTTP). Именно благодаря возможности указания способа кодирования сообщения клиент и сервер могут обмениваться двоичными данными, хотя сам протокол текстовый. Не поддерживает сохранение состояния между парами “запрос-ответ”. Состояние может сохраняться в куки на стороне клиента и сессии на стороне сервера.
Достоинства протокола:
• Простота в реализации
• Расширяемость благодаря внедрению собственных заголовков. Совместимость с другими клиентами и серверами при этом сохраняется: они будут просто игнорировать неизвестные им заголовки
• Распространенность: поддержка протокола в качестве клиента многими программами, выбор среди хостинговых компаний с серверами HTTP
Недостатки протокола:
• Большой размер сообщений по сравнению с передачей двоичных данных
• Отсутствуют в явном виде ср-ва навигации по ресурсам сервера (например: нельзя запросить список доступных файлов)
• Нет поддержки распределенности
Каждое HTTP-сообщение состоит из трех частей, которые передаются в указанном порядке:
1. Стартовая строка (Starting line) – определяет тип сообщения. Содержит метод (указывает операцию над ресурсом), URI, версию протокола
2. Заголовки (Headers) – характеризуют тело сообщения, параметры передачи и прочие сведения (содержат строки с парами параметр:значение)
3. Тело сообщения (Message Body) – непосредственно данные сообщения. Обязательно должно отделяться от заголовков пустой строкой. Тело может отсутствовать.
HTTPS – расширение протокола HTTP, поддерживающее шифрование. Данные “упаковываются” в криптографический протокол SSL или TLS.
Для HTTP обычно используются TCP-порты 80 или 8080, а для HTTPS - 443.
* Зачем нужен объект request?
Контейнер сервлетов создает объект request класса HttpServletRequest и передает его как аргумент в методы сервлета (doGet, doPost и т.д.). Объект request содержит информацию запроса для HTTP-сервлета (пары “ключ-значение” параметров, заголовки запросов, Cookies, URL запроса и т.д.).
* Lifecycle of JSP. Является ли jsp сервлетом? Области видимости переменных в JSP.
JSP – технология, позволяющая создавать содержимое со статическими и динамическими компонентами. Могут использоваться библиотеки JSP тегов, а также EL (Expression Language), для внедрения Java-кода в статическое содержимое JSP-страниц. Отличие между сервлетом и JSP в том, что сервлет обычно внедряет HTML в Java-код, а JSP – наоборот.
В JSP могут использоваться: HTML, комментарии (игнорируются транслятором), скриптовые элементы (Java-код, который впоследствии станет частью конечного сервлета), директивы (начинаются с <%@, позволяют управлять структурой сервлета), действия (для задания используемых beans и контроля над поведением движка сервлета).
Весь код страницы компилируется в java-код сервлета JSP-компилятором Jasper, а затем транслируется в байт-код JVM (потом исполняется - интерпретатором) (т.е. JSP является сервлетом). JSP-компилятор обычно является составной частью сервера приложений и запускается автоматически при первом доступе к JSP, но страницы также могут быть прекомпилированы для улучшения производительности или отслеживания ошибок.
Есть 4 области видимости JavaBean в JSP: page, request, session, application. Без явного указания используется scope=”page”.
* Отличие jsp:include от директивы include.
• Действие jsp:include вставляет содержимое файла при запросе JSP-страницы (поэтому во вставляемом файле исключается наличие кода JSP). Потеря эффективности, но преимущество в гибкости.
Пример записи: <jsp:include page="relativeURL" [flush="true"]>. Необязательный аттрибут flush управляет (не)освобождением буфера выходного потока страницы JSP.
• Директива include вставляет содержимое файла (текстового или JSP) на этапе трансляции. Процедура вставки происходит статически, т.е. текст включаемого файла добавляется к JSP. Если включаемый файл – JSP, его JSP-элементы будут транслироваться наряду с элементами исходного файла.
Пример записи: <%@ include file="relativeURL" %>
В обоих случаях URL интерпретируется относительно страницы, на которой расположено действие/директива, но можно задать расположение относительно корня сервлета, добавив в начало URL символ “/”.
* Чем отличаются методы POST и GET? Если не указать напрямую, какой из этих методов выполнится по умолчанию?
Метод GET (он выполняется по умолчанию) передает всю информацию в заголовке запроса (через URL), а POST – внутри тела запроса. Заголовок запроса имеет ограничение на максимальный размер, соответственно, в GET ограничен объем передаваемых данных.
В спецификации HTTP указано, что метод GET не должен иметь смысл действия, отличного от получения запрашиваемой информации (поэтому он называется «безопасным»). Для выполнения каких-либо операций, изменяющих данные на сервере, должен использоваться метод POST.
Ответы на POST запросы никогда не кэшируются, на GET – кэшируются по умолчанию (может быть отключено изменением заголовка страницы ответа, посылаемого сервером).
POST запрос может “симулировать” GET запрос, указывая параметры как в заголовке запроса, так и в теле.
“Главное” отличие – GET не может передать файл, а POST – может.
* У нас есть одна форма в ней 2 input поля и submit, как переслать первое поле методом POST, второе методом GET? Зачем это может понадобиться?
См. ответ на предыдущий вопрос (о симуляции GET запроса). Это (наверное) может понадобиться, если после нажатия на submit новый url должен содержать значение поля, пересылаемого методом GET.
* В чём различие forward и redirect? Что делает RequestDispatcher.include()?
Пересылка (forward) осуществляется на стороне сервера, при этом новая страница обрабатывает тот же запрос, что и предыдущая. Браузер при этом не догадывается, что в процессе задействовано несколько страниц.
Переадресация (redirect) означает, что первая страница требует от браузера сделать новый запрос к нужной странице. Поэтому URL в браузере будет заменен на новый.
• Переадресация медленнее (т.к. браузер повторяет запрос)
• Объекты, помещенные в контекст запроса, после переадресации становятся недоступными, т.к. создается новый запрос
RequestDispatcher – инструмент для того, чтобы переслать запрос другому ресурсу. Содержит только 2 метода: forward(request, response) – для перенаправления запроса, include(request, response) – для включения в результат работы текущего сервлета результата работы вызываемого сервлета.
RequestDispatcher.include() включает в текущий сервлет статическое содержимое (HTML, JavaScript) каждый раз, когда сервлет обрабатывает запрос.
* Что такое classpath? Если в classpath есть две одинаковые библиотеки (или разные версии одной библиотеки), объект класса из какой библиотеки создастся?
Classpath – это переменная окружения; содержит пути к классам, jar-файлам.
Если в classpath есть несколько одинаковых библиотек, создастся класс из библиотеки, объявленной первой.
* Как скомпилировать и запустить класс, используя консоль?
• <Путь_к_JDK>\bin\javac <Путь_к_java-классу>\<Имя_класса>.java
После этого в папке с java-файлом появится файл <Имя_класса>.class
Более подробно: <Путь_к_JDK>\bin\javac -d <Директория_build> -sourcepath <Список_директорий_через_;> <Путь_к_java-классу>\<Имя_класса>.java
• <Путь_к_JDK>\bin\java <Путь_к_java-классу>\<Имя_класса>
Если путь к JDK прописан в classpath:
• javac <Путь_к_java-классу>\<Имя_класса>.java
• java <Путь_к_java-классу>\<Имя_класса>
* Какие различия в архитектуре, процессе компиляции исходного кода и запуска программ на java и c++? За счёт чего обеспечивается кроссплатформенность приложений на java?
Исходный код транслируется в промежуточный байт-код, формат которого не зависит от архитектуры компьютера. Непосредственно во время работы программы для увеличения производительности байт-код компилируется JIT-компилятором в машинный код. Поэтому программа может выполняться на любых процессорах; для ее работы необходима только JVM (она интерпретирует байт-код). В отличие от С и С++ элементы спецификации Java не зависят от реализации: размеры основных типов данных и арифметические операции над ними строго определены.
* Коллекции, их виды, основные интерфейсы. Особенности разных видов коллекций. Когда какие стоит применять? В частности: сравнить ArrayList и LinkedList, HashMap и Hashtable. Коллекции из пакета concurrent. Реализации коллекций.
http://java.sun.com/docs/books/tutorial/collections/index.html
http://habrahabr.ru/post/127864/
Collection, Set, List, Queue, Map, SortedSet, SortedMap - интерфейсы.
Коллекция (К) представляет собой группу объектов, называемых ее элементами. Класс Collection является базовым для всех Java-коллекций. Перебирать элементы коллекции можно двумя способами:
• при помощи конструкции for-each: for (Object o: collection) { ... }
• при помощи итератора:
```
Iterator it = collection.iterator;
while(it.hasNext()) {
Object o = it.next();
...
}
```
Итератор кроме методов next и hasNext также имеет метод remove, который может быть вызван 1 раз при каждом next (несоблюдение этого условия приводит к исключению).
Collection имеет методы: size, isEmpty, contains, add, remove.
Операции над всей коллекцией сразу:
• containsAll – возвращает true, если данная К содержит все эл-ты указанной К
• addAll – добавляет все элементы указанной К к данной К
• removeAll – удаляет из данной К все эл-ты, содержащиеся в указанной К
• retainAll - удаляет из данной К все эл-ты, НЕ содержащиеся в указанной К
• clear – удаляет все эл-ты К
• перевод коллекции в массив:
```
Object[] a = c.toArray(); //for Object type
String[] a = c.toArray(new String[0]); //for String type, for example
```
* Виды коллекций:
• Set (множество) – не может содержать одинаковых элементов. Интерфейс Set содержит только методы класса Collection и дополнительные ограничения, чтобы избегнуть дубликатов. Есть 3 реализации Set:
= HashSet, хранящий эл-ты в hashtable, что дает лучшую по производительности реализацию, но не гарантирует нужный порядок при итерации
= TreeSet, хранящий элементы в дереве; порядок элементов основывается на их значениях. Медленнее HashSet
= LinkedHashSet, реализующий hashtable с LinkedList, при этом порядок эл-тов основывается на порядке, в котором они добавлялись в множество. Помогает избежать хаотического порядка эл-тов, обеспечиваемого HashSet, чуть более высокой ценой
• List (список) – упорядоченная коллекция (последовательность). Может содержать одинаковые эл-ты. Вдобавок к методам, унаследованным от Collection, List включает следующие операции:
= Позиционный поиск: get(index) и установка: set(index, element)
= Поиск элемента, возвращение индекса: indexOf, lastIndexOf
= Получение собственных итераторов, использующих преимущества “последовательной” природы списка: listIterator(), listIterator(index)
= Получение подсписка текущего списка: subList(from, to)
Список обеспечивает кроме стандартного итератора свой собственный, расширенный итератор, который имеет дополнительные методы: hasPrevious, previous, nextIndex, previousIndex, set, add. Также возможно получить итератор уже установленный на указанный индекс.
Есть 2 реализации списка:
= ArrayList, обычно показывающий лучшую производительность
= LinkedList, дающий лучшую производительность при определенных условиях
= Vector – модифицированная, более ранняя реализация List. Имеет другие (более длинные) имена методов, некоторые методы отсутствуют. Потокобезопасен (обычные (не concurrent) коллекции - нет). Если не нужна потокобезопасность – рекомендуется использовать ArrayList, а не Vector
При добавлении новые эл-ты добавляются в конец списка.
• Queue (очередь) – содержит элементы в определенном порядке. Обычно – FIFO. Кроме методов Collection содержит новые методы:
Операция: Insert (вставляет элемент в порядке, соответствующем типу очереди)
Throws exception: add(e)
Return special value: offer(e)
Операция: Remove (возвращает и удаляет из начала очереди)
Throws exception: remove()
Return special value: poll()
Операция: Examine (возвращает, но не удаляет из начала очереди)
Throws exception: element()
Return special value: peek()
LinkedList реализует FIFO очередь.
PriorityQueue упорядочивает элементы в соответствии с их значениями.
• Map (карта) – объект, обеспечивающий mapping ключей их значениям. Ключи уникальны, не могут повторяться, в качестве ключей могут использоваться Immutable объекты. Методы интерфейса:
= Базовые операции: put, get, remove, containsKey, containsValue, size, isEmpty
= Операции со всей коллекцией сразу: putAll, clear
= Получение вида (view) коллекции: keySet, values, entrySet
Реализации карт: HashMap, TreeMap, LinkedHashMap. Их поведение и производительность аналогичны HashSet, TreeSet, LinkedHashSet.
Hashtable – потокобезопасная реализация Map.
Отличия Map от HashTable:
= Map – интерфейс, HashTable - реализация
= Map обеспечивает получение вида (view) коллекции (см. выше)
= Map позволяет осуществлять итерацию по ключам, значениям или парам ключ-значение; Hashtable не поддерживает 3й вариант
= Hashtable содержит метод contains, который возвращает true, если Hashtable содержит данное значение (а не ключ). Map содержит 2 различных метода: containsKey и containsValue
• SortedSet и SortedMap – множество и карта соответственно, отсортированные в соответствии с натуральным порядком значений эл-тов или в соответствии с компаратором, передаваемым в SortedSet/SortedMap при создании
Их реализации соответственно: TreeSet и TreeMap
Класс Collections содержит статические методы для работы с коллекциями: swap, shuffle, min, max, sort, reverse и т.д. Сортировка выполняется для объектов, реализующих интерфейс Comparable или с передачей в sort компаратора, сравнивающего два эл-та этого типа.
Коллекцию можно сделать синхронизированной при помощи методов класса Collections, например:
Map myMap = Collections.synchronizedMap(myMap); //один lock на весь map
Если класс содержит поле-коллекцию и для нее нужен getter, то возвращать лучше немодифицируемую копию, например: return Collections.unmodifiableSet(mySet).
Коллекции concurrent позволяют потокозащищенно получить любое кол-во одновременных чтений и настраиваемое кол-во одновременных записей. Concurrent Collections содержатся в пакете java.util.concurrent. Существуют следующие интерфейсы:
• BlockingQueue определяет FIFO структуру данных, которая обеспечивает операцию ожидания, пока очередь станет не пустой при получении эл-та и пока в очереди не появится место при добавлении эл-та в нее
Реализации:
ArrayBlockingQueue - блокирующая очередь (БО) на основе array,
DelayQueue - БО, элементы которой могут быть получены по истечению задержки
LinkedBlockingQueue,LinkedBlockingDeque - связанные блокирующие очередь и 2-стороння очередь
PriorityBlockingQueue – БО с приоритетом
SynchronousQueue – очередь, где каждый put должен подождать take и наоборот
• ConcurrentMap – подинтерфейс Map, который определяет полезные atomic операции. Эти операции удаляют или заменяют пару ключ-значение, только если ключ присутствует, или добавляют пару ключ-значение, только если ключ отсутствует
Реализации:
ConcurrentHashMap – блокирующий HashMap
ConcurrentSkipListMap – блокирующий TreeMap
• ConcurrentNavigableMap – подинтерфейс ConcurrentMap
ConcurrentSkipListMap (см. выше)
* Области памяти виртуальной машины (куча, стек и т.д.). Какие области памяти использует java для размещения простых типов, объектов, функций и т.д.?
Память JVM состоит из следующих сегментов:
• Не-куча/стек (non-heap). Стек создается для каждого потока, здесь размещаются локальные переменные примитивных типов и аргументы (значения, переданные методам). Создается при старте JVM
• Куча (heap). Здесь хранятся объекты и переменные примитивных типов, если они являются полями класса. Создается при старте JVM
• Код самой JVM, ее внутренние структуры и т.д.
Ответ на вопрос: функции хранятся в куче, а в стеке – стек их вызовов; простые типы и объекты хранятся в стеке, если являются локальными, или в куче в обратном случае.
* Как работает Garbage Collector в java? Какие самые распространенные алгоритмы? Можно ли самому указать сборщику мусора, какой объект удалить из памяти?
Работа сборщика мусора состоит из:
• определения недостижимых объектов
• собственно, сборки мусора
Для определения недостижимых объектов может использоваться один из двух подходов:
1. Алгоритм выставления флагов.
Для каждого объекта хранится бит, указывающий на достижимость объекта. Изначально все объекты, кроме корневых, считаются недостижимыми. Рекурсивно просматриваются и помечаются как достижимые объекты еще не помеченные и до которых можно добраться из корневых объектов по ссылкам. Объекты с неустановленным битом достижимости считаются недостижимыми. Данный алгоритм гарантированно удаляет неиспользуемые объекты с циклическими ссылками.
2. Алгоритм подсчета ссылок.
Ведется просто подсчет ссылок на объекты. Без дополнительных уточнений этот алгоритм не удаляет объекты с циклическими ссылками.
При сборке мусора используется одна из двух стратегий:
1. Неперемещающий сборщик быстрее освобождает память (нужна только пометка соответствующих блоков, как свободных), но тратит больше времени на ее выделение (память фрагментирована).
2. Перемещающий сборщик требует сравнительно больше времени при сборе мусора (тратится дополнительное время на дефрагментацию памяти и изменение всех ссылок на перемещаемые объекты), но перемещение позволяет использовать простой и быстрый алгоритм выделения памяти.
Неперемещающий сборщик лучше работает с инородным кодом (не изменяет положение существующих объектов в памяти). Также для работы с инородным кодом используется pinning – явная блокировка объекта, запрещающая его перемещение во время сборки мусора.
Практика показывает, что недавно созданные объекты чаще становятся недостижимыми, чем существующие длительное время. Поэтому, современные сборщики подразделяют все объекты на несколько поколений – серий объектов с близким временем существования. Как только память, выделенная одному из поколений, заканчивается, в этом поколении и во всех более «молодых» производится поиск недостижимых объектов. Все они удаляются, а оставшиеся переводятся в более «старое» поколение.
Самому нельзя указать сборщику мусора, что надо удалить определенный объект из памяти, т.к. поведение сборщика недетерминировано.
* Что такое поток? Какими способами можно создать поток, запустить его, остановить? Состояния потока. Как выполнить набор команд в отдельном потоке? Как остановить выполнение потока? Что лучше: наследоваться от Thread или реализовывать Runnable?
Термин поток может обозначать:
• Экземпляр класса java.lang.Thread, являющийся обычным объектом
• Поток выполнения – отдельный процесс, имеющий собственный стек вызовов. Поток выполнения самостоятельной подзадачи в многозадачном окружении. Программа пишется так, словно каждый поток запускается сам по себе и использует процессор в монопольном режиме. Процессор же переключается между потоками, выделяя каждому некоторый отрезок времени (либо используется многопроцессорный компьютер). Это позволяет масштабировать производительность (установкой доп. процессоров)
Для создания потока надо создать экземпляр класса Thread. У класса есть метод run, куда помещается код, который требуется выполнить в отдельном потоке. Определить и инстанциировать поток можно двумя способами:
• Расширить класс Thread:
```
public class MyThread extends Thread {
@Override
public void run() { ... }
}
...
MyThread t = new MyThread(); // Инстанциирование потока
t.start(); // Запуск потока
```
• Реализовать интерфейс Runnable:
```
class MyRunnable implements Runnable {
@Override
public void run() { ... }
}
...
MyRunnable r = new MyRunnable(); // Инстанциирование потока
Thread t = new Thread(r);
t.start(); //Запуск потока
```
Проще говоря, Thread – работник, Runnable – работа.
Предпочтительнее 2й способ, т.к. расширяя Thread, наш класс уже не сможет быть потомком другого класса.
Состояния потока:
• Инстанциированный, но незапущенный пока поток находится в состоянии new (новый) и считается not alive (не живым)
• После вызова метода start экземпляра потока, он становится alive (живым) и переходит в состояние runnable/ready-to-run (готов к запуску, работоспособный). То, что поток alive, не означает, что метод run уже начал выполняться. В состоянии runnable поток ждет своей очереди от процессора. В состояние runnable поток может перейти из состояния running
• Состояние running означает, что поток сейчас запущен. Существует несколько способов попасть в состояние runnable, но в running – есть один способ: планировщик потоков выбрал данный поток из пула потоков.
• Поток считается dead (мертвым) после того, как метод run закончит выполняться. Поток из этого состояния нельзя запустить снова
• Состояния waiting/blocked/sleeping характеризуют поток, как не готовый к работе, т.е. он жив, но в настоящее время не может быть выполнен. При этом он не runnable, но может вернуться в это состояние. Он может быть заблокирован и ждет ресурсов, занятых другим потоком или спит до истечения времени в методе sleep или находится в состоянии ожидания, т.к. в run встретился метод wait (вызов notify или notifyAll переведет поток из состояния waiting в состояние runnable). Один поток не может попросить другой заблокироваться
Для определения запущен ли поток и его состояния используются методы isAlive и getState.
При вызове вручную метода run, метод просто выполнится в том же потоке, из которого был запущен (в основном потоке программы). В каждом отдельном потоке порядок выполнения предсказуем, но порядок выполнения потоков не предсказуем.
Приостановка выполнения потока может быть выполнена следующими способами:
• Отправка в сон: sleep(milliseconds). Гарантированно прекращает выполнение текущего потока как минимум на указанный отрезок времени. Зачем: для принудительного выполнения потоков по очереди, для уменьшения трафика и т.п. По пробуждении поток не запустится сразу, а просто перейдет в состояние runnable. Метод sleep статический, может быть вызван из любого места программы, но в результате ляжет спать текущий поток
• Метод yield пытается принудить планировщик выполнить другой поток, ожидающий своей очереди, посредством попытки перевода потока из running в runnable. Он может не возыметь эффекта
• Вызов join(). Гарантированно останавливает выполнение текущего потока на заданное время или до завершения выполнения потока, метод join которого был вызван
• Дать потоку закончить свое выполнение :)
• Вызвать метод wait()
• Поток не может получить блокировку на объект, метод которого пытается выполниться
Можно только приостановить выполнение потока, но не остановить полностью.
Планировщик потоков является частью JVM (хотя некоторые JVM отображают Java-потоки на нативные потоки ОС) и решает, какой поток из пула потоков будет работать в определенный момент. Поток, переходящий в состояние runnable, помещается в runnable pool. Обычно используется планировщик на основе приоритетов. У класса Thread есть метод setPriority, куда можно отправить приоритет [1;10].
* Написать и запустить поток, бесконечно печатающий в консоль строку
```
public CustomThread implements Runnable {
private final String str;
public CustomThread(String str) {
this.str = str;
}
@Override
public void run() {
while(true) { System.out.println(str); }
}
}
...
CustomThread work = new CustomThread(“Hello!”);
Thread th = new Thread(work);
th.start();
```
* Синхронизация, ее методы. Зачем нужна? Модификатор volatile. По каким объектам синхронизируются статические и нестатические методы? Что такое deadlock? Способы его избежать. Как на уровне ОС реализовано избавление от deadlock?
Синхронизация необходима для решения проблем, возникающих при обращении разных потоков к одному ресурсу (т.н. состязание/гонка потоков).
Ключевое слово synchronized метода/блока означает, что если один поток начал выполнение этого метода/блока, другой поток не сможет его выполнить, пока первый не закончит. Каждый объект в Java имеет встроенную блокировку, которая вступает в игру в том случае, если объект имеет синхронизированные методы. Когда входим в синхронизированный нестатический метод – автоматически получаем блокировку, связанную с текущим экземпляром класса (текущий – код которого выполняется в данный момент).
• Только методы (или блоки) могут быть synchronized
• Каждый объект имеет одну блокировку
• Класс может иметь синхронизированные и несинхронизированные методы
• Спящий поток удерживает все свои блокировки
• Поток может захватить несколько блокировок (войти в синхронизированный метод, захватит блокировку, а затем сразу вызвать синхронизированный метод другого объекта, получив и его блокировку)
• Можно синхронизировать не весь метод, а только блок кода: synchronized(this) { ... }
При синхронизации метода объект, используемый для вызова этого метода, получает блокировку. Но когда синхронизируется блок кода надо указать объект, используемый в качестве блокировки. Можно использовать некий сторонний объект в качестве блокировки для этого куска кода, что дает возможность иметь больше одной блокировки для синхронизированного кода в рамках одного объекта
Нестатический метод класса в качестве блокировки использует экземпляр текущего класса, а статический метод – экземпляр класса java.lang.Class.
Если 2 нестатических метода объявлены как synchronized, то в каждый момент времени из разных потоков на одном объекте может быть вызван только один из них. Поток, который вызывает метод первым, захватит монитор, и второму потоку придется ждать. Важны 3 момента:
• Это верно только для разных потоков. Один и тот же поток может вызвать синхронизированный метод, внутри него – другой синхронизированный метод на том же экземпляре. Поскольку этот поток владеет монитором, проблем второй вызов не создаст
• Это верно только для вызовов методов одного экземпляра. У разных экземпляров разные мониторы, потому одновременный вызов нестатических методов проблем не создаст
• В случае статических методов имеет значение только одно – разные ли потоки, вызывающие синхронизированные методы, или нет. Об экземпляре тут речи не идет, его роль исполняет объект класса.
Замечание. Объекты класса Class существуют в единственном экземпляре только в пределах одного ClassLoader-а. Следовательно, если установить контекстный загрузчик классов потоку – у разных потоков могут быть разные экземпляры одного и того же класса Class и, следовательно, будет возможен одновременный вызов синхронизированных статических методов. Если эти методы используют одни и те же ресурсы – это может вызвать проблемы.
Когда поток не может получить блокировку, он переходит в некий пул для конкретного объекта и находится там, пока блокировка не снимается. Из методов, приостанавливающих выполнение потока, отказывается от блокировок только метод wait. Методы wait, notify, notifyAll должны вызываться из синхронизированного контекста, иначе будет будет брошено исключение IllegalMonitorStateException.
Какие объекты используются для блокировки:
• Потоки, вызывающие нестатические синхронизированные методы в одном классе будут блокировать другие потоки, если они вызываются с помощью того же экземпляра класса
• Потоки, вызывающие статические синхронизированные методы в одном классе будут всегда блокировать друг друга если все они используют один и тот же экземпляр Class
• Статические синхронизированные методы и нестатические синхронизированные методы не будет блокировать друг друга, никогда. Статические методы блокируются на экземпляре класса Class в то время как нестатические методы блокируются на текущем экземпляре (this). Эти действия не мешают друг другу
• При использовании синхронизированных блоков, необходимо обращать внимание на то, какой объект используется для блокирования. Потоки, которые синхронизируются на том же объекте будут блокировать друг друга. Потоки, которые синхронизируются на разных объектах, не будут блокировать друг друга
Модификатор volatile актуален в многопоточных приложениях. Указывает, что операции записи и чтения, выполняемые потоками, происходят напрямую с основной памятью (для эффективности каждый поток может использовать свою «локальную память», т.н. кэш потока). Поэтому каждый поток имеет текущее, актуальное значение volatile-поля.
Declaring a volatile Java variable means:
• The value of this variable will never be cached thread-locally: all reads and writes will go straight to "main memory"
• Access to the variable acts as though it is enclosed in a synchronized block, synchronized on itself
Когда класс тщательно синхронизирован, он является потокобезопасным (thread-safe). StringBuffer – потокобезопасен, StringBuilder – нет.
Deadlock – взаимная блокировка потоков: два потока блокируются, при этом каждый ждет освобождения блокировки, захваченной другим потоком. Это значит, что потоки не получат ожидаемых блокировок никогда. В Java нет встроенных средств предупреждения взаимных блокировок. Все зависит от качества кода. ОС борется с deadlocks следующими способами:
• Игнорирование проблемы в целом (предполагается малая вероятность возникновения, малый ущерб)
• Предотвращение deadlocks (обеспечение условий, исключающих возможность возникновения взаимных блокировок (предотвращение возникновения одного из условий ее возникновения))
• Обнаружение deadlocks (фиксация ситуации, выявление вовлеченных процессов)
• Восстановление после deadlocks (после обнаружения DL, можно вывести из него систему, нарушив одно из условий существования DL)
Ключевое слово synchronized скрывает реализацию синхронизации при помощи мониторов. Монитор – средство обеспечения контроля за доступом к ресурсу. У монитора есть максимум один владелец в каждый текущий момент времени. У каждого экземпляра объекта есть монитор. Любой нестатический synchronized-метод при своем вызове прежде всего пытается захватить монитор того объекта, у которого он вызван (сможет – метод исполняется, нет – поток останавливается и ждет, пока монитор будет отпущен). Компилятор и интерпретатор вставляет код блокировки-разблокировки в соответствующим образом оформленные процедуры, избавляя программиста от явного обращения к примитивам синхронизации.
Семафор - объект, позволяющий войти в заданный участок кода не более чем n потокам. Имеет методы:
• init(n) – счетчик:= n
• enter() – ждать, пока счетчик станет >0; после этого уменьшить его на единицу
• leave() – увеличить счетчик на единицу
Применяется для запрета одновременного выполнения заданных участков кода или поочередного доступа к критическому ресурсу.
Проблемы семафоров:
• Утечка семафора (забыть вызвать leave)
• Лишний вызов leave
• Возможность взаимной блокировки потоков
* Есть код:
```
public class A {
public void method1() {}
public synchronized void method2() {}
public synchronized void method3() {}
public static synchronized void method4() {}
}
```
4 потока одновременно обращаются каждый к своему методу, в каком порядке выполнятся методы и почему?
Одновременно начнут выполняться 3 метода: 1й, 4й и один из двух: 2й или 3й (какой именно – неизвестно заранее). Когда 2й (или 3й) метод выполнится до конца, начнет выполнение 3й (2й). Почему – см. вопрос Синхронизация.
Получил другой ответ: если чуть раньше начал выполняться 1й метод, то сценарий тот же. Но если первым начал выполняться 2й или 3й – то 1й будет ждать. Потом, после окончания 2го (или 3го) – если 1й успеет запуститься – то будет выполняться параллельно с 3м, иначе – 1й будет ждать окончания 3го. На 4й это все не повлияет.
* Что такое сериализация, для чего нужна, когда применяется? Ключевое слово transient, для чего нужно. Что такое UnmarshalException, когда выбрасывается?
Сериализация объектов Java позволяет взять любой объект, реализующий интерфейс Serializable, и превратить его в последовательность байтов, из которой он потом может быть восстановлен. Так реализуется легковесное долговременное хранение. В основном применяется для:
• удаленного вызова методов Java (RMI) (для работы с объектами, находящимися на других компьютерах)
• визуальных компонентов JavaBean (для сохранения их состояний)
Возможна “частичная” сериализация при помощи интерфейса Externalizable, который добавляет два метода: writeExternal, readExternal, позволяя попутно выполнить специфические действия. В этих методах сохранение и загрузку надо самому прописать “руками” в отличие от Serializable.
Чтобы пометить поле класса, как несериализуемое, используется ключевое слово transient.
Исключение UnmarshalException выбрасывается, когда RMI сервер не может восстановить сериализованный объект.
Serializable класс содержит поле static final long serialVersionUID, обычно вычисляемое автоматически. Если мы изменили описание класса, значение автоматически рассчитываемого поля изменится. Хорошим тоном является объявление своего такого поля с заданием его значения.
* Транзакции. Распределенные транзакции. Уровень изоляции транзакции. Свойства и модель транзакции. Привести примеры использования.
= Транзакция – группа последовательных операций, представляющая логическую единицу работы с данными. Т может быть выполнена либо целиком и успешно, соблюдая целостность данных и независимо от параллельно идущих других транзакций, либо не выполнена вообще.
= Распределенная транзакция включает в себя несколько локальных транзакций, каждая из которых либо фиксируется, либо прерывается. Распределенная транзакция фиксируется только в том случае, когда зафиксированы все локальные транзакции, ее составляющие. Если хотя бы одна из них была прервана, то должна быть прервана и распределенная транзакция.
= Уровни изоляции транзакций:
0 — Неподтверждённое чтение (Read Uncommitted, Dirty Read, грязное чтение) — чтение незафиксированных изменений своей транзакции и параллельных транзакций, возможны потерянные обновления, нечистые, неповторяемые чтения и фантомы
1 — Подтверждённое чтение (Read Committed) — чтение всех изменений своей транзакции и зафиксированных изменений параллельных транзакций, нечистые чтения невозможны, возможны неповторяемые чтения и фантомы;
2 — Повторяемое чтение (Repeatable Read, Snapshot) — чтение всех изменений своей транзакции, любые изменения, внесённые параллельными транзакциями после начала своей, недоступны, нечистые и неповторяемые чтения невозможны, возможны фантомы;
3 — Упорядоченный (Serializable, сериализуемый) — упорядоченные (сериализуемые) транзакции. Идентичен ситуации, при которой транзакции выполняются строго последовательно, одна после другой, то есть результат действия которых не зависит от порядка выполнения шагов транзакции (запрещено чтение всех данных, изменённых с начала транзакции, в том числе и своей транзакцией). Фантомы невозможны.
Чем выше уровень изоляции, тем больше требуется ресурсов, чтобы их поддерживать.
Кратко:
• Потерянное обновление: 2 транзакции начинаются одновременно, теряются изменения транзакции, законченной раньше
• Грязное чтение: начали 1 транзакцию, после изменений (но до коммита) 2я транзакция выполнила чтение, после чего 1я – отменила свои действия
• Неповторяющееся чтение: транзакция 1я считывает данные, 2я – меняет содержимое базы, теперь повторение 1й транзакцией считывания дает другой результат
• Фантомное чтение: от неповторяющегося чтения отличается тем, что результат повторного обращения к данным изменился не из-за изменения/удаления самих этих данных, а из-за появления новых (фантомных) данных
= Модели транзакций классифицируются на основании различных св-в:
• Структура транзакции
• Параллельность внутри транзакции
• Продолжительность
= Выделяют следующие типы транзакций:
1. Плоские (классические)
2. Цепочечные
3. Вложенные
Плоские транзакции характеризуются 4 классическими св-вами:
• Атомарность - транзакция должна быть выполнена в целом или не выполнена вовсе
• Согласованность - гарантирует, что по мере выполнения транзакций, данные переходят из одного согласованного состояния в другое, т. е. транзакция не разрушает взаимной согласованности данных
• Изолированность – означает, что конкурирующие за доступ к БД транзакции физически обрабатываются последовательно, изолированно друг от друга, но для пользователей это выглядит так, как будто они выполняются параллельно
• Долговечность (прочность) – если транзакция завершена успешно, то те изменения, в данных, которые были ею произведены, не могут быть потеряны ни при каких обстоятельствах
Иногда данные транзакции называются ACID-транзакциями (Atomicity, Consistency, Isolation, Durability).
= Пример транзакции:
• Начать транзакцию
= прочесть баланс на счету номер N1
= уменьшить баланс на M денежных единиц
= сохранить новый баланс счёта номер N1
= прочесть баланс на счету номер N2
= увеличить баланс на M денежных единиц
= сохранить новый баланс счёта номер N2
• Окончить транзакцию
* JDBC. Написать код подключения к базе данных. Откуда DriverManager знает, какой драйвер использовать?
Подключение Java-программы к реляционной СУБД с помощью JDBC (Java DB Connectivity) выполняется в 3 этапа:
• Установка связи между Java-программой и диспетчером БД
• Передача SQL-команды в БД с помощью объекта Statement
• Чтение полученных результатов из БД и использование их в программе
Драйвер JDBC обычно создается поставщиками СУБД. Их работа заключается в обработке JDBC-подключений и команд, поступающих от Java-приложения, и в генерации машинно-зависимых вызовов по отношению к БД.
Драйвер должен быть загружен, при этом он регистрируется. Способы загрузки:
• из командной строки: java –D jdbc.drivers=mysql.Driver <appClassName>
• из программы: Class.forName(“mysql.Driver”)
Т.е. мы явно указываем менеджеру драйверов, какой драйвер загружать. При этом jar с драйвером должен быть в classpath, либо явно указываться путь к jar. После загрузки драйвера можно работать с БД. Весь код работы с БД:
```
Class.forName(“mysql.Driver”)
Connection connection = DriverManager.getConnection(<dbUrl>,<login>,<password>);
Statement st = connection.createStatement();
ResultSet rs = st.executeQuery(...);
while (rs.next()) {
...
}
rs.close();
st.close();
```
* Три вида Statement. Чем отличается Statement от PreparedStatement? Где сохраняется запрос после первого вызова PreparedStatement? Зачем нужен CallableStatement?
PreparedStatement используется для вызова параметризованного запроса. После первого вызова PreparedStatement, DBMS (Database Management System) прекомпилирует запрос и сохраняет его access plan в БД. После этого DBMS может запускать запрос без предварительной компиляции, поэтому PreparedStatement намного быстрее обычного Statement. Преимущества PreparedStatement:
1. Позволяет писать динамические и параметрические запросы
2. Быстрее обычного Statement
3. Предотвращает SQL injection
4. Лучше читаем
Примечание: PreparedStatement возвращает FORWARD_ONLY ResultSet.
CallableStatement используется для запуска хранимых процедур - объекта базы данных, представляющего собой набор SQL-инструкций, который компилируется 1 раз (при ее первом запуске) и хранится на сервере БД. Хранимая процедура позволяет повысить производительность, расширяет возможности программирования, обеспечивает целостность и надежность БД.
* В чём отличие Exception от RuntimeException?
Исключение – проблема, которая не может быть решена в текущем контексте, необходим переход на другой, более высокий уровень контекста.
В Java исключения делятся на три типа: контролируемые (проверяемые), ошибки и исключения времени выполнения; последние две объединяют в категорию неконтролируемых (непроверяемых) исключений. Контролируемые должны быть обработаны в ходе выполнения программы, включением в блок try-catch или объявлением в сигнатуре метода. Неконтролируемые исключения не требуют обязательной обработки, наличие их обработчика Java не проверяет.
Ловить RuntimeException – скорее дурной тон: вместо устранения причины мы нейтрализуем последствия.
При выборе обрабатывать или объявлять исключение следует придерживаться следующей стратегии: обрабатывайте исключение, когда вы можете это сделать, объявляйте исключение, когда вы вынуждены так поступить.
* Error – в каких случая возникает? Перехват Error: можно ли, есть ли смысл?
При возникновении Error чаще всего продолжение программы невозможно (например OutOfMemoryError, StackOverflowError). Перехват Error возможен, это стоит делать, когда можно изменить на лету логику программы и использовать другой подход (например, выделить меньше памяти, использовать другой алгоритм).
* Напишите класс, который будет принимать аргумент (имя файла) и выводить строчки из этого файла в консоль. Если не будет введён аргумент (имя файла), как поведёт себя написанный класс?
```
public class Main {
public static String read(String fileName) throws FileNotFoundException {
StringBuilder sb = new StringBuilder();
try {
BufferedReader in = new BufferedReader(new FileReader(fileName));
String s;
while ((s = in.readLine()) != null) {
sb.append(s);
sb.append("\n");
}
in.close();
} catch (IOException ex) {
System.out.println("IOException!");
}
return sb.toString();
}
public static void main(String[] args) {
try {
System.out.println( read(args[0]) );
} catch (FileNotFoundException ex){
System.out.println("FileNotFoundException");
} catch (ArrayIndexOutOfBoundsException ex) {
System.out.println("No argument");
}
}
}
```
Если не будет введен аргумент (имя файла), еще при получении элемента массива по индексу будет брошено исключение ArrayIndexOutOfBoundsException.
* Какую из трёх исключительных ситуаций мы получим на выходе в данном блоке кода? Почему?
```
try {
throw new Exception1();
} catch (Exception ex) {
throw new Exception2();
} finally {
throw new Exception3();
}
```
Будет брошено Exception3. Java finally block is always executed whether exception is handled or not.
* Что будет возвращено в данном блоке кода ниже? Почему?
```
try {
return 1;
} catch(Exception e) {
return 2;
} finally {
return 3;
}
```
Вернется 3.
• Секция finally может быть не выполнена только в случае использования потоков-демонов (они завершают выполнение метода run без использования секции finally). Блок finally может вызвать потерю исключений, поэтому: в приведенном примере Exception1 - перехватывается, Exception2 – теряется, Exception3 – бросается
• Будет возвращено значение 3 (см. предыдущий ответ)
* Перегрузка и переопределение, в чем отличие? Является ли это перегрузкой, если в классе есть 2 метода, отличающихся только возвращаемым параметром?
Перегрузка (overloading) – возможность делать разные действия единообразным способом. Перегруженные методы:
• могут быть как в классе, так и в подклассах
• имеют то же имя, но различаются списком параметров
• могут различаться типом возвращаемого значения
Переопределение (overriding) – переопределение родительского метода. Переопределенные методы:
• появляются в подклассах
• имеют то же имя, что и метод суперкласса
• имеют тот же список параметров и тот же тип возвращаемого значения, что и метод суперкласса
• модификатор доступа метода не может быть уже, чем модификатор метода суперкласса
Ответ на вопрос: это не является перегрузкой, класс не будет откомпилирован.
* Каким требованиям должен отвечать xml-документ, чтобы называться well-formed? В чём отличие между понятиями well-formed и valid? Xml namespace.
Well-formed xml-документ соответствует всем правилам синтаксиса XML. Не well-formed не может считаться xml-документом. Правила well-formed документа:
• Первая строка документа: <?xml version="1.0(1.1)" encoding="UTF-8"?>
• Документ имеет один корневой элемент
• Открывающему тегу соответствует закрывающий
• Тег без тела: <tag><tag/> или <tag /> или <tag/>
• Спецсимволы определяются как ссылки по номеру символа в Юникод:   =
Valid xml-документ – соответствует заранее определенным, но уже внешним правилам. Дополнительные правила нужны для минимизации кол-ва ошибок структуры и состава xml-документа. Правила хранятся в схемах; проверяет соответствие схеме - валидатор.
Xml namespace – пространство имен xml. Синтаксис объявления: xmlns:prefix=”...”, где prefix – название пространства имен. Возможно объявление пространства имен по умолчанию: xmlns=”...”. Нельзя использовать зарезервированные пространства имен, начинающиеся с “xml”.
* Напишите well-formed xml-документ, содержащий информацию о трёх user’ах (ID user’а – атрибут, имя и отдел – вложенные элементы).
```
<?xml version="1.0" encoding="UTF-8"?>
<users>
<user id=”id1”>
<name>Ivan</name>
<department>Finance</department>
</user>
...
</users>
```
* Написать метод equals для класса, содержащего одно поле типа String.
```
public boolean equals(Object obj) {
if (obj == this) return true; // obj равен самому себе
if (obj == null) return false;
// Удостоверимся, что ссылки имеют тот же самый тип
if (getClass() != obj.getClass()) return false;
MyClass tmp = (MyClass)obj;
return (tmp.fieldName == this.fieldName);
}
```
• Проверяем равенство экземпляра класса самому себе и неравенство null
• Выясняем, является ли сравниваемый объект экземпляром класса, к которому должен принадлежать. Если нет - автоматически считаем, что они не равны
• Выясняем, одинаковы ли поля fieldName в обоих экземплярах
* OOP abstraction
Абстракция дает возможность сделать класс абстрактным (АК). Экземпляр АК не может быть создан. Вся остальная функциональность класса может существовать.
* Чем отличается абстрактный класс от интерфейса?
• Класс может реализовывать несколько интерфейсов, но наследоваться только от одного абстрактного класса
• Интерфейс не содержит реализации; абстрактный класс – может содержать
• Интерфейс часто используется для описания внешних возможностей класса, а не его главного назначения (-able (например Runnable) или can-do); абстрактный класс идентифицирует (is-a) класс и его потомков
• Все методы интерфейса public abstract по умолчанию, константы могут быть только static final, нельзя вычислять константы (их начальное значение); в абстрактных классах можно использовать скрытый код и вычислять константы
* Наследование. Переопределение (сужение/расширение) уровней доступа полей/методов
Наследование – включение поведения (т.е. методов) и состояния (т.е. полей) базового класса в наследуемый класс. Наследуются поля и методы public, protected. Если подкласс находится в том же пакете, что и суперкласс, - наследуются члены класса с уровнем доступа package.
Можно в подклассе:
• объявить такое же поле, как и в суперклассе, скрыв его (не рекомендуется)
• объявить новую реализацию метода с той же сигнатурой, что и в суперклассе, таким образом переопределив его
• объявить новый static метод с той же сигнатурой, что и суперклассе, скрыв оригинальный метод
• объявить новые поля и методы, которых нет в суперклассе
• написать собственный конструктор, который вызывает конструктор суперкласса ключевым словом super
Хотя private члены суперкласса не наследуются, но, если суперкласс имеет public или protected методы, для получения доступа к private полям, они также могут использоваться и в подклассе.
Nested-класс (содержащийся в другом классе), имеет доступ ко всем private членам содержащего его класса. Таким образом, public или protected nested-класс, наследуемый подклассом, имеет косвенный доступ ко всем private членам суперкласса.
Проверка класса объекта: if(obj instanceof ClassName) { ... }.
```
non-static метод суперкласса static метод суперкласса
non-static метод подкласса Переопределение Ошибка компиляции
static метод подкласса Ошибка компиляции Скрытие
```
При наследовании можно только расширять область видимости метода. Для поля изменение области видимости приводит к тому, что используется поле потомка (поле предка скрывается).
* Полиморфизм. Участвуют ли статические/приватные методы в полиморфизме? Вызов методов этого/базового класса из конструктора.
Полиморфизм - возможность работы с подклассом, используя ссылку на суперкласс или возможность объектов с одинаковой спецификацией иметь различную реализацию. Кратко: один интерфейс, множество реализаций. Позволяет писать более абстрактные программы, повысить коэффициент повторного использования кода. В статическом полиморфизме смысл фрагмента зависит от окружающего его кода, а в динамическом – смысл фрагмента определяется только на этапе исполнения.
Приватные методы в полиморфизме не участвуют, т.к. не видны в подклассе.
Статические методы в полиморфизме не участвуют, т.к. к ним не применимы принципы позднего связывания.
При полиморфизме используются восходящее и нисходящее преобразования: восходящее– преобразование к базовому классу (автоматически), нисходящее – к потомку (принудительно).
Ковариантность возвращаемых типов - начиная с Java 5, появилась возможность возвращения переопределенным методом значения с типом, отличным от типа у метода базового класса.
Из конструктора вызывать стоит только final-методы базового класса и private-методы своего класса (т.к. они автоматически считаются final). Иначе (из-за полиморфизма) поведение может быть неожиданным.
Throws в методах:
• Переопределяемый метод в подклассе не может содержать в throws исключений, не обрабатываемых в соответствующем методе суперкласса. Если же при объявлении метода суперкласса инструкция throws присутствует, то в подклассе эта инструкция может вообще отсутствовать или в ней могут быть объявлены любые исключения, являющееся подклассами исключения из блока throws метода суперкласса
• Конструктор подкласса должен включить в свой throws все классы исключений или их суперклассы из блока throws конструктора суперкласса, к которому он обращается при создании объекта
* SQL statements: SELECT, INSERT, UPDATE, DELETE.
```
SELECT
[DISTINCT | DISTINCTROW | ALL] select_expression,...
[FROM table_references]
[WHERE where_definition]
[GROUP BY {unsigned_integer | col_name | formula}]
[HAVING where_definition]
[ORDER BY {unsigned_integer | col_name | formula} [ASC | DESC], ...]
```
где
WHERE - определение, какие строки должны быть выбраны или включены в GROUP BY
GROUP BY - объединение строк с общими значениями в элементы меньшего набора строк
HAVING - определение, какие строки после GROUP BY должны быть выбраны
ORDER BY - определение, какие столбцы используются для сортировки итогового набора данных
Для ограничения кол-ва возвращаемых строк используются оконные функции ROW_NUMBER() и RANK()
INSERT
• Используя перечисление значений, с указанием столбцов:
INSERT INTO <название таблицы> ([<Имя столбца>, ... ]) VALUES (<Значение>,...)
• Используя перечисление значений, без указания столбцов:
INSERT INTO <название таблицы> VALUES (<Значение>,...)
• Используя SELECT:
INSERT INTO <название таблицы> SELECT <имя столбца>,... FROM <название таблицы>
В последнем случае, в таблицу может вставиться более одной записи.
UPDATE [top(x)] <объект (таблица или представление)>
SET <присваивание1 [, присваивание2, ...]>
[WHERE <условие>]
[OPTION <хинт1 [, хинт2, ...]>]
Команда выполнится только x раз.
DELETE
• Удаление из одной таблицы:
DELETE FROM <Имя Таблицы> WHERE <Условие отбора записей>
• Удаление сразу из нескольких таблиц:
DELETE <Имя записи для удаления> FROM <Имя Таблицы1> JOIN <Имя Таблицы2> ON <условие объединения>
* SQL-запросы с использованием INNER JOIN, GROUP BY, HAVING. Виды JOIN, отличие OUTER от INNER. Уметь сходу писать запросы.
JOIN – SQL оператор, позволяющий соединять записи из двух таблиц БД. Входит в раздел FROM оператора SELECT и отдельно от него не используется.
Синтаксис: SELECT FIELD [,...n] FROM Table1 {INNER | {LEFT | RIGHT | FULL} OUTER | CROSS } JOIN Table2 ON <condition>.
В большинстве СУБД можно опустить:
• слово INNER (т.е. по умолчанию join = inner join)
• слово OUTER при указании LEFT,RIGHT,FULL
В общем случае СУБД при выполнении join проверяет условие condition. Для CROSS JOIN условие не указывается. Для CROSS JOIN в некоторых реализациях SQL используется оператор «запятая» (,): SELECT ... FROM TABLE1,TABLE2.
Различия JOIN:
• INNER JOIN – объединяет 2 таблицы, где каждая строка обеих таблиц в точности соответствует условию. Если для строки одной таблицы не найдено соответствия в другой таблице, строка не включается в набор
• OUTER JOIN – присоединение таблицы с необязательным присутствием записи в таблице
= LEFT OUTER JOIN. К левой таблице присоединяются все записи из правой, соответствующие условию (по правилам inner join), плюс все не вошедшие записи из левой таблицы, поля правой таблицы заполняются значениями NULL
= RIGHT OUTER JOIN. Аналогично left outer join, но применяется для правой таблицы. К правой таблице присоединяются все записи из левой, соответствующие условию (по правилам inner join), плюс все не вошедшие записи из правой таблицы, поля левой таблицы заполняются значениями NULL
= FULL OUTER JOIN. К левой таблице присоединяются все записи из правой, соответствующие условию (по правилам inner join), плюс все не вошедшие записи из правой таблицы, поля левой таблицы заполняются значениями NULL и плюс все не вошедшие записи из левой таблицы, поля правой таблицы заполняются значениями NULL
= CROSS JOIN. Все возможные сочетания из обеих таблиц. Как уже говорилось выше, условие для этого типа оператора JOIN не указывается
Агрегатные функции: MIN, MAX, SUM, AVG, COUNT.
GROUP BY – указывает подмножество, для которого применяется агрегатная функция.
HAVING – необязательный параметр оператора SELECT для указания условия на результат агрегатных функций. HAVING <условия> аналогичен WHERE <условия> но строки отбираются не по значениям столбцов, а строятся из значений столбцов указанных в GROUP BY и значений агрегатных функций, вычисленных для каждой группы, образованной GROUP BY.
Необходимо, чтобы в SELECT были заданы только требуемые в выходном потоке столбцы, перечисленные в GROUP BY и/или агрегированные значения. Распространённая ошибка — указание в SELECT столбца, пропущенного в GROUP BY.
Если параметр GROUP BY в SELECT не задан, HAVING применяется к «группе» всех строк таблицы, полностью дублируя WHERE (допускается не во всех реализациях стандарта SQL).
Объяснение формирования результата JOIN-ов другими словами (по википедии):
• INNER JOIN (симметричный оператор) – Каждая строка одной таблицы сопоставляется с каждой строкой второй таблицы, после чего для полученной «соединённой» строки проверяется условие соединения (вычисляется предикат соединения). Если условие истинно, в таблицу-результат добавляется соответствующая «соединённая» строка
• OUTER JOIN - Соединение двух таблиц, в результат которого в обязательном порядке входят строки либо одной, либо обеих таблиц
• LEFT OUTER JOIN (асимметричный оператор) – 1.В результат включается внутреннее соединение (INNER JOIN) левой и правой таблиц по предикату p. 2.Затем в результат добавляются те записи левой таблицы, которые не вошли во внутреннее соединение на шаге 1. Для таких записей поля, соответствующие правой таблице, заполняются значениями NULL
• RIGHT OUTER JOIN (асимметричный оператор) - 1.В результат включается внутреннее соединение (INNER JOIN) левой и правой таблиц по предикату p. 2.Затем в результат добавляются те записи правой таблицы, которые не вошли во внутреннее соединение на шаге 1. Для таких записей поля, соответствующие левой таблице, заполняются значениями NULL
• FULL OUTER JOIN (симметричный оператор) - 1.В результат включается внутреннее соединение (INNER JOIN) первой и второй таблиц по предикату p. 2.В результат добавляются те записи первой таблицы, которые не вошли во внутреннее соединение на шаге 1. Для таких записей поля, соответствующие второй таблице, заполняются значениями NULL. 3.В результат добавляются те записи второй таблицы, которые не вошли во внутреннее соединение на шаге 1. Для таких записей поля, соответствующие первой таблице, заполняются значениями NULL
• CROSS JOIN (симметричный оператор) - Тело результата логически формируется следующим образом. Каждая строка одной таблицы соединяется с каждой строкой второй таблицы, давая тем самым в результате все возможные сочетания строк двух таблиц
* Объяснить модель MVC. Что в Struts является контроллером?
Модель - предоставляет знания: данные и методы работы с этими данными, реагирует на запросы, изменяя своё состояние. Не содержит информации, как эти знания можно визуализировать.
Представление - отвечает за отображение информации (визуализацию). Часто в качестве представления выступает форма (окно) с графическими элементами.
Контроллер - обеспечивает связь между пользователем и системой: контролирует ввод данных пользователем и использует модель и представление для реализации необходимой реакции.
MVC – патерн проектирования, с помощью которого модель данных приложения, пользовательский интерфейс и взаимодействие с пользователем разделены на 3 отдельных компонента, поэтому модификация одного из компонентов оказывает минимальное воздействие на остальные. Различают 2 основные модификации:
• Пассивная модель. Модель не имеет никаких способов воздействовать на представление или контроллер, и используется ими в качестве источника данных для отображения. Изменения модели отслеживаются контроллером, и он же отвечает за прорисовку представления, если необходимо. В это случае модель представляет просто структуру данных, без методов их обрабатывающих.
• Активная модель. Модель оповещает представление о том, что в ней произошли изменения, а представления, которые заинтересованы в оповещении, подписываются на эти сообщения. Это позволяет сохранить независимость модели как от контроллера, так и от представления.
За счет разделения модели и представления повышается возможность повторного использования кода.
В Struts входит сервлет-контроллер, который перенаправляет (в соответствие с мэпингом в struts-config.xml) HTTP-запросы к другим объектам среды, поставляемым разработчиком приложения: JSP и наследникам класса Action.
* Как работать с БД без Hibernate?
= Через JDBC
= Через iBatis/MyBatis
= Через JPA + другой (не Hibernate) фреймворк
* Какие в JDBC есть типы драйверов для соединения с СУБД?
http://jdbc-tutorial.com/jdbc-driver-types.htm
В JDBC определяют четыре типа драйверов:
• Драйвер, использующий другой прикладной интерфейс взаимодействия с СУБД, в частности ODBC (т.н. JDBC-ODBC мост) (ODBC = Open DB Connectivity, такой драйвер удовлетворяет стандарту Microsoft). Входит в JDK, не рекомендуется для промышленного использования
• Драйвер, работающий через внешние (native) библиотеки (т.е. клиента СУБД)
Обычно быстрее драйвера JDBC-ODBC, изменение типа БД требует смены драйвера, обычно не потокобезопасен, не может использоваться для Интернета, не полностью написан на Java (проблемы при портировании), считается устаревшим
• Драйвер, работающий по сетевому и независимому от СУБД протоколу, с промежуточным Java-сервером, который уже подключается к СУБД
Использования промежуточного сервера замедляет получение данных, требуется установка серверного приложения, гибок в плане получения доступа к различным БД при помощи одного драйвера. Обычно обеспечивает кэширование соединений, результатов запросов и т.д. Считается наиболее эффективным из 4 типов драйверов
• Сетевой драйвер, работающий напрямую с нужной СУБД. Не требуется установка дополнительного ПО, драйвер можно быть загружен динамически, полностью написан на Java (т.е. независим от платформы), при смене БД нужна смена драйвера
* XML парсеры (DOM, SAX, StAX).
• DOM (Document Object Model) парсер обеспечивает очень гибкое API для создания, чтения, редактирования и удаления узлов дерева. Парсер создает XML-дерево в памяти; при этом загружается сразу весь XML-документ, что снижает производительность.
• SAX (Simple API for XML) парсер предоставляет интерфейс обратных вызовов. Предназначен только для чтения. Парсер ожидает, что весь XML-документ будет прочтен, но не требует содержания всего документа в памяти во все моменты времени. Хороший выбор для парсинга больших документов.
• StAX (Streaming API for XML) похож на SAX, но позволяет читать и писать в документ, имеет курсор и итератор. Не требуется содержать весь документ в памяти, не требуется читать весь документ (некоторые части могут быть пропущены).
• TrAX парсер использует XSLT-трансформацию для преобразования исходного документа в результирующий. Источник для TrAX может быть создан при помощи SAX или DOM.
Краткое резюме:
• SAX и StAX лучше по производительности и использованию памяти. Для случаев DOM и TrAX это зависит от того, насколько велик документ и какие ставятся цели
• DOM и StAX поддерживают CRUD
• SAX и StAX двигаются только вперед, тогда как DOM и TrAX позволяют двигаться в обоих направлениях
При использовании StAX приложение “тянет” информацию из парсера, когда это необходимо, тогда как в событийном API SAX парсер “толкает” данные в приложение, ожидая, что приложение сохраняет состояние между событиями и отслеживает положение внутри документа.
* Применение классов HttpServletRequestWrapper и HttpServletResponseWrapper.
Классы реализуют паттерн Wrapper (или Decorator) и позволяют «обертывать» запрос и ответ, соответственно (можно менять HTTP-заголовок). Применение – например шифрование HTTP-контента.
* Почему в Singleton не работает двойная блокировка?
Двойная блокировка: сначала проверяется условие блокировки без какой-либо синхронизации; поток делает попытку получить блокировку только, если результат проверки говорит о том, что ни один другой поток не владеет блокировкой. Была придумана для ускорения инициализации, т.к. после инициализации синглтона уже нет необходимости в синхронизации. Считается антипаттерном.
В отношении синглтона: дело в порядке создания объектов в Java:
• Выделяется память под объект
• Инициализируется указатель на объект
• Конструируется объект (инициализируются поля)
Поэтому между вторым и третьим этапом возникает ситуация, при которой другой поток может получить и начать использовать (если указатель !=null) не полностью сконструированный объект.
* В какой последовательности выполняются сервлетные фильтры?
Сервлетный фильтр (СФ) – Java-код, позволяющий преобразовать содержание HTTP-запросов, HTTP-ответов и информацию, содержащуюся в заголовках HTML. СФ занимается предварительной обработкой запроса, прежде чем тот попадает в сервлет, и/или последующей обработкой ответа, исходящего из сервлета. СФ могут:
• Перехватывать инициацию сервлета прежде, чем сервлет будет инициирован
• Определить содержание запроса прежде, чем сервлет будет инициирован
• Модифицировать заголовки и данные запроса, в которые упаковывается поступающий запрос
• Модифицировать заголовки и данные ответа, в которые упаковывается получаемый ответ
• Перехватывать инициацию сервлета после обращения к сервлету
Имеет 3 метода:
• init – вызывается (единожды) прежде, чем фильтр начинает работать, настраивает конфигурационный объект фильтра
• doFilter – выполняет непосредственно работу фильтра (вызывается столько раз, сколько нужно)
• destroy – вызывается после того, как фильтр заканчивает свою работу
Контейнер сервлетов запускает фильтры в том порядке, в котором они указаны в deployment descriptor (в web.xml).
* Как обрабатывается тег с телом?
• Вызываются сеттеры для атрибутов
• Вызывается метод doStartTag(). Уже известны значения атрибутов, но неизвестно содержимое тела тега
• Вызывается метод doEndTag(). Содержимое тела тега уже известно: getBodyContent().getString()
Для работы с библиотекой тегов ей в tld-файле должен быть поставлен в соответствие uri и быть выполнено описание тега, а в заголовок JSP-страницы должна быть включена директива taglib с указанием выбранного uri.
* Работа с JSTL тегами
JSTL – стандартная библиотека тегов JSP. Расширяет спецификацию JSP, является альтернативой встроенной в JSP логики (скриптлетам). Использование стандартизированного множества тегов предпочтительнее, т.к. код легче поддерживать и проще отделять бизнес-логику от логики отображения. JSTL породила технологию EL (Expression Language). JSTL включает теги, которые:
• Устанавливают атрибуты объектов web-приложений (c:set)
• Выводят текст на web-страницы (c:out x:out)
• Перебирают элементы набора данных (c:forEach и x:forEach)
• Форматируют числа, даты, валюты, используя интернациональные стили (fmt:formatDate, fmt:formatNumber)
• Выполняют преобразование XML (x:transform)
• Взаимодействуют с БД, используя SQL (sql:query, sql:update)
• Позволяют вставлять вызовы функций в код JSP
Для подключения:
<%@ taglib uri=”http://java.sun.com/jstl/core” prefix=”c” %>
<%@ taglib uri=”http://java.sun.com/jstl/xml” prefix=”x” %> и т.д.
* Что происходит при добавлении в ArrayList нового элемента и как бы ты это реализовал?
ArrayList реализует интерфейс List. Только что созданный объект list содержит св-ва elementData (массив определенного типа, указанного в generic, или просто Object) и size. Если вызывается конструктор без параметров, то по умолчанию будет создан массив из 10-ти элементов типа Object (с приведением к типу, разумеется). При добавлении элемента:
• Проверяется, достаточно ли места в массиве для вставки нового элемента. Если нет – создается новый массив размером (oldCapacity*3)/2+1, и в него функцией System.arraycopy() копируется содержимое исходного массива
• Добавляется элемент в конец (согласно значению size) массива
При добавлении в “середину” списка:
• проверяется, достаточно ли места в массиве для вставки нового элемента
• подготавливается место для нового элемента с помощью System.arraycopy()
• перезаписывается значение у элемента с указанным индексом
В случаях, когда в исходный список необходимо добавить другую коллекцию, да еще и в «середину», стоит использовать метод addAll(index, Collection).
Удалять элементы можно 2 способами: по индексу remove(index), по значению remove(value). При удалении элемента:
• Определяется, какое количество элементов надо скопировать
• Копируются элементы, используя System.arraycopy()
• Уменьшаем размер массива и забываем про последний элемент
При удалении по значению, в цикле просматриваются все элементы списка, до тех пор пока не будет найдено соответствие. Удален будет лишь первый найденный элемент.
Итоги:
— Быстрый доступ к элементам по индексу за время O(1)
— Доступ к элементам по значению за линейное время O(n)
— Медленный, когда вставляются и удаляются элементы из «середины» списка
— Позволяет хранить любые значения в том числе и null
— Не синхронизирован (синхронизирован Vector)
* Операции сдвига >>, <<, >>>.
В случае сдвига влево << и беззнакового сдвига вправо >>> новые биты просто устанавливаются в ноль. В случае сдвига вправо со знаком >> новые биты принимают значение старшего (самого левого) бита перед сдвигом.
* Реализация HashMap.
Объект HashMap содержит ряд св-в:
• table – массив типа Entry[], который является хранилищем ссылок на списки (цепочки) значений
• loadFactor – коэффициент загрузки, по умолчанию =0.75
• threshold – предельное кол-во элементов, при достижению которого размер хэш-таблицы увеличивается вдвое; =(capacity * loadFactor)
• size – кол-во элементов HashMap-а
Можно указать свои емкость и коэффициент загрузки конструкторами HashMap(capacity) и HashMap(capacity, loadFactor). Максимальная емкость равна половине макс. значения int.
• При добавлении элемента ключ проверяется на null (если ==null, то просматривается цепочка, привязанная к table[0]; при нахождении элемента с ключом null его значение перезаписывается; при ненахождении - добавляется в цепочку, привязанную к table[0]).
• Рассчитывается хэш ключа и позиция в массиве, куда будет помещен элемент. Перезапись происходит только если хэш и ключ нового элемента совпадают с хэшем и ключом существующего элемента, в обратном случае – происходит добавление элемента в цепочку, соответствующую расчетной позиции в массиве.
Когда массив table[] заполняется до предельного значения, его размер увеличивается вдвое и происходит перераспределение элементов. При удалении элементов размер массива table[] не уменьшается (можно пересоздать HashMap конструктором копирования).
* Внутренние классы, цели использования. Области видимости данных при определенных ситуациях
Внутренний класс не может существовать без внешнего класса. Есть 4 типа:
• Статические внутренние классы. Декларируются внутри основного класса и обозначаются ключевым словом static. Не имеют доступа к членам внешнего класса за исключением статических. Может содержать статические поля, методы и классы, в отличие от других типов внутренних классов
• Внутренние классы. Декларируются внутри основного класса. В отличие от статических внутренних классов, имеют доступ к членам внешнего класса.
• Локальные классы. Декларируются внутри методов основного класса. Могут быть использованы только внутри этих методов. Имеют доступ к членам внешнего класса. Имеют доступ как к локальным переменным, так и к параметрам метода при одном условии - переменные и параметры, используемые локальным классом, должны быть задекларированы final
• Анонимные (безымянные классы). Декларируются внутри методов основного класса. Могут быть использованы только внутри этих методов. В отличие от локальных классов, анонимные классы не имеют названия. Главное требование к анонимному классу - он должен наследовать существующий класс или реализовывать существующий интерфейс
Последние 3 – не могут содержать определение (но могут наследовать) статических полей, методов и классов (кроме констант).
* Autoboxing и unboxing. Принцип действия на примерах.
Autoboxing - автоматическое преобразование примитивных типов (int, double, float и т.д.) к их объектным эквивалентам (Integer, Float, Double и т.д.) при присваивании и вызове методов/конструкторов.
Unboxing – wrapper-типы автоматически преобразуются в их примитивные эквиваленты, если это необходимо для присваивания или вызова конструктора/метода.
Примеры:
Integer i2 = 5; // autoboxing
int i = 0;
i = new Integer(5); // auto-unboxing
* Generics - что такое и для чего применяются? Во что превращается во время выполнения ? Использование wildcards.
Generics являются средством выражения ограничений поведения классов или методов для исходно неизвестных типов: «какой бы тип не использовался для переменной X, он должен совпадать с типом переменной Y».
Пример: ArrayList<T> tArray.
Wildcards позволяют задать границы для семейства типов, определенных каким-нибудь generic-классом.
Пример:
ArrayList<? extends Number> numArray
ArrayList<T super ?> numArray (T super Integer означает, что T может быть Integer или Number)
Проверка корректности типов для generics происходит во время компиляции. При этом generic-информация о типе удаляется, что называется стиранием типа. В результате тип не может быть определен во время выполнения. JRE не нуждается в знании типов в generics, поэтому хранит только одну скомпилированную версию generic-класса или функции независимо от числа использованных параметризованных типов. Поэтому нельзя использовать generics в объявлении static переменных и static методов.
* Какие принципы ООП используются CSS. Привести примеры.
Наследование, переопределение. Пример:
```
a:link {
color: blue;
font-weight: bold;
}
a:link:hover {
color: black;
}
```
* Mutable и Immutable объекты. Привести примеры. Написать класс, который будет immutable.
Mutable объекты могут изменять свое состояние после создания. Примеры из JDK: StringBuilder, Date.
Immutable называются объекты, чье состояние не изменяется после создания. Примеры из JDK: String, Integer. Достоинства:
• Просты в создании, тестировании, использовании
• Автоматически потокобезопасны, не нуждаются в синхронизации
• Не нужны конструктор копирования, и имплементация клонирования
• Значение hashCode может быть кэшировано
• Хорошо подходят как ключи Map и элементы Set
Чтобы сделать класс Immutable:
• Запретить перегрузку класса - сделать его final или использовать статическую фабрику и сделать конструктор private
• Поля должны быть private и final
• Создавать объект за один шаг, в отличие от идеологии JavaBeans (используя конструктор без аргументов и последовательность вызовов сеттеров)
• Не описывать никаких методов (даже сеттеров), которые изменяют состояние объекта любым способом
• Если класс имеет любые mutable поля – они должны защищенно копироваться (defensive copying) при передаче между классом и вызывающим его
Пример immutable класса:
```
public final class Planet {
private final Double mass; //immutable field
private final String name; //immutable field
private final Date dateOfDiscovery; //mutable field
public Planet(Double mass, String name, Date dateOfDiscovery) {
this.mass = mass;
this.name = name;
//this.dateOfDiscovery = dateOfDiscovery; //this is NOT private copy
//this.dateOfDiscovery = dateOfDiscovery.clone(); //private copy
this.dateOfDiscovery = new Date(dateOfDiscovery.getTime()); //private copy
}
public Double getMass() { return mass; }
public String getName() { return name; }
public Date getDateOfDiscovery() {
return new Date(dateOfDiscovery.getTime()); //defensive copy of field
}