Inheritance and Constructor – The Calling Convention

Inheritance and Constructor: पिछले Program में हमने Employee व Scientist दोनों ही Classes के Objects को Initialize करने के लिए setData() नाम के एक Member Function का प्रयोग किया है। लेकिन हम इन Objects को Constructors का प्रयोग करके भी Initialize कर सकते हैं। यदि हम इसी Program में Define की गई Super Class में Constructors का प्रयोग करें, तो Employee Class को हम निम्नानुसार Modify कर सकते हैं:

	class Employee
	{
		private int ID;	
		private String name;	
	
		Employee(int empID, String empName)
		{
			ID = empID;
			name = empName;
		}
	
		public void showData()
		{
			System.out.println("\tName   : " + name);
			System.out.println("\tID     : " + ID);
		}
	}

अब यदि हम इस Class के Object Create करना चाहें, तो Object Create करते ही उसे निम्नानुसार Initialize भी कर सकते हैं:

        Employee you = new Employee(1000, “Mohan”);

चूंकि हम जानते हैं कि Constructor एक ऐसा Method होता है, जिसका वही नाम होता है, जो उस Method की Class का नाम होता है, जिसमें Method Define किया जाता है। जब हम इस प्रकार का Statement लिखते हैं तब Compiler you Object को Create करते समय Employee Class के 2-Argument Constructor को Call करता है और you Object के दोनों Data Members को वे मान Initialize कर देता है, जो मान Arguments के रूप में Object Create करते समय Pass किए जाते हैं।

अब यदि हम इस Employee Class को Extend करें तो Extend होने वाली Class में भी हम Constructor Define कर सकते हैं। यानी यदि हम इस Modified Employee Class के आधार पर Scientist Class को भी Modify करें, तो इस Class को भी हम निम्नानुसार Define कर सकते हैं:

	class Scientist extends Employee
	{
		private float salary;	
	
		Scientist(int empID, String empName, float sciSalary)
		{
			super(empID, empName);
			salary = sciSalary;
		}
	
		public void showData()
		{
			super.showData();
			System.out.println("\tSalary : " + salary);
		}
	}

इस Class में हमने फिर से super Keyword का प्रयोग किया है, लेकिन चूंकि इस बार super Keyword से हमें Super Class के किसी Method को Call नहीं करना है, इसलिए इसे अकेले ही Use किया है। हम देख सकते हैं कि ये भी एक तरह का Method ही है, क्योंकि इसके आगे एक Parenthesis है जिसमें दो Arguments Pass किए गए हैं। इस Method को जावा में super() Method कहा जाता है और इस Method को तभी Use किया जाता है, जब हमें किसी Sub Class में उस Sub Class की Super Class के Constructor को Call करना होता है।

Scientist Class में ये super() Method Super Class Employee के Constructor को Call कर रहा है। यदि हम चाहें तो अब एक main() Method Class को निम्नानुसार Define कर सकते हैं, जिसमें दोनों ही Class के Objects Create हो रहे हैं और उनके मान Initialize व Display हो रहे हैं:

	class ConstructorInheritance
	{
		public static void main(String args[])
		{
			Employee you = new Employee(1000, "Mohan");
			Scientist me = new Scientist(2000, "Govind", 15000);
	
			System.out.println("Your Information");
			you.showData();
	
			System.out.println("\nMy Information");
			me.showData();
		}
	}

इस Program का भी हमें वही Output प्राप्त होता है, जो पिछले Program का हो रहा है। इस Program में हमनें Employee Class व Scientist Class दोनों Classes के ही एक-एक Object Create किए हैं। जब हम Employee Class का Object Create करते हैं, तब चूंकि Employee Class में दो ही Data Members हैं, इसलिए हमें Employee Class के Constructor में केवल दो ही मान देने होते हैं, लेकिन जब हम Scientist Class का Object Create करते हैं, तब हमें उसके Constructor में तीन Arguments Pass करने होते हैं।

जब हम Scientist Sub Class का Object Create करते हैं, तब इस Class का 3-Argument Constructor Execute होता है, जो कि निम्नानुसार है:

	Scientist(int empID, String empName, float sciSalary)
	{
		super(empID, empName);
		salary = sciSalary;
	}

इस Constructor के पहले Statement के रूप में इसकी Super Class के Constructor को super() Method का प्रयोग करके Call किया गया है। चूंकि Super Class के Constructor को हमें दो मान Pass करने होते हैं, वही दोनों मान हम super() Method में Argument के रूप में दे देते हैं। Super Class के Data Members Initialize होने के बाद Sub Class के Data Members Initialize होते हैं।

एक बात हमेंशा ध्‍यान रखें कि Inheritance की Hierarchy में हमेंशा सबसे पहले Super Class का Constructor Execute होता है। इसलिए किसी भी Sub Class Constructor में हमें हमेंशा super() Method को सबसे पहले Statement के रूप में Define करना जरूरी होता है।

 यदि हम ऐसा नहीं करते हैं, तो Compiler Error Generate करता है, क्योंकि जावा में Internally भी सबसे पहले Super Class का Constructor Execute होता है और Super Class के Data Members Initialize होने के बाद उसकी Sub Classes के Data Members Initialize होते हैं।

यानी यदि हम उपरोक्त Code Segment में निम्नानुसार परिवर्तन करके पहले Sub Class के salary Data Member को Initialize कर दें:

	Scientist(int empID, String empName, float sciSalary)
	{
		salary = sciSalary;
		super(empID, empName);
	}

तो जावा Compiler हमें निम्नानुसार Error Message प्रदान करता है, जो हमें बताता है कि super() Method को हमेंशा पहले Statement के रूप में लिखा जाना चाहिए।

D:\Java\ConstructorInheritance.java:25: cannot resolve symbol
symbol  : constructor Employee  ()
location: class Employee
        {
        ^
D:\Java\ConstructorInheritance.java:27: call to super must be first statement in constructor
                super(empID, empName);
                     ^
2 errors

जब हम किसी Class में कोई Constructor Define नहीं करते हैं, तब भी जावा हमें एक No-Argument Constructor प्रदान करता है, जिसे Default Constructor कहते हैं। इसी वजह से हमने बिना किसी Constructor को Define किए हुए भी InheritanceDemo Class के Program में Employee व Scientist Class के Objects youme को निम्नानुसार Create कर लिया था:

Employee you = new Employee()     // No-Argument Constructor
Scientist me = new Scientist()           // No-Argument Constructor

लेकिन जब हम किसी भी Class में कोई भी ऐसा Constructor बना देते हैं, जिसमें n Arguments हों, तो Constructor Define करने के बाद जावा हमें Default Constructor नहीं देता है। इस स्थिति में Default Constructor भी हमें ही बनाना पडता है।

उदाहरण के लिए पिछले Program में Super Class Employee में हमने एक 2-Argument Constructor Define किया है, जबकि Sub Class Scientist में हमने एक 3-Argument Constructor Define किया है। इस स्थिति में दोनों ही Super व Sub Classes को जावा Default Constructor प्रदान नहीं करता है। इसलिए अब यदि हम निम्नानुसार Program Create करके Compiler करें, तो जावा Compiler हमें अग्रानुसार Error प्रदान करता है:

// Program
	class ConstructorInheritance
	{
		public static void main(String args[])
		{
			Employee you = new Employee();
			Scientist me = new Scientist();
	
			System.out.println("Your Information");
			you.showData();
	
			System.out.println("\nMy Information");
			me.showData();
		}
	}

// Output 
   D:\Java\ConstructorInheritance.java:41: cannot resolve symbol
   symbol  : constructor Employee  ()
   location: class Employee
                Employee you = new Employee();
                               ^
   D:\Java\ConstructorInheritance.java:42: cannot resolve symbol
   symbol  : constructor Scientist  ()
   location: class Scientist
                Scientist me = new Scientist();
                               ^
		2 errors

Error के Output में हम देख सकते हैं कि दोनों ही Errors में Compiler हमें बता रहा है कि उसे Default Constructor नहीं मिल रहा है। यदि हम इस Program को भी ठीक तरह से Run करवाना चाहते हैं, तो हमें Super Class व Sub Class दोनों में ही एक No-Argument Constructor Define करना होगा। यानी हमें दोनों ही Classes में निम्नानुसार परिवर्तन करना होगा:

// Program 
	class Employee
	{
		private int ID;	
		private String name;	
	
		Employee() {}					// No-Argument Constructor
		Employee(int empID, String empName)		// 2-Argument Constructor
		{
			ID = empID;
			name = empName;
		}
		public void showData()
		{
			System.out.println("\tName   : " + name);
			System.out.println("\tID     : " + ID);
		}
	}
	
	class Scientist extends Employee
	{
		private float salary;	
	
		Scientist() {} 						//No-Argument Constructor
		Scientist(int empID, String empName, float sciSalary) 	//3-Argument Constructor
		{
			super(empID, empName);
			salary = sciSalary;
		}
		public void showData()
		{
			super.showData();
			System.out.println("\tSalary : " + salary);
		}
	}
	
	class ConstructorInheritance
	{
		public static void main(String args[])
		{
			Employee you = new Employee();
			Scientist me = new Scientist();
			System.out.println("Your Information");
			you.showData();
			System.out.println("\nMy Information");
			me.showData();
		}
	}

// Output 
   Your Information
        Name   : null
        ID     : 0

   My Information
        Name   : null
        ID     : 0
        Salary : 0.0

चूंकि Object Create करने के लिए हमने No-Argument Constructor का प्रयोग किया है, इसीलिए youme दोनों ही Objects Un-Initialized हैं और जब जावा में कोई Class Data Member Un-Initialized रहता है, तब वह Default मानों से Initialize हो जाता है। इसीलिए इस Program के Output में हमें उपरोक्त Information प्राप्त हो रही है।

जब हम किसी Class को Extend करते हैं, तब Extend होने वाली Sub Class व उसकी Super Class के बीच में “Kind Of” Relationship होती है। यानी हम ये भी कह सकते हैं कि%

      Sub Class is a “Kind Of” Super Class

और क्योंकि एक Super Class Object Super Class के किसी भी दूसरे Object को Refer कर सकता है, क्योंकि एक ही Class के सभी Objects समान Type के या समान प्रकार के (“Kind Of”) होते हैं, इसीलिए Super Class का Object Sub Class के Object को भी Refer कर सकता है। क्योंकि Sub Class का Object भी एक प्रकार का (“Kind Of”) Super Class का Object ही होता है।

लेकिन एक Sub Class का Object कभी भी अपनी Super Class के Object को Refer नहीं कर सकता है, क्योंकि हर Sub Class Type का Object अपनी Super Class Type का नहीं होता है। जबकि हर Super Class Type का Object अपनी Sub Class Type का Object तो होता ही है। क्योंकि हर Sub Class में उसकी Super Class के सभी गुण होते ही हैं, लेकिन हर Super Class में उसकी किसी भी Sub Class के सभी गुण नहीं हो सकते हैं।

यदि हम बहुत ही सरल शब्दों में इस Concept को कहें तो हम ये कह सकते हैं कि एक Super Class का Object अपनी Sub Class के किसी Object को Refer कर सकता है, लेकिन Sub Class का कोई भी Object अपनी Super Class को Refer नहीं कर सकता है।

इसी तरह से किसी भी Method में किसी Parameter के रूप में यदि किसी Super Class के Object की जरूरत हो तो हम उस Parameter में Argument के रूप में उसकी Sub Class के Object को Pass कर सकते हैं, क्योंकि Super Class का Object Sub Class के Object को Refer कर सकता है।

लेकिन यदि किसी Method में Parameter के रूप में किसी Sub Class के Object की जरूरत हो, तो हम उसकी Super Class के Object को Parameter में Argument के रूप में Pass नहीं कर सकते हैं, क्योंकि Sub Class का Object Super Class के Object को Refer नहीं कर सकता है। इस Concept को हम निम्न Program द्वारा समझ सकते हैं:

// Program
	class Box 
	{
		double width;
		double height;
		double length;
		
		Box(double wid, double hei, double len)
		{
			width = wid;
			height = hei;
			length = len;
		}
		void getData()
		{
			System.out.println("Width = " + width);	
			System.out.println("height = " + height);
			System.out.println("length = " + length);
		}
		double getVolume()
		{
			return width * height * length;
		}
	}
	
	class DerivedBox extends Box
	{
		double weight;
		
		DerivedBox(double wid, double hei, double len, double wei)
		{
			super(wid, hei, len);
			weight = wei;
		}
		public void getData()
		{
			super.getData();
			System.out.println("Weight = " + weight);		
		}
	}
	
	class DerivedBoxDemonstration
	{
		public static void main(String args[])
		{
			Box cpuCabinet = new Box(10, 20, 30);
			DerivedBox hardDisk = new DerivedBox(1, 2, 3, 4);
			
			double cpuCabinetVolume;
			double hardDiskVolume;
			
			cpuCabinetVolume = cpuCabinet.getVolume();
			System.out.println("CPU Cabinet Volume = " + cpuCabinetVolume);
			cpuCabinet.getData();
	
			cpuCabinet = hardDisk;
			hardDiskVolume = cpuCabinet.getVolume();
			System.out.println("Hard Disk Volume = " + hardDiskVolume);		
			hardDisk.getData();
		}
	}

// Output 
   CPU Cabinet Volume = 6000.0
      Width = 10.0
      height = 20.0
      length = 30.0

   Hard Disk Volume = 6.0
      Width = 1.0
      height = 2.0
      length = 3.0
      Weight = 4.0

main() Method Class में हमने Box Class का एक Object cpuCabinet व DerivedBox Class का एक Object hardDisk Create किया है। साथ ही दोनों को Initialize भी किया है। फिर double प्रकार के दो Variables cpuCabinet व hardDisk दोनों Objects के Volume को Hold करने के लिए Define किया है। फिर cpuCabinet का Volume Calculate करने के लिए हमने Box Class के Method getVolume() को cpuCabinet के साथ Call किया है।

चूंकि cpuCabinet Box Class का ही Object है, इसलिए हम इसके साथ getVolume() Method को Call कर सकते हैं। फिर हमने Box Class के Object cpuCabinet के Dimensions प्राप्त करने के लिए getData() Method को Call किया है। अगले Statement में हमने Box Class के Object cpuCabinet में Box Class की Sub Class DerivedBox Class के Object hardDisk का Reference निम्नानुसार Statement द्वारा प्रदान किया है:

        cpuCabinet = hardDisk;

हम ऐसा इसलिए कर सकते हैं क्योंकि DerivedBox Class Box Class के प्रकार (“Kind Of”) की ही है। जब हम ऐसा करते हैं, तब वास्तव में hardDisk Object को cpuCabinet Object द्वारा Refer कर सकते हैं और hardDisk Object के लिए जो कि Box Class की Sub Class का Object हैं, Box Class के Methods को Call कर सकते हैं।

चूंकि हमनें Sub Class में getVolume() नाम का Method Create नहीं किया है, फिर भी हम Super Class Box के getVolume() Method का प्रयोग करके Sub Class DerivedBox के Object का Volume भी ज्ञात कर सकते हैं, जैसाकि इस Program के अगले Statement में किया गया है।

cpuCabinetVolume = cpuCabinet.getVolume();

cpuCabinet = hardDisk;
hardDiskVolume = cpuCabinet.getVolume();

इन दोनों Statement में हम देख सकते हैं कि हमने दोनों ही बार cpuCabinet के Reference में ही getVolume() Method को Call किया है। लेकिन जब पहली बार cpuCabinet के लिए getVolume() Method को Call करते हैं, तब Box Class का getVolume() Method Super Class Box के Object cpuCabinet का Volume Calculate करता है, क्योंकि इस समय cpuCabinet Object में Box Class के Object का Reference है।

लेकिन जैसे ही हम Box Class के cpuCabinet Object में DerivedBox Sub Class के hardDisk Object का Reference देते हैं, cpuCabinet नाम का Super Class का Object Sub Class के Object को Refer करने लगता है। इसलिए अब फिर से जब हम इस cpuCabinet Object के साथ Super Class के getVolume() Method को Call करते हैं, तो इस बार cpuCabinet Object Box Class के Object की Volume Calculate करने के बजाय DerivedBox Class के Object का Volume Calculate करता है।

इस Program में हम देख सकते हैं कि हमने Super Class Box के Object cpuCabinet में Sub Class DerivedBox के Object का Reference Store किया है। हम ऐसा कर सकते हैं, क्योंकि Sub Class हमेंशा “Kind Of” Super Class होता है। लेकिन यदि हम इस Statement को उल्टा करें, यानी Sub Class के Object में Super Class के Object का Reference प्रदान करें, तो जावा Compiler हमें निम्नानुसार Compile Time Error देता है:

D:\Java\DerivedBoxDemonstration.java:59: incompatible types
	found   : Box
	required: DerivedBox
	                hardDisk=cpuCabinet;
       		                  ^
	1 error

जावा Compiler हमें ये Error इसलिए देता है, क्योंकि Super Class कभी भी “Kind Of” Sub Class नहीं होती है, बल्कि Super Class Sub Class का एक Part होता है। इसलिए Super Class व Sub Class के बीच “Has A “ व “Part Of “ की Relationship बन जाती है। चूंकि हम Super Class के Object से किसी भी Sub Class Object को Refer कर सकते हैं और एक Super Class Object से ही विभिन्न प्रकार की Sub Classes के Methods को Call कर सकते हैं, इसलिए जावा में ये Process Polymorphism की सुविधा प्रदान करता है।

Multilevel Hierarchy

जावा में हम किसी Derive की गई Sub Class को फिर से Derive कर सकते हैं। जब हम किसी Derive की गई Sub Class को फिर से Derive करते हैं, तो इस Process को Multilevel Hierarchy कहा जाता है। उदाहरण के लिए जावा की सबसे Top Level की Class Object Class है। Object Class से awt Class को Inherit किया गया है। फिर awt Class से Component Class को Derive किया है। फिर Component Class से Container Class को Derive किया है। फिर Container Class से Panel Class को Derive किया है और अन्त में Panel Class से Applet Class को Derive किया है। इस तरह से हम Applet Class की Multilevel Hierarchy को समझ सकते हैं।

Constructor Calling Convention

जावा में जब हम किसी Class को Derive करते है, तो Super Class का Constructor कभी भी Sub Class में नहीं आता है। इसलिए हमें हमेंशा Sub Class के Constructor में Super Class के Constructor को Call करना पडता है। जावा Multiple Hierarchy को Support करता है। इसलिए हम चाहे किसी भी Level की Hierarchy की Class को Inherit करें, उस Inherited Class के Object Create करते ही Sub Class का Constructor Execute हो जाता है और Derived Class का Constructor Execute होते ही Super Class के Constructor को Execute करता है।

यदि हमने Sub Class में कोई Constructor नहीं बनाया है, तो Class का Default या No-Argument Constructor Execute होता है और Derived Class का Constructor Base Class या Super Class के Default Constructor को Execute कर देता है।

यानी सारांश में कहें तो हम Hierarchy में चाहे जिस Level की Class का Object Create करें, हमेंशा Hierarchy के Top Level Class का Constructor सबसे पहले Execute होता है और फिर क्रम से नीचे की Classes के Constructors Execute होते हैं।

यदि किसी Super Class में कोई n Argument Constructor हो तो हमें Sub Class में भी n Argument Constructor बनाना जरूरी हो जाता है, जबकि यदि Sub Class में कोई n Argument Constructor हो तो Super Class में n Argument Constructor का होना जरूरी नहीं होता है। जब ऐसी स्थिति होती है, तब Sub Class का तो n Argument Constructor Execute होता है लेकिन Super Class का No-Argument Constructor Execute हो जाता है।

किसी Sub Class के Constructor में Super Class के Constructor को Call करने के लिए हमें super() Method को Call करना होता है। लेकिन यदि हम किसी Sub Class Constructor में उसकी Super Class के Constructor को Call ना करें, तो भी Super Class का Default Constructor तो Execute होती ही है, साथ ही वह Sub Class के Constructor से पहले Execute होता है।

Method Overriding in Java
Runtime Polymorphism in Java - Dynamic Method Dispatch

Java Programming Language in Hindiये Article इस वेबसाईट पर Selling हेतु उपलब्‍ध EBook Java in Hindi से लिया गया है। इसलिए यदि ये Article आपके लिए उपयोगी रहा, तो निश्चित रूप से ये पुस्तक भी आपके लिए काफी उपयोगी साबित होगी। 

Java Programming Language in Hindi | Page: 682 | Format: PDF

BUY NOW GET DEMO REVIEWS