Leer Java voor Android-ontwikkeling innerlijke klassen

In deze tutorial zul je vertrouwd raken met het concept van innerlijke klassen in Java - die klassen waarvan de reikwijdte en definitie zijn opgenomen in een andere klasse. Je leert ook over anonieme innerlijke klassen, die vrij vaak worden gebruikt bij het ontwikkelen met de Android SDK.

Android-applicaties zijn geschreven in de Java, een object-georiënteerde programmeertaal. In deze tutorial leer je over innerlijke klassen, wanneer en waarom ze gebruiken en hoe ze werken. Je leert ook hoe je dynamisch nieuwe objecten kunt maken met behulp van anonieme innerlijke klassen.

Wat je nodig hebt

Technisch gezien heb je geen tools nodig om deze tutorial te voltooien, maar je zult ze zeker nodig hebben om Android-applicaties te ontwikkelen.

Om Android-applicaties (of welke Java-applicaties dan ook) te ontwikkelen, hebt u een ontwikkelomgeving nodig om applicaties te schrijven en te bouwen. Eclipse is een zeer populaire ontwikkelomgeving (IDE) voor Java en de geprefereerde IDE voor Android-ontwikkeling. Het is gratis beschikbaar voor Windows-, Mac- en Linux-besturingssystemen.

Zie de Android-ontwikkelaarswebsite voor volledige instructies over het installeren van Eclipse (inclusief welke versies worden ondersteund) en de Android SDK.

Wat is een innerlijke klasse?

De meeste klassen in Java zijn klassen op het hoogste niveau. Deze klassen en de objecten die ze definiëren, staan ​​op zichzelf. U kunt ook geneste klassen maken om onderliggende objecten duidelijk in te kaderen en te definiëren die alleen van belang zijn in de context van de buitenklasse. Geneste klassen worden innerlijke klassen genoemd.

Innerlijke klassen kunnen alle kenmerken van een reguliere klasse hebben, maar hun reikwijdte is beperkt. Innerlijke klassen hebben nog een ander voordeel: ze hebben volledige toegang tot de klasse waarin ze zijn genest - deze functie maakt innerlijke klassen perfect voor het implementeren van adapterfunctionaliteit zoals iterators.

Hier is een voorbeeld van een klas op het hoogste niveau met twee innerlijke klassen:

 public class User // Gebruikersvelden, inclusief variabelen van type LoginInfo en UserPreferences // Miscodermethodieklasse LoginInfo // Aanmeldingsinfo-velden // Aanmeldings- / Uitlogmethoden // Toegang tot Gebruikersvelden / -methoden class Preferences // Gebruiker voorkeurvelden // Voorkeurmethoden ophalen / instellen // Voorkeuren-methode resetten // Toegang krijgen tot gebruikersvelden / -methoden 

In dit voorbeeld heeft de klasse User twee inner classes: LoginInfo en Preferences. Hoewel alle gebruikersgerelateerde gegevens en functionaliteit kunnen worden gedefinieerd in de klasse User, kan het gebruik van de interne klassen om de functionaliteit te compartimenteren, de code gemakkelijker leesbaar en leesbaar maken. De interne klassen LoginInfo en Preferences hebben ook toegang tot de beschermde / private velden en methoden die beschikbaar zijn in de Gebruikersklasse, die ze anders niet zouden hebben vanwege beveiliging, als ze zelf als zelfstandige klassen waren gedefinieerd.

Het is echter belangrijk om te onthouden dat innerlijke klassen eigenlijk alleen bestaan ​​om de ontwikkelaar te helpen bij het organiseren van code; de compiler behandelt binnenklassen net als elke andere klasse, behalve dat de binnenklassen een beperkte reikwijdte hebben en daarom worden vastgemaakt aan de klasse waarmee ze zijn gedefinieerd. Anders gezegd, u zou de LoginInfo- of Preferences-klassen niet kunnen gebruiken of instantiëren, behalve met een instantie van de klasse User, maar de interne klassen zouden toegang kunnen krijgen tot alle velden of methoden die beschikbaar zijn in de outer class-gebruiker, indien nodig.

Statische geneste klassen gebruiken

Een in het bijzonder gebruik voor geneste klassen is statisch geneste klassen. Een statische binnenklasse definieert gedrag dat niet is gebonden aan een specifieke objectinstantie, maar dat van toepassing is op alle exemplaren. We kunnen bijvoorbeeld een derde geneste klasse toevoegen, deze keer statisch, aan de klasse User om de servergerelateerde functionaliteit te beheren:

 public class User // Gebruikersvelden, inclusief variabelen van het type LoginInfo en UserPreferences // Misc User methods class LoginInfo  public static class ServerInfo  // Serverinfo is van toepassing op alle instanties van Gebruiker 

Omdat het openbaar is, kan deze statische geneste klasse worden geïnstantieerd met behulp van de volgende nieuwe instructie:

 User.ServerInfo sInfo = nieuwe User.ServerInfo (); 

De outer class hoeft niet te worden geïnstantieerd om deze instantiatie uit te voeren, dus het gebruik van de klassenaam. Als zodanig heeft een statische geneste klasse, in tegenstelling tot een niet-statische geneste klasse (ook wel innerlijke klasse genoemd), geen toegang tot leden van de buitenklasse - ze mogen niet eens worden geïnstantieerd.

De kracht van anonieme innerlijke klassen

Android gebruikt anonieme innerlijke klassen met groot effect. Anonieme binnenklassen zijn in feite ontwikkelaars stenografisch, waardoor de ontwikkelaar een aangepast object allemaal in één "regel" kan maken, definiëren en gebruiken. Je hebt misschien voorbeelden gezien van het gebruik van anonieme innerlijke klasse in voorbeeldcode en je hebt het zelfs niet gerealiseerd.
Als u een anonieme innerlijke klasse wilt maken, geeft u alleen de rechterkant van de definitie op. Begin met het nieuwe sleutelwoord, gevolgd door de klasse of interface die u wilt uitbreiden of implementeren, gevolgd door de klassendefinitie. Hiermee wordt de klasse gemaakt en geretourneerd als een waarde die u vervolgens kunt gebruiken om een ​​methode aan te roepen.
Wanneer we een anonieme innerlijke klasse gebruiken, krijgt het gemaakte object geen naam toegewezen (dus de term anoniem). Het neveneffect is natuurlijk dat het object maar één keer wordt gebruikt. Het is bijvoorbeeld gebruikelijk om een ​​anonieme binnenklasse te gebruiken om een ​​aangepaste versie van een object als retourwaarde te maken. Hier breiden we bijvoorbeeld de klasse Truck uit (aangenomen dat deze elders is gedefinieerd en heeft een veld met de naam mpg en twee methoden, start () en stop ():

 Truck getTruck () return new Truck () int mpg = 3; void start () / * start implementatie * / void stop () / * stop implementatie * /;  

Laten we nu kijken naar praktische voorbeelden van anonieme inner classes die in Android worden gebruikt.

Een anonieme binnenklasse gebruiken om een ​​luisteraar te definiëren

Android-ontwikkelaars gebruiken vaak anonieme interne klassen om gespecialiseerde luisteraars te definiëren, die callbacks voor specifiek gedrag registreren wanneer een gebeurtenis plaatsvindt. Als u bijvoorbeeld wilt luisteren naar klikken op een View-besturingselement, moet de ontwikkelaar de methode setOnClickListener () aanroepen, waarvoor één parameter nodig is: een View.OnClickListener-object.
Ontwikkelaars gebruiken routinematig de anonieme techniek van de innerlijke klasse om hun aangepaste View.OnClickListener als volgt te maken, te definiëren en te gebruiken:

 Button aButton = (Button) findViewById (R.id.MyButton); aButton.setOnClickListener (new View.OnClickListener () public void onClick (View v) // Gebruiker heeft op mijn knop geklikt, doe hier iets!); 

Een anonieme binnenklasse gebruiken om een ​​draad te beginnen

Laten we naar een ander voorbeeld kijken. Het is heel gebruikelijk om een ​​nieuwe Thread-klasse te definiëren, de uitvoering van de methode run () te bieden en die thread in één keer te starten:

 new Thread () public void run () doWorkHere ();  .start (); 

Een benoemde innerlijke klasse gebruiken

Het gebruik van anonieme inner classes voor luisteraars in Android is zo gewoon dat het bijna een tweede natuur is om dit te doen. Waarom zou je ze dan niet willen gebruiken? Laten we dit beantwoorden aan de hand van een hypothetisch voorbeeld.
Laten we zeggen dat je een scherm hebt met 100 knoppen erop (we zeiden wel hypothetisch, toch?). Laten we nu zeggen dat elke knop, wanneer ingedrukt, doet de exact hetzelfde. In dit geval luisteren we gewoon naar klikken en roosteren we de tekst uit het View-object dat is doorgegeven (de tekst die wordt weergegeven op de knop waarop is geklikt):
Hier is de pseudo-code om dat te doen:

 Knop [] knoppen = getAllOneHundredButtonsAsArray (); for (Knop-knop: knoppen) button.setOnClickListener (nieuwe View.OnClickListener () openbare ongeldige onClick (View v) showToast (v.getText ()););  

Kort en elegant, dus wat is er mis mee? Bij elke iteratie wordt een nieuw OnClickListener-object geïnstantieerd. Omdat elk precies hetzelfde is, is er geen goede reden om er 100 van te maken. In plaats daarvan kunt u een enkele, benoemde, innerlijke klasse maken, deze één keer instantiëren en deze vervolgens doorgeven aan de methode setOnClickListener (). Bijvoorbeeld:

 class MyActivity breidt activiteit uit public void myMethod () MyClickHandler handler = new MyClickHandler (); Knop [] knoppen = getAllOneHundredButtonsAsArray (); voor (knop Knop: knoppen) button.setOnClickListener (handler);  class MyClickHandler implementeert View.OnClickListener public void onClick (View v) showToast (((Button) v) .getText ());  

Als je de voorkeur geeft aan anonimiteit, kun je nog steeds een anonieme innerklasse aan een variabele toewijzen en dat gebruiken, zoals:

 class MyActivity breidt Activiteit uit public void myMethod () View.OnClickListener handler = new View.OnClickListener () public void onClick (View v) showToast (((Button) v) .getText ()); ; Knop [] knoppen = getAllOneHundredButtonsAsArray (); voor (knop Knop: knoppen) button.setOnClickListener (handler);  

De methode is aan jou, maar houd rekening met mogelijke geheugen- en prestatieproblemen die een stelletje objecten kunnen veroorzaken.

Een opmerking over Nuances

Deze tutorial is bedoeld als inleidende handleiding voor innerlijke klassen op Java. Er zijn stijloverwegingen en nuances bij het gebruik van innerlijke klassen op verschillende en creatieve manieren. Zelfs daarna kunt u verder verkennen om meer te weten te komen over de interne effecten en marginale prestatieverschillen die kunnen optreden wanneer u geneste klassen op verschillende manieren gebruikt. Dit alles valt echter buiten het bestek van deze tutorial.

Een snelle opmerking over terminologie

Hoewel we hebben geprobeerd om consistent te zijn met de terminologie op geneste en innerlijke klassen, is de terminologie niet altijd consistent uit verschillende online en offline bronnen. Hierna volgt een lijst met termen uit de huidige Sun / Oracle-documentatie, die net zo goed is als die voor autoritatief zijn op Java:

  • Geneste klasse: een klasse gedefinieerd in een andere klasse
  • Statische geneste klasse: een statische klasse gedefinieerd in een andere klasse
  • Innerlijke klasse: een niet-statische geneste klasse die is gedefinieerd in een andere klasse
  • Lokale binnenklasse: een klasse gedefinieerd binnen een methode
  • Anonieme binnenklasse: een naamloze klasse gedefinieerd binnen een methode

Verward? U kunt de methoden java.lang.Class genaamd isLocalClass () en isAnonymous () gebruiken voor klassen die zijn geïnstantieerd om een ​​aantal van deze eigenschappen te bepalen. Een Oracle-blogitem probeert ook een beetje duidelijkheid te scheppen met een mooi Venn-diagram.

Afsluiten

De Java-programmeertaal ondersteunt geneste klassen, waardoor de ontwikkelaar veel flexibiliteit heeft bij het definiëren van objecten. Binnenklassen kunnen worden gebruikt om klassefunctionaliteit te organiseren of om gespecialiseerd gedrag te definiëren dat de ontwikkelaar anders zou vragen klasse-gegevens en -functionaliteit bloot te leggen die echt niet zouden moeten worden blootgesteld. Statische binnenklassen kunnen worden gebruikt om velden en functionaliteit te definiëren die van toepassing zijn op alle instanties van een klasse. Ten slotte bieden anonieme interne klassen een handige steno voor ontwikkelaars die in één keer een aangepast object willen maken, definiëren en gebruiken.