1. Minden osztály örökölObject

A Java minden osztálya implicit módon örökli az Objectosztályt.

A Java Core küldetésben elemezzük, mi az öröklődés, és hogyan működik a Java nyelven. Egyelőre egy egyszerű tényt veszünk figyelembe, amely ebből következik:

Bármely osztály objektuma hozzárendelhető egy Objectváltozóhoz. Példa:

Kód jegyzet
Object o = new Scanner(System.in);
A változó egy objektumra ovaló hivatkozást tárolScanner
Object o = new String();
A változó egy objektumra ovaló hivatkozást tárolString
Object o = new Integer(15);
A változó egy objektumra ovaló hivatkozást tárolInteger
Object o = "Hello";
A változó egy objektumra ovaló hivatkozást tárolString

Itt ér véget a jó hír. A fordító nem követi nyomon a változóban elmentett objektum eredeti típusát Object, így nem lehet más metódusokat hívni a mentett objektumon, csak az osztály metódusait Object.

Ha meg kell hívnia az objektum eredeti típusához tartozó metódusokat, akkor először el kell mentenie egy hivatkozást egy megfelelő típusú változóba, majd meghívnia kell a metódusokat azon a változón:

Kód jegyzet
Object o = new Scanner(System.in);
int x = o.nextInt();
A program nem fog lefordítani. Az Objectosztálynak nincs nextInt()metódusa.
Object o = new Scanner(System.in);

Scanner console = (Scanner) o;

int x = console.nextInt();
Ez működni fog.

Itt elmentünk egy hivatkozást egy változóban Scannerlévő objektumra egy typecast operátorScanner segítségével .

Nem lehet egyszerűen hozzárendelni egy Objectváltozót a Scanner-változóhoz, még akkor sem, ha a Objectváltozó hivatkozást tárol egy Scannerobjektumra. De ezt megteheti, ha a typecast operátort használja , amelyet már ismer. Ez az általános megjelenése:

Type name1 = (Type) name2;

Ahol name1egy változó neve Type, és name2egy olyan változó neve Object, amely egy objektumra való hivatkozást tárol Type.

Typecasting

Ha a változó típusa és az objektum típusa nem egyezik, akkor a-t ClassCastExceptiondob ​​ki. Példa:

Kód jegyzet
Object o = new Integer(5);
String s = (String) o;
Futás közben hiba fog fellépni: itt
a ClassCastExceptionlesz dobva

Van egy módja annak, hogy elkerüljük ezt a hibát a Java-ban: ezt úgy tehetjük meg, hogy ellenőrizzük a változóban tárolt objektum típusát :

name instanceof Type

Az instanceofoperátor ellenőrzi, hogy a nameváltozó objektum-e Type.

Példaként keressünk egy karakterláncot különböző objektumok tömbjében:

Kód jegyzet
Object[] objects = {10, "Hello", 3.14};

for (int i = 0; i < objects.length; i++)
{
   if (objects[i] instanceof String)
   {
      String s = (String) objects[i];
      System.out.println(s);
   }
}
IntegerAz Autoboxing ezeket az értékeket , String, és formátumba konvertálja Double.

Hurok az objektumok tömbjén

Ha az objektum egy String

Mentés változóba A Stringváltozó
megjelenítése a képernyőn.


2. Miért jelentek meg a generikumok – gyűjtemények

Térjünk vissza a gyűjteményekhez.

Amint a Java fejlesztők létrehozták az ArrayListosztályt, univerzálissá akarták tenni, hogy bármilyen típusú objektumot tárolhasson. Tehát egy s tömböt használtak Objectaz elemek tárolására.

Ennek a megközelítésnek az az erőssége, hogy bármilyen típusú objektumot hozzáadhat a gyűjteményhez.

Természetesen több gyenge pont is van.

Hátrány 1.

A gyűjtemény elemeinek lekérésekor mindig meg kellett írni egy típuskonverziós operátort:

Kód jegyzet
ArrayList numbers = new ArrayList();


for (int i = 0; i < 10; i++)
   numbers.add(i * 10);


int sum = 0;
for (int i = 0; i < 10; i++)
{
   sum = sum + (Integer) numbers.get(i);
}
ObjectGyűjtemény létrehozása az objektumokra való hivatkozások tárolására

Töltse ki a gyűjteményt számokkal 10, 20, ... 100;



Összegezzük a gyűjtemény elemeit


Typecasting szükséges

Hátrány 2.

Nem volt garancia arra, hogy egy gyűjtemény meghatározott típusú elemet tartalmaz

Kód jegyzet
ArrayList numbers = new ArrayList();


for (int i = 0; i < 10; i++)
   numbers.add(i * 2.5);


int sum = 0;
for (int i = 0; i < 10; i++)
{
   sum = sum + (Integer) numbers.get(i);
}
ObjectGyűjtemény létrehozása az objektumokra való hivatkozások tárolására

A gyűjteményt objektumként ábrázolt számokkal töltjük fel Double:
0.0, 2.5, 5.0, ...


A gyűjtemény elemeinek összegzése


Hiba lesz: a Doublenem küldhető át egyInteger

Az adatok bárhol behelyezhetők a gyűjteménybe:

  • más módszerrel
  • egy másik programban
  • fájlból
  • hálózaton keresztül

Hátrány 3.

A gyűjteményben lévő adatok véletlenül megváltozhatnak.

Az adataival feltöltött gyűjteményt átadhatja valamilyen módszernek. Ez a módszer, amelyet egy másik programozó írt, hozzáadja az adatait a gyűjteményéhez.

A gyűjtemény neve nem jelzi egyértelműen, hogy milyen típusú adatok tárolhatók benne. És még ha egyértelmű nevet ad is a változónak, a rá való hivatkozás átadható egy tucat metódusnak, és ezek a metódusok biztosan nem fognak tudni semmit a változó eredeti nevéről.


3. Általános szerek

Generics Java nyelven

A Java-ban mindezeket a problémákat kiküszöböli ez a klassz dolog, az úgynevezett generikus.

A Java nyelvben az általános kifejezés azt jelenti, hogy típusparamétereket adhatunk a típusokhoz. Az eredmény egy összetett összetett típus. Az ilyen összetett típus általános nézete a következő:

ClassName<TypeParameter>

Ez egy általános osztály. És bárhol használható, ahol általában osztályokat használ.

Kód Leírás
ArrayList<Integer> list;
Változók létrehozása
list = new ArrayList<Integer> ();
Objektumok létrehozása
ArrayList<Integer>[] array;
Tömbök létrehozása

Egy ilyen gyűjteményben csak Integerváltozók tárolhatók:

Kód Leírás
ArrayList<Integer> list = new ArrayList<Integer>();
list.add(new Integer(1));
list.add(2);
list.add("Hello");
ArrayListgyűjtemény Integerelemekkel
Ez megengedett
És ez is működni fog
Autobox

De ez nem megengedett: fordítási hiba

Megtanulja, hogyan hozhat létre saját osztályokat típusparaméterekkel a Java Collections küldetésben. Egyelőre megnézzük, hogyan kell használni és hogyan működnek.


4. Hogyan működnek a generikumok

Valójában a generikumok borzasztóan primitívek.

A fordító egyszerűen lecseréli az általános típusokat közönséges típusokra. Ám ha általános típusú metódusokat használnak, a fordító egy typecast operátort ad hozzá, hogy a típusparaméterekhez öntsön paramétereket:

Kód Mit csinál a fordító
ArrayList<Integer> list = new ArrayList<Integer>();
ArrayList list = new ArrayList();
list.add(1);
list.add( (Integer) 1 );
int x = list.get(0);
int x = (Integer) list.get(0);
list.set(0, 10);
list.set(0, (Integer) 10);

Tegyük fel, hogy van egy metódusunk, amely az egész számok gyűjteményében lévő számokat összegzi:

Kód Mit csinál a fordító
public int sum(ArrayList<Integer> numbers)
{
   int result = 0;

   for (int i = 0; i < numbers.size(); i++)
      result = result + numbers.get(i);

   return result;
}
public int sum(ArrayList numbers)
{
   int result = 0;

   for (int i = 0; i < numbers.size(); i++)
      result = result + (Integer) numbers.get(i);

   return result;
}

Más szóval, a generikumok egyfajta szintaktikai cukor, mint az autoboxing, de egy kicsit több. Az autoboxing esetén a fordító metódusokat ad hozzá az an- intra Integerés fordítva, az általánosoknál pedig typecast operátorokat ad hozzá.

Miután a fordító összeállította az általános osztályokat a típusparaméterekkel, egyszerűen átalakítja őket közönséges osztályokká és typecast operátorokká. Az általános típusú változóknak átadott típusargumentumokkal kapcsolatos információk elvesznek. Ezt a hatást típustörlésnek is nevezik .

Néha az általános osztályokat (típusparaméterekkel rendelkező osztályokat) író programozóknak valóban szükségük van az argumentumként átadott típusokra vonatkozó információkra. A Java Collections küldetés során megtudhatja, hogyan kezelje ezt, és mit jelent ez.



5. Néhány tény a generikus gyógyszerekről

Íme néhány érdekes tény a generikus gyógyszerekről.

Az osztályoknak többféle típusparamétere lehet. Valahogy így néz ki:

ClassName<TypeParameter1, TypeParameter2, TypeParameter3>

Valójában ez nem is meglepő. Bárhol, ahol a fordító hozzá tud adni egy operátort egy típushoz, több typecast operátort is hozzáadhat.

Példák:

Kód jegyzet
HashMap<Integer, String> map = new HashMap<Integer, String>();
map.put(7, "Hello");
map.put(-15, "Hello");
A putmetódus első paramétere an Integer, a második pedig aString

Általános típusok is használhatók paraméterként . Valahogy így néz ki:

ClassName<TypeParameter<TypeParameterParameter>>

Tegyük fel, hogy szeretnénk létrehozni egy listát, amely karakterláncok listáját tárolja. Ebben az esetben valami ilyesmit kapunk:

// List of greetings
ArrayList<String> listHello = new ArrayList<String>();
listHello.add ("Hello");
listHello.add ("Hi");

// List of goodbyes
ArrayList<String> listBye = new ArrayList<String>();
listBye.add("Bye");
listBye.add ("Goodbye");

// List of lists
ArrayList<ArrayList<String>> lists = new ArrayList<ArrayList<String>>();
lists.add(listHello);
lists.add(listBye);

Az általános típusok (típusparaméterekkel rendelkező típusok) tömbtípusként is használhatók. Valahogy így néz ki:

ClassName<TypeParameter>[] array = new ClassName<TypeParameter>[size];

Itt nem történik semmi varázslatos: a szögletes zárójelek csak a típus nevét jelzik:

Kód Nem általános megfelelője
ArrayList<String>[] list = new ArrayList<String>[10];
StringArrayList[] list = new StringArrayList[10];
ArrayList<Integer>[] list = new ArrayList<Integer>[10];
IntegerArrayList[] list = new IntegerArrayList[10];
ArrayList<Scanner>[] list = new ArrayList<Scanner>[10];
ScannerArrayList[] list = new ScannerArrayList[10];