Pure Java – 78 Generics & Collections – Generics – 03
Merhaba Arkadaslar,
Bu bolumde Generics konusuna devam edecegiz. Bu bolume kadar type-safe collection yapisini gorduk. Burada Generics konusunun basinda bahsettigimiz su ozelligi inceleyegiz;
Generics yapisi, type kavramini class ve interfaceler icin aktif eder. Class, interface veya method taniminda(define/declare) parametre ile bu tip bilgisini kullanabilmemizi saglar. Peki bunun en onemli faydasi nedir ? type parametreleri kodunuza tekrar kullanilabilirlik ozelligi kazandiririr.
Generics yapisini kullanarak farkli type degerine sahip Collection’lar icin kullanilabilecek, customized ozellige sahip , type safe ve kolay okunabilir bir kod yazilabilir.
Aslinda cok uzaga gitmeye gerek yok , Collection API yapisinda bir cok class ve interface bu sekilde yazilmistir, ornegin ;
public interface List<E> extends Collection<E> {..} public interface Set<E> extends Collection<E> {..} public interface Map<K,V> {...} public class TreeSet<E> extends AbstractSet implements NavigableSet<E>, Cloneable, java.io.Serializable {...}
Class ve interface’lerde oldugu gibi yine bir cok metot Collection API’de bu sekildedir.
boolean add(E e); E remove(int index); V put(K key, V value);
Peki burada class , interface ya da metotlarda kullanilan E , K, V gibi harflerin anlami nedir neden kullanilmaktadir ?
<E> ifadesi bizim icin placeholder/yer tutucu gorevi ustlenmektedir. List arabirimi bizim icin generic/genel bir “template/taslak” ozelligi tasir.
Biz kod yazdigimizda dilersek List<Dog> , List<Car> , List<String> vb gibi bu List’in tipini degistirebiliriz.
Burada isim olarak E harfi kullanilmasi zorunlu degildir fakat convention geregi E , “Element” anlaminda kullanilmaktadir.
Diger kullanilan ya da bizim uygun yerlerde (conventiona uyacak sekilde) kullanmamiz gereken harfler ve anlamlari soyledir ;
E – Element
K – Key
N – Number
T – Type
V – Value
Bu durumda ArrayList’teki eleman ekleme metoduna bakalim.Bu ne anlama geliyor olabilir ?
public boolean add(E e) { ensureCapacity(size + 1); // Increments modCount!! elementData[size++] = e; return true; }
Bunun anlami E yi hangi tipte tanimladiysak , o tipte eleman ekleme yapabilirz. List<String> tipinde bir generics ifadeye Integer tipinde eleman ekleyemeyiz.
Generic Class
Generic Class tanimi , non-generic class tanimindan farkli olarak deklarasyonda type parametresi eklenerek yapilir.
Generic Class tanimina ornek Comparable arabirimi kisa ve guzel bir ornek olacaktir.
public interface Comparable<T> { public int compareTo(T o); }
Daha iyi anlamak icin kendimiz bir ornek yapalim;
class MyGenericClass <T>{ // T , type paremetresi //instance degisken T tipi olabilir. T genericReference; //Metot donus tipi T olabilir. public T getGenericReference() { return genericReference; } public MyGenericClass(T genericReference) { this.genericReference = genericReference; } } public class GenericTest { public static void main(String[] args) { MyGenericClass <Integer> intOb = new MyGenericClass<IntegeR>(100); MyGenericClass <String> strOb = new MyGenericClass<String>("Test"); MyGenericClass raw = new MyGenericClass(10.5); Integer intValue = intOb.getGenericReference(); String strValue = strOb.getGenericReference(); double doubleValue = (double) raw.getGenericReference(); System.out.println("int :" + intValue); System.out.println("String :" + strValue); System.out.println("double :" + doubleValue); } }
Generic Class taniminda birden fazla type parametresi kullanabiliriz.
class UseTwo<T, X> { T one; X two; public T getOne() { return one; } public X getTwo() { return two; } public UseTwo(T one, X two) { this.one = one; this.two = two; } } public class TwoTypeParameterTest { public static void main(String[] args) { UseTwo<String, Integer> twos = new UseTwo<String, Integer>("Java", 2014); String one = twos.getOne(); int two = twos.getTwo(); } }
Generics Method & Constructor
Suana kadar olan orneklerde parameter type bilgisini class taniminda yaptik fakat class taniminda yapmayip metot taniminda da yapabiliriz.
public class GenericMethodTest { public static<E> void genericMethod(E[] myArray) { for (E element : myArray) { System.out.println(element); } } public static void main(String[] args) { Integer[] intArray = { 1, 2, 3, 4, 5 }; Double[] doubleArray = { 1.1, 2.2, 3.3, 4.4 }; Character[] charArray = { 'H', 'E', 'L', 'L', 'O' }; System.out.println( "Array integerArray contains:" ); genericMethod( intArray ); // pass an Integer array System.out.println( "\nArray doubleArray contains:" ); genericMethod( doubleArray ); // pass a Double array System.out.println( "\nArray characterArray contains:" ); genericMethod( charArray ); // pass a Character array } }
Donus tipimiz de T olabilir ;
public class Test { public static <T> testMethod(T t) { // instanceof kontrolu yapabiliriz. if (t instanceof Integer) { // Sonrasinda cast edebiliriz. Integer number = (Integer) t; number = number + 20; t = (T) number; } return t; } public static void main(String[] args) { System.out.println(testMethod(10)); } }
Type parametresi sinif taniminda yapilmissa bu type paramertesini non-static metotlarda sorunsuzca kullanabiliriz fakat static metotlarda bu type parametresini kullanamayiz. Bu nedenle static metotlar icin type parametresini tekrar tanimlamak gereklidir.
public class GenericStaticTest<T> { public void nonStaticMethod(T t) { } // public static void staticMethodWithoutType(T t) { // // } public static<T> void staticMethodWithType(T t) { } }
Bounded Type Parameters
Onceki bolumlerde ? wildcard kullanimini incelemistik. Kendimiz bir type belirledigimizde bunu sinirlandirmak isteyebiliriz. Ornegin sayisal islemler yaptigimiz bir generic metot dusunelim bunu Number sinifi ve altsiniflari icin sinirlandirabiliriz.
public class BoundedTypeParameter { public static<T extends Number> void boundedTypeMethod(T t) { System.out.println("T: " + t.getClass().getName()); } public static void main(String[] args) { boundedTypeMethod(100); boundedTypeMethod(100.5); boundedTypeMethod(100.5f); // boundedTypeMethod("compile error"); } }
Upper Bounded wildcard kullanimi ile , unbounded wildcard kullanimini karistirmayalim.
public class NumberHolder<? extends Number> { } //unbounded wildcard
public class NumberHolder<?> { ? aNum; } //unbounded wildcard //derleme hatasi
public class NumberHolder { T aNum; } // Yes
Multiple Bounds
& (ampersand) karakteri kullanilarak birden fazla (multiple) bounds tanimi yapilabilir. Ornegin java.util.Collections sinifinda yer alan max metodunu inceleyelim ;
public static <T extends Object & Comparable<? super T>> T max(Collection<? extends T> coll) { Iterator<? extends T> i = coll.iterator(); T candidate = i.next(); while (i.hasNext()) { T next = i.next(); if (next.compareTo(candidate) > 0) candidate = next; } return candidate; }
Exception Handling
java.lang.Throwable sinifinin alt siniflari parametrik olarak tanimlanamaz.
Bu durumda asagidaki kod derleme hatasi verir. Exception IS-A Throwable
public class ParametricException extends Exception { // compile-time error private final T value; public ParametricException(T value) { this.value = value; } public T getValue() { return value; } }
Yazimi burada sonlandiriyorum.
Herkese Bol Javali Gunler dilerim.
Be an oracle man , import java.*;
Levent Erguder
OCP, Java SE 6 Programmer
OCE, Java EE 6 Web Component Developer
Leave a Reply