You are on page 1of 31

================================================

Ziv библеотека, за по-добра работа с collections.

Hi,

I upgraded library ‘commons-collections’ to version 3.2.2.

Please let me know if you have compilation errors or runtime errors that you think is related to this
library.

About the library:

‘commons-collections’ - https://commons.apache.org/proper/commons-collections/
It added many powerful data structures that accelerate development of most significant Java
applications. Since that time it has become the recognised standard for collection handling in Java.
Commons-Collections seek to build upon the JDK classes by providing new interfaces, implementations
and utilities. There are many features, including:

• Bag interface for collections that have a number of copies of each object
• BidiMap interface for maps that can be looked up from value to key as well and key to value
• MapIterator interface to provide simple and quick iteration over maps
• Transforming decorators that alter each object as it is added to the collection
• Composite collections that make multiple collections look like one
• Ordered maps and sets that retain the order elements are added in, including an LRU based map
• Reference map that allows keys and/or values to be garbage collected under close control
• Many comparator implementations
• Many iterator implementations
• Adapter classes from array and enumerations to collections
• Utilities to test or create typical set-theory properties of collections such as union, intersection,
and closure
=================================================

Chapter 3. Tools of the Trade

System Properties

Идеята е, че java ни предоставя допълнителен механизъм за задаване на предварителни


конфигурационни настойки на приложението (general configuration information). Освен
възможността, на Java да чете от host environment variales на операционната система. Могат да се
достъпят чрез System.getProperty() метода, инициализират се при старт на JVM-a. Въпроса е, как се
конфигурират, май може и чрез command line-a.

The Classpath

Това е env variable, която предоставя на приложението списък от места където може да се търси
даден ресурс. Най-добрия пример е път към executable програми. Примерно ако искам да
стартирам от моята java програма, някакъв файл, който е на python или на bash script.
Java CLASSPATH environment variable е списък от локации, където се търси за Java class файлове.
JVM-a и компилатора използват CLASSPATH-a, когато търсят пакети и класове. Пример е
директория за jar файлове. (също и zip, jar и zip реално са същия формат). Jar файловете са по-
специализирани, тъй като включват допълнителни metadata файлове, които описват
съдържанието на jar-a. Те се създават от JDK jar utility.

Java - Unicode поддръжка. Това означава, че ще са необходими поне два байта (bytes), да
пресъздадат всеки символ вътрешно.
Unicode (стандарт за енкодване и представяне на текстови символи, дефинира над 100 хил.
символа). Енкодване на символи (character encoding) означава използване на някаква определена
енкодинг система, която позволява да се назначи номер на всеки от символите за дигитално
представяне.
Реално ако въвеждам всичко като стринг, аз рискувам символите да трябва да се енкодват и
декодват постоянно.
Тука пише, че реално java кода, може да се пише във всякакъв вид езици, примерно имена на
променливи, класове и т.н.

The Java char type and String class съпортват Unicode values. Вътрешно текста е сторнат, като
multibyte characters using the UTF-16 encoding.

Unicode is also very ASCII-friendly (ASCII is the most common character encoding for English).
The first 256 characters are defined to be identical to the first 256 characters in the ISO 8859-1 (Latin-1)
character set, so Unicode is effectively backward-compatible with the most common English character
sets.
Furthermore, one of the most common file encodings for Unicode, called UTF-8, preserves ASCII values
in their single byte form.
This encoding is used by default in compiled Java class files, so storage remains compact for English text.

??? това е интересен въпрос, какво представляват java компилираните класове.

A Unicode character can be represented with this escape sequence:

\uxxxx

xxxx is a sequence of one to four hexadecimal digits. The escape sequence indicates an ASCII-encoded
Unicode character.
This is also the form Java uses to output (print) Unicode characters in an environment that doesn’t
otherwise support them.
Java also comes with classes to read and write Unicode character streams in specific encodings,
including UTF-8.

Types

Типовата система на всеки от програмните езици описва как data елементите (променливи и
константи), се асоциират с конкретни места в паметта и как се отнасят едно към друго.

- Примитиви: проста стойност, която има билд ин функционалност в езика.


Примитивните типове не са обекти (както в някои други езици), но когато ситуацията
изисква, Java предоставя т.н. wrraper класове.
Джава можела лесно да конвертира между примитивни типове.

- Референтни типове (class types): обекти и масиви, казват се референтни типове, защото
реферират към по-голям тип данни (large data type), който се предава by reference. Generic
типовете са вид разновидност на този тип.
Variable declaration and initialization

Важно:
Локалните променливи,(които търпят докато се изпълни метода и т.н.), трябва задължително да
се инициализират.
Променливите, които са част от класа, може и да не се инициализират. Той класа ги сетва към
дефолтни стойносити: char = null, numеric types = 0, boolean = false.

Reference Types

Най-важното нещо е принципа, че класовете в java винаги имат parent/child relationship и child
класа, наследява всички методи и пропъртита на parent-а.
Това означава, че той съдържа в себе си parent класа и променливи, които изискват parent класа
или методи, които изискват такъв параметър, спокойно могат да бъдат инициализирани с обект на
child класа.
Това е т.н. subtype полиморфизъм и е една от типичните черти на обектно ориентираните езици.

Примитивните типове във Java се използват и пренасят "by value", т.е. копират се един в друг,
докато reference types, винаги се достъпват по референция.

!!!! Значи променливата, която очаква определен тип обект/клас, държи поинтер към обектите от
този тип или субтип, и вече при инициализация ние просто даваме името на дадения обект и така
се получава пълна референция, т.е. референцията само държи поинтер към дадения обект, а не
самия обект.

Системата с интерфейсите позволява на Джава да създадва обекти, които принадлежат към


различни типове. !!!!!

A Word About Strings

Стринговете в Java са обекти, т.е. те са така или иначе reference types.


Когато имаме конкатенация с + ние дефакто събираме два обекта в един.

====================

Statements and Expressions

Expression-a произвежда резултат (value), което ще се използва в друг експешън или стейтмънт.

Извикване на методи, алокиране на обекти, математически функции и т.н. са примери за


експрешъни.
Condition-a e Boolean expression. Или експрешън, който може да се евалюейтне до true/falsе.
Примерно казуса дали 0 е true или false.

Важно: можем да слагаме множество expressions, тук в началото на for цикъла.

for (int i = 0, j = 10; i < j; i++, j-- ) {


...
}

A continue statement causes for and while loops to move on to their next iteration by returning to the
point where they check their condition.
A break causes Java to stop the current block statement and resume execution after it. In the following
example, the while loop goes on endlessly until the condition() method returns true, triggering a break
statement that stops the loop and proceeds at the point marked “after while.”

labelOne:
while ( condition ) {
...
labelTwo:
while ( condition ) {
...

// break or continue point


}
// after labelTwo
}
// after labelOne

Това е пример за т.н. Lable-ing.

The null value


Експрешъна null, може да бъде назначен към всеки референтен тип. Това означава „няма
референция“. Създаването на обект е тип експрешън, който води като резултат, референция към
обект.
The instanceof operator

Instanceof operator-a, може да сеизползва за да детерминира типа на обекта, по време на


рънтайм.

Exceptions
----------

Много пакети дефинират техен собствен тип ексепшъни, които обикновенно са подкласове на
Exception или са част от важния подклас RuntimeException.

In Java 7, there is an alternative to using multiple catch clauses, and that is to handle multiple discrete
exception types in a single catch clause using the “|” or syntax:

try {
// read from network...
// write to file..
catch ( ZipException | SSLException e ) {
logException( e );
}

exception - бъбълва докато не бъде хендълнат от някакъв метод.

Assertions
----------

Нещо като допълнително тестване на дадено условие, след което показва съобщение на
потребителя. Дали евентуално не може да се използва в транзакции свързни с инсърт на нещо в
база или нещо от сорта.
Нещо като try/catch, или по-скоро рънтайм тестване на някакво условие.
Използва се специална дума assert.
Като си има и механизъм за изпращане на съобщения до user-ите.

assert foo != null : "foo is null!" // shows message "foo is null!" to user

Да се видят допълнителни примери ако се наложи да се ползва.


Arrays
------
Масивът е специален тип обект, който може да дъжи подредена (под номер), колекция от
елементи.
Типът на елементите в масива може да бъде всякакъв примитивни или референс типове.
Дължината му е фиксирана.

Array-ите са пълноправни first-class джава обекти, но се различават от стандартните java обекти, по


три параметъра:
- java специално създава array class type за нас, когато ние декларираме нов тип масив.
- достъпват се с оператора [] и номер на елемента, освен get и set както е с останалите
класове.
- java предоставя възможност с този оператор на конструираме масив със специфична
дължина и да го инициализираме директно от структура от стойности.

Array Types:

Създаване и инициализация на масиви:

int [] arrayOfInts;

arrayOfInts = new int [42];


someStrings = new String [ number + 2 ];

Component [] widgets = new Component [12]; - комбиниран подход

Да се прави едно важно разграничение. В повечето езици създаването на масив и алокирането на


място в паметта за неговите елементи е един и същ процес. В java, новосъздадения масив има
reference variables, които са със null стойност.
Има алокирана памет, но тя съхранява само празни слотове.

int [] primes = { 2, 3, 5, 7, 7+4 }; - това също е валиден синтаксис.

length е единственото достъпно пропърти на масива, това е променлива не метод.

Ако се опитаме да достъпим елемент, който е извън range-а, получаваме


ArrayIndexOutOfBoundsException.
Можем да копираме range от елементи от един масив в друг. Има различни начини, като един от
тях е arraycopy() метода на System класа. java.util.ArrayscopyOf() and copyOfRange() methods:.

Можем да имаме и анонимни масиви, които използваме само веднъж.

Пример за синтаксиса:

setPets ( new Animal [] { pokey, boojum, simon })

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

Color [][][] rgbCube = new Color [256][256][256];


rgbCube[0][0][0] = Color.black;
rgbCube[255][255][0] = Color.yellow;

Така се назначава стойност.


Не е задължително да знаем дължината на допълнителните дименсии, а само на основната първа.

===========================
== Chapter 5. Objects in Java ==
===========================

Дизайна на обекти е методология и правила, които да помогнат едно приложение да може да се


разбие на обекти, които да са преизползваеми и т.н.
Има различни методологии.
Често това означава просто мапване на ентитита и концепции от реалния живот, към компоненти
в приложението (т.н. problem domain).
Има различни методологии, но нито една няма да помогне при всички случаи. Помага опита.

- Hide as much of your implementation as possible. Never expose more of the internals of an
object than you need to.
This is key to building maintainable, reusable code.
Avoid public variables in your objects, with the possible exception of constants.
Instead define accessor methods to set and return values (even if they are simple types).
Later, when you need to, you’ll be able to modify and extend the behavior of your
objects without breaking other classes that rely on them.

- Да скриваме колкото можем повече от имплементацията. Да не експозваме въртешността


на обекта повече отколко е необходимо. Да избягваме публик променливи, доколкото е
възможно и да използваме гетъри и сетъри, които могат лесно да се модифицират ако се
наложи, без да се чупи целия клас и всички подкласове, които разчитат на него. По лесно е
за екстендване.
Може би да скрием колкото се може повече от това как класа си върши работата,
малко на принципа на черната кутия.
Това означава, ли че трябва да извикам само един метод от инстанцията на класа:
instance.doJob(), а после doJob() да извика doFirstStep(), doSecondStep(),
doTrirdStep().
Или директно от инстанцията да извикам последователните стъпки > по-скоро
първото. !!!! бележка 21.09..... това да се проучи в контекста на дизайн патерните. До какво ниво
да се разбива на методи, дали да се направи един главен метод, който да вика последователно
по-малките, когато имаме код със стъпки за изпълнение.

- Създавай специализирани обекти, само когато има нужда от това. Наместо това е по-
добре да се използват композитни обекти. Композиране на обекти наместо наследяване
на обекти. Композиране означава, като използваме обект в друг обект. Наследяването
чупи енкапсулацията на обекта и трябва да се използва само когато има нужда от това.
Тоест ние няма да наследяваме целия интерфейс на обекта (и неговия тип), може просто
да делегираме определена работа на новия обект, чрез композиране.
Допълнително да се потърси каква е разликата между composition и inheritance.

- Да се минимизират отношенията между обектите и да се организират свързани обекти в


пакети.

Only expose classes that you intend other people to use. The more loosely coupled your objects
are, the easier it will be to reuse them later.

Classes
-------

Pendulum p;
p = new Pendulum();

В първия ред, ние не създаваме обект Pendelium, а само декларираме променлива, която държи
референция към обект от тип Pendelium.
Трябва да създадем обекта с new, както се вижда на втория ред.
Методите на обекта (инстанционните, не статичните) достъпват пропъртитата на обекта, но java
обекта, няма свое копие на самите методи, което да се копира при всяка инстанция.

Several factors affect whether class members can be accessed from another class. You can use the
visibility modifiers public, private, and protected to control access;
Classes can also be placed into a package, which affects their scope.
The private modifier, for example, designates a variable or method for use only by other members of
the class itself.

Static Members
--------------
Достъпват се както през инстанцията на обекта (стойността им е еднаква за всички инстанции),
така и директно през класа.
Име на класа . име на статик променливата.
Много са полезни за данни, които се шерват между различните класове, по време на рънтайм.
Static + final думичката се използват за създаване на константи.
Статик членовете са полезни за флагове и идентификатори, които могат да бъдат достъпни
отвсякъде. Както и за стойности, които са нужни на конструкторите на класовете да създадат
инстанция на даден клас.

Тука казват, че можем да създадем специални методи, които да регистрират инстанциите на


обектите, така че да могат да комуникират и да ни е по-лесно да проследим какво се случва.
!!! тук може би се има предвид, това което имаме във sales raider, където имаме отделни методи
за инициализация на отделните класове, които обслужват DB таблиците на ентититата и заявките
към тях, както и open, close и т.н.

========= дотук съм стигнал ========

Enumeration
-----------
An enum is a special "class" that represents a group of constants (unchangeable variables, like final
variables).

To create an enum, use the enum keyword (instead of class or interface), and separate the constants
with a comma. Note that they should be in uppercase letters:
enum Level {
LOW,
MEDIUM,
HIGH
}

Level myVar = Level.MEDIUM;

Methods:
--------

If the method is executing concurrently in different threads, each thread has its own version of the
method’s local variables.

Принципно локалните променливи се унищожават, след като метода спре да се изпълнява, обаче
има една специфика, ако имаме локален обект.

If, however, we assign the object to an instance variable of an object, pass it as an argument to another
method, or pass it back as a return value, it may be saved by another variable holding its reference.
We’ll discuss object creation and garbage collection in more detail shortly.

Инициализиране на променливи в методи:

void myMethod() {
int foo = 42;
int bar;

bar += 1; // compile-time error, bar uninitialized

bar = 99;
bar += 1; // would be OK here
}

Argument Passing and References


-------------------------------

Да се върна да дочета за методите (wrraper класове, енкапсулация и т.н.)


Тук има някакви насоки, когато предадеш обект на даден метод (което реално е предаване на
референция към обекта), как можело да промениш референцията
да сочи към друг обект. Малко тъпо е написано и не успях да го разбера на 100%.

Wrappers for Primitive Types


-----------------------------

Java поддържа два начина на работа с примитивни типове:


- нормален, който е необходим от гледна точка на performance etc. (ако смяташ числа, ще искаш
изчисленията да се правят по-леко)
- примитивните типове като обекти. когато искаме да ползваме редица предимства, които има
обекта за да работим с примитивни типове.
има т.н. wrraper класове, за всеки от примитивните типове.
void - java.lang.Void

boolean - java.lang.Boolean

char - java.lang.Character

Инстанцията на даден клас енкапсулира единична стойност на кореспондиращия тип.


Това е immutable object (да прочета допълнително !!!), който служи за контейнер за да държи
стойността и да ни позволи да е гет-нем, когато имаме нужда.

Float pi = new Float( 3.14 );


Float pi = new Float( "3.14" );

При този пример ефекта е един и същ. Стринга във втория случай се парсва, като ако има грешка
при
парсването се хвърля ексепшън.

Обектите са удобни за кастване към различни типове.


Пример:

Double size = new Double ( 32.76 );

double d = size.doubleValue(); // 32.76


float f = size.floatValue(); // 32.76
long l = size.longValue(); // 32
int i = size.intValue(); // 32

Най-голямата нужда от wrapper класовете, е когато искаме да предадем примитивна стойност на


метод, който приема само обекти.
Пример за това е CollectionAPI-то. Класовете в него работят с групи от обекти, като list, sets, maps.
За да сложим примитивна стойност в такъв клас, трябва да я кастнем като обект.

Autoboxing and Unboxing of Primitives


-------------------------------------
Java компилатора автоматично wrap-ва примитиви към техните wrapper типове и ги unwraps-ва,
когато е необходимо.
това е т.н. процес autoboxing и unboxing.

Не е кой знае какво. Просто трябва да знаем, че понякога Java автоматично wrap-ва и unwraps-ва.

int i = new Integer(5);


Да се прецени кога ще е необходимо това, защото самия процес е ресурсоемък и ако трябва да се
wrap-ват и unwrap-ват много обекти
тогава по-добре да се пренапише кода и да се използват само примитиви.

Variable-Length Argument Lists


------------------------------
Методите в Java могат да имат т.н. variable-length argument lists or “varargs”, което означава, че
могат да приемат различен брой
аргументи, когато са извикани.

Най-типичния пример е използването на метода printf(), който принти всички аргументи, които му
се предадат.
Такъв тип методи (които приемат различен брой аргументи) е еквивалентен на методите, които
приемат масив от даден тип обекти.
Разликата е, че компилатора автоматично прави така, че метода да приема индивидуални comma
separated values, след което ги пакетира
в масив. Синатаксиса за деклариране на такъв тип методи е ( ... )
Пример:
void printObjects( Object ... list ) {
// list is an Object []
for( Object o : list )
System.out.println( o );
}

Може да имаме първоначално някколко бройки фиксирани аргументи, след което да имаме
varargs декларация.

void printf( String format, Object ... args ) { ... }

Method Overloading
------------------
Това е възможността да дефинираме различни методи с едно и също име в един клас и когато
метода е извикан компилатора избира коректния метод за изпълнение на база на аргументите,
които са му предадени. Различен тип или брой аргументи.
Идеята е да се създадат методи, които се държат по еднакъв начин при различен тип аргументи.

Object Creation
---------------

Обектите в Java са алокирани в системната heap memory space. За разлика от някои други
програмни езици, Java програмистите нямат възможност да управляват тази памет. Java го прави
автоматично.
Constructors
------------
Метод, който се извиква при създаване на обекта и дава възможност да се сетъпнат някакви
стойности в обекта.
Могат да приемат аргументи и да бъдат overloaded, както и останалите методи, но не се
наследяват като останалите методи.
Ако имаме няколко конструктора т.н. дефолтен конструктор, ще бъде този, който е без никакви
аргументи.
Ако сетнем референция към обект на null > това е ясен знак за garbage collection.
Конструкторите могат да бъдат дефинирани като public, private или protected, за да се контролира
тяхната видимост, но не могат да се дефинират като abstract, synchronized(!!!! да прочета
допълнително за това), or final.

Working with Overloaded Constructors


------------------------------------
Конструктора може да реферира към друг конструктор във същия клас или към суперклас с
помощта на this и super референциите.
Може да се направи първо извикване на конструктура, което да зададе някакви базови параметри
на обекта, след което да извика втори конструктор, който да направи някакви по засукани
настройки, параметри и т.н. на обекта.
Когато извикваме втори конструктор от дефолтния е важно да се знае, че това трябва да бъде
първия стейтмънт, ако е втория или третия ще даде compile error.

Car( String m ) {
int doors = determineDoors();
this( m, doors ); // Error: constructor call
// must be first statement
}

class Car {
...
final int default_doors = 4;
...

Car( String m ) {
this( m, default_doors ); // Error: referencing
// uninitialized variable
}
...
}
Тук във втория пример, също ще даде грешка, защотото променливата не е инициализирана, но
това може да се преодолее, ако използваме static променливи.

Static and Nonstatic Initializer Blocks


---------------------------------------
Тези блокове могат да се използват за допълнителни настройки на обекта.
Ако са статик те се изпълняват при прочитане на класа, ако не са, се изпълняват при
инициализация на обекта.

Instance initializer blocks могат да бъдат нещо като допълнение към instance variable initialization-a.
Викат се когато се инициализират променливите.
Пример:
class MyClass {
Properties myProps = new Properties();
// set up myProps
{
myProps.put("foo", "bar");
myProps.put("boo", "gee");
}
int a = 5;

Object Destruction
------------------

Наличието на garbage collector, който да разрушава обектите, помага на програмистите, тъй като
не се налага да търсим постоянно memory leak-ове, както например C, C++ програмистите.
Когато всички референции към обекта са заминали и той не е достъпен повече, garbage collector-а
го маркира като unreachable и изисква обратно паметта, към пула с налична памет, за работа на
програмата.
Има различни алгоритми. Първоначалните алгоритми не са хващали обекти, които реферират
един към друг.
Те са част от runtime system-a на Java.
Преди даден обект да се разруши се вика неговия finalize() метод, който може да зачисти разни
неща. Връзки към бази и т.н.
Но идеята, е че не се знае кога това ще се случи. Ако има достатъчно място на машината garbage
collector-а може никога да не се извика.

Weak and Soft References


------------------------
Различни типове референции, които казват как да работи garbage collectora.
Примерно soft референцият, казва че обекта може да бъде премахнат, само ако няма достатъчно
памет на машината.
Слагат се специални wrraper-и, към референциите, за да се постигне такъв ефект.

Enumerations
------------

Това е тип обект в Java, който е лимитиран до определен сет от стойности.


Стойностите имат ред, който е дефиниран от техния ред на декларация в кода и имат
кореспонденция със string name, който е същия като декларираното име в кода. ???

Пример за използването им:

enum Weekday { Sunday, Monday, Tuesday, Wednesday, Thursday, Friday,


Saturday }

// usage
setDay( Weekday.Sunday );

Какво се случва отзад. т.е. компилатора какво прави.

public final class Weekday extends java.lang.Enum {


public static final Weekday Sunday;
public static final Weekday Monday;
public static final Weekday Tuesday;
public static final Weekday Wednesday;
public static final Weekday Thursday;
public static final Weekday Friday;
public static final Weekday Saturday;

public static final Weekday[] values();


public static Weekday valueOf(java.lang.String);
}

Java не позволява да има други референции към този клас.


Тъй като enumerations са статик стойности, те могат да бъдат импортнати със Java static import.

import static mypackage.Weekday.*;


...
setDay( Friday );
setDeadline( Sunday );

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

Могат да бъдат декларирани и в тялото на самия клас, както и на интерфейс.

Enum Values
-----------
Списъка със всички enum values, можем да вземем със static values() method.

Weekday [] weekdays = Weekday.values();

Имаме билднат compareTo() метод в енум типовете, който сравнява една стойност със друга, но
трябва да са от същия енум тип.

enum Cat {
Himilayan, Siamese, Caleco,
Persian {
public void someMethod() { ... }
}
}

Можем и така да къстъмизираме някаква стойност.

Chapter 6. Relationships Among Classes


=======================================

Subclassing and Inheritance


---------------------------

Класа наследава само от един клас, като наследява всички членове, които не са маркирани като
private.

Shadowed Variables
------------------

In Chapter 5, we saw that a local variable of the same name as an instance variable shadows (hides) the
instance variable.
Similarly, an instance variable in a subclass can shadow an instance variable of the same name in its
parent class

Overriding Methods
------------------

Overriding methods to change the behavior of objects is called subtype polymorphism.

@Override
---------

A common programming error in Java is to accidentally overload a method when trying to override it.
Any difference in the number or type of arguments (the method signature) produces two overloaded
methods instead of a single, overridden method.
The new annotations syntax in Java 5.0 provides a way to get the compiler to help with this problem.
An annotation, as we’ll describe in Chapter 7, allows us to add special markers or metadata to source
code that can be read by the compiler or runtime tools.
One of the standard annotations that Java defines is called @Override and it tells the compiler that the
method it marks is intended to override a method in the superclass.
The compiler then warns if the method doesn’t match.

Overridden methods and dynamic binding


--------------------------------------

In a previous section, we mentioned that overloaded methods are selected by the compiler at compile
time. Overridden methods, on the other hand, are selected dynamically at runtime.
Even if we create an instance of a subclass our code has never seen before (perhaps a new class loaded
over the network), any overriding methods that it contains are located and used at runtime, replacing
those that existed when we last compiled our code.

Интересно, ако отнякъде се появи jar, който съдържа екстенднат клас и оверрайднат метод, на
класа от първия jar, то тогава рънтайм ще се прецени да се вземе новия екстенднат клас.
final methods and performance
-----------------------------

Ако декларираме някакъв метод final, то той не може да бъде overridе-нат от друг клас и метод.

We have seen final used with variables to effectively make them constants. When applied to a method,
final means that its implementation is constant—no overriding allowed.
final can also be applied to an entire class, which means the class can’t be subclassed.
Exceptions and overridden methods
---------------------------------

The new method cannot throw new types of checked exceptions.


It can only declare that it throws exception types assignable to those thrown by the method in the
parent class;
Има определени условия, в които това е позволено.

Return types and overridden methods


-----------------------------------

Can we change the return type of a method by overriding it?


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

class Animal {
Animal create() { ... }
}
class Mammal extends Animal {
Mammal create() { ... }
}

Casting
-------

A cast explicitly tells the compiler to change the apparent type of an object reference. The main use for
casts is when an object is temporarily assigned to a more general type.
Основното използване на case е когато обекта е назначен към по-генерален тип обект.
For example, if a String were assigned to a variable of type Object, to use it as a String again, we’d have
to perform a cast to get it back.
В случая компилатора ще разпознае декларирания тип на променливата (Object), но няма да
разпознае, че има String в нея.
В Java кастването се проверява и в compile time и във runtime.
Attempting to cast an object to an incompatible type at runtime results in a ClassCastException.
Only casts between objects in the same inheritance hierarchy (and, as we’ll see later, to appropriate
interfaces) are legal in Java and pass the scrutiny of the compiler and the runtime system.
Casts in Java affect only the treatment of references; they never change the form of the actual object.
This is an important rule to keep in mind.
You never change the object pointed to by a reference by casting it; you change only the compiler’s (or
runtime system’s) notion of it.

Full Disclosure: Constructors and Initialization


-----------------------------
Обобщение как работят конструкторите, когато са в процес на наследяване и т.н.
- ако първия стейтмънт в настоящия конструктор е нормален, а не викане на super() или this
конструктори > Java прави call към super() конструктора и чак след неговото изпълнение, се връща
към изпълнението на кода в настоящия конструктор.

- същото се отнася и ако имаме изричнo викане на super като първи statement.
- ако първия стейтмънт е викане на Overloaded конструктор с this, то тогава Java извиква избрания
конструктор и след неговото връщане, продължава с изпълнението на кода от настоящия
конструктор. Викането на super конструктора ще се случи по време на изпълнението на Overloaded
конструктора.

Abstract Methods and Classes


----------------------------

A method in Java can be declared with the abstract modifier to indicate that it’s just a prototype. An
abstract method has no body; it’s simply a signature declaration followed by a semicolon.
You can’t directly use a class that contains an abstract method; you must instead create a subclass that
implements the abstract method’s body:

abstract void vaporMethod( String name );

In Java, a class that contains one or more abstract methods must be explicitly declared as an abstract
class, also using the abstract modifier:

abstract classVaporClass {
...
abstract void vaporMethod( String name );
...
}

An abstract class can contain other nonabstract methods and ordinary variable declarations, but it can’t
be instantiated.
To be used, it must be subclassed and its abstract methods must be “overridden” with methods that
implement a body.
Not all abstract methods have to be implemented in a single subclass, but a subclass that doesn’t
override all its superclass’s abstract methods with actual, concrete implementations must also be
declared abstract.

class MyVaporImplementation extends VaporClass {


void vaporMethod( String name ) { ... }
}

Abstract classes provide a framework for classes that is to be “filled in” by the implementer.

The java.io.InputStream class, for example, has a single abstract method called read().
Various subclasses of InputStream implement read() in their own ways to read from their own sources.
The rest of the InputStream class, however, provides extended functionality built on the simple read()
method.
A subclass of InputStream inherits these nonabstract methods to provide functionality based on the
simple read() method that the subclass implements.

Interfaces
==========

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


Често е по-лесно/практично да специфицираш група от абстрактни методи, като се дефинира
някакво поведение в тях, без да се вързват към някаква имплементация. Това е интерфейса.
??? Доколкото разбирам абстрктния клас се вързва към имплементация, тъй като трябва да бъде
екстенднат от имплементиращия го клас, а интерфейса само се казва, че имплементира
изискваните методи, т.е. нямаме връзка с цялата верига на наследяване и т.н. ???

Лист от методи, които дефинират някакво поведение на обект. т.е. това е като значка в скаутските
организации. ако можеш да палиш огън и опъваш палатка, значи имаш две значки и това са
конкретни умения, което ти имаш като част от групата.
Интерфейсите се декларират към класовете в compile time.
Типа на интерфейса се държи като тип на класа:
- могат да се дефинират променливи, които да са от типа на интерфейса
- могат да се дефинират аргументи към методи, които приемат типа на интерфейса
- могат да се специфицират return type-ове на методи, които да са от типа на интерфейса

т.е. само обект, който имплементира интерфейса може да приеме тази роля.
В този смисъл интерфейсите са обратни на нормалната йерархия от класове.
Те прекъсват йерархията, която казва какво дадения item/обект е, със това какво може да прави.
Всмисъл аз съм историк, но мога да програмирам.
Класа може да имплементира колкото си иска интерфейси.
Това до някаква степен замества множественото наследяване, което го има в други езици.
Интерфейса изглежда като абстрактен клас. Методи без body, само име и аргументи.
Методите на интерфейса винаги са публични.
Тук дават интересен пример с клас Превозно средство, който има методи (старт двигател, стоп
двигател, завой, стоп), и този интерфейс се имплементира от класове: Автомобил, и Градинска
косачка.

Interfaces as Callbacks
-----------------------
Интерфейсите могат да се използват за имплементиране на callbacks. Това е когато обекта предава
референция към един или няколко от неговите методи към друг обект.
Callback-а се появява когато извикания обект последователно извиква един от своите методи.
В C и C++ това се прави с т.н. function pointers, а в Java се използват интерфейси.
По-генерално, тази концепция е екстендната в Java към конценпцията за events, в които listener
обекта регистрира event източници.
Аз съм обект и викам друг метод от друг обект > предавам му референция към някои от моите
методи > другия метод изпълнява някакъв код,след което вика референцията, която му е
предадена. ??? как обаче се използват интерфейсите за това.

Има два класа:


Единия Tape дисплейва някакви данни, а другия TextSource му предоставя необходимата
информация.
Искаме TextSource да изпрати някакви нови данни. Можем да направим така, че TextSource да
държи референция към Tape обекта, но тогава ние няма да можем да използваме класа
TextSource да изпраща данни към друг вид обект.
Има начин да се разреши този проблем с някакви субкласове и т.н., но доста по-елегантен начин е
да направим TextSource да държи референция към interface type TextReceiver. (??? т.е. трети тип
клас се появява в примера).

interface TextReceiver {
void receiveText( String text );
}

class TickerTape implements TextReceiver {


public void receiveText( String text ) {
System.out.println("TICKER:\n" + text + "\n");
}
}

class TextSource {
TextReceiver receiver;

TextSource( TextReceiver r ) {
receiver = r;
}

public void sendText( String s ) {


receiver.receiveText( s );
}
}

Interface Variables
-------------------
Въпреки, че интерфейсите ни позволяват да специфицираме поведение без имплементация, има
едно изключение.
Интерфейса може да съдържа константи (static final variables), които могат да реферирани
директно през името на интерфейса, и ще се появат във всеки клас, който имплементира
интерфейса.
Това позволява константите да бъдат пакетирани заедно с методите на интерфейса и така да се
използват заедно.

interface Scaleable {
static final int BIG = 0, MEDIUM = 1, SMALL = 2;
void setScale( int size );
}

class Box implements Scaleable {

void setScale( int size ) {


switch( size ) {
case BIG:
...
case MEDIUM:
...
case SMALL:
...
}
}
...
}

Технически не е грешно да се използва така, но откакто Java добавя enumerations и static imports,
това се обезмисля.
Още повече, че тези константи могат да объркат хората, които имплементират интерфейса. И не
могат да се махнат.
По добре е да се използва енумерация със собствен клас в който има константи, след което да се
направи static import.

enum SizeConstants { BIG, MEDIUM, SMALL }

// usage
static import mypackage.SizeConstants;
...
setSize( MEDIUM );

Flag Interfaces
---------------
Понякога напълно празен интерфейс може да случи за маркер, че класа има специфично
пропърти.
Това е като инструкция към java компилатора. Примерно java.io.Serializeable interface казва на Java,
че искаме този клас да може да се сериализира по някакъв начин.
В по-новите версии на Java това става излишно, тъй като се използват анотации за тази цел.

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

Overlapping and conflicting methods


-----------------------------------
Можем да имаме случаи в които когато клас екстендва повече от един интерфейс. Може да
имаме презастъпване на имената на методите. Ако са еднакви като име няма проблем, обаче ако
са различни като параметри > тогава ще трябва да се имплементират и двата метода.

Packages and Compilation Units


==============================
Java използва package name-овете, за да локализира даден клас по време на компилация и
runtime.
Пакетите предоставят допълнително ниво на scope and context на методите и променливите в тях.

Compilation Units
-----------------
The compiler relies on the names of source files to find and compile dependent classes.
There can be only one package statement, and it applies to the entire file.
Package names are hierarchical in nature, using a dot-separated naming convention.

Names
-----
By default, package name components correspond to directory names and serve as a unique path for
the compiler and runtime systems to locate Java source files and classes.
Но освен за локализация, java не създава друг вид релация между пакетите (както е при
класовете). Няма такова нещо като подпакет subpackage.
Тези класове, на които не сме им дали имена попадат в един голям анонимен пакет.

Class Visibility
----------------
By default, a class is accessible only to other classes within its package.
To be used outside of its package, a class must be declared as public
Това става като интерфейс към външния свят. Тоест ние достъпваме пакета чрез един външен
клас,
а той вече вика останалите които му трябват отвътре. т.е. нещо като боотстрап механизъм.

Интересен пример е как използваме static import. Защото тогава буквално оставаме с
впечатлението, че работим с билдин функции, а те реално са декларирани в пакета, който
импортваме.

import static java.lang.Math.*;

// usage
double circumference = 2 * PI * radius;
double length = sin( theta ) * side;
int bigger = max( a, b );
int positive = abs( num );

Visibility of Variables and Methods


===================================

One of the most important aspects of object-oriented design is data hiding, or encapsulation.
By treating an object in some respects as a “black box” and ignoring the details of its implementation,
we can write more resilient, simpler code with components that can be easily reused.

protected - специфицира права за виждане само за неговите субкласове.


Когато се пренаписват методи от суперкласа, те трябва да са видими поне колкото самия
суперметод. Възможно е да вземем private метод и да го пренапишем като public в своя subclass,
но обратното не е възможно. Не може да пренапишем public method към private method.

Interfaces and Visibility


-------------------------
Interfaces behave like classes within packages. An interface can be declared public to make it visible
outside its package.
Under the default visibility, an interface is visible only inside its package. Like classes, only one public
interface can be declared in a compilation unit (file).

Arrays and the Class Hierarchy


==============================

Array classes live in a parallel Java class hierarchy under the Object class.

!!! да се довърши !!!

Chapter 7. Working with Objects and Classes


===========================================

The Object Class


----------------

java.lang.Object is the ancestor of all objects; it’s the primordial class from which all other classes are
ultimately derived.
Methods defined in Object are, therefore, very important because they appear in every instance of
every class, throughout all of Java
At last count, there were nine public methods and two protected methods in Object. Five of these are
versions of wait() and notify() that are used to synchronize threads on object instances, as we’ll discuss
in Chapter 9.
The remaining four methods are used for basic comparison, conversion, and administration.
Every object has a toString() method that can be called when it’s to be represented as a text value.
PrintStream objects use toString() to print data, as discussed in Chapter 12. toString() is also used
implicitly when an object is referenced in a string concatenation. Here are some examples:

Equality and Equivalence


------------------------

equals() determines whether two objects are equivalent. Precisely what that means for a particular class
is something that you’ll have to decide for yourself.
Two String objects, for example, are considered equivalent if they hold precisely the same characters in
the same sequence:

Using equals() is not the same as the “==” operator in Java:

if ( userName == suspectName ) // Wrong!


This statement tests whether the two reference variables, userName and suspectName, refer to the
same object. It is a test for identity, not equality.

It is possible in Java to construct two String objects with the same contents that are, nonetheless,
different instances of the String class—although, as we’ll describe later, Java tries to help you avoid that
when it can.

equals метода може да се override-не, за да направим наша собствена версия на него.

Hashcodes
---------
The hashCode() method returns an integer that is a hashcode for the object.
A hashcode is like a signature or checksum for an object; it’s a random-looking identifying number that is
usually generated from the contents of the object.
The hashcode should always be different for instances of the class that contain different data, but
should be the same for instances that compare “equal” with the equals() method.
Hashcodes are used in the process of storing objects in a Hashtable or a similar kind of collection.

Cloning Objects
---------------

The Java Object class provides the mechanism to make a simple copy of an object including all of its
“shallow” state—a bitwise copy.
What’s so shallow about it? Java has simply copied the values of our variables.
But by default, this capability is turned off.
To make itself cloneable, an object must implement the java.lang.Cloneable interface.
This is a flag interface indicating to Java that the object wants to cooperate in being cloned (the
interface does not actually contain any methods).
If the object isn’t cloneable, the clone() method throws a CloneNotSupportedException.
!!! още един пример за работата на интерфейсите !!!

clone() is a protected method, so by default it can be called only by an object on itself, an object in the
same package, or another object of the same type or a subtype. If we want to make an object cloneable
by everyone, we have to override its clone() method and make it public.

Here is a simple, cloneable class—Sheep:

import java.util.HashMap;
public class Sheep implements Cloneable {
HashMap flock = new HashMap();

public Object clone() {


try {
return super.clone();
} catch (CloneNotSupportedException e ) {
throw new Error(
"This should never happen because we implement Cloneable!");
}
}
}

The Class Class


===============

Classes in Java source code are represented at runtime by instances of the java.lang.Class class.

There’s a Class object for every object type you use; this Class object is responsible for producing
instances of that type.
But you don’t generally have to worry about that unless you are interested in loading new kinds of
classes dynamically at runtime or using a highly abstracted API that wants a “type” instead of an actual
argument.
The Class object is also the basis for “reflecting” on a class to find its methods and other properties,
allowing you to find out about an object’s structure or invoke its methods programmatically at runtime.
We get the Class associated with a particular object with the getClass() method:

String myString = "Foo!"


Class stringClass = myString.getClass();

We can also get the Class reference for a particular class statically, using the .class notation:

Class stringClass = String.class;

Най-важните неща, които можем да правим с class обекта е:


- да поискаме от него да си каже името.
- да направи нова инстанция на неговия тип обекти.
String s2 = (String)stringClass.newInstance();

Да се има предвид, че можем да направим инстанция на този клас, само ако има достъпен public
дефолтен конструктор.
Не можем да предадем накакви аргументи на този конструктор.

interface Typewriter {
void typeLine( String s );
...
}

class Printer implements Typewriter {


...
}

class MyApplication {
...
String outputDeviceName = "Printer";

try {
Class newClass = Class.forName( outputDeviceName );
Typewriter device = (Typewriter)newClass.newInstance();
...
device.typeLine("Hello...");
}
catch ( Exception e ) { ... }
}

!!! да се довърши. !!!

!!! Combining these tools, we have the power to load new kinds of classes dynamically.
When combined with the power of interfaces, we can use new data types loaded by a string name in our
applications: !!!

interface Typewriter {
void typeLine( String s );
...
}

class Printer implements Typewriter {


...
}

class MyApplication {
...
String outputDeviceName = "Printer";

try {
Class newClass = Class.forName( outputDeviceName );
Typewriter device = (Typewriter)newClass.newInstance();
...
device.typeLine("Hello...");
}
catch ( Exception e ) { ... }
}

!!!! Важен пример: Тук ние зареждаме имплементация на Typewriter interface, като само знаем
името на класа.
Ако това име идва от конфигурационен файл или от някъде другъде (примерно да вземем всички
класове, които имплементират дадения интерфейс), то тогава възможностите са много големи.
Този принцип стои в основата на много конфигурационни механизми в Java.

Reflection
==========

In this section, we’ll take a look at the Java Reflection API, supported by the classes in the
java.lang.reflect package.
As its name suggests, reflection is the ability for a class or object to examine itself.
Reflection lets Java code look at an object (more precisely, the class of the object) and determine its
structure.
Within the limits imposed by the security manager, you can find out what constructors, methods, and
fields a class has, as well as their attributes.
You can even change the value of fields, dynamically invoke methods, and construct new objects, much
as if Java had primitive pointers to variables and methods.
And you can do all this on objects that your code has never even seen before.
The Annotations API also has the ability to preserve metadata about source code in the compiled classes
and we can retrieve this information with the Reflection API.

The Reflection API can be used to determine the capabilities of objects at runtime.
It’s used by object serialization to tear apart and build objects for transport over streams or into
persistent storage.

====
Казус:
Ако имаме статик променлива в Абстрактен клас и ако този абстрактен клас се достъпва от
различни класове, дали стойността на статик променливата ще е еднаква.
Аз мисля, че ще е еднаква.

You might also like