PDA

View Full Version : سوال: استفاده از تابع!



سعیدسعید
شنبه 28 فروردین 1389, 23:09 عصر
با سلام خدمت همه دوستان
بنده یک سوال در مورد استفاده خاص از توابع یک کلاس دارم
فرض کنید کلاس C1 دارای یک تابع به نام fun1 است که یک نوع داده را بر می گرداند.
حال در داخل کلاس C2 یک شیئ از کلاس C1 به نام O1 تعریف می شود.
اما در داخل کلاس C2 نیز یک تابع به نام Fun1 وجود دارد که می خواهیم موقع فراخوانی C2.Fun1 تابع Fun1 مربوط به شیئ O1 اجرا گردد و دقیقا همان نوع داده را بر گرداند( یعنی C2.Fun1 همان نوع داده را برگرداند).

این کار چگونه می تواند در جاوا صورت گیرد؟ لطفا بنده را راهنمایی فرمایید.
البته کلاس C1 به صورت Generic تعریف شده است.

jlover
یک شنبه 29 فروردین 1389, 01:37 صبح
....
می خواهیم موقع فراخوانی C2.Fun1 تابع Fun1 مربوط به شیئ O1 اجرا گردد و دقیقا همان نوع داده را بر گرداند( یعنی C2.Fun1 همان نوع داده را برگرداند).

این کار چگونه می تواند در جاوا صورت گیرد؟ لطفا بنده را راهنمایی فرمایید.
البته کلاس C1 به صورت Generic تعریف شده است.
اگر منظورتون این باشه که متد C2.fun1 مقدار متد C1.fun1 رو برگردونه، در کلاس C2 داریم :


C1ReturnType fun1)(
}
// implementation
return o1.fun1();
{

البته باید مقدار بازگشتی هر دو تابع fun1 یکی باشه

سعیدسعید
یک شنبه 29 فروردین 1389, 18:41 عصر
سلام
ممنون. اما مشکل اینه که ما نمی دونیم مقدار برگشتی C1.fun1 از چه نوعی هست.
C1 به صورت Generic تعریف شده یعنی موقع ایجاد O1 نوع برگشتی تابع C1.fun1 مشخص می شود. ما الان نمی دونیم که data type مربوط به C1.fun1 چیست.
در این حالت باید چکار کرد؟

jlover
یک شنبه 29 فروردین 1389, 20:57 عصر
سلام
ممنون. اما مشکل اینه که ما نمی دونیم مقدار برگشتی C1.fun1 از چه نوعی هست.
C1 به صورت Generic تعریف شده یعنی موقع ایجاد O1 نوع برگشتی تابع C1.fun1 مشخص می شود. ما الان نمی دونیم که data type مربوط به C1.fun1 چیست.
در این حالت باید چکار کرد؟
مهم نوع بازگشتی متد fun1 در کلاس C1 هستش. اگر اون رو قرار بدید بهتر میشه نظر داد !

بدون داشتن اطلاعات در مورد کلاس C1 و متد fun1 در اون هیچ نظر قطعی ای نمیتونم بدم !
چندین حدس دارم. فقط میدونم که مشکلی وجود نداره اگه نوع بازگشتی هم میتونه از نوع Generic باشه

سعیدسعید
دوشنبه 30 فروردین 1389, 01:07 صبح
مهم نوع بازگشتی متد fun1 در کلاس C1 هستش. اگر اون رو قرار بدید بهتر میشه نظر داد !

بدون داشتن اطلاعات در مورد کلاس C1 و متد fun1 در اون هیچ نظر قطعی ای نمیتونم بدم !
چندین حدس دارم. فقط میدونم که مشکلی وجود نداره اگه نوع بازگشتی هم میتونه از نوع Generic باشه


کلاس C1 به صورت زیر تعریف شده است:



public class C1<Type>
{
private LinkedList <Type>Buff=new LinkedList<Type>();

public Type Fun1()
{
return(Buff.removeFirst());
}
}



حال در داخل کلاس C2 کد های زیر را داریم:



public class C2
{
protected C1 O1;
public <Type> void SetType(Type T)
{
O1=new C1<Type>();
}


public ??? Fun1()
{
return (O1.Fun1());
}
}




در داخل C2 نوع برگشتی متد Fun1 چه باید باشد؟(به جای ؟؟؟ چه چیز باید نوشته شود)

اگر راهنمایی کنید ممنون میشم.
البته با یک عمل تبدیل نوع مشکل تا حدودی حل می شود ولی وقتی که یک شیئ از نوع C2 می سازم و دو خروجی از تابع C2.fun1 را باهم جمع (+) می کنم با پیغام خطای
The operator + is undefined for the argument type(s) java.lang.Object, java.lang.Object
مواجه می شوم.

jlover
دوشنبه 30 فروردین 1389, 10:10 صبح
البته با یک عمل تبدیل نوع مشکل تا حدودی حل می شود ولی وقتی که یک شیئ از نوع C2 می سازم و دو خروجی از تابع C2.fun1 را باهم جمع (+) می کنم با پیغام خطای
The operator + is undefined for the argument type(s) java.lang.Object, java.lang.Object
مواجه می شوم.

اولش باید عرض کنم که بنده اینطور طراحی رو جز به منظور امتحان و یادگیری و fun جایز نمیبینم. راه درستش اینه که در کلاس C1 یک متغیر تعریف کنید که مقدار نوع رو در خودش نگهداری کنه و در سازنده نمونه سازی بشه :

Type t;
C1 (Type t){
this.t = t;
}
و اونوقت میتونید با داشتن نمونه ای از کلاس (در اینجا o1) مشکلات ناشی از عدم دونستن نوع رو برطرف کنید.

مشکل اصلن مربوط به این متد نیست که مثلن بیایم اینطوری دستکاریش کنیم :


public <T extends C1> T fun1()
{
return (T) (o1.fun1());
}

شما متدی به نام setType تعریف کردید به صورت زیر :


public <Type> void SetType(Type T)
{
o1=new C1<Type>();

}

حالا من از شما سوالی می پرسم :

- Type چی هست ؟

اگر تونستید به این سوال جواب بدید، میتونید برنامه تون رو دنبال کنید و به دلیل گرفتن خطا پی ببرید. درسته که دلیل خطا واضحه و جلوی چشم شماست، اما دلیل تعجب شما از جایی دورتر ناشی میشه و انتظاری که از نوع Type دارید. نوع کلاس C1 در همون اعلان و تعریف متد setType تعیین میشه، نه زمانییکه از این متد استفاده میکنید !
و کنجکاوم بدونم که اصلن چرا از ()o1.fun1 به طور مستقیم استفاده نمیکنید، البته شاید هم لازم باشه حتمن طوری که کلاس شما محاسبه رو انجام میده...

سعیدسعید
دوشنبه 30 فروردین 1389, 13:27 عصر
اولش باید عرض کنم که بنده اینطور طراحی رو جز به منظور امتحان و یادگیری و fun جایز نمیبینم. راه درستش اینه که در کلاس C1 یک متغیر تعریف کنید که مقدار نوع رو در خودش نگهداری کنه و در سازنده نمونه سازی بشه :

Type t;
C1 (Type t){
this.t = t;
}و اونوقت میتونید با داشتن نمونه ای از کلاس (در اینجا o1) مشکلات ناشی از عدم دونستن نوع رو برطرف کنید.

مشکل اصلن مربوط به این متد نیست که مثلن بیایم اینطوری دستکاریش کنیم :


public <T extends C1> T fun1()
{
return (T) (o1.fun1());
}شما متدی به نام setType تعریف کردید به صورت زیر :


public <Type> void SetType(Type T)
{
o1=new C1<Type>();

}حالا من از شما سوالی می پرسم :

- Type چی هست ؟

اگر تونستید به این سوال جواب بدید، میتونید برنامه تون رو دنبال کنید و به دلیل گرفتن خطا پی ببرید. درسته که دلیل خطا واضحه و جلوی چشم شماست، اما دلیل تعجب شما از جایی دورتر ناشی میشه و انتظاری که از نوع Type دارید. نوع کلاس C1 در همون اعلان و تعریف متد setType تعیین میشه، نه زمانییکه از این متد استفاده میکنید !
و کنجکاوم بدونم که اصلن چرا از ()o1.fun1 به طور مستقیم استفاده نمیکنید، البته شاید هم لازم باشه حتمن طوری که کلاس شما محاسبه رو انجام میده...


Type یک نوعه که موقع نمونه سازی از C1 بهش گفته میشه. در داخل C1 اگر دقت کنید یک لیست پیوندی تعریف کردم که می خوام این لیست داده های با نوع Type را در خود نگهداری کند. متد Fun یک ایتم از این لیست را بر میگرداند به کلاس C2 حال در داخل کلاس C2 یک متد دیگری با همان نامFun تعریف شده که داده گرفته شده از C1 را باید برگرداند. حالا به نظر شما من باید چکار کنم تا این عملیات قابل انجام باشد؟
برای مثال ممکن است نوع کلاس C1 را بااستفاده از متد integer، settype تعریف کنیم در این حالت لیست پیوندی ما داده های int را در خود نگهداری خواهد کرد. حالا متد C1.fun یک ایتم از ان داده های int را برگشت خواهد داد.
حالا من در کاربرد از متد C1.fun استفاده نمی کنم بلکه متد C2.fun را فراخوانی خواهم کرد اما C2.fun به نوبه خود متد C1.fun را فراخوانی خواهد کرد پس باید همان داده int گرفته شده از C1 را برگشت دهد. اما مشکل این است که من در C2.fun نمی دانم نوع برگشتی را چطور و چی چیزی باید تعریف کنم؟ لطفا اگر شما راه حل دیگری برای انجام این کار دارید کمک کنید.
ممنون

jlover
دوشنبه 30 فروردین 1389, 19:00 عصر
Type یک نوعه که موقع نمونه سازی از C1 بهش گفته میشه. ...
...
... اما مشکل این است که من در C2.fun نمی دانم نوع برگشتی را چطور و چی چیزی باید تعریف کنم؟ لطفا اگر شما راه حل دیگری برای انجام این کار دارید کمک کنید.
ممنون
متاسفانه شما بقدری ذهنتون روی همون نقطه ی نوع بازگشتی متد setType متمرکز شده که تلاش من برای تحریکش به سمتی که کل داستان رو درک کنید و توضیحات بعدی من رو کاملن متوجه بشید بی نتیجه بوده !
اما برای اینکه فکر نکنید منظور نادرستی داشتم، خودم واضحتر ادامه میدم :


یک نوع generic حتمن باید از نوع ارجاع باشه (یک کلاس و نه نوع ابتدایی)
جاییکه کلمه ی Type برای اولین بار وارد میشه (یعنی در همون متد setType )، نقش یک کلاس رو داره، این کلاس رو شما هیچ جایی پیاده سازی نکردید و در اعلانش هم اون رو توسعه ی صریحی از کلاس دیگه ای قرار ندادید (کلمه ی کلیدی extends)، بنابراین بطور پیشفرض، کامپایلر، کلاس Type رو زیرکلاسی از Object در نظر میگیره و چون در جایی پیاده سازی نشده، همون رفتار و خصوصیات Object رو خاهد داشت (یعنی همون متدهای و فیلدهای عمومی و موروثی )، و خب اون خطا باید رخ بده، توضیحش واضحه :
با این حساب، نوع کلاس C1 ، از نوع Object خاهد بود (به همین ترتیب نوع عناصر لیست پیوندی شما و همچنین نوع بازگشتی متد fun1 در کلاس C1 ).

به گواه زیر دقت کنید :

public class C2
{
protected C1 o1;
public <Type> void SetType(Type T)
{
o1=new C1<Type>();

}


public <T extends C1> T fun1()
{
return (T) (o1.fun1());
}
public static void main(String[] args){
C2 example = new C2();
example.SetType(new java.awt.Point());
// no compile time error
}

}
java.awt.Point هم یک زیر کلاس از Object هست و مشکلی برای اینکه آرگومان متد setType (یعنی همون نوع Type که به سادگی یک Object هست و نوع کلاس C1) باشه پیش نمیاد !
شاید حالا بپرسید پس چرا یه عدد که یک نوع ابتدایی هست هم میتونه به عنوان آرگومان به SetType فرستاده بشه ؟ --> کامپایلر بطور ضمنی اون نوع رو در یک کلاس پوشان متناسب میپیچونه و اون عدد هم در قالب شیءی از یک کلاس (که البته مثل همه ی کلاسها زیرکلاسی از Object هست) ارایه میشه و خطایی رخ نمیده.
اصلن شما اینجا هر چی بذارید آزادید !چون کلاس نوعیتون از نوع Object هست.


میبینید، همه ی اینها در همون اعلان و تعریف متد setType مشخص میشه. حالا شما چه بیاید یک عدد رو به عنوان آرگومان وارد این متد کنید، چه یک رشته و یا حتی یک نوع دیگه مثل java.awt.Point باز هم تغییری در نوع کلاس C1، یعنی Object، داده نمیشه. این نوع از مقداری که بین <> قرار داره گرفته میشه، نه در جاییکه شما آرگومان وارد setType میکنید.

بعلاوه : نوع کلاس نوعی، در هنگام کامپایل معین میشه و بصورت ایستا تا پایان کامپایل و همینطور اجرای برنامه، این نوع ثابت خاهد بود. فکر نکنید که میشه با متد setType در زمان اجرا، یک نوع متفاوتی از نوع زمان ترجمه، برای کلاس نوعی تون رقم بزنید، وگرنه سازندگان کلاس، امکان به این واضحی رو خودشون برای همه ی کلاسهای نوعی، در خود زبان میگنجوندند !


شما چیکار میتونید بکنید ؟
درست همونطوری که هر جای دیگه ای که من تا حالا برخورد داشتم، شیء o1تون رو نمونه سازی کنید، با نوعی متناسب با کارتون از کلاس C1 .
مثلن :

C1<Number> o1 = new C1<Number>();
برای تمام مقادیر عددی
اونوقت نوع بازگشتی متد fun1 در کلاس C2 هم بسادگی Number خاهد بود .