हाय! चला दुसर्या प्रकारच्या नेस्टेड क्लासेसबद्दल बोलूया. मी स्थानिक वर्गांबद्दल बोलत आहे (पद्धत-स्थानिक अंतर्गत वर्ग). आत जाण्यापूर्वी, आपण प्रथम नेस्टेड वर्गांच्या संरचनेत त्यांचे स्थान लक्षात ठेवले पाहिजे. आमच्या आकृतीवरून, आम्ही पाहू शकतो की स्थानिक वर्ग ही अंतर्गत वर्गांची उपप्रजाती आहेत, ज्याबद्दल आम्ही मागील सामग्रीमध्ये तपशीलवार बोललो . तथापि, स्थानिक वर्गांमध्ये सामान्य आतील वर्गांपेक्षा अनेक महत्त्वाची वैशिष्ट्ये आणि फरक आहेत. मुख्य गोष्ट त्यांच्या घोषणेमध्ये आहे: स्थानिक वर्ग केवळ कोडच्या ब्लॉकमध्ये घोषित केला जातो. बहुतेकदा, ही घोषणा बाह्य वर्गाच्या काही पद्धतींमध्ये असते. उदाहरणार्थ, ते यासारखे दिसू शकते:
public class PhoneNumberValidator {
public void validatePhoneNumber(String number) {
class PhoneNumber {
private String phoneNumber;
public PhoneNumber() {
this.phoneNumber = number;
}
public String getPhoneNumber() {
return phoneNumber;
}
public void setPhoneNumber(String phoneNumber) {
this.phoneNumber = phoneNumber;
}
}
// ...number validation code
}
}
महत्त्वाचे!जर तुमच्याकडे Java 7 स्थापित असेल, तर IDEA मध्ये पेस्ट केल्यावर हा कोड संकलित होणार नाही. आम्ही धड्याच्या शेवटी याची कारणे सांगू. थोडक्यात, स्थानिक वर्ग कसे कार्य करतात हे भाषेच्या आवृत्तीवर अवलंबून असते. हा कोड तुमच्यासाठी संकलित करत नसल्यास, तुम्ही IDEA मधील भाषा आवृत्ती Java 8 वर स्विच करू शकता किंवा मेथड पॅरामीटरमध्ये शब्द जोडू शकता final
जेणेकरून ते असे दिसेल: validatePhoneNumber(final String number)
. त्यानंतर, सर्वकाही कार्य करेल. हा एक छोटा प्रोग्राम आहे जो फोन नंबर प्रमाणित करतो. त्याची validatePhoneNumber()
पद्धत इनपुट म्हणून स्ट्रिंग घेते आणि तो फोन नंबर आहे की नाही हे निर्धारित करते. आणि या पद्धतीच्या आत, आम्ही आमचा स्थानिक PhoneNumber
वर्ग घोषित केला. तुम्ही यथोचित कारण विचारू शकता. आपण पद्धतीमध्ये वर्ग का घोषित करू? सामान्य आतील वर्ग का वापरत नाही? खरे आहे, आम्ही बनवू शकलो असतोPhoneNumber
वर्ग आणि अंतर्गत वर्ग. परंतु अंतिम समाधान तुमच्या प्रोग्रामची रचना आणि उद्देश यावर अवलंबून आहे. आतील वर्गांवरील धड्यातून आमचे उदाहरण आठवूया:
public class Bicycle {
private String model;
private int maxWeight;
public Bicycle(String model, int maxWeight) {
this.model = model;
this.maxWeight = maxWeight;
}
public void start() {
System.out.println("Let's go!");
}
public class HandleBar {
public void right() {
System.out.println("Steer right!");
}
public void left() {
System.out.println("Steer left!");
}
}
}
त्यात आम्ही HandleBar
बाईकचा एक आतील वर्ग बनवला. फरक काय आहे? सर्व प्रथम, वर्ग वापरण्याची पद्धत वेगळी आहे. HandleBar
दुसऱ्या उदाहरणातील वर्ग हा पहिल्या उदाहरणातील वर्गापेक्षा अधिक गुंतागुंतीचा घटक आहे PhoneNumber
. प्रथम, HandleBar
सार्वजनिक right
आणि left
पद्धती आहेत (हे सेटर्स/गेटर नाहीत). दुसरे म्हणजे, आपल्याला त्याची आणि त्याच्या बाह्य वर्गाची कुठे गरज भासेल हे आधीच सांगणे अशक्य आहे Bicycle
. एकाच कार्यक्रमात डझनभर वेगवेगळी ठिकाणे आणि पद्धती असू शकतात. परंतु वर्गासह PhoneNumber
, सर्व काही खूप सोपे आहे. आमचा कार्यक्रम अगदी सोपा आहे. त्याचा एकच उद्देश आहे: नंबर वैध फोन नंबर आहे की नाही हे तपासणे. बहुतांश घटनांमध्ये, आमच्याPhoneNumberValidator
हा एक स्वतंत्र प्रोग्राम देखील नसेल, परंतु मोठ्या प्रोग्रामसाठी अधिकृतता तर्काचा एक भाग असेल. उदाहरणार्थ, वापरकर्ते साइन अप करतात तेव्हा विविध वेबसाइट अनेकदा फोन नंबर विचारतात. तुम्ही क्रमांकांऐवजी काही मूर्खपणा प्रविष्ट केल्यास, वेबसाइट त्रुटी नोंदवेल: "हा फोन नंबर नाही!" अशा वेबसाइटचे विकसक (किंवा त्याऐवजी, त्याची वापरकर्ता अधिकृतता यंत्रणा) आमच्यासारखे काहीतरी समाविष्ट करू शकतातPhoneNumberValidator
त्यांच्या कोडमध्ये. दुसऱ्या शब्दांत, आमच्याकडे एका पद्धतीसह एक बाह्य वर्ग आहे, जो प्रोग्राममध्ये एकाच ठिकाणी वापरला जाईल आणि कोठेही नाही. आणि जर ते वापरले गेले, तर त्यात काहीही बदल होणार नाही: एक पद्धत त्याचे कार्य करते - आणि तेच आहे. या प्रकरणात, सर्व तर्कशास्त्र एका पद्धतीमध्ये एकत्रित केल्यामुळे, तेथे अतिरिक्त वर्ग समाविष्ट करणे अधिक सोयीचे आणि योग्य असेल. गेटर आणि सेटरशिवाय त्याच्या स्वतःच्या कोणत्याही पद्धती नाहीत. खरं तर, आम्हाला फक्त कन्स्ट्रक्टरकडून डेटा हवा आहे. हे इतर पद्धतींमध्ये गुंतलेले नाही. त्यानुसार, ज्या पद्धतीचा वापर केला जातो, त्या पद्धतीच्या बाहेर त्याची माहिती घेण्याचे कारण नाही. आम्ही एक उदाहरण देखील दिले ज्यामध्ये स्थानिक वर्ग एका पद्धतीने घोषित केला जातो, परंतु हा एकमेव पर्याय नाही. हे फक्त कोड ब्लॉकमध्ये घोषित केले जाऊ शकते:
public class PhoneNumberValidator {
{
class PhoneNumber {
private String phoneNumber;
public PhoneNumber(String phoneNumber) {
this.phoneNumber = phoneNumber;
}
}
}
public void validatePhoneNumber(String phoneNumber) {
// ...number validation code
}
}
किंवा अगदी लूपमध्ये for
!
public class PhoneNumberValidator {
public void validatePhoneNumber(String phoneNumber) {
for (int i = 0; i < 10; i++) {
class PhoneNumber {
private String phoneNumber;
public PhoneNumber(String phoneNumber) {
this.phoneNumber = phoneNumber;
}
}
// ...some logic
}
// ...number validation code
}
}
परंतु अशी प्रकरणे अत्यंत दुर्मिळ आहेत. बहुतेक प्रकरणांमध्ये, घोषणा पद्धतीच्या आत होईल. म्हणून, आम्ही घोषणा शोधल्या, आणि आम्ही "तत्वज्ञान" बद्दल देखील बोललो :) अंतर्गत वर्गांच्या तुलनेत स्थानिक वर्गांमध्ये कोणती अतिरिक्त वैशिष्ट्ये आणि फरक आहेत? स्थानिक वर्गाचा ऑब्जेक्ट ज्या पद्धती किंवा ब्लॉकमध्ये घोषित केला आहे त्या बाहेर तयार केला जाऊ शकत नाही. कल्पना करा की आम्हाला अशा generatePhoneNumber()
पद्धतीची आवश्यकता आहे जी यादृच्छिक फोन नंबर तयार करेल आणि PhoneNumber
ऑब्जेक्ट परत करेल. आमच्या सध्याच्या परिस्थितीत, आम्ही आमच्या प्रमाणीकरण वर्गात अशी पद्धत तयार करू शकत नाही:
public class PhoneNumberValidator {
public void validatePhoneNumber(String number) {
class PhoneNumber {
private String phoneNumber;
public PhoneNumber() {
this.phoneNumber = number;
}
public String getPhoneNumber() {
return phoneNumber;
}
public void setPhoneNumber(String phoneNumber) {
this.phoneNumber = phoneNumber;
}
}
// ...number validation code
}
// Error! The compiler does not recognize the PhoneNumber class
public PhoneNumber generatePhoneNumber() {
}
}
स्थानिक वर्गांचे आणखी एक महत्त्वाचे वैशिष्ट्य म्हणजे स्थानिक व्हेरिएबल्स आणि पद्धत पॅरामीटर्समध्ये प्रवेश करण्याची क्षमता. जर तुम्ही विसरलात तर, मेथडमध्ये घोषित केलेले व्हेरिएबल "स्थानिक" व्हेरिएबल म्हणून ओळखले जाते. म्हणजेच, जर आपण मेथडमध्ये काही कारणास्तव स्थानिक String usCountryCode
व्हेरिएबल तयार केले validatePhoneNumber()
तर आपण ते स्थानिक वर्गातून ऍक्सेस करू शकतो PhoneNumber
. तथापि, प्रोग्राममध्ये वापरल्या जाणार्या भाषेच्या आवृत्तीवर अवलंबून असलेल्या अनेक सूक्ष्मता आहेत. धड्याच्या सुरुवातीला, आम्ही लक्षात घेतले की जावा 7 मध्ये उदाहरणांपैकी एक कोड संकलित होऊ शकत नाही, लक्षात ठेवा? आता याची कारणे पाहू या :) Java 7 मध्ये, लोकल क्लास लोकल व्हेरिएबल किंवा मेथड पॅरामीटरमध्ये प्रवेश करू शकतो जर ते final
मेथडमध्ये घोषित केले असेल तरच:
public void validatePhoneNumber(String number) {
String usCountryCode = "+1";
class PhoneNumber {
private String phoneNumber;
// Error! The method parameter must be declared as final!
public PhoneNumber() {
this.phoneNumber = number;
}
public void printUsCountryCode() {
// Error! The local variable must be declared as final!
System.out.println(usCountryCode);
}
}
// ...number validation code
}
येथे कंपाइलर दोन त्रुटी निर्माण करतो. आणि येथे सर्वकाही क्रमाने आहे:
public void validatePhoneNumber(final String number) {
final String usCountryCode = "+1";
class PhoneNumber {
private String phoneNumber;
public PhoneNumber() {
this.phoneNumber = number;
}
public void printUsCountryCode() {
System.out.println(usCountryCode);
}
}
// ...number validation code
}
आता तुम्हाला माहिती आहे की धड्याच्या सुरुवातीपासूनचा कोड का संकलित केला जात नाही: Java 7 मध्ये, स्थानिक वर्गाला फक्त final
पद्धत पॅरामीटर्स आणि final
स्थानिक व्हेरिएबल्समध्ये प्रवेश असतो. Java 8 मध्ये, स्थानिक वर्गांचे वर्तन बदलले आहे. भाषेच्या या आवृत्तीमध्ये, स्थानिक वर्गाला केवळ final
स्थानिक व्हेरिएबल्स आणि पॅरामीटर्समध्येच प्रवेश नाही, तर त्यामध्ये देखील प्रवेश आहे effective-final
. Effective-final
एक व्हेरिएबल आहे ज्याचे मूल्य सुरुवातीपासून बदललेले नाही. उदाहरणार्थ, Java 8 मध्ये, आम्ही usCountryCode
कन्सोलवर व्हेरिएबल सहजपणे प्रदर्शित करू शकतो, जरी ते नसले तरीही final
. महत्त्वाची गोष्ट म्हणजे त्याचे मूल्य बदलत नाही. खालील उदाहरणात, सर्वकाही जसे पाहिजे तसे कार्य करते:
public void validatePhoneNumber(String number) {
String usCountryCode = "+1";
class PhoneNumber {
public void printUsCountryCode() {
// Java 7 would produce an error here
System.out.println(usCountryCode);
}
}
// ...number validation code
}
पण इनिशिएलायझेशननंतर लगेच व्हेरिएबलची व्हॅल्यू बदलली तर कोड कंपाइल होणार नाही.
public void validatePhoneNumber(String number) {
String usCountryCode = "+1";
usCountryCode = "+8";
class PhoneNumber {
public void printUsCountryCode() {
// Error!
System.out.println(usCountryCode);
}
}
// ...number validation code
}
स्थानिक वर्ग ही आतील वर्गाच्या संकल्पनेची उपप्रजाती आहे यात आश्चर्य नाही! त्यांच्यात सामान्य वैशिष्ट्ये देखील आहेत. स्थानिक वर्गाला बाह्य वर्गाच्या सर्व (अगदी खाजगी) फील्ड आणि पद्धतींमध्ये प्रवेश असतो: स्थिर आणि नॉन-स्टॅटिक दोन्ही. String phoneNumberRegex
उदाहरणार्थ, आमच्या व्हॅलिडेटर क्लासमध्ये स्टॅटिक फील्ड जोडूया :
public class PhoneNumberValidator {
private static String phoneNumberRegex = "[^0-9]";
public void validatePhoneNumber(String phoneNumber) {
class PhoneNumber {
// ......
}
}
}
हे स्टॅटिक व्हेरिएबल वापरून प्रमाणीकरण केले जाईल. [^0-9]
पास केलेल्या स्ट्रिंगमध्ये रेग्युलर एक्सप्रेशन " " (म्हणजे 0 ते 9 पर्यंतचा अंक नसलेला कोणताही वर्ण) न जुळणारे वर्ण आहेत की नाही हे पद्धत तपासते . लोकल PhoneNumber
क्लासमधून आपण या व्हेरिएबलमध्ये सहज प्रवेश करू शकतो. उदाहरणार्थ, एक गेटर लिहा:
public String getPhoneNumberRegex() {
return phoneNumberRegex;
}
स्थानिक वर्ग आतील वर्गांसारखेच असतात, कारण ते कोणतेही स्थिर सदस्य परिभाषित किंवा घोषित करू शकत नाहीत. स्थिर पद्धतींमधील स्थानिक वर्ग केवळ संलग्न वर्गाच्या स्थिर सदस्यांचा संदर्भ देऊ शकतात. उदाहरणार्थ, जर तुम्ही एनक्लोजिंग क्लासचे व्हेरिएबल (फील्ड) स्टॅटिक म्हणून परिभाषित केले नाही, तर Java कंपाइलर एक त्रुटी निर्माण करतो: "नॉन-स्टॅटिक व्हेरिएबलचा संदर्भ स्थिर संदर्भातून दिला जाऊ शकत नाही." स्थानिक वर्ग स्थिर नसतात, कारण त्यांना संलग्न ब्लॉकमधील उदाहरण सदस्यांपर्यंत प्रवेश असतो. परिणामी, त्यामध्ये बहुतेक प्रकारचे स्थिर घोषणा असू शकत नाहीत. तुम्ही ब्लॉकमध्ये इंटरफेस घोषित करू शकत नाही: इंटरफेस स्वाभाविकपणे स्थिर असतात. हा कोड संकलित करत नाही:
public class PhoneNumberValidator {
public static void validatePhoneNumber(String number) {
interface I {}
class PhoneNumber implements I{
private String phoneNumber;
public PhoneNumber() {
this.phoneNumber = number;
}
}
// ...number validation code
}
}
परंतु जर बाह्य वर्गामध्ये इंटरफेस घोषित केला असेल, तर PhoneNumber
वर्ग त्याची अंमलबजावणी करू शकतो:
public class PhoneNumberValidator {
interface I {}
public static void validatePhoneNumber(String number) {
class PhoneNumber implements I{
private String phoneNumber;
public PhoneNumber() {
this.phoneNumber = number;
}
}
// ...number validation code
}
}
स्थानिक वर्गांमध्ये स्टॅटिक इनिशियलायझर्स (इनिशियलायझेशन ब्लॉक्स) किंवा इंटरफेस घोषित केले जाऊ शकत नाहीत. परंतु स्थानिक वर्गांमध्ये स्थिर सदस्य असू शकतात, जर ते स्थिर व्हेरिएबल्स ( static final
) असतील. आणि आता तुम्हाला स्थानिक वर्गांबद्दल माहिती आहे, लोक! जसे आपण पाहू शकता, त्यांच्यात सामान्य आतील वर्गांपेक्षा बरेच फरक आहेत. भाषेच्या विशिष्ट आवृत्त्या कशा कार्य करतात हे समजून घेण्यासाठी आम्हाला त्यांच्या वैशिष्ट्यांचा देखील अभ्यास करावा लागला :) पुढील धड्यात, आम्ही अनामित अंतर्गत वर्गांबद्दल बोलू - नेस्टेड वर्गांचा शेवटचा गट. तुमच्या अभ्यासात शुभेच्छा! :)
GO TO FULL VERSION