1. Общ преглед
Просто казано, преди да можем да работим с обект на JVM, той трябва да бъде инициализиран.
В следващите раздели ще разгледаме различни начини, по които можем да инициализираме примитивни типове и обекти.
2. Декларация срещу инициализация
Нека започнем, като се уверим, че сме на една и съща страница.
Декларацията е процес на дефиниране на променливата заедно с нейния тип и име.
Тук декларираме променливата id :
int id;
От друга страна, инициализацията е свързана с присвояване на стойност; например:
id = 1;
За да демонстрираме, ще създадем потребителски клас с име и id свойства:
public class User { private String name; private int id; // standard constructor, getters, setters, }
След това ще видим, че инициализацията работи по различен начин в зависимост от типа поле, което инициализираме.
3. Обекти срещу примитиви
Java предоставя два вида представяне на данни: примитивни типове и референтни типове. В този раздел ще обсъдим разликите между двете по отношение на инициализацията.
Java има осем вградени типа данни, посочени като примитивни типове Java; променливи от този тип държат своите стойности директно.
Референтните типове съдържат препратки към обекти (екземпляри на класове). За разлика от примитивните типове, които държат своите стойности в паметта, където е разпределена променливата, препратките не съдържат стойността на обекта, към който се отнасят.
Вместо това препратката сочи към обект, като съхранява адреса на паметта, където се намира обектът.
Имайте предвид, че Java не ни позволява да открием какъв е физическият адрес на паметта. По-скоро можем да използваме препратката само за препратка към обекта.
Нека да разгледаме пример, който декларира и инициализира референтен тип извън нашия потребителски клас:
@Test public void whenIntializedWithNew_thenInstanceIsNotNull() { User user = new User(); assertThat(user).isNotNull(); }
Както виждаме тук, препратка може да бъде присвоена на нова с помощта на ключовата дума new, която е отговорна за създаването на новия потребителски обект.
Нека продължим с научаването на повече за създаването на обекти.
5. Създаване на обекти
За разлика от примитивите, създаването на обекти е малко по-сложно. Това е така, защото не просто добавяме стойността към полето; вместо това задействаме инициализацията с помощта на новата ключова дума. Това в замяна извиква конструктор и инициализира обекта в паметта.
Нека обсъдим конструкторите и новата ключова дума по-подробно.
Най- новата ключова дума е отговорен за разпределянето на памет за новия обект чрез конструктор.
Конструктор обикновено се използва за инициализиране на променливи на екземпляра, представляващи основните свойства на създадения обект .
Ако не предоставим изрично конструктор, компилаторът ще създаде конструктор по подразбиране, който няма аргументи и просто разпределя памет за обекта.
Един клас може да има много конструктори, стига списъците с параметри да са различни ( претоварване ) . Всеки конструктор, който не извиква друг конструктор в същия клас, има извикване към своя родителски конструктор, независимо дали е написан изрично или е вмъкнат от компилатора чрез super () .
Нека добавим конструктор към нашия потребителски клас:
public User(String name, int id) { this.name = name; this.id = id; }
Сега можем да използваме нашия конструктор, за да създадем потребителски обект с начални стойности за неговите свойства:
User user = new User("Alice", 1);
6. Променлив обхват
В следващите раздели ще разгледаме различните видове обхвати, в които дадена променлива в Java може да съществува и как това влияе на процеса на инициализация.
6.1. Променливи на инстанция и клас
Променливите на инстанция и клас не изискват от нас да ги инициализираме. Веднага след като декларираме тези променливи, те получават стойност по подразбиране, както следва:

Сега, нека се опитаме да дефинираме някои променливи, свързани с екземпляр и клас и да тестваме дали те имат стойност по подразбиране или не:
@Test public void whenValuesAreNotInitialized_thenUserNameAndIdReturnDefault() { User user = new User(); assertThat(user.getName()).isNull(); assertThat(user.getId() == 0); }
6.2. Локални променливи
Локалните променливи трябва да бъдат инициализирани преди употреба , тъй като нямат стойност по подразбиране и компилаторът не ни позволява да използваме неинициализирана стойност.
Например следният код генерира грешка в компилатора:
public void print(){ int i; System.out.println(i); }
7. Последната ключова дума
На финалната дума нанася поле означава, че стойността на полето вече не могат да бъдат променяни, след инициализация. По този начин можем да определим константи в Java.
Let's add a constant to our User class:
private static final int YEAR = 2000;
Constants must be initialized either when they're declared or in a constructor.
8. Initializers in Java
In Java, an initializer is a block of code that has no associated name or data type and is placed outside of any method, constructor, or another block of code.
Java offers two types of initializers, static and instance initializers. Let's see how we can use each of them.
8.1. Instance Initializers
We can use these to initialize instance variables.
To demonstrate, let’s provide a value for a user id using an instance initializer in our User class:
{ id = 0; }
8.2. Static Initialization Block
A static initializer or static block – is a block of code which is used to initialize static fields. In other words, it’s a simple initializer marked with the keyword static:
private static String forum; static { forum = "Java"; }
9. Order of Initialization
When writing code that initializes different types of fields, of course, we have to keep an eye on the order of initialization.
In Java, the order for initialization statements is as follows:
- static variables and static initializers in order
- instance variables and instance initializers in order
- constructors
10. Object Life Cycle
Now that we've learned how to declare and initialize objects, let's discover what happens to objects when they're not in use.
Unlike other languages where we have to worry about object destruction, Java takes care of obsolete objects through its garbage collector.
All objects in Java are stored in our program's heap memory. In fact, the heap represents a large pool of unused memory, allocated for our Java application.
On the other hand, the garbage collector is a Java program that takes care of automatic memory management by deleting objects that are no longer reachable.
For a Java object to become unreachable, it has to encounter one of the following situations:
- The object no longer has any references pointing to it
- All reference pointing to the object are out of scope
In conclusion, an object is first created from a class, usually using the keyword new. Then the object lives its life and provides us with access to its methods and fields.
Finally, when it's no longer needed, the garbage collector destroys it.
11. Other Methods for Creating Objects
In this section, we’ll take a brief look at methods other than new keyword to create objects and how to apply them, specifically reflection, cloning, and serialization.
Reflection is a mechanism we can use to inspect classes, fields, and methods at run-time. Here's an example of creating our User object using reflection:
@Test public void whenInitializedWithReflection_thenInstanceIsNotNull() throws Exception { User user = User.class.getConstructor(String.class, int.class) .newInstance("Alice", 2); assertThat(user).isNotNull(); }
In this case, we're using reflection to find and invoke a constructor of the User class.
The next method, cloning, is a way to create an exact copy of an object. For this, our User class must implement the Cloneable interface:
public class User implements Cloneable { //... }
Сега можем да използваме метода clone () , за да създадем нов обект clonedUser, който има същите стойности на свойствата като потребителския обект:
@Test public void whenCopiedWithClone_thenExactMatchIsCreated() throws CloneNotSupportedException { User user = new User("Alice", 3); User clonedUser = (User) user.clone(); assertThat(clonedUser).isEqualTo(user); }
Също така можем да използваме класа sun.misc.Unsafe, за да разпределим памет за обект, без да извикваме конструктор:
User u = (User) unsafeInstance.allocateInstance(User.class);
12. Заключение
В този урок разгледахме инициализация на полета в Java. Открихме различни типове данни в Java и как да ги използваме. Също така разгледахме задълбочено няколко начина за създаване на обекти в Java.
Пълното изпълнение на този урок може да бъде намерено в Github.