August 3, 2012

Generics

Generics ဆိုသည်မှာ


Generics ဆိုသည်မှာ Generics Programming ဟုအမည်ရသော ပရိုဂရမ်ရေးသားနည်း၏ အမည်မှ ရယူထားသော အမည် တစ်ခုဖြစ်ပါသည်။ ဆိုရမည် ဆိုလျှင် Generic Programming သည် Object Oriented Programming နည်းနှင့် ပတ်သက်ခြင်း မရှိသော သီးခြားနည်းပညာ တစ်ခု ဖြစ်ပါသည်။ Generics Programming တွင် ပုံစံ (Type) သတ်မှတ်ချက်များနှင့် ချုပ်နှောင်ထားခြင်း မရှိပဲ၊ Type များအား Parameter အနေဖြင့် အသုံးပြုနိုင်ပါသည်။

Java ဘာသာရပ်တွင် Generics အား အသုံးများသည်မှာ Collections Framework တွင် ဖြစ်၏။ Java 5 (Tiger) အရောက်တွင် Javaတွင်လည်း Generics ကိုထည့်သွင်း အသုံးပြုခဲ့ပြီး၊ Java 7 အား အသုံးပြုနေသည့် ယနေ့ အချိန်ဆိုပါက Java အားလေ့လာသူများသည် Generics အကြောင်းအား လေ့လာပြီး၊ သိရှိပြီး ဖြစ်နေပါလိမ့်မည်။ ဘာကြောင့် Generics အား အသုံးပြုရန် လိုအပ်ခဲ့သနည်း၊ Generics အား အသုံးပြုခြင်း၏ အကျိုးကျေးဇူးမှာ အဘယ်နည်း အစရှိသည်များအား စကားလုံးဖြင့် ရှင်းပြနေသည်ထက် နမှုနာ ကုဒ်များအား ရေးသားကြည့်သည်က ပို၍ မြန်ပါလိမ့်မည်။

NonGenericsSample.java
package com.mmju.java.se.generics;

import java.util.LinkedList;
import java.util.List;

public class NonGenricsSample {

 public static void main(String[] args) {
     List list = new LinkedList();
     
     for(String s : args) {
      list.add(s);
     }
     
     for(int i=0; i<list.size(); i++) {
      String s = (String) list.get(i);
      System.out.println(s);
     }
      
    }
}
List အော့ဘဂျက်သည် မည်သည့် အော့ဘဂျက်ကိုမဆို ကော်လက်ရှင် အနေဖြင့် အသုံးပြုနိုင်သောကြောင့်၊ ရုတ်တရက်ကြည့်လျှင် အစဉ်ပြေသလို ဖြစ်သော်လည်း၊ မည်သည့် အော့ဘဂျက်ကိုသာ အသုံးပြုမည်ဟု သတ်မှတ်၍ မရနိုင်ခြင်း၊ တဖန် List#get ဖြင့် သိမ်းဆည်းထားသော အော့ဘဂျက်အား ထုတ်ယူရာတွင် Cast လုပ်ရန် လိုအပ်ခြင်း အစရှိသည့် အခက်အခဲများအား ဖြစ်ပွားစေနိုင်ပါသည်။

GenericsSample.java
package com.mmju.java.se.generics;

import java.util.LinkedList;
import java.util.List;

public class GenricsSample {

 public static void main(String[] args) {
     List<String> list = new LinkedList<>();
     
     for(String s : args) {
      list.add(s);
     }
     
     for(int i=0; i<list.size(); i++) {
      String s = list.get(i);
      System.out.println(s);
     }
      
    }
}
Generics အား အသုံးပြုသည့်အခါတွင် <> အတွင်းတွင်၊ ကော်လက်ရှင် အတွင်းတွင် အသုံးပြုနိုင်သည့် ပုံစံအား String ဟု သတ်မှတ်နိုင်ပါသည်။ ဤနည်းအားဖြစ် ထို List အတွင်းတွင် String မှ အပါး ထည့်သွင်း အသုံးပြု၍ မရနိုင်ပေ။ တဖန် List#get ဖြင့်ကော်လက်ရှင် အတွင်းမှ အော့ဘဂျက်များအား ထုတ်ယူရာတွင်လည်း Cast လုပ်စရာ မလိုအပ်တော့ပေ။


Generics Class နှင့် Interface များအား ရေးသားခြင်း

ရှင်းပါသည်။ Generics အားအသုံးပြုထားသော ကလပ်စ်များအား Generics Class ဟု၎င်း၊ အင်တာဖေစ်များအား Generics Interface ဟု၎င်း ခေါ်ဆိုပါသည်။ ဦးစွာ ကျွှန်တော်တို့ Generics Interface ၏ ရေးသားပုံကို လေ့လာကြည့်ပါမည်။ ပြီးခဲ့သော နမှုနာတွင် အသုံးပြုခဲ့သည့် Listအင်တာဖေစ် အား လေ့လာကြည့်ပါမည်။

List.java
public interface List<E> extends Collection<E> {
 
 public boolean add(E object);
 
 public E get(int index);

အထပ်ပါ ကုဒ်များသည် java.util.List ၏ တစ်စိတ်တစ်ပိုင်အား ဖော်ပြထားခြင်း ဖြစ်ပါသည်။ အထက်ဖော်ပြပါ ကုဒ်များတွင် List<E> ဟု ရေးသားထားသည်ကို တွေ့ရပါမည်။ ဤနေရာသင် Java 5 အရောက်တွင် ဖြည့်စွက်ခဲ့သော Generics ၏ ရေးသားပုံ ဖြစ်ပါသည်။ <> ဤ အစိတ်အပိုင်းအား ပုံစံပါရာမီတာဟု ခေါ်ဆိုပြီး၊ ကလပ်စ် အတွင်းတွင် အသုံးပြုမည့် ကိန်းရှင်များအား ပုံစံအား ပါရာမီတာ အဖြစ်ရယူနိုင်ပါသည်။ <E> ဟု ရေးသားထားရာတွင် E သည် ပုံစံ ကိန်းရှင် ဖြစ်ပြီး၊ E နေရာတွင် အစားထိုးသော ပုံစံ အား အခြေခံ ပုံစံ အဖြစ်အသုံးပြုနိုင်မည် ဖြစ်ပါသည်။ List#add ၏ နေရာတွင် E နေရာတွင် ရေးသားထားသော ပုံစံအား အသုံးပြုမည် ဖြစ်ပြီး၊ List#get ၏ ရလဒ်သည်လည်း E နေရာတွင် အစားထိုးမည့် အော့ဘဂျက်အား ပြန်လည်ရရှိမည် ဖြစ်ပါသည်။

အကယ်၍ List<String> ဟု ရေးသားထားပါက String Object များအား အသုံးပြုသော List အား အသုံးပြုနိုင်မည် ဖြစ်သည်။ ထို့ကြောင့် List#add ၏ ပါရာမီတာသည် String Object ကို အသုံးပြုရန် လိုအပ်ပြီး၊ List#get ၏ ရလဒ်သည်လည်း String Object ဖြစ်မည် ဆိုသည်ကို သိရှိနိုင်ပါသည်။

တဖန် List အင်တာဖေစ်အား ဖြည့်စွက် ရေးသားထားသော LinkedList ကလပ်စ်၏ ရေးသားပုံမှာ အောက်ပါအတိုင်း ဖြစ်၏။

LinkedList.java
public class LinkedList<E>
       extends AbstractSequentialList<E>
       implements List<E>, Deque<E>, Cloneable, java.io.Serializable
{

    @Override
    public boolean add(E object) {
     // အသေးစိတ်အား အထက်ဖော်ပြပါ လင့်ခ်တွင် လေ့လာပါ
     return false;
    }

    @Override
    public E get(int index) {
     // အသေးစိတ်အား အထက်ဖော်ပြပါ လင့်ခ်တွင် လေ့လာပါ
     return null;
    }

အင်တာဖေစ် List အား ပံ့ပိုးထားသော ကလပ်စ် LinkedList အား ရေးသားရာတွင်၊ အင်တာဖေစ် ကဲ့သို့ပင် Generics အား အသုံးပြုရန် လိုအပ်ပါသည်။ ရေးသားရာတွင်လည်း အင်တာဖေစ်နှင့် ထပ်တူ <E> ဟု ရေးသားထားပါသည်။

ကျွှန်တော်တို့ နမှုနာတွင် List<String> list = new LinkedList<>() ဟု အင်တာဖေစ် List<String> အော့ဘဂျက်အား LinkedList ကလပ်စ်အား အင်းစတန့်စ် လုပ်ခြင်းအားဖြင့် ရေးသားပါသည်။ <> ရေးသားပုံမှာ Java 7 တွင် စတင် အသုံးပြုလာသော ပုံစံဖြစ်ပြီး  Diamond ပုံစံဟု ခေါ်ဆိုပါသည်။ ဘယ်ဘက်တွင် List<String> ဟုပုံစံကိန်းရှင်အား သတ်မှတ် ရေးသားထားပါက၊ ညာဘက်ချမ်း၊ အင်းစတန့်စ်အား ရေးသားသည့်ဘက်တွင် <> ဟု ရေးသားသည်နှင့် အလိုအလျှောက် ဘယ်ဘက်တွင် ရေးသားထားသော ပုံစံ ကိန်းရှင်အား အသုံးပြုနိုင်မည် ဖြစ်ပါသည်။ ထို့ကြောင့် String အား အသုံးပြုပါသဖြင့် LinkedList ၏ ပုံစံကိန်းရှင်သည်လည်း String ဖြစ်မည် ဖြစ်ပါသည်။


ပုံစံပါရာမီတာ

ကျွှန်တော်တို့ <> ဖြင့် ရေးသားသော ပုံစံပါရာမီတာ အကြောင်းကို ဆက်လက် လေ့လာကြည့်ပါဦးမည်။ ပုံစံပါရာမီတာသည် ကလပ်နှင့် အင်တာဖေစ်များအား Declare လုပ်ရာတွင် အမည်၏ နောက်တွင်၎င်း၊ လုပ်ဆောင်ချက်များတွင်၎င်း Generics Method အနေဖြင့် ရေးသားလေ့ရှိပါသည်။ <> အထဲတွင် ပုံစံကိန်းရှင်များကို တစ်ခုထက်မက အသုံးပြု ရေးသားနိုင်ပါသည်။ ကိန်းရှင်များအား ကော်မာခံ၍ ရေးသားနိုင်ပါသည်။
public interface Map<K, V> {
    ...
အသုံးပြုသော ပုံစံကိန်းရှင်များ၏ အမည်မှာလည်း သာမန်ကိန်းရှင်များကဲ့သို့ ရေးသားနိုင်သော်လည်း၊ အင်္ဂလိပ်စာလုံးကြီး တစ်လုံးကို အသုံးပြုသည်က များပါသည်။

သက်မှတ်ထားသော ကိန်းရှင်များအားလည်း ယခုတိုင်ဖော်ပြခဲ့သော Extends ဝါကျ၊ Implements ဝါကျ များသာမက၊ လုပ်ဆောင်ချက်၏ ပါရာမီတာများနှင့် ရလဒ်များ၊ အင်းစတန့်စ် ကိန်းရှင်များနှင့် လုပ်ဆောင်ချက် အတွင်းရှိ ကိန်းရှင်များတွင်ပါ အသုံးပြုနိုင်သည်။

တနည်းဆိုရသော် ပုံစံကိန်းရှင်အား အသုံးပြုခြင်း အားဖြင့်၊ အော့ဘဂျက်အတွင်း မည်သည့် နေရာမှ မဆို ဆက်သွယ် အသုံးပြုနိုင်မည် ဖြစ်သည်။လက်တွေ့ ရေးသားကြည့်ပါဦးမည်။

MyData.java
public class MyData<S> {
 
 private S myData = null;
 
 public MyData (S data) {
  this.myData = data;
 }

 public String getMyData() {
  return myData.toString();
 }

 public void setMyData(S myData) {
  this.myData = myData;
 }
}
အထက်ပါ နမှုနာထဲတွင် အင်းစတန့်စ် ကိန်းရှင် myData ၏ ပုံစံအား ပုံစံကိန်းရှင် S အား အသုံးပြုကာ၊ တဖန် ပါရာမီတာအဖြစ်ရယူသော S data ဖြင့်အစားထိုးပါသည်။ အတွင်းပိုင်းရှိ S ၏ နေရာတွင် အဆိုပါ ကလပ်စ်အား Instance လုပ်သည့်အခါတွင် ပုံစံပါရာမီတာ အတွင်းတွင် ရေးသားထားသော ပုံစံအား အစားထိုး အသုံးပြုသွားမည် ဖြစ်ပါသည်။ အတွင်းပိုင်းရှိ S များအားလုံးအား အစားထိုး အသုံးပြုသွားနိုင်မည် ဖြစ်ပါသည်။

တဖန် စာကြောင်း ၉ အားကြည့်ပါ။ ဤ ကလပ်စ်အား ရေးသားစဉ်က S သည် မည်သည့်ပုံစံ ဖြစ်သည်ကို မသိရပေ။ သို့သော်လည်း getMyData ၏ ရလဒ်အား String ဟု ရေးသားထားပါသည်။ အတွင်းပိုင်းမှာမူ data.toString() ဟု Object ကလပ်စ်၏ လုပ်ဆောင်ချက်ကို အသုံးပြုထားပါသည်။ အဘယ်ကြောင့်ဆိုသော် S အား အစားထိုး၍ အသုံးပြုမည့် ကလပ်စ်များသည် Object ကလပ်စ်၏ Sub Class များ ဖြစ်သောကြောင့် ဖြစ်ပါသည်။ ထို့ကြောင့် java.lang.Object ၏ လုပ်ဆောင်ချက် toString အား ခေါ်ယူ အသုံးပြုနိုင်ခြင်း ဖြစ်ပါသည်။

Object တင်မက အခြားသော ကလပ်စ်များကိုလည်း အသုံးပြုလိုပါက အောက်ပါအတိုင်း အသုံးပြု ရေးသားနိုင်ပါလိမ့်မည်။

MyDateData.java
import java.util.Date;

public class MyDateData<S extends Date, E extends Date> {

 private S startDate = null;
 private E endDate = null;

 public MyDateData(S s, E e) {
  this.startDate = s;
  this.endDate = e;
 }

 public long calSpan() {
  return this.endDate.getTime() - this.startDate.getTime();
 }

}

အထက်ပါ နမှုနာထဲတွင် S နှင့် E ပုံစံကိန်းရှင်များအား extends Keyword အား အသုံးပြု၍ java.util.Date ၏ အမွေဆက်ခံမှု့ကို ရယူစေပါသည်။ ထို့အတွက် S နှင့် E အား Date ၏ Sub Class များသာ အစားထိုးနိုင်ပြီး၊ အတွင်းပိုင်းရှိ အင်းစတန့်စ် ကိန်းရှင်များဖြစ်ကြသော startDate နှင့် endDate များသည် java.util.Date ၏ လုပ်ဆောင်ချက်များအား အသုံးပြုနိုင်မည် ဖြစ်ပါသည်။

ကျွှန်တော်တို့သည် Generics သုံး ကလပ်စ်များကိုသာ အသုံးပြုနေရုံမက၊ ကိုယ်တိုင်လည်း Generics များအား အသုံးပြု၍ ရေးသားနိုင်သည်ဟု သိရှိနိုင်မည် ဖြစ်ပါသည်။


ကိုးကား

http://www.techscore.com/tech/Java/JavaSE/JavaLanguage/1/

ဆက်ပါဦးမည်။ လေးစားစွာဖြင့်။
မင်းလွင်

No comments:

Post a Comment