CodeGym /Kurslar /Java SELF AZ /Java-da Parametrizə Edilmiş Tiplər – Generics

Java-da Parametrizə Edilmiş Tiplər – Generics

Java SELF AZ
Səviyyə , Dərs
Mövcuddur

1. Bütün siniflər Object-dən miras alır

Java-da bütün siniflər dolayısı ilə (gizli şəkildə) Object sinifindən miras alır.

Mirasın nə olduğunu və Java-da necə işlədiyini Java Core bölməsində öyrənəcəyik. İndisə bundan çıxan sadə bir faktı nəzərdən keçirək:

Object tipində olan dəyişənə istənilən sinifdən bir obyekt mənimsətmək olar. Məsələn:

Kod Qeydlər
Object o = new Scanner(System.in);
o dəyişənində Scanner tipində obyektin istinadını saxlayır
Object o = new String();
o dəyişənində String tipində obyektin istinadını saxlayır
Object o = new Integer(15);
o dəyişənində Integer tipində obyektin istinadını saxlayır
Object o = "Salam";
o dəyişənində String tipində obyektin istinadını saxlayır

Burada yaxşı xəbərlər bitir. Kompilyator nəzarət etmir, hansı tipdə obyekt Object tipində dəyişəndə saxlanılıb, buna görə də saxlanılmış obyektin olan metodlarını, ancaq Object tipində dəyişənin metodlarını çağırmaq olmaz.

Əgər belə obyektin metodlarını çağırmaq lazımdırsa, onda əvvəlcə onun istinadını düzgün tipdə dəyişəndə saxlamaq, sonra isə həmin dəyişəndə metodları çağırmaq lazımdır:

Kod Qeydlər
Object o = new Scanner(System.in);
int x = o.nextInt();
Proqram kompilyasiya edilmir. Object sinfində nextInt() metodu yoxdur.
Object o = new Scanner(System.in);

Scanner console = (Scanner) o;

int x = console.nextInt();
Bu halda işləyəcək.

Burada biz Scanner tipində obyektin istinadını Scanner tipində dəyişəndə saxlayırıq tipin çevrilməsi operatoru vasitəsilə.

Object tipində dəyişəni Scanner tipinə mənimsətmək sadəcə belə mümkün deyil, hətta əgər Object tipində dəyişəndə Scanner tipində obyekt saxlanılırsa belə. Amma bu, sizə artıq məlum olan tipin çevrilməsi operatoru ilə mümkün ola bilər. Ümumi halda bu, belə görünür:

Tip ad1 = (Tip) ad2;

Burada ad1 – Tip tipində dəyişənin adı, ad2 – bu isə Object tipində dəyişənin adı, hansında ki, Tip tipində obyektin istinadı saxlanılır.

Tip çevrilməsi

Əgər dəyişən və obyektin tipləri fərqlidirsə, ClassCastException xəta baş verəcək. Məsələn:

Kod Qeydlər
Object o = new Integer(5);
String s = (String) o;
İcra zamanı xəta baş verəcək:
burada ClassCastException atılacaq

Java-da bu xətanın qarşısını almağın yolu var: dəyişən daxilində hansı tipin olduğunu yoxlamağın üsulu mövcuddur:

ad instanceof Tip

instanceof operatoru yoxlayır, müəyyən edir ki, ad dəyişəni, Tip tipində bir obyekt olub-olmadığını.

Məsələn — məlumatlar massivində sətri tapmaq:

Kod Qeydlər
Object[] obyektlər = {10, "Salam", 3.14};

for (int i = 0; i < obyektlər.length; i++)
{
   if (obyektlər[i] instanceof String)
   {
      String s = (String) obyektlər[i];
      System.out.println(s);
   }
}
Autoboxing bu dəyərləri Integer, StringDouble-a çevirir.

Obyektlər massivində dövr

Əgər obyekt String tipində olarsa

Onu String tipində dəyişəndə saxlayırıq
Dəyişəni ekrana çap edirik.


2. Şablonların yaranma səbəbi (kolleksiyalar)

Kolleksiyalara qayıdırıq.

Java proqramçıları ArrayList sinfini yaratmağa başladıqda, onu universal etmək istəyirdilər ki, istənilən tipdə obyektləri orada saxlamaq mümkün olsun. Buna görə elementləri saxlamaq üçün Object tipli massivdən istifadə etdilər.

Belə yanaşmanın güclü tərəfi odur ki, kolleksiyaya istənilən tipdə obyekt əlavə edilə bilər.

Bəs zəif tərəfləri? Bir neçə belə zəif cəhət dərhal görünür.

Çatışmazlıq 1.

Kolleksiyadan elementləri çıxararkən hər zaman tip çevirmə operatorundan istifadə etmək lazım idi:

Kod Qeyd
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);
}
Obyektləri Object tipinə aid referensləri saxlamaq üçün kolleksiya yaradırıq.

Kolleksiyanı 10, 20, ... 100 rəqəmləri ilə doldururuq;



Kolleksiyanın elementlərini cəmləyirik


Tip çevirmədən istifadə olunmalıdır

Çatışmazlıq 2.

Kolleksiyadakı elementlərin müəyyən bir tipdə olacağına zəmanət yox idi

Kod Qeyd
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);
}
Obyektləri Object tipinə aid referensləri saxlamaq üçün kolleksiya yaradırıq.

Kolleksiyanı Double tipində rəqəmlərlə doldururuq:
0.0, 2.5, 5.0, ...


Kolleksiyanın elementlərini cəmləyirik


Xəta olacaq: Double tipini Integer tipinə çevirə bilməzsiniz

Kolleksiyaya məlumatlar hər hansı bir yerdən doldurula bilər:

  • başqa bir metodda
  • başqa bir proqramda
  • fayldan yüklənərək
  • şəbəkədən alınaraq

Çatışmazlıq 3.

Kolleksiyanın məlumatlarını bilməyərəkdən dəyişmək mümkündür.

Siz öz məlumatlarınızla doldurduğunuz kolleksiyanı hər hansı metodun içərisinə ötürə bilərsiniz, lakin həmin metod, hansı ki başqa bir proqramçı tərəfindən yazılıb, sizin kolleksiyanıza öz məlumatlarını əlavə edə bilər.

Kolleksiyanın adına baxaraq hansı tipdə məlumatların saxlanıldığını anlamaq mümkün deyil. Hətta dəyişkənə belə bir ad versəniz belə, ona referens ötürərək onlarla metoda göndərmək olar və orada dəyişkənin ilkin adı haqqında heç bir məlumat olmaz.


3. Generics

Generics Java-da

Java-da Generics (Generics) kimi gözəl bir şey bütün bu problemləri həll edir.

Java-da generics dedikdə, tiplərə parametr-tiplər əlavə etmək imkanı nəzərdə tutulur. Bu yolla mürəkkəb birləşmiş tiplər əmələ gəlir. Belə bir birləşmiş tip ümumi halda belə görünür:

ƏsasTip<TipParametr>

Hər şey birlikdə — bu məhz tipdir. Və o, adi halda tiplərin istifadə oluna biləcəyi yerlərdə istifadə oluna bilər.

Kod Təsvir
ArrayList<Integer> list;
Dəyişənlərin yaradılması
list = new ArrayList<Integer> ();
Obyektlərin yaradılması
ArrayList<Integer>[] array;
Massivlərin yaradılması

Belə bir kolleksiyaya yalnız Integer tipində dəyişənlər saxlamaq olar:

Kod Təsvir
ArrayList<Integer> list = new ArrayList<Integer>();
list.add(new Integer(1));
list.add(2);
list.add("Salam");
ArrayList tipi ilə kolleksiya, elementləri Integer tipindədir
Belə edə bilərsən
Və belə də olar: işləyəcək
autoboxing

Amma belə olmaz: kompilyasiya xətası

Parametr-tipləri olan öz siniflərinizi necə yaratmağı Java Collections missiyasında öyrənəcəksiniz. İndi isə bunun necə istifadə edildiyini və necə işlədiyini nəzərdən keçirəcəyik.


4. Generics necə işləyir

Əslində Generics çox primitiv şəkildə işləyir.

Compiler sadəcə parametrli tipi elə həmin tipə çevirir, yalnız parametrlərsiz. Onun metodları ilə qarşılıqlı əlaqədə isə tipi parametrə çevirmə əməliyyatı əlavə edir:

Kod Compiler nə edəcək
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);

Tutaq ki, bizdə tam ədədlər kolleksiyasındakı ədədləri toplayan metodun kodu var idi:

Kod Compiler nə edəcək
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;
}

Yəni mahiyyətcə generics — autoboxing kimi sintaktik şəkər növüdür, yalnız bir az daha böyükdür. Autoboxing-də compiler bizdən int tipini Integer-ə və əksinə çevirmə metodlarını əlavə edir, generics üçün isə tip çevirmə operatorlarını əlavə edir.

Compiler sizin kodunuzu generics ilə compile etdikdən sonra, içində parametrli tipli bütün siniflər sadəcə siniflərə və tip çevirmə operatorlarına çevrilmiş olur. Başlanğıcda mürəkkəb tipli dəyişənlərin hansı tip-parametrdə olduğu məlumatı itir. Bu effektə bəzən tiplərin silinməsi də deyirlər.

Bəzən öz parametrli tipləri olan siniflərini yazan proqramçılara ora parametr kimi ötürülən tiplər haqqında məlumat çox lazım olur. Bununla necə mübarizə aparıldığını və nəticədə nə baş verdiyini Java Collections mövzusunda öyrənəcəksiniz.



5. Generics haqqında bir neçə məqam

Generics haqqında maraqlı faktlar.

Siniflərin yalnız bir deyil, bir neçə tip parametri ola bilər. Təxminən belə görünür:

ƏsasTip<TipParametr1, TipParametr2, TipParametr3>

Əslində, bu heç də təəccüblü deyil. Kompilyator bir tipə cast operatoru əlavə edə bildiyi yerdə, bir neçə də əlavə edə bilər.

Nümunələr:

Kod İzah
HashMap<Integer, String> map = new HashMap<Integer, String>();
map.put(7, "Salam");
map.put(-15, "Salam");
put metodunun birinci parametri Integer tipindədir, ikinci isə String tipindədir

Bundan əlavə, mürəkkəb tiplər də parametr kimi istifadə edilə bilər. Təxminən belə görünür:

ƏsasTip<TipParametr<TipParametrParametri>>

Gəlin təsəvvür edək ki, biz bir siyahı yaratmaq istəyirik, həmin siyahı da string-lərdən ibarət siyahıları saxlayır. Belə bir kod alarıq:

// salamlaşmalar siyahısı
ArrayList<String> listHello = new ArrayList<String>();
listHello.add("Salam");
listHello.add("Hi");

// vidalaşmalar siyahısı
ArrayList<String> listBye = new ArrayList<String>();
listBye.add("Hələlik");
listBye.add("Good Bye");

// siyahılar siyahısı
ArrayList<ArrayList<String>> lists = new ArrayList<ArrayList<String>>();
lists.add(listHello);
lists.add(listBye);
Şərhlər
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION