Java Generics - Hızlı Kılavuz

Bir Integer dizisindeki, String dizisindeki veya sıralamayı destekleyen herhangi bir tipteki bir dizideki öğeleri sıralayabilen tek bir sıralama yöntemi yazabilirsek güzel olurdu.

Java Genel yöntemler ve genel sınıflar, programcıların sırasıyla tek bir yöntem bildirimiyle, bir dizi ilişkili yöntemi veya tek bir sınıf bildirimiyle bir dizi ilişkili türü belirtmesini sağlar.

Generics ayrıca, programcıların derleme zamanında geçersiz türleri yakalamasına olanak tanıyan derleme zamanı tür güvenliği sağlar.

Java Generic kavramını kullanarak, bir dizi nesneyi sıralamak için genel bir yöntem yazabiliriz, ardından dizi öğelerini sıralamak için Tamsayı dizileri, Çift diziler, Dize dizileri vb. İle genel yöntemi çağırabiliriz.

Yerel Ortam Kurulumu

JUnit, Java için bir çerçevedir, bu nedenle ilk gereksinim, makinenizde JDK'nın kurulu olmasıdır.

Sistem gereksinimleri

JDK 1.5 veya üstü.
Hafıza Minimum gereklilik yok.
Disk alanı Minimum gereklilik yok.
İşletim sistemi Minimum gereklilik yok.

Adım 1: Makinenizde Java Kurulumunu Doğrulayın

Öncelikle konsolu açın ve üzerinde çalıştığınız işletim sistemine göre bir java komutu yürütün.

işletim sistemi Görev Komut
pencereler Komut Konsolunu Aç c: \> java sürümü
Linux Komut Terminalini Aç $ java sürümü
Mac Açık Terminal machine: <joseph $ java -version

Tüm işletim sistemleri için çıktıyı doğrulayalım -

işletim sistemi Çıktı
pencereler

java sürümü "1.6.0_21"

Java (TM) SE Çalışma Zamanı Ortamı (derleme 1.6.0_21-b07)

Java HotSpot (TM) Client VM (derleme 17.0-b17, karma mod, paylaşım)

Linux

java sürümü "1.6.0_21"

Java (TM) SE Çalışma Zamanı Ortamı (derleme 1.6.0_21-b07)

Java HotSpot (TM) Client VM (derleme 17.0-b17, karma mod, paylaşım)

Mac

java sürümü "1.6.0_21"

Java (TM) SE Çalışma Zamanı Ortamı (derleme 1.6.0_21-b07)

Java HotSpot (TM) 64-Bit Sunucu VM (derleme 17.0-b17, karma mod, paylaşım)

Sisteminizde Java yüklü değilse, aşağıdaki bağlantıdan Java Yazılım Geliştirme Kitini (SDK) indirin https://www.oracle.com. Bu öğretici için Java 1.6.0_21 sürümünü yüklü sürüm olarak kabul ediyoruz.

Adım 2: JAVA Ortamını Ayarlayın

Yı kur JAVA_HOMEJava'nın makinenizde kurulu olduğu temel dizin konumunu gösteren ortam değişkeni. Örneğin.

işletim sistemi Çıktı
pencereler JAVA_HOME ortam değişkenini C: \ Program Files \ Java \ jdk1.6.0_21 olarak ayarlayın
Linux dışa aktar JAVA_HOME = / usr / local / java-current
Mac dışa aktar JAVA_HOME = / Kitaplık / Java / Ana Sayfa

Java derleyici konumunu Sistem Yoluna ekleyin.

işletim sistemi Çıktı
pencereler Dizeyi ekleyin C:\Program Files\Java\jdk1.6.0_21\bin sistem değişkeninin sonunda, Path.
Linux dışa aktarma PATH = $PATH:$JAVA_HOME / bin /
Mac gerekli değil

Komutu kullanarak Java kurulumunu doğrulayın java -version yukarıda açıklandığı gibi.

Sınıf adının ardından bir tür parametresi bölümü gelmesinin dışında, genel bir sınıf bildirimi, genel olmayan bir sınıf bildirimine benzer.

Genel bir sınıfın tür parametresi bölümü, virgülle ayrılmış bir veya daha fazla tür parametresine sahip olabilir. Bu sınıflar, bir veya daha fazla parametre kabul ettikleri için parametreli sınıflar veya parametreli türler olarak bilinir.

Sözdizimi

public class Box<T> {
   private T t;
}

Nerede

  • Box - Box, genel bir sınıftır.

  • T- Genel sınıfa iletilen genel tür parametresi. Herhangi bir Nesneyi alabilir.

  • t - Genel tip T örneği.

Açıklama

T, Box genel sınıfına iletilen bir tür parametresidir ve bir Box nesnesi oluşturulduğunda iletilmelidir.

Misal

Seçtiğiniz herhangi bir düzenleyiciyi kullanarak aşağıdaki java programını oluşturun.

GenericsTester.java

package com.tutorialspoint;

public class GenericsTester {
   public static void main(String[] args) {
      Box<Integer> integerBox = new Box<Integer>();
      Box<String> stringBox = new Box<String>();

      integerBox.add(new Integer(10));
      stringBox.add(new String("Hello World"));

      System.out.printf("Integer Value :%d\n", integerBox.get());
      System.out.printf("String Value :%s\n", stringBox.get());
   }
}

class Box<T> {
   private T t;

   public void add(T t) {
      this.t = t;
   }

   public T get() {
      return t;
   }   
}

Bu, aşağıdaki sonucu verecektir.

Çıktı

Integer Value :10
String Value :Hello World

Kural olarak, tür parametresi adları tek, büyük harfler olarak adlandırılır, böylece bir tür parametresi sıradan bir sınıf veya arabirim adıyla kolayca ayırt edilebilir. Yaygın olarak kullanılan tür parametresi adlarının listesi aşağıdadır -

  • E - Element ve esas olarak Java Koleksiyonları çerçevesi tarafından kullanılır.

  • K - Anahtar ve esas olarak bir haritanın anahtarının parametre türünü temsil etmek için kullanılır.

  • V - Değer ve esas olarak bir haritanın değerinin parametre türünü temsil etmek için kullanılır.

  • N - Sayı ve esas olarak sayıları temsil etmek için kullanılır.

  • T - Tür ve esas olarak ilk genel tür parametresini temsil etmek için kullanılır.

  • S - Tür ve esas olarak ikinci genel tür parametresini temsil etmek için kullanılır.

  • U - Tür ve esas olarak üçüncü genel tür parametresini temsil etmek için kullanılır.

  • V - Tür ve esas olarak dördüncü genel tür parametresini temsil etmek için kullanılır.

Aşağıdaki örnek, yukarıda bahsedilen kavramı gösterecektir.

Misal

Seçtiğiniz herhangi bir düzenleyiciyi kullanarak aşağıdaki java programını oluşturun.

GenericsTester.java

package com.tutorialspoint;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

public class GenericsTester {
   public static void main(String[] args) {
      Box<Integer, String> box = new Box<Integer, String>();
      box.add(Integer.valueOf(10),"Hello World");
      System.out.printf("Integer Value :%d\n", box.getFirst());
      System.out.printf("String Value :%s\n", box.getSecond());

      Pair<String, Integer> pair = new Pair<String, Integer>(); 
      pair.addKeyValue("1", Integer.valueOf(10));
      System.out.printf("(Pair)Integer Value :%d\n", pair.getValue("1"));

      CustomList<Box> list = new CustomList<Box>();
      list.addItem(box);
      System.out.printf("(CustomList)Integer Value :%d\n", list.getItem(0).getFirst());
   }
}

class Box<T, S> {
   private T t;
   private S s;

   public void add(T t, S s) {
      this.t = t;
      this.s = s;
   }

   public T getFirst() {
      return t;
   } 

   public S getSecond() {
      return s;
   } 
}

class Pair<K,V>{
   private Map<K,V> map = new HashMap<K,V>();

   public void addKeyValue(K key, V value) {
      map.put(key, value);
   }

   public V getValue(K key) {
      return map.get(key);
   }
}

class CustomList<E>{
   private List<E> list = new ArrayList<E>();

   public void addItem(E value) {
      list.add(value);
   }

   public E getItem(int index) {
      return list.get(index);
   }
}

Bu, aşağıdaki sonucu verecektir.

Çıktı

Integer Value :10
String Value :Hello World
(Pair)Integer Value :10
(CustomList)Integer Value :10

Tür çıkarımı, Java derleyicisinin bir yöntem çağrısına ve tür bağımsız değişkenlerini kontrol etmek ve belirlemek için ilgili bildirimine bakma becerisini temsil eder. Çıkarım algoritması, bağımsız değişkenlerin türlerini kontrol eder ve varsa, atanan tür döndürülür. Çıkarım algoritmaları, tüm tür parametrelerini doldurabilecek belirli bir tür bulmaya çalışır.

Derleyici, tür çıkarımının kullanılmaması durumunda denetlenmeyen dönüştürme uyarısı oluşturur.

Sözdizimi

Box<Integer> integerBox = new Box<>();

Nerede

  • Box - Box, genel bir sınıftır.

  • <> - Elmas operatörü, tür çıkarımını belirtir.

Açıklama

Elmas operatörünü kullanarak, derleyici parametrenin türünü belirler. Bu operatör Java SE 7 sürümünden itibaren mevcuttur.

Misal

Seçtiğiniz herhangi bir düzenleyiciyi kullanarak aşağıdaki java programını oluşturun.

GenericsTester.java

package com.tutorialspoint;

public class GenericsTester {
   public static void main(String[] args) {
      //type inference   
      Box<Integer> integerBox = new Box<>();
      //unchecked conversion warning
      Box<String> stringBox = new Box<String>();

      integerBox.add(new Integer(10));
      stringBox.add(new String("Hello World"));

      System.out.printf("Integer Value :%d\n", integerBox.get());
      System.out.printf("String Value :%s\n", stringBox.get());
   }
}

class Box<T> {
   private T t;

   public void add(T t) {
      this.t = t;
   }

   public T get() {
      return t;
   }   
}

Bu, aşağıdaki sonucu verecektir.

Çıktı

Integer Value :10
String Value :Hello World

Farklı türlerdeki argümanlarla çağrılabilen tek bir genel yöntem bildirimi yazabilirsiniz. Genel yönteme iletilen bağımsız değişkenlerin türlerine bağlı olarak, derleyici her yöntem çağrısını uygun şekilde işler. Genel Yöntemleri tanımlayan kurallar aşağıdadır -

  • Tüm genel yöntem bildirimleri, yöntemin dönüş türünden (sonraki örnekte <E>) önce gelen açılı ayraçlarla (<ve>) ayrılmış bir tür parametresi bölümüne sahiptir.

  • Her tür parametresi bölümü, virgülle ayrılmış bir veya daha fazla tür parametresi içerir. Tür değişkeni olarak da bilinen bir tür parametresi, genel bir tür adı belirten bir tanımlayıcıdır.

  • Tür parametreleri, dönüş türünü bildirmek ve gerçek tür bağımsız değişkenleri olarak bilinen genel yönteme iletilen bağımsız değişkenlerin türleri için yer tutucu olarak hareket etmek için kullanılabilir.

  • Jenerik bir yöntemin gövdesi, diğer herhangi bir yönteminki gibi bildirilir. Tür parametrelerinin yalnızca başvuru türlerini temsil edebileceğini, ilkel türleri (int, double ve char gibi) temsil edemeyeceğini unutmayın.

Misal

Aşağıdaki örnek, tek bir Genel yöntem kullanarak farklı türden bir diziyi nasıl yazdırabileceğimizi göstermektedir -

public class GenericMethodTest {
   // generic method printArray
   public static < E > void printArray( E[] inputArray ) {
      // Display array elements
      for(E element : inputArray) {
         System.out.printf("%s ", element);
      }
      System.out.println();
   }

   public static void main(String args[]) {
      // Create arrays of Integer, Double and Character
      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:");
      printArray(intArray);   // pass an Integer array

      System.out.println("\nArray doubleArray contains:");
      printArray(doubleArray);   // pass a Double array

      System.out.println("\nArray characterArray contains:");
      printArray(charArray);   // pass a Character array
   }
}

Bu, aşağıdaki sonucu verecektir -

Çıktı

Array integerArray contains:
1 2 3 4 5 

Array doubleArray contains:
1.1 2.2 3.3 4.4 

Array characterArray contains:
H E L L O

Bir Generic sınıf, çoklu tip parametrelere sahip olabilir. Aşağıdaki örnek, yukarıda bahsedilen kavramı gösterecektir.

Misal

Seçtiğiniz herhangi bir düzenleyiciyi kullanarak aşağıdaki java programını oluşturun.

GenericsTester.java

package com.tutorialspoint;

public class GenericsTester {
   public static void main(String[] args) {
      Box<Integer, String> box = new Box<Integer, String>();
      box.add(Integer.valueOf(10),"Hello World");
      System.out.printf("Integer Value :%d\n", box.getFirst());
      System.out.printf("String Value :%s\n", box.getSecond());

      Box<String, String> box1 = new Box<String, String>();
      box1.add("Message","Hello World");
      System.out.printf("String Value :%s\n", box1.getFirst());
      System.out.printf("String Value :%s\n", box1.getSecond());
   }
}

class Box<T, S> {
   private T t;
   private S s;

   public void add(T t, S s) {
      this.t = t;
      this.s = s;
   }

   public T getFirst() {
      return t;
   } 

   public S getSecond() {
      return s;
   } 
}

Bu, aşağıdaki sonucu verecektir.

Çıktı

Integer Value :10
String Value :Hello World
String Value :Message
String Value :Hello World

Generic bir sınıf, bir tür parametresinin parametreli bir türle değiştirilebildiği parametreli türlere sahip olabilir. Aşağıdaki örnek, yukarıda bahsedilen kavramı gösterecektir.

Misal

Seçtiğiniz herhangi bir düzenleyiciyi kullanarak aşağıdaki java programını oluşturun.

GenericsTester.java

package com.tutorialspoint;

import java.util.ArrayList;
import java.util.List;


public class GenericsTester {
   public static void main(String[] args) {
      Box<Integer, List<String>> box
         = new Box<Integer, List<String>>();
      
      List<String> messages = new ArrayList<String>();
      
      messages.add("Hi");
      messages.add("Hello");
      messages.add("Bye");      
      
      box.add(Integer.valueOf(10),messages);
      System.out.printf("Integer Value :%d\n", box.getFirst());
      System.out.printf("String Value :%s\n", box.getSecond());

      
   }
}

class Box<T, S> {
   private T t;
   private S s;

   public void add(T t, S s) {
      this.t = t;
      this.s = s;
   }

   public T getFirst() {
      return t;
   } 

   public S getSecond() {
      return s;
   } 
}

Bu, aşağıdaki sonucu verecektir.

Çıktı

Integer Value :10
String Value :[Hi, Hello, Bye]

Bir ham tür, oluşturma sırasında tür bağımsız değişkenleri iletilmezse, genel bir sınıfın veya arabirimin bir nesnesidir. Aşağıdaki örnek, yukarıda bahsedilen kavramı gösterecektir.

Misal

Seçtiğiniz herhangi bir düzenleyiciyi kullanarak aşağıdaki java programını oluşturun.

GenericsTester.java

package com.tutorialspoint;

public class GenericsTester {
   public static void main(String[] args) {
      Box<Integer> box = new Box<Integer>();
      
      box.set(Integer.valueOf(10));
      System.out.printf("Integer Value :%d\n", box.getData());
      
      
      Box rawBox = new Box();
      
      //No warning
      rawBox = box;
      System.out.printf("Integer Value :%d\n", rawBox.getData());
      
      //Warning for unchecked invocation to set(T)
      rawBox.set(Integer.valueOf(10));
      System.out.printf("Integer Value :%d\n", rawBox.getData());
      
      //Warning for unchecked conversion
      box = rawBox;
      System.out.printf("Integer Value :%d\n", box.getData());
   }
}

class Box<T> {
   private T t; 

   public void set(T t) {
      this.t = t;
   }

   public T getData() {
      return t;
   } 
}

Bu, aşağıdaki sonucu verecektir.

Çıktı

Integer Value :10
Integer Value :10
Integer Value :10
Integer Value :10

Bir tür parametresine geçirilmesine izin verilen tür türlerini kısıtlamak isteyeceğiniz zamanlar olabilir. Örneğin, sayılar üzerinde çalışan bir yöntem, yalnızca Number veya alt sınıflarının örneklerini kabul etmek isteyebilir. Sınırlı tip parametreleri bunun içindir.

Sınırlı bir tür parametresi bildirmek için, tür parametresinin adını, ardından extends anahtar sözcüğünü ve ardından üst sınırını listeleyin.

Misal

Aşağıdaki örnek, extends'in genel anlamda "extends" (sınıflarda olduğu gibi) veya "uygulama" (arayüzlerde olduğu gibi) anlamında nasıl kullanıldığını göstermektedir. Bu örnek, Karşılaştırılabilir üç nesneden en büyüğünü döndürmek için Genel yöntemdir -

public class MaximumTest {
   // determines the largest of three Comparable objects
   
   public static <T extends Comparable<T>> T maximum(T x, T y, T z) {
      T max = x;   // assume x is initially the largest
      
      if(y.compareTo(max) > 0) {
         max = y;   // y is the largest so far
      }
      
      if(z.compareTo(max) > 0) {
         max = z;   // z is the largest now                 
      }
      return max;   // returns the largest object   
   }
   
   public static void main(String args[]) {
      System.out.printf("Max of %d, %d and %d is %d\n\n", 
         3, 4, 5, maximum( 3, 4, 5 ));

      System.out.printf("Max of %.1f,%.1f and %.1f is %.1f\n\n",
         6.6, 8.8, 7.7, maximum( 6.6, 8.8, 7.7 ));

      System.out.printf("Max of %s, %s and %s is %s\n","pear",
         "apple", "orange", maximum("pear", "apple", "orange"));
   }
}

Bu, aşağıdaki sonucu verecektir -

Çıktı

Max of 3, 4 and 5 is 5

Max of 6.6,8.8 and 7.7 is 8.8

Max of pear, apple and orange is pear

Bir tür parametresinin birden çok sınırı olabilir.

Sözdizimi

public static <T extends Number & Comparable<T>> T maximum(T x, T y, T z)

Nerede

  • maximum - maksimum, genel bir yöntemdir.

  • T- Genel yönteme iletilen genel tür parametresi. Herhangi bir Nesneyi alabilir.

Açıklama

T, Box genel sınıfına iletilen bir tür parametresidir ve Number sınıfının alt türü olmalıdır ve Karşılaştırılabilir arabirimi uygulamalıdır. Bir sınıfın bağlı olarak geçirilmesi durumunda, arabirimden önce geçilmesi gerekir, aksi takdirde derleme zamanı hatası oluşur.

Misal

Seçtiğiniz herhangi bir düzenleyiciyi kullanarak aşağıdaki java programını oluşturun.

package com.tutorialspoint;

public class GenericsTester {
   public static void main(String[] args) {
      System.out.printf("Max of %d, %d and %d is %d\n\n", 
         3, 4, 5, maximum( 3, 4, 5 ));

      System.out.printf("Max of %.1f,%.1f and %.1f is %.1f\n\n",
         6.6, 8.8, 7.7, maximum( 6.6, 8.8, 7.7 ));
   }

   public static <T extends Number 
      & Comparable<T>> T maximum(T x, T y, T z) {
      T max = x;      
      if(y.compareTo(max) > 0) {
         max = y;   
      }

      if(z.compareTo(max) > 0) {
         max = z;                    
      }
      return max;      
   }

   // Compiler throws error in case of below declaration
   /* public static <T extends Comparable<T> 
      & Number> T maximum1(T x, T y, T z) {
      T max = x;      
      if(y.compareTo(max) > 0) {
         max = y;   
      }

      if(z.compareTo(max) > 0) {
         max = z;                    
      }
      return max;   
   }*/
}

Bu, aşağıdaki sonucu verecektir -

Çıktı

Max of 3, 4 and 5 is 5

Max of 6.6,8.8 and 7.7 is 8.8

Java, Liste arayüzünde genel destek sağlamıştır.

Sözdizimi

List<T> list = new ArrayList<T>();

Nerede

  • list - Liste arayüzünün nesnesi.

  • T - Liste bildirimi sırasında iletilen genel tür parametresi.

Açıklama

T, genel arabirim Listesine ve onun uygulama sınıfı ArrayList'e iletilen bir tür parametresidir.

Misal

Seçtiğiniz herhangi bir düzenleyiciyi kullanarak aşağıdaki java programını oluşturun.

package com.tutorialspoint;

import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;

public class GenericsTester {
   public static void main(String[] args) {

      List<Integer> integerList = new ArrayList<Integer>();
  
      integerList.add(Integer.valueOf(10));
      integerList.add(Integer.valueOf(11));

      List<String> stringList = new ArrayList<String>();
  
      stringList.add("Hello World");
      stringList.add("Hi World");
 

      System.out.printf("Integer Value :%d\n", integerList.get(0));
      System.out.printf("String Value :%s\n", stringList.get(0));

      for(Integer data: integerList) {
         System.out.printf("Integer Value :%d\n", data);
      }

      Iterator<String> stringIterator = stringList.iterator();

      while(stringIterator.hasNext()) {
         System.out.printf("String Value :%s\n", stringIterator.next());
      }
   }  
}

Bu, aşağıdaki sonucu verecektir -

Çıktı

Integer Value :10
String Value :Hello World
Integer Value :10
Integer Value :11
String Value :Hello World
String Value :Hi World

Java, Set arayüzünde genel destek sağlamıştır.

Sözdizimi

Set<T> set = new HashSet<T>();

Nerede

  • set - Set Interface nesnesi.

  • T - Küme bildirimi sırasında geçen genel tür parametresi.

Açıklama

T, genel arabirim Setine ve onun uygulama sınıfı HashSet'e iletilen bir tür parametresidir.

Misal

Seçtiğiniz herhangi bir düzenleyiciyi kullanarak aşağıdaki java programını oluşturun.

package com.tutorialspoint;

import java.util.HashSet;
import java.util.Iterator;
import java.util.Set;

public class GenericsTester {
   public static void main(String[] args) {

      Set<Integer> integerSet = new HashSet<Integer>();
  
      integerSet.add(Integer.valueOf(10));
      integerSet.add(Integer.valueOf(11));

      Set<String> stringSet = new HashSet<String>();
  
      stringSet.add("Hello World");
      stringSet.add("Hi World");
 

      for(Integer data: integerSet) {
         System.out.printf("Integer Value :%d\n", data);
      }

      Iterator<String> stringIterator = stringSet.iterator();

      while(stringIterator.hasNext()) {
         System.out.printf("String Value :%s\n", stringIterator.next());
      }
   }  
}

Bu, aşağıdaki sonucu verecektir -

Çıktı

Integer Value :10
Integer Value :11
String Value :Hello World
String Value :Hi World

Java, Harita arayüzünde genel destek sağlamıştır.

Sözdizimi

Set<T> set = new HashSet<T>();

Nerede

  • set - Set Interface nesnesi.

  • T - Küme bildirimi sırasında geçen genel tür parametresi.

Açıklama

T, genel arabirim Setine ve onun uygulama sınıfı HashSet'e iletilen bir tür parametresidir.

Misal

Seçtiğiniz herhangi bir düzenleyiciyi kullanarak aşağıdaki java programını oluşturun.

package com.tutorialspoint;

import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;

public class GenericsTester {
   public static void main(String[] args) {

      Map<Integer,Integer> integerMap 
         = new HashMap<Integer,Integer>();
  
      integerMap.put(1, 10);
      integerMap.put(2, 11);

      Map<String,String> stringMap = new HashMap<String,String>();
    
      stringMap.put("1", "Hello World");
      stringMap.put("2","Hi World");
 

      System.out.printf("Integer Value :%d\n", integerMap.get(1));
      System.out.printf("String Value :%s\n", stringMap.get("1"));

      // iterate keys.
      Iterator<Integer> integerIterator   = integerMap.keySet().iterator();

      while(integerIterator.hasNext()) {
         System.out.printf("Integer Value :%d\n", integerIterator.next());
      }

      // iterate values.
      Iterator<String> stringIterator   = stringMap.values().iterator();

      while(stringIterator.hasNext()) {
         System.out.printf("String Value :%s\n", stringIterator.next());
      }
   }  
}

Bu, aşağıdaki sonucu verecektir -

Çıktı

Integer Value :10
String Value :Hello World
Integer Value :1
Integer Value :2
String Value :Hello World
String Value :Hi World

Soru işareti (?) Joker karakteri temsil eder, jenerikte bilinmeyen türü temsil eder. Bir tür parametresine geçirilmesine izin verilen tür türlerini kısıtlamak isteyeceğiniz zamanlar olabilir. Örneğin, sayılar üzerinde çalışan bir yöntem, yalnızca Number veya alt sınıflarının örneklerini kabul etmek isteyebilir.

Üst sınırlı bir Wildcard parametresi bildirmek için? İşaretini, ardından extends anahtar sözcüğünü ve ardından üst sınırını listeleyin.

Misal

Aşağıdaki örnek, bir üst sınır joker karakterini belirtmek için extends'in nasıl kullanıldığını gösterir.

package com.tutorialspoint;

import java.util.Arrays;
import java.util.List;

public class GenericsTester {

   public static double sum(List<? extends Number> numberlist) {
      double sum = 0.0;
      for (Number n : numberlist) sum += n.doubleValue();
      return sum;
   }

   public static void main(String args[]) {
      List<Integer> integerList = Arrays.asList(1, 2, 3);
      System.out.println("sum = " + sum(integerList));

      List<Double> doubleList = Arrays.asList(1.2, 2.3, 3.5);
      System.out.println("sum = " + sum(doubleList));
   }
}

Bu, aşağıdaki sonucu verecektir -

Çıktı

sum = 6.0
sum = 7.0

Soru işareti (?) Joker karakteri temsil eder, jenerikte bilinmeyen türü temsil eder. Bir yöntemin Object sınıfında sağlanan işlevsellik kullanılarak uygulanabildiği veya kodun type parametresinden bağımsız olduğu zamanlar herhangi bir nesnenin kullanılabileceği zamanlar olabilir.

Sınırsız Joker Karakter parametresi bildirmek için,? bir tek.

Misal

Aşağıdaki örnek, sınırsız bir joker karakter belirtmek için extends'in nasıl kullanıldığını gösterir.

package com.tutorialspoint;

import java.util.Arrays;
import java.util.List;

public class GenericsTester {
   public static void printAll(List<?> list) {
      for (Object item : list)
         System.out.println(item + " ");
   }

   public static void main(String args[]) {
      List<Integer> integerList = Arrays.asList(1, 2, 3);
      printAll(integerList);
      List<Double> doubleList = Arrays.asList(1.2, 2.3, 3.5);
      printAll(doubleList);
   }
}

Bu, aşağıdaki sonucu verecektir -

Çıktı

1 
2 
3 
1.2 
2.3 
3.5

Soru işareti (?) Joker karakteri temsil eder, jenerikte bilinmeyen türü temsil eder. Bir tür parametresine geçirilmesine izin verilen tür türlerini kısıtlamak isteyeceğiniz zamanlar olabilir. Örneğin, sayılar üzerinde çalışan bir yöntem, yalnızca Tamsayı örneklerini veya Number gibi üst sınıflarını kabul etmek isteyebilir.

Daha düşük sınırlı bir Wildcard parametresi bildirmek için,? İşaretini, ardından super anahtar sözcüğünü ve ardından alt sınırını listeleyin.

Misal

Aşağıdaki örnek, süper'in bir alt sınır joker karakterini belirtmek için nasıl kullanıldığını gösterir.

package com.tutorialspoint;

import java.util.ArrayList;
import java.util.List;

public class GenericsTester {

   public static void addCat(List<? super Cat> catList) {
      catList.add(new RedCat());
      System.out.println("Cat Added");
   }

   public static void main(String[] args) {
      List<Animal> animalList= new ArrayList<Animal>();
      List<Cat> catList= new ArrayList<Cat>();
      List<RedCat> redCatList= new ArrayList<RedCat>();
      List<Dog> dogList= new ArrayList<Dog>();

      //add list of super class Animal of Cat class
      addCat(animalList);

      //add list of Cat class
      addCat(catList);

      //compile time error
      //can not add list of subclass RedCat of Cat class
      //addCat(redCatList);

      //compile time error
      //can not add list of subclass Dog of Superclass Animal of Cat class
      //addCat.addMethod(dogList); 
   }
}
class Animal {}

class Cat extends Animal {}

class RedCat extends Cat {}

class Dog extends Animal {}

Bu, aşağıdaki sonucu verecektir -

Cat Added
Cat Added

Joker karakterler üç şekilde kullanılabilir -

  • Upper bound Wildcard-? Türü genişletir.

  • Lower bound Wildcard-? süper Tür.

  • Unbounded Wildcard -?

Koşula en uygun joker karakter türüne karar vermek için, önce bir yönteme geçirilen parametrelerin türünü şu şekilde sınıflandıralım: in ve out parametre.

  • in variable- Bir in değişkeni, koda veri sağlar. Örneğin, kopyalayın (src, dest). Burada src, değişkende kopyalanacak veri olarak hareket eder.

  • out variable- Bir çıkış değişkeni, kod tarafından güncellenen verileri tutar. Örneğin, kopyalayın (src, dest). Burada dest, verileri kopyalayan değişkendeki gibi davranır.

Joker Karakterler için Yönergeler.

  • Upper bound wildcard - Bir değişken ise in kategori, kullanım anahtar kelimeyi joker karakterle genişletir.

  • Lower bound wildcard - Bir değişken ise out kategori, joker karakterli süper anahtar kelime kullanın.

  • Unbounded wildcard - Bir değişkene Object sınıfı yöntemi kullanılarak erişilebiliyorsa, o zaman ilişkisiz bir joker karakter kullanın.

  • No wildcard - Kod her ikisinde de değişkene erişiyorsa in ve out kategorisi bu durumda joker karakterler kullanmayın.

Misal

Aşağıdaki örnek, yukarıda bahsedilen kavramları göstermektedir.

package com.tutorialspoint;

import java.util.ArrayList;
import java.util.List;

public class GenericsTester {

   //Upper bound wildcard
   //in category
   public static void deleteCat(List<? extends Cat> catList, Cat cat) {
      catList.remove(cat);
      System.out.println("Cat Removed");
   }

   //Lower bound wildcard
   //out category
   public static void addCat(List<? super RedCat> catList) {
      catList.add(new RedCat("Red Cat"));
      System.out.println("Cat Added");
   }

   //Unbounded wildcard
   //Using Object method toString()
   public static void printAll(List<?> list) {
      for (Object item : list)
         System.out.println(item + " ");
   }

   public static void main(String[] args) {

      List<Animal> animalList= new ArrayList<Animal>();
      List<RedCat> redCatList= new ArrayList<RedCat>();

      //add list of super class Animal of Cat class
      addCat(animalList);
      //add list of Cat class
      addCat(redCatList);  
      addCat(redCatList);  

      //print all animals
      printAll(animalList);
      printAll(redCatList);

      Cat cat = redCatList.get(0);
      //delete cat
      deleteCat(redCatList, cat);
      printAll(redCatList); 
   }
}

class Animal {
   String name;
   Animal(String name) { 
      this.name = name;
   }
   public String toString() { 
      return name;
   }
}

class Cat extends Animal { 
   Cat(String name) {
      super(name);
   }
}

class RedCat extends Cat {
   RedCat(String name) {
      super(name);
   }
}

class Dog extends Animal {
   Dog(String name) {
      super(name);
   }
}

Bu, aşağıdaki sonucu verecektir -

Cat Added
Cat Added
Cat Added
Red Cat 
Red Cat 
Red Cat 
Cat Removed
Red Cat

Jenerikler, derleme zamanında daha sıkı tip kontrolleri için ve genel bir programlama sağlamak için kullanılır. Genel davranışı uygulamak için, java derleyicisi tür silme işlemini uygular. Tür silme, derleyicinin genel bir parametreyi gerçek sınıf veya köprü yöntemiyle değiştirdiği bir işlemdir. Tür silme işleminde, derleyici fazladan sınıfların oluşturulmamasını ve çalışma zamanı ek yükü olmamasını sağlar.

Tür Silme kuralları

  • Sınırlı tür parametreleri kullanılıyorsa, genel türdeki tür parametrelerini sınırlarıyla değiştirin.

  • Sınırsız tür parametreleri kullanılıyorsa, genel türdeki tür parametrelerini Object ile değiştirin.

  • Tip güvenliğini korumak için tip kalıpları yerleştirin.

  • Polimorfizmi genişletilmiş genel türlerde tutmak için köprü yöntemleri oluşturun.

Java Compiler, sınırlı tür parametreleri kullanılıyorsa, genel türdeki tür parametrelerini sınırlarıyla değiştirir.

Misal

package com.tutorialspoint;

public class GenericsTester {
   public static void main(String[] args) {
      Box<Integer> integerBox = new Box<Integer>();
      Box<Double> doubleBox = new Box<Double>();

      integerBox.add(new Integer(10));
      doubleBox.add(new Double(10.0));

      System.out.printf("Integer Value :%d\n", integerBox.get());
      System.out.printf("Double Value :%s\n", doubleBox.get());
   }
}

class Box<T extends Number> {
   private T t;

   public void add(T t) {
      this.t = t;
   }

   public T get() {
      return t;
   }   
}

Bu durumda, java derleyici T'yi Number sınıfıyla değiştirecek ve tür silme işleminden sonra, derleyici aşağıdaki kod için bayt kodu üretecektir.

package com.tutorialspoint;

public class GenericsTester {
   public static void main(String[] args) {
      Box integerBox = new Box();
      Box doubleBox = new Box();

      integerBox.add(new Integer(10));
      doubleBox.add(new Double(10.0));

      System.out.printf("Integer Value :%d\n", integerBox.get());
      System.out.printf("Double Value :%s\n", doubleBox.get());
   }
}

class Box {
   private Number t;

   public void add(Number t) {
      this.t = t;
   }

   public Number get() {
      return t;
   }   
}

Her iki durumda da sonuç aynıdır -

Çıktı

Integer Value :10
Double Value :10.0

Java Compiler, sınırsız tür parametreleri kullanılıyorsa, genel türdeki tür parametrelerini Object ile değiştirir.

Misal

package com.tutorialspoint;

public class GenericsTester {
   public static void main(String[] args) {
      Box<Integer> integerBox = new Box<Integer>();
      Box<String> stringBox = new Box<String>();

      integerBox.add(new Integer(10));
      stringBox.add(new String("Hello World"));

      System.out.printf("Integer Value :%d\n", integerBox.get());
      System.out.printf("String Value :%s\n", stringBox.get());
   }
}

class Box<T> {
   private T t;

   public void add(T t) {
      this.t = t;
   }

   public T get() {
      return t;
   }   
}

Bu durumda, java derleyici T'yi Object sınıfıyla değiştirecek ve tür silme işleminden sonra, derleyici aşağıdaki kod için bayt kodu üretecektir.

package com.tutorialspoint;

public class GenericsTester {
   public static void main(String[] args) {
      Box integerBox = new Box();
      Box stringBox = new Box();

      integerBox.add(new Integer(10));
      stringBox.add(new String("Hello World"));

      System.out.printf("Integer Value :%d\n", integerBox.get());
      System.out.printf("String Value :%s\n", stringBox.get());
   }
}

class Box {
   private Object t;

   public void add(Object t) {
      this.t = t;
   }

   public Object get() {
      return t;
   }   
}

Her iki durumda da sonuç aynıdır -

Çıktı

Integer Value :10
String Value :Hello World

Java Derleyici, genel türdeki tür parametrelerini, sınırsız tür parametreleri kullanılıyorsa Object ile ve yöntem parametreleri olarak bağlı parametreler kullanılıyorsa türle değiştirir.

Misal

package com.tutorialspoint;

public class GenericsTester {
   public static void main(String[] args) {
      Box<Integer> integerBox = new Box<Integer>();
      Box<String> stringBox = new Box<String>();

      integerBox.add(new Integer(10));
      stringBox.add(new String("Hello World"));
      
      printBox(integerBox);
      printBox1(stringBox);
   }
   
   private static <T extends Box> void printBox(T box) {
      System.out.println("Integer Value :" + box.get());
   }
   
   private static <T> void printBox1(T box) {
      System.out.println("String Value :" + ((Box)box).get());
   }
}

class Box<T> {
   private T t;

   public void add(T t) {
      this.t = t;
   }

   public T get() {
      return t;
   }   
}

Bu durumda, java derleyici T'yi Object sınıfıyla değiştirecek ve tür silme işleminden sonra, derleyici aşağıdaki kod için bayt kodu üretecektir.

package com.tutorialspoint;

public class GenericsTester {
   public static void main(String[] args) {
      Box integerBox = new Box();
      Box stringBox = new Box();

      integerBox.add(new Integer(10));
      stringBox.add(new String("Hello World"));
      
      printBox(integerBox);
      printBox1(stringBox);
   }
	
   //Bounded Types Erasure
   private static void printBox(Box box) {
      System.out.println("Integer Value :" + box.get());
   }
	
   //Unbounded Types Erasure
   private static void printBox1(Object box) {
      System.out.println("String Value :" + ((Box)box).get());
   }
}

class Box {
   private Object t;

   public void add(Object t) {
      this.t = t;
   }

   public Object get() {
      return t;
   }   
}

Her iki durumda da sonuç aynıdır -

Çıktı

Integer Value :10
String Value :Hello World

Jenerikler kullanıldığında, ilkel türler tür parametreleri olarak geçirilemez. Aşağıda verilen örnekte int primitive type'ı box sınıfına geçirirsek compiler şikayet eder. Aynısını azaltmak için, int ilkel tip yerine Integer nesnesini geçmemiz gerekir.

Misal

package com.tutorialspoint;

public class GenericsTester {
   public static void main(String[] args) {
      Box<Integer> integerBox = new Box<Integer>();

      //compiler errror
      //ReferenceType
      //- Syntax error, insert "Dimensions" to complete
      ReferenceType
      //Box<int> stringBox = new Box<int>();

      integerBox.add(new Integer(10));
      printBox(integerBox);
   }

   private static void printBox(Box box) {
      System.out.println("Value: " + box.get());
   }  
}

class Box<T> {
   private T t;

   public void add(T t) {
      this.t = t;
   }

   public T get() {
      return t;
   }   
}

Bu, aşağıdaki sonucu verecektir -

Çıktı

Value: 10

Bir tür parametresi, nesnesini bir yöntem içinde başlatmak için kullanılamaz.

public static <T> void add(Box<T> box) {
   //compiler error
   //Cannot instantiate the type T
   //T item = new T();  
   //box.add(item);
}

Bu tür bir işlevselliğe ulaşmak için yansımayı kullanın.

public static <T> void add(Box<T> box, Class<T> clazz) 
   throws InstantiationException, IllegalAccessException{
   T item = clazz.newInstance();   // OK
   box.add(item);
   System.out.println("Item added.");
}

Misal

package com.tutorialspoint;

public class GenericsTester {
   public static void main(String[] args) 
      throws InstantiationException, IllegalAccessException {
      Box<String> stringBox = new Box<String>();
      add(stringBox, String.class);
   }  

   public static <T> void add(Box<T> box) {
      //compiler error
      //Cannot instantiate the type T
      //T item = new T();  
      //box.add(item);
   }

   public static <T> void add(Box<T> box, Class<T> clazz) 
      throws InstantiationException, IllegalAccessException{
      T item = clazz.newInstance();   // OK
      box.add(item);
      System.out.println("Item added.");
   }   
}

class Box<T> {
   private T t;

   public void add(T t) {
      this.t = t;
   }

   public T get() {
      return t;
   }   
}

Bu, aşağıdaki sonucu verecektir -

Item added.

Jenerikler kullanıldığında tür parametrelerinin statik olmasına izin verilmez. Statik değişken nesne arasında paylaşıldığı için derleyici hangi türün kullanılacağını belirleyemez. Statik tür parametrelerine izin veriliyorsa aşağıdaki örneği göz önünde bulundurun.

Misal

package com.tutorialspoint;

public class GenericsTester {
   public static void main(String[] args) {
      Box<Integer> integerBox = new Box<Integer>();
	  Box<String> stringBox = new Box<String>();
	  
      integerBox.add(new Integer(10));
      printBox(integerBox);
   }

   private static void printBox(Box box) {
      System.out.println("Value: " + box.get());
   }  
}

class Box<T> {
   //compiler error
   private static T t;

   public void add(T t) {
      this.t = t;
   }

   public T get() {
      return t;
   }   
}

StringBox ve integerBox'ın her ikisinin de yıldızlı bir statik tür değişkeni olduğundan, türü belirlenemez. Bu nedenle statik tip parametrelerine izin verilmez.

Parametreli bir türe çevrim, sınırsız joker karakterlerle parametrelendirilmediği sürece izin verilmez.

Box<Integer> integerBox = new Box<Integer>();
Box<Number> numberBox = new Box<Number>();
//Compiler Error: Cannot cast from Box<Number> to Box<Integer>
integerBox = (Box<Integer>)numberBox;

Aynı şeyi başarmak için sınırsız joker karakterler kullanılabilir.

private static void add(Box<?> box) {
   Box<Integer> integerBox = (Box<Integer>)box;
}

Derleyici tür silmeyi kullandığından, çalışma zamanı tür parametrelerini takip etmez, bu nedenle Box <Integer> ile Box <String> arasındaki çalışma zamanı farkı instanceOf operatörü kullanılarak doğrulanamaz.

Box<Integer> integerBox = new Box<Integer>();

//Compiler Error:
//Cannot perform instanceof check against 
//parameterized type Box<Integer>. 
//Use the form Box<?> instead since further 
//generic type information will be erased at runtime
if(integerBox instanceof Box<Integer>) { }

Parametreli tür dizilerine izin verilmez.

//Cannot create a generic array of Box<Integer>
Box<Integer>[] arrayOfLists = new Box<Integer>[2];

Derleyici tür silmeyi kullandığından, tür parametresi Nesne ile değiştirilir ve kullanıcı diziye herhangi bir tür nesne ekleyebilir. Ve çalışma zamanında kod, ArrayStoreException oluşturamaz.

// compiler error, but if it is allowed
Object[] stringBoxes = new Box<String>[];
  
// OK
stringBoxes[0] = new Box<String>();  

// An ArrayStoreException should be thrown,
//but the runtime can't detect it.
stringBoxes[1] = new Box<Integer>();

Genel bir sınıfın Throwable sınıfını doğrudan veya dolaylı olarak genişletmesine izin verilmez.

//The generic class Box<T> may not subclass java.lang.Throwable
class Box<T> extends Exception {}

//The generic class Box<T> may not subclass java.lang.Throwable
class Box1<T> extends Throwable {}

Bir yöntemin, bir tür parametresi örneğini yakalamasına izin verilmez.

public static <T extends Exception, J> 
   void execute(List<J> jobs) {
      try {
         for (J job : jobs) {}
  
         // compile-time error
         //Cannot use the type parameter T in a catch block
      } catch (T e) { 
         // ...
   }
}

Bir throws cümlesinde tür parametrelerine izin verilir.

class Box<T extends Exception>  {
   private int t;

   public void add(int t) throws T {
      this.t = t;
   }

   public int get() {
      return t;
   }   
}

Bir sınıfın, tür silme işleminden sonra aynı imzaya sahip olabilen iki aşırı yüklenmiş yönteme sahip olmasına izin verilmez.

class Box  {
   //Compiler error
   //Erasure of method print(List<String>) 
   //is the same as another method in type Box
   public void print(List<String> stringList) { }
   public void print(List<Integer> integerList) { }
}