I denna handledning kommer du att bli bekant med begreppet inre klasser i Java-de klasser vars omfattning och definition ingår i en annan klass. Du lär dig också om anonyma inre klasser, som används ganska ofta när de utvecklas med Android SDK.
Android-applikationer skrivs i Java, ett objektorienterat programmeringsspråk. I denna handledning läser du om inre klasser, när och varför att använda dem och hur de fungerar. Du lär dig också att skapa nya objekt dynamiskt med anonyma inre klasser.
Tekniskt behöver du inga verktyg för att slutföra denna handledning, men du kommer säkert att behöva dem för att utveckla Android-applikationer.
För att utveckla Android-applikationer (eller Java-program, för den delen) behöver du en utvecklingsmiljö för att skriva och bygga applikationer. Eclipse är en mycket populär utvecklingsmiljö (IDE) för Java och den föredragna IDE för Android utveckling. Det är fritt tillgängligt för Windows, Mac och Linux operativsystem.
För fullständiga instruktioner om hur du installerar Eclipse (inklusive vilka versioner som stöds) och Android SDK, se webbplatsen för Android-utvecklaren.
De flesta klasserna i Java är högklassiga klasser. Dessa klasser och de objekt de definierar är fristående. Du kan också skapa nestade klasser för att tydligt inkapsla och definiera underordnade objekt som bara spelar roll i yttre klassens sammanhang. Nested klasser kallas inre klasser.
Inre klasser kan ha alla funktioner i en vanlig klass, men deras omfattning är begränsad. Inre klasser har en annan fördel: de har full tillgång till den klass där de är kapslade - den här funktionen gör inre klasser perfekt för att implementera adapterfunktionalitet som iteratorer.
Här är ett exempel på en högklassig klass med två inre klasser:
allmän klass Användare // Användarfält, inklusive variabler av typen LoginInfo och UserPreferences // Diverse användarmetoder klass LoginInfo // Inloggningsfält // Logga in / utloggningsmetoder // Kan komma åt Användarfält / metoder klass Preferenser // User preferensfält // Hämta / Ange preferensmetoder // Återställ inställningsmetod // Kan komma åt Användarfält / metoder
I det här exemplet har användarklassen två inre klasser: LoginInfo och Preferences. Medan alla användarrelaterade data och funktionalitet kan definieras i användarklassen, kan de enklare läs och underhålla koden genom att använda de inre klasserna för att avdela funktionalitet. De inre klasserna LoginInfo och Preferences har också tillgång till de skyddade / privata fälten och metoderna som finns tillgängliga i Användarklassen, vilket de annars inte skulle ha på grund av säkerhet om de definierades som fristående klasser själva.
Det är viktigt att komma ihåg att de inre klasserna verkligen bara existerar för att hjälpa utvecklaren att organisera kod; kompilatorn behandlar inre klasser precis som någon annan klass, förutom att de inre klasserna har ett begränsat räckvidd och är därför bundna till den klass de definieras med. På ett annat sätt skulle du inte kunna använda eller instansera klasserna LoginInfo eller Preferences, förutom med en förekomst av användarklassen, men de inre klasserna kan komma åt alla fält eller metoder som finns tillgängliga i den yttre klassen Användaren, efter behov.
En särskild användning för kapslade klasser är statiska kapslade klasser. En statisk inre klass definierar beteende som inte är knutet till en specifik objektinstans, men gäller i alla fall. Till exempel kan vi lägga till en tredje kapslad klass, denna gång statisk, till användarklassen för att kontrollera serverrelaterad funktionalitet:
public class User // Användarfält, inklusive variabler av typen LoginInfo och UserPreferences // Diverse användarmetoder klass LoginInfo offentliga statiska klass ServerInfo // Serverinformation gäller alla instanser av Användare
Eftersom den är offentlig kan den här statiska kapslade klassen instantieras med följande nya uttalande:
User.ServerInfo sInfo = nytt User.ServerInfo ();
Den yttre klassen behöver inte vara instansierad för att utföra denna instansering, sålunda användningen av klassnamnet. Som sådan har en statisk inbäddad klass, till skillnad från en icke-statisk inbäddad klass (aka inre klass), inte tillgång till medlemmar i ytterklassen - de kan inte ens vara instanserade.
Android använder anonyma inre klasser till stor effekt. Anonyma inre klasser är i grunden utvecklare stenografi, så att utvecklaren kan skapa, definiera och använda ett anpassat objekt i en "linje". Du kan ha sett exempel på användningen av anonym inre klass i provkod och inte ens insett det.
För att skapa en anonym inre klass ger du bara den högra sidan av definitionen. Börja med det nya sökordet följt av klassen eller gränssnittet du vill utvidga eller genomföra, följt av klassdefinitionen. Detta kommer att skapa klassen och returnera det som ett värde som du då kan använda för att ringa en metod.
När vi använder en anonym inre klass får det skapade objektet inte tilldelats ett namn (alltså termen anonym). Biverkningen är givetvis att objektet används bara en gång. Det är till exempel vanligt att använda en anonym inre klass för att konstruera en anpassad version av ett objekt som ett returvärde. Till exempel, här förlänger vi klassen Truck (förutsatt att den definieras annorstädes och har ett fält som heter mpg och två metoder, starta () och stoppa ():
Lastbil getTruck () returnera ny lastbil () int mpg = 3; void start () / * start implementation * / void stop () / * sluta implementering * /;
Låt oss nu titta på praktiska exempel på anonyma inre klasser som används i Android.
Android-utvecklare använder ofta anonyma inre klasser för att definiera specialiserade lyssnare, som registrerar återuppringningar för specifikt beteende när en händelse inträffar. Till exempel för att lyssna efter klick i en View-kontroll måste utvecklaren ringa metoden setOnClickListener (), som tar en enda parameter: ett View.OnClickListener-objekt.
Utvecklare använder rutinmässigt den anonyma inre klasstekniken för att skapa, definiera och använda deras anpassade View.OnClickListener, enligt följande:
Knapp aButton = (Knapp) findViewById (R.id.MyButton); aButton.setOnClickListener (new View.OnClickListener () public void onClick (Visa v) // Användaren klickade på min knapp, gör något här!);
Låt oss titta på ett annat exempel. Det är ganska vanligt att definiera en ny trådklass, tillhandahålla genomförandet av sin run () -metod och starta den tråden, allt på en gång:
ny tråd () public void run () doWorkHere (); .Start();
Att använda anonyma inre klasser för lyssnare i Android är så vanligt att det är praktiskt taget andra naturen att göra det. Varför skulle du då inte vilja använda dem? Låt oss svara på detta genom ett hypotetiskt exempel.
Låt oss säga att du har en skärm som har 100 knappar på den (vi sa hypotetiska, eller hur?). Låt oss nu säga varje knapp, när den trycks, gör exakt samma sak. I det här fallet lyssnar vi bara på klick och sköt texten från visningsobjektet som skickats in (texten som visas på knappen som klickades):
Här är pseudokoden för att göra det:
Knapp [] knappar = getAllOneHundredButtonsAsArray (); för (Knappknapp: knappar) button.setOnClickListener (new View.OnClickListener () public void onClick (Visa v) showToast (v.getText ()););
Kort och elegant, så vad är det för fel? Vid varje iteration skapas ett nytt OnClickListener-objekt. Eftersom var och en är exakt densamma, finns det ingen anledning att skapa 100 av dem. I stället kan du skapa en enda, namngiven, inre klass, instansera den en gång och sedan överföra den till metoden setOnClickListener (). Till exempel:
klass MyActivity utökar aktivitet public void myMethod () MyClickHandler handler = ny MyClickHandler (); Knapp [] knappar = getAllOneHundredButtonsAsArray (); för (Knappknapp: knappar) button.setOnClickListener (handler); klass MyClickHandler implementerar View.OnClickListener public void onClick (Visa v) showToast (((Button) v) .getText ());
Om du föredrar anonymitet kan du fortfarande tilldela en anonym inre klass till en variabel och använda det, som så:
klass MyActivity utökar aktivitet public void myMethod () View.OnClickListener handler = ny View.OnClickListener () public void onClick (Visa v) showToast (((Button) v) .getText ()); ; Knapp [] knappar = getAllOneHundredButtonsAsArray (); för (Knappknapp: knappar) button.setOnClickListener (handler);
Metoden är upp till dig, men tänk på att eventuella minnes- och prestationsproblem som instanserar en massa objekt kan ha.
Denna handledning är tänkt att vara en introduktionsguide till inre klasser i Java. Det finns stilhänsyn och nyanser när man använder inre klasser på olika och kreativa sätt. Utöver det kan du utforska vidare för att lära dig mer om de interna effekterna och marginella prestationsskillnader som kan dyka upp när du använder inbyggda klasser på olika sätt. Allt detta är dock långt bortom omfattningen av denna handledning.
Även om vi har försökt att överensstämma med terminologin på nestade och inre klasser, är terminologin inte alltid konsekvent från olika online- och offline-resurser. Nedan följer en lista med termer från den aktuella Sun / Oracle dokumentationen, vilket är lika bra som någon för att vara auktoritativ på Java:
Förvirrad? Du kan använda java.lang.Class-metoderna som heter isLocalClass () och isAnonymous () klass på instantierade klasser för att bestämma ett par av dessa egenskaper. En Oracle blogginmatning försöker också klargöra situationen lite med ett trevligt Venn-diagram.
Java-programmeringsspråket stödjer kapslade klasser, vilket gör att utvecklaren har stor flexibilitet när det gäller att definiera objekt. Inre klasser kan användas för att organisera klassfunktionalitet eller för att definiera specialbeteenden som annars skulle kräva att utvecklaren utsätter klassdata och funktionalitet som egentligen inte ska exponeras. Statiska inre klasser kan användas för att definiera fält och funktionalitet som gäller i alla fall i en klass. Slutligen ger anonyma inre klasser en användbar stenografi för utvecklare som vill skapa, definiera och använda ett anpassat objekt på en gång.