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

Print Friendly, PDF & Email

Leave a Reply

Your email address will not be published. Required fields are marked *