Típusszerkezet
Mivel a J# a Java nyelv specifikációját valósítja meg, így megörökölte annak típusrendszerét is.
Két féle típus van. Az egyik az elemi típus, a másik a referencia típus. Azonban a Visual J# fordító
lehetővé teszi, hogy használjuk a .NET Framework-ben definiált érték típusokat is, vagy amiket más
felhasználó definiált egy külső assembly-ben.
Elemi típusok
Fajtái:
- Logikai típus:
Műveletei: ! && ||
- boolean (true vagy false)
- Egész típusok:
Műveletei: + - * / % < > <= >= & | << >>
- byte (8 bites előjeles)
- short (16 bites előjeles)
- int (32 bites előjeles)
- long (64 bites előjeles)
- Valós (lebegőpontos) típusok:
Műveletei: + - * / % < > <= >= & | << >>
- float (32 bites lebegőpontos)
- double (64 bites lebegőpontos)
- Karakter típus:
- char (16 bites Unicode 3.0 karakter)
Elemi típusok jellemzői:
- stack-ben tárolódnak
- érték szerint adódnak át
- egészben lemásolódnak
- nem származnak semmiből
- nincs konstruktoruk
Referencia típusok
Minden típus ami nem elemi típus, az referencia típus. Ezek nem mások, mint az objektumok.
Bővebben lásd az Objektum-orientált programozás c. fejezetben.
Referencia típusok jellemzői:
- heap-ben tárolódnak
- referencia szerint adódnak át
- másolásnál a referencia másolódik le
- minden osztály a object ősosztályból származik
- konstruktorral inicializálódnak
Függvénypointer típusok
A Visual J# fordító engedélyezi delegate-ek (függvény-pointerek) létrehozását. Fontos, hogy a kötés
fordítási időben történik. A delegate típus deklarációjának a következő komponensekből áll:
- az attribútum: /**@delegate*/
- egy hozzáférési szint: public, protected, private
- a delegate vagy multicast delgate kulcsszó
- a visszaadott típus, és a metódus szignatúrája
- a delegate típus neve, a visszaadott érték és a metódus szignatúrája között
/** @delegate */
public delegate void EventHandler();
Delegate kezelő definiálása
J#-ban a delegate típus referencia típus. A referencia típus definiálása 2 részből áll:
- Egy névvel ellátott kezelő
- A kezelt osztály név nélküli példánya, melyet a new operátor segítségével hozunk létre
Proc p1;
p1 jelenti a Proc delegate típus delegate objektumának kezelőjét, nem a delegate objektumot.
Egy delegate objektum meghatározása
Nézzük az alábbi osztályokat
public class MyDateClass {
public void DisplayDate() {
Date dt = new Date();
System.out.println("The date is: " + dt.getDate());
}
}
public class MyTimeClass {
public static void DisplayTime() {
Date dt = new Date();
System.out.println("The time is: "
+ dt.getHours() + 'h' + ' ' + dt.getMinutes() + 'm');
Ahhoz, hogy a p1-et a
MyDateClass DisplayDate metódusához kössük, a Proc delegate típusból új példányt kell
létrehoznunk a
new operátorral. A konstruktor paramétere az a név, amelyet az objektum és metódus nevének
a
’.’ operátorral való összefűzésével kapunk.
MyDateClass d = new MyDateClass();
Proc p1 = new Proc(d.DisplayDate);
p1 = new Proc(MyTimeClass.DisplayTime);
Multicast delegate
Az összetett delegate-eket összefűzhetjük multicast(csoport) delegate-kké A System.Delegate típus két metódust
támogat a multicats delegate-k kezelésére: Combine és Remove. Nézzük meg az alábbi delegate objektum a MyTimeClass
DisplayTime metódusát címzi meg.
Proc p2 = new Proc(MyTimeClass.DisplayTime);
Most a p1 és p2 delegate-ket kombinálhatjuk:
Proc p3 = (Proc) System.Delegate.Combine(p1, p2);
A p3 egy delegate lánc. A p3.Invoke() metódus hívása a p1 és p2 Invoke() metódusát hívja meg(ebben a sorrendben).
A System.Delegate.Remove metódus lehetővé teszti delegate eltávolítását a delegate láncból.
A fordító delegate támogatása
Az alábbi metódus egy delegate típust definiál:
/** @delegate */
public delegate void Proc();
Amikor a J# fordító ehhez a két sorhoz ér, egy teljes osztály definíciót ad:
Az eredmény IL-ben:
.class public auto ansi sealed Proc
extends [mscorlib]System.MulticastDelegate
{
.method public hidebysig specialname rtspecialname
instance void .ctor(object 'object',
native int 'method') runtime managed
{
} // end of method Proc::.ctor
.method public hidebysig strict virtual
instance void Invoke() runtime managed
{
} // end of method Proc::Invoke
.method public hidebysig newslot strict virtual
instance class [mscorlib]System.IAsyncResult
BeginInvoke(class [mscorlib]System.AsyncCallback callback,
object 'object') runtime managed
{
} // end of method Proc::BeginInvoke
.method public hidebysig newslot strict virtual
instance void EndInvoke(
class [mscorlib]System.IAsyncResult result)
runtime managed {
} // end of method Proc::EndInvoke
} // end of class Proc
Az alábbi kód lefoglalja a delegate objektumot és meghívja a konstruktort:
p1 = new Proc(MyTimeClass.DisplayTime);
Az eredmény IL-ben :
...
IL_000b: ldftn void MyTimeClass::DisplayTime()
IL_0011: newobj instance void Proc::.ctor(object,
native int)
...
Az alábbi kód végrehajtja a delegate-t:
p1.Invoke();
IL-ben az eredmény:
callvirt instance retType DelegateClass::Invoke( )
Típus ekvivalencia
A delegate név-ekvivalenciát támogat. Két különböző delegate típus, amelyeknek ugyanazok a paraméterei és a
visszatérési értéke, következésképpen különböző delegate típusok.
Vezessünk be egy új delegate-t:
/** @delegate */
public delegate void Proc2;
Proc2 p2 = new Proc2(MyTimeClass.DisplayTime);
if (p1 == p2) ... // FordĂtás idejű hiba ;
P1 és P2 különböző típusúak.
Ahhoz, hogy ellenőrizzük, hogy a két delegate ugyanazokat a metódusokat tartalmazza, az equals metódust kell
használnunk:
if (p1.equals(p2)) ... // Ok
Típuskonstrukciók
Mivel a nyelv objektum orientált, ezért a típuskonstrukció elsődleges eszköze az objektum (lásd az
Objektum-orientált programozás c. fejezetet). De van néhány más lehetőség
is. Ilyen a tömb és a felsorolási típus.
Tömb
Sok azonos típusú elemek tárolására használható. Valójában a tömb is referencia típusú. Így tehát a
tömbváltozó létrehozása nem hozza létre a tömböt, hanem azt külön létre kell létrehozni, és hozzákötni
a tömbváltozóhoz.
Előnye:
- hatékony indexelés
- dinamikus létrehozás a tömbméret megadásával
- inicializáló lista lehetősége
Hátránya:
- nem polimorf (általában a tömb egyik nyelvben sem az)
Indexelés:
tömbváltozó[index]
Hossz lekérdezése:
tömbváltozó.length
int[] t = new int[3] {0,1,2};
t[0] = t[1] + t.length;
Felsorolási típus
A J# támogatja egyedi felsorolási típusok definiálását. A felsorolási típusok, speciális érték-típusok.
Egy felsorolási típus valójában egy int ahol a megfelelő nevek meg vannak feleltetve
a számoknak.
Deklarációja hasonló az osztály deklarációhoz, a következő kivételekkel:
- a class kulcsszó helyett az enum kulcsszót használjuk
- a felsorolási típusok implicit kiterjesztései az Enum-nak
- felsorolási típusokat nem lehet abstract-ként deklarálni
- a felsorolási típusok nem lehetnek protected-ek
- felsorolási típusoknak nem lehetnek metódusai, property-ei, eseményei
- a felsorolási típusok nem implementálhatnak interface-eket
public enum ColorEnum
{
Red,
Green,
Blue
}
Egy felsorolási elem értékét lehet cast-olni:
int i = (int) ColorEnum.Red
Ha egy felsorolási értéket a new kulcsszóval akarunk használni, akkor ez hibához vezet.
Az egész értékét egy felsorolási típus egy tagjának a következő szintaxissal lehet megadni:
public enum ColorEnum
{
Red(1),
Green(2),
Blue(3)
}
Ha ezeket az értékeket nem adjuk meg explicit, akkor ezeket a fordító beállítja, a legelső elemnek
0-t, majd az összes többinek az előzőnek a rákövetkezőjét.
public enum ColorEnum
{
Red,
Green(10),
Blue
}
Itt a Red a 0 értéket, a Green a 10-et, a Blue pedig a 11-et kapja.
A többszörös felsorolási típusokban meg lehet osztani az azonos egész értékeket.
Egy felsorolási típusban a tagok egymástól való függősége engedélyezett, kivéve a ciklikus függés.
public enum ColorEnum
{
Red,
Blue,
Green(Blue);
}
Az implicit típuskonverzió nem megengedett, csak cast-olással lehet konvertálni.
int i = Color.Red; // error
int i = (int) Color.Red; // OK
A következő operátorokat lehet használni a felsorolási típus értékeinek összehasonlítására:
==, !=, <, >, <=, >=, +, -, ^, &, |, ~
Leggyakoribb használatuk: switch szakaszban:
ColorEnum color = Color.Red;
switch( color )
{
case ColorEnum.Red:
// ...
break;
case ColorEnum.Blue:
// ...
break;
case ColorEnum.Green:
//...
break;
default:
break;
}
Típuskonverziók
Referencia típus esetében a felfelé cast-olás (upcast) automatikusan megtörténik, ha erre szükség van.
A lefelé cast-olást (downcast) explicit módon kényszeríthetjük ki. Ez hasonló módon történik J#-ban,
mint azt a C/C++ nyelvekben megszokhattuk. A változó elé zárójelbe írt típusnév hatására a változó
tartalma a megadott típusra konvertálódik, amennyiben a konverzió lehetséges. Ezt érték típusú változók
esetén is megtehetjük.
int i = 10;
double d = (double)i;
Egy érték-típusra irányuló kérés lehet közvetlenül, mint egy
Object-re. A Visual J#
fordító implicit elvégzi a szükséges box-olást(bedobozolást), amikor az értékből objektum lesz. Hasonlóan
a "kidobozolást" vagy cast-olást is elvégzi a fordító automatikusan.
Változók, konstansok
Változókat a következő szintaxissal deklarálhatunk:
láthatóság módosítók
típus változónév [= <kifejezés>] (, változónév [= <kifejezés>])*;
Ahol:
- Láthatóság:
- public: teljesen nyilvános, mindenki számára látható
- protected: az adott osztály objektumai, a leszármazott osztály objektumai, ill. az azonos
fordítási egységben lévő osztályok objektumai láthatják
- private: magánjellegű, a külvilág felé egyáltalán nem látszik, csak az adott osztály
objektumai láthatják
- Módosító:
- const: konstans, kötelező inicializálni
- static: osztályszintű, példányosítás nélkül is elérhető az osztály nevére való
hivatkozással
- synchronized: párhuzamos futatás esetén biztosítja a kölcsönös kizárást (lásd a
Párhuzamosság c. fejezetet)
public int i, j = 10, k = i+j*2;
private const double d = (double)i;
Kifejezések, operátorok
Egy kifejezés vagy aritmetikai, vagy logikai. Ez attól függ, hogy mi az utoljára végrehajtott művelet
eredménye. Ha a kifejezés elmarad, akkor üres utasításról beszélünk (;) (lásd a
Utasítások, vezérlési szerkezetek c. fejezetet)
Az értékadás is egy kifejezés. Ennek operátorai: =, +=, -= *=, /=, ++, --
(lásd a Utasítások, vezérlési szerkezetek c. fejezetet)
Operátorok:
- unáris: !, -, ++, --
- bináris: +, -, *, /, %, <, >, &, |, ==, !=, <=, >=, <<, &&, ||, >>, >>>, +=, -=, *=, /=, &=,
|=, ^=, %=, <<=, >>=, >>>=
- triáris: ? :