1. Свойства: гетери и сетери

Когато голям проект се разработва от десетки програмисти едновременно, често възникват проблеми, ако те обработват данните, съхранени в полетата на класа, по различен начин.

Може би хората не успяват да проучат подробно documentацията на класа or може би тя не описва всеки случай. В резултат на това има чести ситуации, когато вътрешните данни на даден обект могат да се „повредят“, правейки обекта невалиден.

За да се избегнат тези ситуации, обичайно е всички полета на класа да бъдат частни в Java . Само методите на класа могат да променят променливите на класа. НиHowви методи от други класове нямат директен достъп до променливите.

Ако искате други класове да могат да получават or променят данните вътре в обектите на вашия клас, трябва да добавите два метода към вашия клас — метод get и метод set. Пример:

Код Забележка
class Person
{
   private String name;

   public Person(String name)
   {
      this.name = name;
   }

   public String getName()
   {
      return name;
   }

   public void setName(String name)
   {
      this.name = name;
   }
}


privateполе за име



Инициализация на полето чрез конструктора


getName()— Този метод връща стойността на полето за име




setName()— Този метод променя стойността на полето за име

Никой друг клас не може директно да промени стойността на полето за име. Ако някой трябва да получи стойността на полето за име, той ще трябва да извика метода getName() на Personобект. Ако няHowъв code иска да промени стойността на полето за име, той ще трябва да извика метода setName() на Personобект.

Методът getName()се нарича също „ получател за полето за име“, а методът setName()се нарича „ поставител за полето за име“.

Това е много често срещан подход. В 80-90% от целия code на Java никога няма да видите публични променливи в клас. Вместо това те ще бъдат декларирани private(or protected) и всяка променлива ще има публични гетери и сетери.

Този подход прави codeа по-дълъг, но по-надежден.

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

Да приемем, че искате да създадете клас, който описва точка ( x, y). Ето How би го направил един начинаещ програмист:

class Point
{
   public int x;
   public int y;
}

Ето How опитен Java програмист би го направил:

Код
class Point {
   private int x;
   private int y;

   public Point(int x, int y) {
      this.x = x;
      this.y = y;
   }

   public int getX() {
      return x;
   }

   public void setX(int x) {
      this.x = x;
   }

   public int getY() {
      return y;
   }

   public void setY(int y) {
      this.y = y;
   }
}

Кодът по-дълъг ли е? Несъмнено.

Но можете да добавите валидиране на параметри към гетери и сетери. Например, можете да се уверите, че xи yвинаги са по-големи от нула (or не по-малко от нула). Пример:

Код Забележка
class Point {
   private int x;
   private int y;

   public Point(int x, int y) {
      this.x = x < 0 ? 0 : x;
      this.y = y < 0 ? 0 : y;
   }

   public int getX() {
      return x;
   }

   public void setX(int x) {
      this.x = x < 0 ?  0 : x;
   }

   public int getY() {
      return y;
   }

   public void setY(int y) {
      this.y = y < 0 ? 0 : y;
   }
}


2. Живот на обекта

Вече знаете, че обектите се създават с помощта на newоператора, но How се изтриват обектите? Те не съществуват вечно. Няма достатъчно памет за това.

В много езици за програмиране, като C++, има специален deleteоператор за изтриване на обекти. Но How работи това в Java?

В Java всичко е подредено малко по-различно. Java няма оператор за изтриване. Това означава ли, че обектите не се изтриват в Java? Не, те се изтриват, разбира се. В противен случай Java applicationsта бързо биха изчерпали паметта си и нямаше да се говори за програми, работещи без прекъсване с месеци.

В Java изтриването на обекти е напълно автоматизирано. Самата Java машина се справя с изтриването на обекти. Този процес се нарича събиране на боклук, а механизмът, който събира боклука, се нарича събирач на боклук ( GC ).

И така, How Java машината знае кога да изтрие обект?

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

В Java не можете да създадете препратка към съществуващ обект — можете да присвоите само препратки, които вече имате. Ако изтрием всички препратки към даден обект, той се губи завинаги.

Циркулярни препратки

Тази логика звучи страхотно, докато не се натъкнем на прост контрапример: да предположим, че имаме два обекта, които се препращат един към друг (съхраняват препратки един към друг). Никой друг обект не съхранява препратки към тези обекти.

Тези обекти не могат да бъдат достъпни от codeа, но те все още са посочени.

Ето защо събирачът на боклук разделя обектите на достъпни и недостъпни, а не на "реферирани" и "нереферирани".

Достъпни обекти

Първо, обекти, които са 100% живи, се добавят към списъка с достъпни. Например текущата нишка ( Thread.current()) or конзолата InputStream ( System.in).

След това списъкът с достъпни обекти се разширява, за да включва обекти, които са посочени от първоначалния набор от достъпни обекти. След това се разширява отново, за да включва обекти, които са посочени от този разширен набор и т.н.

Това означава, че ако има обекти, които се отнасят само един към друг, но няма начин да се достигне до тях от достъпни обекти, тогава тези обекти ще се считат за боклук и ще бъдат изтрити.


3. Събиране на боклука

Фрагментация на паметта

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

В резултат на това лесно можем да попаднем в ситуация, в която да не можем да създадем голям обект (например масив с мorон елемента), защото няма голямо парче свободна памет. С други думи, може да има свободна памет, дори много от нея, но може да няма голям непрекъснат блок свободна памет

Оптимизиране на паметта (дефрагментиране)

Java машината решава този проблем по специфичен начин. Изглежда нещо подобно:

Паметта е разделена на две части. Всички обекти се създават (и изтриват) само в едната половина на паметта. Когато дойде време за почистване на дупките в паметта, всички обекти от първата половина се копират във втората половина. Но те се копират точно един до друг, за да няма дупки.

Процесът изглежда приблизително така:

Стъпка 1: След създаване на обекти

Събиране на боклук в Java

Стъпка 2: Поява на "дупки"

Събиране на отпадъци в Java 2

Стъпка 3: Премахване на "дупките"

Събиране на боклук в Java 3

И затова не е необходимо да изтривате обекти. Java машината просто копира всички достъпни обекти на ново място и освобождава цялата област от паметта, където са бor съхранявани обектите.