1. Egenskaper: getters och setters

När ett stort projekt utvecklas av dussintals programmerare samtidigt, dyker ofta problem upp om de hanterar data som lagras i klassfält på olika sätt.

Kanske misslyckas folk med att studera klassdokumentationen i detalj, eller kanske beskriver den inte varje fall. Som ett resultat finns det ofta situationer när ett objekts interna data kan bli "skadade", vilket gör objektet ogiltigt.

För att undvika dessa situationer är det vanligt att göra alla klassfält privata i Java . Endast klassens metoder kan modifiera klassens variabler. Inga metoder från andra klasser kan komma direkt åt variablerna.

Om du vill att andra klasser ska kunna hämta eller ändra data inuti objekt i din klass, måste du lägga till två metoder till din klass - en get-metod och en set-metod. Exempel:

Koda Notera
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;
   }
}


privatenamnfält



Initiering av fältet via konstruktorn


getName()— Denna metod returnerar värdet på namnfältet




setName()— Denna metod ändrar värdet på namnfältet

Ingen annan klass kan direkt ändra värdet på namnfältet. Om någon behöver få värdet på namnfältet måste de anropa getName() metoden på ett Personobjekt. Om någon kod vill ändra värdet på namnfältet måste den anropa setName() metoden på ett Personobjekt.

Metoden getName()kallas också " getter för namnfältet", och metoden setName()kallas " sättare för namnfältet".

Detta är ett mycket vanligt tillvägagångssätt. I 80-90% av all Java-kod kommer du aldrig att se publika variabler i en klass. Istället kommer de att deklareras private(eller protected), och varje variabel kommer att ha offentliga getters och setters.

Detta tillvägagångssätt gör koden längre, men mer tillförlitlig.

Att komma åt en klassvariabel direkt är som att vända din bil genom dubbla gula linjer : det är enklare och snabbare, men om alla gör det blir det värre för alla.

Låt oss säga att du vill skapa en klass som beskriver en punkt ( , x) y. Så här skulle en nybörjare göra det:

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

Så här skulle en erfaren Java-programmerare göra det:

Koda
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;
   }
}

Är koden längre? Otvivelaktigt.

Men du kan lägga till parametervalidering till getters och seters. Till exempel kan du se till att xoch yalltid är större än noll (eller inte mindre än noll). Exempel:

Koda Notera
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. Objektets livslängd

Du vet redan att objekt skapas med newoperatorn, men hur raderas objekt? De finns inte för alltid. Det finns inte tillräckligt med minne för det.

I många programmeringsspråk, som C++, finns det en speciell deleteoperatör för att radera objekt. Men hur fungerar detta i Java?

I Java är allt upplagt lite annorlunda. Java har ingen delete-operator. Betyder detta att objekt inte raderas i Java? Nej, de raderas såklart. Annars skulle Java-applikationer snabbt få slut på minne, och det skulle inte vara tal om att program körde utan avbrott i månader.

I Java är raderingen av objekt helt automatiserad. Java-maskinen hanterar själv raderingen av objekt. Denna process kallas garbage collection, och mekanismen som samlar in sopor kallas garbage collector ( GC ).

Så hur vet Java-maskinen när den ska radera ett objekt?

Sophämtaren delar upp alla föremål i "nåbara" och "otillgängliga". Om det finns minst en referens till ett objekt anses det nåbart. Om det inte finns någon variabel som refererar till ett objekt anses objektet vara oåtkomligt och förklaras som skräp, vilket innebär att det kan raderas.

I Java kan du inte skapa en referens till ett befintligt objekt – du kan bara tilldela referenser som du redan har. Om vi ​​raderar alla referenser till ett objekt är det förlorat för alltid.

Cirkulära referenser

Den logiken låter bra tills vi kommer på ett enkelt motexempel: anta att vi har två objekt som refererar till varandra (lagrar referenser till varandra). Inga andra objekt lagrar referenser till dessa objekt.

Dessa objekt kan inte nås från koden, men de refereras fortfarande.

Det är därför som sopsamlaren delar in föremål i nåbara och oåtkomliga snarare än "refererade" och "orefererade".

Nåbara föremål

Först läggs objekt som är 100 % levande till i listan som kan nås. Till exempel den aktuella tråden ( Thread.current()) eller konsolens InputStream ( System.in).

Sedan utökas listan med objekt som kan nås och inkluderar objekt som refereras till av den initiala uppsättningen av objekt som kan nås. Sedan utökas den igen för att inkludera objekt som refereras av denna förstorade uppsättning, och så vidare.

Det betyder att om det finns några objekt som bara hänvisar till varandra, men det inte finns något sätt att nå dem från nåbara objekt, kommer dessa objekt att betraktas som skräp och kommer att raderas.


3. Sophämtning

Minnesfragmentering

En annan viktig punkt relaterad till objektradering är minnesfragmentering. Om du ständigt skapar och tar bort objekt kommer minnet snart att bli kraftigt fragmenterat: områden med upptaget minne kommer att varvas med områden med ledigt minne.

Som ett resultat kan vi lätt hamna i en situation där vi inte kan skapa ett stort objekt (till exempel en array med en miljon element), eftersom det inte finns en stor del ledigt minne. Med andra ord kan det finnas ledigt minne, till och med mycket av det, men det kanske inte finns ett stort sammanhängande block med ledigt minne

Minnesoptimering (defragmentering)

Java-maskinen löser detta problem på ett specifikt sätt. Det ser ut ungefär så här:

Minnet är uppdelat i två delar. Alla objekt skapas (och raderas) på bara ena halvan av minnet. När det är dags att rensa upp hålen i minnet kopieras alla föremål i den första halvan till den andra halvan. Men de är kopierade precis bredvid varandra så att det inte blir några hål.

Processen ser ungefär ut så här:

Steg 1: Efter att ha skapat objekt

Sophämtning i Java

Steg 2: Utseende av "hål"

Sophämtning i Java 2

Steg 3: Eliminering av "hål"

Sophämtning i Java 3

Och det är därför du inte behöver ta bort objekt. Java-maskinen kopierar helt enkelt alla nåbara objekt till en ny plats och frigör hela minnesområdet där objekten brukade lagras.