آموزش مبانی شی گرایی جاوا — مرور مفاهیم و دستورات

 

مبانی برنامه نویسی شیء گرا

یکی از موضوعات مهمی که ما در برنامه نویسی جاوا احتیاج داریم که خیلی روی آن تمرکز داشته باشیم و از آن استفاده بکنیم، بحث برنامه نویسی شیء گرا است. یا Object-Oriented-Programing یا به اختصار (OOP) یکی از مهمترین مفاهیم است که در حوزه برنامه نویسی و نرم افزار به وجود امده است و عملا امروزه بدون استفاده از این مفاهیم ما نمی توانیم برنامه ها را پیاده سازی بکنیم.

مبانی برنامه نویسی شیء گرا

یکی از موضوعات مهمی که ما در برنامه نویسی جاوا احتیاج داریم که خیلی روی آن تمرکز داشته باشیم و از آن استفاده بکنیم، بحث برنامه نویسی شیء گرا است. یا Object-Oriented-Programing یا به اختصار (OOP) یکی از مهمترین مفاهیم است که در حوزه برنامه نویسی و نرم افزار به وجود آمده است و عملا امروزه بدون استفاده از این مفاهیم ما نمی توانیم برنامه ها را پیاده سازی بکنیم.

Class به عبارتی یک نوع داده است. در عین حال بخشی از برنامه است که دارای هویت و یک حقیقتی و یک چیزی را دارد توصیف می کند. برای نمونه در پروژه زیر خود (Project011) یک کلاس است و System یک کلاس است و همچنین در عبارت زیر Scanner یک کلاس است و input یک شیء است. همچنین کتابخانه Math یک کلاس است.

 

import java.util.*;
public class Project011 {
public static void main(String[] args) {
Scanner input = new Scanner(System.in);
float x;
String ans;
while(true) {
System.out.print(“Enter a number: “);
x = input.nextFloat();
System.out.format(“%f\t%f\t%f\n”, x, Math.pow(x, 2), Math.pow(x, 3));
System.out.print(“Do you want to continue [Y/N]? “);
ans = input.next();
if (!ans.toLowerCase().startsWith(“y”)) break;

کلاس: در حالت کلی تعریف کننده مفهوم است و شیء نمونه ای از آن مفهوم است. برای مثال انسان یک مفهوم است. یک موجود زنده با قابلیت هایی که می شناسیم آن را می شود تعریف کرد. اینکه می گوییم انسان این و این خاصیت های زیستی و این خاصیت های روانی و این خاصیت رفتاری و… اگر همه این ها را در نظر بگیریم این می شود انسان و مفهوم است. همه ما انسان ها هر کدام یک انسان هستیم ولی به تنهایی انسان را توصیف نمی کنیم. چون شاید چیزهایی در انسان باشد ولی یک نفر آن را نداشته باشد یا خیلی بیشتر داشته باشد.

هرکدام از ما یک نمونه از کلاس انسان هستیم. به ما می گویند شیء ولی انسان یک مفهوم است که همه انسان ها را می تواند توصیف کند. همین طور در مورد ماشین. خودرو یک وسیله نقلیه است که سوارش می شویم و می تواند ما را حمل کند و این یک مفهوم است و هر یک از ماشین هایی که در خیابان می بینیم یک شیء یا یک نمونه از کلاس ماشین هستند. جالب این است که ما می بینیم که وقتی یک کلمه خودرو را توصیف می کنیم: خودروی سواری و خودروی سنگین و خودروی دیزلی و سبک و خیلی چیزهای دیگر که می فهمیم که یک سلسله مراتبی را می شود بین آن تعریف کرد و هرچه در این سلسله مراتب پایین می رویم مثلا فرض می کنیم که خودروی سواری و سواری شاسی بلند و غیر شاسی بلند فرضاً. خوب وقتی داریم این ها را تعریف می کنیم در حال ریزتر شدن هستیم و می دانیم که همه این خودروها سواری هستند و همه جزء کلاس خودرواند و همه چرخ ترمز فرمان و … را دارند. این مفهوم در آن بالایی تعریف شده است. مثلا اگر دو دیفرانسیل باشد یا نه. یک چیزی است که جزء کلاس خاص است.

همان حقایقی که در زندگی فیزیکی داریم اگر به زبان نرم افزار بخواهیم بیان کنیم روی مفهوم شیء و کلاس باید کار بکنیم و برنامه هایی که اجزای سازنده آن ها بتواند از کلاس ها و شیء باشند، آن نوع برنامه نویسی را، برنامه نویسی شیء گرا می گویند.

تاکید: کلاس مفهوم است و شیء یک نمونه از آن کلاس است. برای اینکه خودمان یک کلاس اضافه بکنیم ابتدا یک پروژه ایجاد می کنیم. این پروژه خودش یک کلاس دارد اما ما می خواهیم خودمان یک کلاس دیگر به این اضافه بکنیم. در قسمت project، پکیج های سورس است. default package  که داخل project قرار دارد، شامل یک فایل است با پسوند java. این فایل سورسی است که وجود دارد. ما اگر به آدرسی که این ذخیره شده است برویم یک فایل جاوا وجود دارد که ان را با (note pad++) هم می توان باز کرد و حتی در آن هم می توانیم برنامه را بنویسیم ولی امکانات (IDE) را ندارد.

ما برای اینکه یک کلاس دیگر درست بکنیم مجبوریم که یک فایل جدید را تعریف کنیم. یکی از قراردادهایی که در کار با جاوا باید رعایت بشود این است که هر کلاس (public) یا عمومی، باید در یک فایل جداگانه باشد. کلاس هایی که غیرعمومی باشند می توانند بعد از کلاس عمومی تعریف بشوند. بر روی default package کلیک راست کرده در زیر مجموعه new java class< را انتخاب می کنیم.

در قسمت نام می گوید که چه کلاسی را می خواهید ایجاد کنید؟ فرض می کنیم که ما می خواهیم به عنوان مثال: یک کلاس می خواهیم ایجاد که انواع مثلا معادلات را برای ما حل کند. بنابراین اسم کلاس را EquationSolver می گذاریم.

قواعد نام گذاری: نام متغیرها توابع و کلاس ها

  • فقط می تواند شامل حروف اعداد و کاراکتر زیر خط _ باشد. (پس فاصله نمی تواند داشته باشد.)
  • باید با یک حرف یا کاراکتر زیر خط شروع شود. (نمی تواند با عدد شروع شود.)

سپس فینیش را می زنیم. سپس بخش کامند را حذف می کنیم:

اگرچه اصلا نباید حذف بشود ولی چون هدف آموزش است حذفش می کنیم. می توانیم از کلاسی که اضافه کردیم در کلاس اصلی استفاده کنیم. مثال:

این solver یک شیء از جنس EquationSolver است. ولی کار خاصی را انجام نمی دهد چون اصلا کلاسمان چیزی در داخلش ندارد. ما باید تعریف کنیم که مثلا این کلاس چه کارهایی را می تواند انجام دهد. سپس یک تابع در کلاسمان تعریف می کنیم که aوb را بگیرد و در نتیجه بگوید که پاسخ aوb و معادله چیست. سپس مانند نمونه سورس یک معادله درجه اول را در کلاسمان می نویسیم:

 

public class EquationSolver {
// Solves a*x + b = 0
public static void SolveEq1(double a, double b) {
double x = -b/a;
System.out.print(“Solving equation: “);
System.out.format(“%f * x + %f = 0\n”, a, b);
System.out.format(“Results:\nx = %f\n”, x);
}
}

بعد در کلاس اصلی برای استفاده از آن ابتدا یک اسکنر تعریف می کنیم. بعد از تعریف اسکنر یک اعلان برای کاربر درباره عملی که قرار است انجام شود می نویسیم بعد از او درخواست وارد کردن a را می کنیم و سپس هم مانند قبل از کاربر یک b می گیریم. حال به جایی رسیدیم که باید از کلاسمان کمک بگیریم، چون این از جنس یک تابعی است که داخل آن تعریف شده و static هم است. مستقیماً اگر نام کلاس را بنویسیم و یک نقطه بزنیم solveEq1 می آید و می شود از آن استفاده کرد.

 

می توانیم بگوییم: aوb و همین کافی است و برای این ها بی این معادله را حل کنید. یعنی این تابع solveEq1 را بیا از کلاس EquationSolver فراخوانی بکن. به دلیل اینکه این تابع static است خود کلاس می تواند آن به صورت مستقیم اجرا کند چون نیاز به ایجاد نمونه از این کلاس نیست. حال می توانیم برنامه را اجرا و از آن استفاده کنیم و معادله را حل بکنیم و همه این حل داخل تابع solveEq1 که داخل کلاس EquationSolver است. حال اگر بخواهیم معادله درجه ۲ را نیز اضافه بکنیم خیلی راحت می توانیم یک تابع دیگر مانند این تابع نوشته و آن solveEq2 می شود. بعد مستقل از اینکه این تابع در حال استفاده از چه الگوریتمی است ما در حال کمک گرفتن از کلاس هستیم و با داخل آن کار نداریم و آن به ما خدمات ارائه می دهد. از بابت حل این معادله تنها چیزی که لازم دارد این است که ما اطلاعات را در اختیارش قرار بدهیم. حتی گاهی اوقات می توانیم بدون اینکه اطلاعات را از کاربر دریافت کنیم خودمان عدد وارد بکنیم و ما می توانیم از این تابع به تعداد دلخواه استفاده کنیم. مثلا می توانیم از همان کلاسمان و تابعش به جای (a.b)/(b.a) را حل کنیم:

 

حالا این از مزایای برنامه نویسی تابع است. اما اینکه از مزایای OOP نیز محسوب بشود به صورت مستقیم نیست. این یک استفاده پیش افتاده از کلاس بود. کلاسی که ما نمونه نیز از آن نساختیم چون یک تابع static داخل آن بود و ما توانستیم بدون اینکه نمونه از آن بسازیم، آن را فراخوانی کنیم. بعد اگر بخواهیم این برنامه را به صورت کنسولی اجرا کنیم،در net beans در قسمت project روی پروژه کلیک راست می کنیم و گزینه Clean and Build را می زنیم:

 

یک پوشه dist هم در محل ذخیره پروژه می آید. در داخل این پوشه روی فایل java کلیک راست می کنیم و Run as console App را می زنیم. دقیقا همان نتیجه در آنجا اجرا می شود، ولی جواب را نمی بینیم! یک تکنیک قبلاً برای این کار یاد گرفتیم. آن تکنیک برای برای وقتی است که ما قبلا از input استفاده نکرده باشیم. به دلیل اینکه این جواب نمی دهد از یک رویکرد دیگر استفاده می کنیم: خوب یک اعلان برای کاربر چاپ می کنیم با مضمون اینکه برای خروج اینتر را بزند. بعد ازتابع (;()System.in.read استفاده می کنیم. این تابعی است که به ما کمک می کند که یک کلید را از کاربر بخوانیم. ولی یک موضوعی که اینجا است این است که این نیازمند یک جور فراخوانی خاص است. چون این یک حالت استثنایی را در واقع raise می کند. برای اینکه از این استفاده بکنیم از این ساختار استفاده می کنیم: try می کنیم این عبارت را System.in.read و catch می کنیم چیزی به نام {}(exception ex) و کار خاصی انجام نمی دهیم. حال اگر دوباره Build کنیم و آن را در محیط کنسول اجرا کنیم. الان دیگر منتظر می ماند و تا اینتر را می زنیم بسته می شود.

 

نتیجه: اگر قبلااز input استفاده کرده باشیم از این الگو بهره می گیریم.

این چیزی که اینجا دیدیم استفاده مستقیم از stream input و خواندن تک کاراکتر است. که این input scanner امکانش را به این صورت به درستی ایجاد نمی کند. چون اینجا این input است که برای گرفتن ورودی است.

کل پروژه ۱۴(project014): کلاس اصلی

 

public class EquationSolver {
// Solves a*x + b = 0
public static void SolveEq1(double a, double b) {
double x = -b/a;
System.out.print(“Solving equation: “);
System.out.format(“%f * x + %f = 0\n”, a, b);
System.out.format(“Results:\nx = %f\n”, x);
}
}

 

کلاسی که خودمان در این پروژه ساختیم:

 

import java.util.*;
public class Project014 {
public static void main(String[] args) {
Scanner input = new Scanner(System.in);
System.out.println(“Enter coefficients of equation: a*x + b = 0.\n”);
System.out.print(“Enter a: “);
double a = input.nextFloat();
System.out.print(“Enter b: “);
double b = input.nextFloat();
EquationSolver.SolveEq1(a, b);
System.out.println(“Press Enter to exit …”);
try {System.in.read();}
catch (Exception ex){}
}

}

می خواهیم یک پروژه ایجاد بکنیم برای چنین مثلثی محاسبات انجام دهد:

خوب پروژه را ایجاد می کنیم. ما کلاس جدیدی را که در پروژه ایجاد می کنیم برای محاسبات و اسمش را Triangleمی گذاریم. این کلاس یک سری خواص دارد، که دوتا از خواص های اصلی آن برای ما مهمتر هستند؛ که اسمی آن ها aوb است. این دو تا متغیرند که داخل کلاس تعریف شده اند و کلاس ممبراند:

ما اگر تعریف بکنیم که به عنوان مثال: (;()(Triangle t=new Triangle این را به این صورت تعریف کنیم. حال اگر بنویسیم (.T) می بینیم که aوbهست و می شود مقدار این ها را ست کرد و به این صورت مقادیر این ها را تعیین کرد:

منتهی ما خواهیم این مقادیر همان اول که دارند مثلا می سازیم این را یک جوری باشند که مثلا بگوییم:

(;a,Triangle t=new Triangle(10,15) بشود ۱۰ و b بشود ۱۵، این را می خواهیم این گونه فراخوانی کردنش درست بشود، به این اصطلاحا سازنده گفته می شود چون یک new Triangle می سازد، برای تعریف همچین چیزی می آییم می گوییم که :public، اسم کلاس هرچه باشد می نویسیم، بعد دو پارامتر دارد پارامتر اولی را اسمش را (double a), و دومی را (double b) فقط حواسمان باید باشد این اسامی بهتر است که تکرار اسامی قبلی نباشند، لذا این ها را (a1,b1) می گذاریم:

حال یعنی چه؟

یعنی اینکه یک مثلث با این دو تا پارامتر را بساز؛ خوب ما می آییم می گوییم که این کلاسی که می خواهیم بسازیم به این صورت تعریف می شود، تعریف می کنیم(a=a1;,b=b1) و مرسوم است که به این صورت هم می توان نوشت:

(this.a=a1;,this.b=b1;)

 

یک تابع هم برای چاپ اطلاعات مثلث می نویسیم، یک تابعی باشد که هیچ خروجی خاصی قرار نیست برگرداند و عمومی نیز است:

الان اگر تابع PrintInfo را در کلاس اجرا بکنیم . بگوییم که(.T)PrintInfo، می آید و اگر آن را اجرا بکنیم مقدار aوb را چاپ می کند. می توانیم به این صورت نیز تعریف کنیم و جالب است (۱۰) که در اینجا در نظر گرفته بودیم خنثی می شود:

 

حال اگر بخواهیم وتر مثلث را پیدا کنیم (از رابطه فیثاغورس) یا در شکل همان خاصیت (C) را بگیریم از این یا بگوییم این را محاسبه کند:

خوب یک تابع عمومی و دارای خروجی (پس باید از نوع doubleباشد) و اسمش را نیز (get-c) مثلا می گذاریم بعد در داخل تابع تعریف می کنیم:

 

public double get_c() {
double c = Math.sqrt(a*a + b*b);
return c;
}

تابع رادیکال است. حال مانند بالا (C) را returnمی کنیم (یعنی مقدار c را که محاسبه کردی برگردان).

نکته: به این صورت نیز می توانستیم تابع را تعریف کنیم:

return Math.sqrt(a*a + b*b);

حال در تابع قبل (C) را نیز برای چاپ کردن تعریف می کنیم و آن را قبل از تابع اینگونه تعریف می کنیم: double

c=get-c();

یا اینکه در تابع فرمت در جایی که قرار است (%f) را مقداردهی کنیم، بنویسیم:

get-c();

همچنین برای اینکه متدهای (a,b,c) هر کدام در یک خط چاپ شوند آنها را اینگونه جداگانه تعریف کنیم:

اگر بخواهیم این نتیجه این توابع را به صورت درجه ببینیم، به این صورت عمل می کنیم که در توابع بعد از دستور atan2(b,a)، را ضرب در ۱۸۰ کرده و بر عدد PI تقسیم می کنیم. این کار را در تابع phi نیز پیاده سازی می کنیم:

حال یک مشکل که وجود دارد این است که اگر یک نفر در کلاس اصلی در قسمت مقداردهی (Triangle)، عدد منفی وارد کند چه می شود؟

این درست نیست و نباید عدد منفی قبول بکند؛ برای کنترل این منظور مقدار (a) و (b) را با یک کلمه (praivate) خصوصی می کنیم:

(a) و (b) چون (praivate) شده اند دیگر خوانده نمی شوند و در دسترس در خارج از کلاس نیستند. حال اگر بخواهیم از بیرون مقدار (a) را عوض کنیم چه؟ این امکان را یا ایجاد نمی کنیم و یا به این شکل ایجاد می کنیم که یک تابع باشد. پس یک تابع عمومی را ایجاد می کنیم و به صورت (void) با نام (set-a) که مقدار (a) را می خواهیم ست بکنیم و البته باید مقدار آن را داشته باشیم (set-a(double value)): یعنی می خواهیم مقدار (value) را بگذاریم به جای (a) و در داخل تابع در ساده ترین حالت مقدار (a) را می گذاریم (value):a=value;. و بعد هم یک تابع مانند قبلی درست می کنیم با نام get-a قرار می دهیم ولی این تابع را دیگر ورودی نمی دهیم و در داخل آن هم (a) را return می کنیم. پس اگر می خواهیم (a) را بخوانیم از تابع get-a استفاده می کنیم و اگر می خواهیم بنویسیم از تابع set-a استفاده می کنیم. دقیقا برای (b) هم همین را پیاده سازی می کنیم:

حال برای تعریف (a) در کلاس اصلی نمی توانیم به این صورت عمل می کنیم که:

از ما اشکال می گیرد، چون (a) خصوصی است، برای همین به این صورت عمل می کنیم:

و ما مسیر دسترسی به این چیز خصوصی را فقط از طریق (set) و (get) گذاشته ایم. Get برای خواندنش و set برای نوشتنش. حال دیگر می توانیم وارد کنترل بشویم. یعنی اینکه این (value) را کنترل کنیم. مثلا بگوییم که اگر کمتر از صفر بود، همان صفر را در نظر گرفته شود، پس ما می آییم در داخل این تابع (set) به جای (value) می نویسیم:

Math.max(value,0);

یعنی ماکسیموم بین این valueو۰، یعنی اینکه value و صفر هر کدامش بزرگتر است آن را استفاده بکن. حالا یا value مثبت است که خوب و اگر هم نه که صفر استفاده می شود. این کار را برای set-b نیز انجام می دهیم. پس دیگر ما عدد منفی نمی توانیم بگذاریم یا اگر مثلا بخواهیم یکم بهتر بشود: اگر منفی گذاشت قرینه آن در نظر گرفته بشود یا همیشه قدر مطلقش را استفاده بکنیم؛ پس می گوییم:

Math.abs(value);

 

یعنی مقدار قدر مطلق value:

در تابع Triangle نیز باید باید اینگونه تنظیم بشود:

set-a(a1);وset-b(b1);

این چیزی که ما در اینجا داریم یک روند استاندارد است برای دسترسی به ویژگی های (private)که می توانند باشند. اصطلاحا به این یک متد و ست متد گفته می شود. ما نمونه هایی از این ها را داشته ایم، مثلا تابع های.(phi), (theta)، (Area) این ها چیزهایی هستند که فقط خواندنی اند، به خاطراین، این طوری اند. ولی مثلا (set-b)، (get-b)، (set-a)، (get-a) این ها چیزهایی هستند که هم خواندنی و هم نوشتنی اند.

این کلاسی که نوشتیم تقریبا دیگر عملکردش کامل است و ما با یک سری مفاهیم دیگر هم آشنا شدیم. مفاهیمی مثل getمتدها و setمتدها و یک سری ویژگی هایی که به صورت وابسته قابل تعریف اند، مثلا مساحت یک ویژگی وابسته است، get-c یک ویژگی وابسته است، یک سری ویژگی های اصیل تر اند. منتهی یک warning در تابع Triangle داریم:

اگر بخواهیم این رفع بشود، این get-a وget-b  که در تصویر نیز می بینید، چون در اینجا استفاده شده اند، برای اینکه مشکلی پیش نیاید این ها را باید به صورت تعریف final بکنیم که خطا warning ندهد، هر چند اشکالی در اجرای برنامه به وجود نمی آید. این فاینال ها باعث می شوند که این warningها رفع بشوند و این توابع به صورت تابعی که دیگر پیاده سازی اش نهایی شده است و قرار نیست بعدا دست کاری بشوند، در می آیند و یا اینکه کل کلاس را فاینال می کنیم:

حال می توانیم از این برنامه چندین بار فقط با یک بار که نوشتیم استفاده کنیم:

یکی از موضوعاتی که دیدیم این بود که کلمه ای مانند (private) می تواند کنترل کند که یک چیز کجا در دسترس باشد. مثلا همین تابع Area در بیرون از برنامه در دسترس است، مثلا اگر بنویسیم (.T1) در دسترس است:

اما اگر این را به صورت private تعریف بکنیم، دیگر در بیرون از کلاس در دسترس نیست:

کل پروژه ۱۵(project015): کلاس اصلی

 

public class Project015 {
public static void main(String[] args) {
System.out.println(“Triangle T1”);
Triangle T1 = new Triangle(3, 4);
T1.PrintInfo();
System.out.println(“____________________”);
System.out.println(“Triangle T2”);
Triangle T2 = new Triangle(5, 12);
T2.PrintInfo();
System.out.println(“____________________”);
System.out.println(“Triangle T3”);
Triangle T3 = new Triangle(7, 24);
T3.PrintInfo();
System.out.println(“____________________”);
Triangle T4 = T3;
T4.set_a(17);
//Triangle T5 = Triangle.copy(T3);
Triangle T5 = T3.copy();
T5.set_a(80);
System.out.println(“Triangle T3”);
T3.PrintInfo();
System.out.println(“____________________”);
System.out.println(“Triangle T4”);
T4.PrintInfo();
System.out.println(“____________________”);
System.out.println(“Triangle T5”);
T5.PrintInfo();
System.out.println(“____________________”);
}
}

کلاسی که خودمان در این پروژه ساختیم:

 

public final class Triangle {
private double a;
private double b;
public Triangle(double a1, double b1) {
set_a(a1);
set_b(b1);
}
public double get_a() {
return a;
}
public void set_a(double value) {
a = Math.abs(value);
}
public double get_b() {
return b;
}
public void set_b(double value) {
b = Math.abs(value);
}
public double get_c() {
double c = Math.sqrt(a*a + b*b);
return c;
}
public double get_theta() {
return Math.atan2(b, a)*180/Math.PI;
}
public double get_phi() {
return Math.atan2(a, b)*180/Math.PI;
}
private double get_Area() {
return (a*b)/2;
}
public void PrintInfo() {
System.out.println(“Triangle:”);
System.out.format(“a = %f\n”, a);
System.out.format(“b = %f\n”, b);
System.out.format(“c = %f\n”, get_c());
System.out.format(“theta = %f\n”, get_theta());
System.out.format(“phi = %f\n”, get_phi());
System.out.format(“S = %f\n”, get_Area());
}
/*
public static Triangle copy(Triangle T) {
return new Triangle(T.a, T.b);
}
*/
public Triangle copy() {
return new Triangle(a, b);
}

}

این پروژه را می بندیم و یک پروژه دیگر را ایجاد می کنیم.

ما نوع داده string را قبلا استفاده کرده ایم، حال در اینجا نیز یک داده string ایجاد می کنیم، مثلا با نام (s) و مساوی (“!Welcome to java programming course”) این شد کلاس string و یک آبجکت از آن کلاس(s) ،ما می خواهیم از آن استفاده بکنیم. قبل از همه می خواهیم طول این را داشته باشیم پس به این صورت عمل می کنیم:

String s = “Welcome to Java Programming Course!”;
System.out.format(“String is: %s\n”, s);
System.out.format(“Length = %d\n”, s.length());

دقیقا می تواند طول آن را چاپ کند. بعد مثلا خالی است یا نه، این را می توانیم به صورت رشته نشان دهیم. چه چیزی را می خواهیم نشان بدهیم؟ ();S.isEmpty >این تابع ();isEmpty از نوع Boolean است. این را اگر همین طوری بخواهیم نشان بدهیم، در جواب می نویسد False یعنی خالی نیست:

خوب اگر بخواهیم کاراکتری که در محل سه قرار دارد (۳) را نمایش دهیم، به این صورت عمل می کنیم:

در مقدار دهی از ;S.CharAt(index) استفاده کرده ایم که از ما اندیس می خواهد. خوب اندیس شماره سه. در جواب کاراکتر (c) را نشان می دهد، چرا؟ چون رشته ها و آرایه ها در جاوا مثل زبان c از صفر شروع می شود. برای نشان دادن کاراکتر c باید اندیس را ۴ وارد بکنیم.

حال اگر بخواهیم همه این رشته را به حروف کوچک تبدیل کنیم، از ();تابعS.tolowerCase استفاده می کنیم و مثل همین ();S.upperCase را هم داریم:

فرض می کنیم که اندیس اولین space را می خواهیم پیدا بکنیم. یعنی کجا اولین اسپیس را می توانیم ببینیم. از تابع استفاده می کنیم. (“یک فاصله”);s.indexof. (‘ ’)هم می توانیم استفاده بکنیم. این (‘ ’) کاراکتر است نه رشته، در واقع این از نوع داده کاراکتر است. ولی (“”)Indexof خوبی آن این است که ما مثلا می توانیم دنبال کلمه بگردیم:

برای اینکه بدانیم با چه چیزی تمام می شود از تابع (“”);s.endswith استفاده می کنیم و در زیر منظور این است که آیا با (“!”) تمام می شود یا نه؟ که جواب true است و ما می توانیم این را با نقطه هم استفاده کنیم:

خاصیت های دیگر نیز است، مثلا اگر بخواهیم یک مروری روی این ها داشته باشیم :

charAt(int index)> این کاراکتر در یک اندیس به خصوص است.

compare To(string anotherString)> مقایسه می کند با یک رشته دیگر، اگر این compare To بزرگتر باشد مثبت می شود و اگر این کوچکتر باشد منفی می شود و اگر عین هم باشند نتیجه صفر می شود.

compare To Igno recase(string str)> یعنی مقایسه می کند بدون در نظر گرفتن حروف بزرگ و کوچک.

Concat(string str)> دو تا رشته را می تواند به هم وصل کند.

Contains(charsequence s)> چک می کند که آیا یک عبارتی شامل یک رشته است یا نه.

lastIndexof(int ch,int from index)> یعنی آخرین وقوع مثلا یک عبارت در یک چیز، مثلا آخرین اسپیسی که وجود دارد را بخواهیم پیدا کنیم.

matches(string regex)> اگر با عبارت های قانونمند اشنا باشیم، چک می کند که آیا مثلا توی این رشته این عبارت وجود دارد یا نه.

replace و replace All> این ها بخشی از جمله را می توانند جایگزین بکنند.

Split> نسبت به یک عبارت می تواند اسپلیت بکند، مثلا با ویرگور اسپلیت بکند. در واقع یک آرایه از رشته ها را تحویل ما می دهد.

Subsequence> یک بخش از زیر رشته از این، مثلا از کاراکتر شماره پنج تا کاراکتر شماره یازده را جدا بکند و به ما تحویل بدهد.

toLowercase و touppercase> تبدیل می کند به حروف بزرگ و کوچک.

tostring> هر چیزی را بدهیم به string تبدیل می کند.

trim> از ابتدا به انتهای این اصطلاحاً حالا اسپیس وجود داشته باشد را حذف می کند.

کل پروژه۱۶(project016): کلاس اصلی

 

public class Project016 {
public static void main(String[] args) {
String s = “Welcome to Java Programming Course!”;
System.out.format(“String is: %s\n”, s);
System.out.format(“Length = %d\n”, s.length());
System.out.format(“IsEmpty = %s\n”, s.isEmpty());
System.out.format(“Char at Position 3: %s\n”, s.charAt(2));
System.out.format(“Lower Case: %s\n”, s.toLowerCase());
System.out.format(“Upper Case: %s\n”, s.toUpperCase());
System.out.format(“First Space Index: %d\n”, s.indexOf(“Java”));
System.out.format(“Ends With !: %s\n”, s.endsWith(“!”));
System.out.format(“Ends With .: %s\n”, s.endsWith(“.”));
}
}

داده های Reference Types

ما داده هایی که تا حالا با ان ها کار کردیم،یک تعدادشان primitive Deta Types بودند. primitive Deta Typesها داده های اساسی اند، مثل int ،flouat ،double. در مقابل این ها نوع دیگری از داده ها هستند، این ها از بعضی جهات با هم مخالف اند، به این ها اصطلاحاً Reference Types می گویند.

داده های مقداری Primitive

Reference> داده های ارجایی

این ها داده هایی هستند که در حافظه ذخیره می شوند و هر موقع، مثلا فرض می کنیم که (int a=10;) و (int b=a;) بعد (a++;) به مقدارش اضافه شود. دیگر b تغییر نمی کند، چون b کپی از a است. به همچین داده هایی داده های نوع مقداری گفته می شود. اما بعضی دیگر از داده ها اینگونه نیستند، وقتی b=a،b برابر aبشود، دیگر هر تغییری که روی a انجام بشود، این تغییر روی b نیز اعمال می شود. یعنی روی یکیشان تغییر بدهیم، روی آن یکی هم تغییر اعمال خواهد شد.

این داده های زیر که همان داده های Primitive یا داده های (value) هستند یا داده های مبتنی بر ارزش. نتیجه این را اگر اجرا بکنیم این است (a=11): و (b=10) خواهد شد.

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

Triangle T4=T3;

T4.set-a(17);

فرض می کنیم که (;Triangle T4=t3به این صورت؛ یعنی T4 را تعریف بکنیم برابر T3.

اگر بگوییم که ;T4.set-a(17)، مثلا به جای هفت بزنیم هفده، اینگونه تعریف کنیم. حالا اگر بیاییم بگوییم که: نتایج T3 وT4 را می نویسیم؛ خوب می خواهیم ببینیم که چقدر با هم تفاوت دارند. T3 در ابتدا هفت و بیست و چهار بوده است، ولی بعد از ست شدن a آن هفده شده است. T4 هم هفده شده است. خوب طبیعی است، چون روی T4 کار کردیم. اینکه T3 اثر می گیرد ناشی از این است که این ها از نوع داده Reference هستند و در واقع ما آدرس این ها داریم در حافظه ذخیره می کنیم.

برای اینکه حالا دید روشن تری نسبت به این موضوع داشته باشیم، دلیل اینکه چرا اینطور است، برمی گردد به اینکه موقعی که می گوییم Triangle T4 داریم با آدرس ذخیره سازی این T3 در حافظه کار می کنیم و همان را می دهیم به T4 و T3و T4 در حال هدف قرار دادن یک جا از حافظه هستند و هر دو یک چیز را، منتهی با دو اسم می آیند و هدف قرار می دهند. اما در اینجا اینطور نیست و این ها چون داده های primitive هستند به این شکل تعریف می شوند. این ها ذاتاً در جاوا با آدرس کار نمی شوند، یعنی یک جای دیگری از حافظه ذخیره می شوند، به خاطر این a و b جدا از هم اند. الان در برنامه هر تغییری در T3وT4  انجام بدهیم روی دیگری نیز اعمال می شود.

string هم جز داده های Reference Types است، ما اگر روی یک string تغییر ایجاد بکنیم که کپی از یک string دیگر باشد،آن اصلی هم تغییر می کند. کلا کلاس ها به صورت Reference Types در جاوا تعریف شده اند. این داده ها هم می تواننند خوب باشند و یک مقدار کارها را آسان کنند و اگر هم حواسمان نباشد می توانند مشکلاتی را ایجا بکنند، مثلا الان T4 را مساوی T3 در نظر می گیریم، ست می کنیم و غافل از اینکه T3 هم اثر گرفته است و مثلا فرض کنید که این قرار نبوده است اینگونه باشد. ما باید این در ذهنمان باشد و در موقع لزوم، فرض می کنیم که اگر بخواهیم از این T3 یک کپی بگیریم و تغییرات بدهیم، باید اینگونه تعریف بکنیم:

یعنی یک مثلث جدید باید با این مقادیر درست بکنیم، دیگرT3 از این اثر نگرفته است، چرا؟ چون اصلا یک چیز مستقل است که در یک جای دیگر از حافظه ذخیره شده است. حتی اگر بخواهیم بهتر به این موضوع نگاه کنیم:

یک تابع در کلاس Triangle تعریف می کنیم با نام،Triangle copy(Triangle T)و می گوییم که return کن یک ;new triangle(T.a,T.b)

t.a و t.b را داریم از آن یک مثلث جدید می سازیم و این را return می کنیم و به جای همه این صحبت هایی که اینجا داریم می توانیم بنویسیم: ;T5=Triangle.copy(T3) این باعث می شود که یک کپی از از این را داشته باشیم.

این یک حالت static بود این را کامنت می کنیم. به جای این این حالت را نیز می تواند داشته باشد؛ قبلی مربوط به خود کلاس بود ولی این یک نمونه از کلاس است:

یعنی توی این نمونه که هستیم a و b را بردار و از این یک مثلث بساز ;()۵=T3.copy

یعنی یک کپی از T3 تهیه بکن. در ابتدا copy یک تابعی است در کلاس Triangle و دیگر نیازی به ساختن نمونه نیست. می گوییم که در کلاس مثلث یک کپی تهیه بکن از این T3:

ولی در این یکی می گوییم که از T3 یک کپی تهیه بکن:

 

 

 

آنچه مطالعه کردید، توسط جناب آقای حسین یاسبلاغی به عنوان پیاده سازی و برداشت متنی بخش هایی از آموزش «اجزای سازنده برنامه ها و انواع داده ها در جاوا» تهیه شده و جهت استفاده مخاطبین گرامی در متلب سایت منتشر می شود.

 

 

 

پاسخی بگذارید

نشانی ایمیل شما منتشر نخواهد شد. بخش‌های موردنیاز علامت‌گذاری شده‌اند *