Java Language
ऑब्जेक्ट क्लास के तरीके और कंस्ट्रक्टर
खोज…
परिचय
यह प्रलेखन पृष्ठ जावा क्लास कंस्ट्रक्टर्स और ऑब्जेक्ट क्लास मेथड्स के बारे में उदाहरण के साथ विवरण दिखाने के लिए है जो स्वचालित रूप से किसी भी नए बनाए गए वर्ग के सुपरक्लास Object
से विरासत में मिले हैं।
वाक्य - विन्यास
- सार्वजनिक अंतिम मूल वर्ग <!> getClass ()
- सार्वजनिक अंतिम देशी शून्य सूचित ()
- सार्वजनिक अंतिम देशी शून्य InformAll ()
- सार्वजनिक अंतिम देशी शून्य प्रतीक्षा (लंबे समय तक) इंटरप्टेड अपवाद को फेंकता है
- सार्वजनिक अंतिम शून्य प्रतीक्षा () इंटरप्टेड अपवाद को फेंकता है
- सार्वजनिक अंतिम शून्य प्रतीक्षा (लंबे समय तक, इंट नेनोस) रुकावट को बाधित करता है
- सार्वजनिक देशी इंट हैशकोड ()
- सार्वजनिक बूलियन बराबर (ऑब्जेक्ट obj)
- सार्वजनिक स्ट्रिंग toString ()
- संरक्षित मूल वस्तु क्लोन () CloneNotSupportedException फेंकता है
- संरक्षित शून्य को अंतिम रूप दें () फेंकता है
.String () विधि
toString()
विधि का उपयोग ऑब्जेक्ट की सामग्री का उपयोग करके किसी ऑब्जेक्ट का String
प्रतिनिधित्व बनाने के लिए किया जाता है। अपनी कक्षा लिखते समय इस पद्धति को ओवरराइड किया जाना चाहिए। जब किसी वस्तु को "hello " + anObject
रूप में स्ट्रिंग में "hello " + anObject
जाता है, तो toString()
को स्पष्ट रूप से कहा जाता है।
निम्नलिखित को धयान मे रखते हुए:
public class User {
private String firstName;
private String lastName;
public User(String firstName, String lastName) {
this.firstName = firstName;
this.lastName = lastName;
}
@Override
public String toString() {
return firstName + " " + lastName;
}
public static void main(String[] args) {
User user = new User("John", "Doe");
System.out.println(user.toString()); // Prints "John Doe"
}
}
यहाँ Object
क्लास से toString()
को प्रिंट करते समय ऑब्जेक्ट के बारे में सार्थक डेटा प्रदान करने के लिए User
वर्ग में ओवरराइड किया जाता है।
println()
का उपयोग करते समय, ऑब्जेक्ट के toString()
विधि को स्पष्ट रूप से कहा जाता है। इसलिए, ये कथन समान कार्य करते हैं:
System.out.println(user); // toString() is implicitly called on `user`
System.out.println(user.toString());
यदि उपर्युक्त User
वर्ग में User@659e0bfd
toString()
को ओवरराइड नहीं किया गया है, तो User@659e0bfd
System.out.println(user)
User@659e0bfd
या समान स्ट्रिंग के साथ लगभग कोई उपयोगी जानकारी नहीं दे सकता है सिवाय वर्ग नाम के। ऐसा इसलिए होगा क्योंकि कॉल बेस जावा Object
क्लास के toString()
कार्यान्वयन का उपयोग करेगा जो User
वर्ग की संरचना या व्यावसायिक नियमों के बारे में कुछ भी नहीं जानता है। यदि आप अपनी कक्षा में इस कार्यक्षमता को बदलना चाहते हैं, तो केवल विधि को ओवरराइड करें।
बराबर () विधि
टी एल; डॉ
==
संदर्भ समानता के लिए परीक्षण (चाहे वे एक ही वस्तु हों )
.equals()
मूल्य समानता के लिए परीक्षण (चाहे वे तार्किक रूप से "समान" हों )
equals()
समानता के लिए दो वस्तुओं की तुलना करने के लिए उपयोग की जाने वाली विधि है। Object
क्लास में equals()
विधि का डिफ़ॉल्ट क्रियान्वयन true
और तभी होता है जब दोनों संदर्भ एक ही उदाहरण की ओर इशारा करते हैं। इसलिए यह ==
द्वारा तुलना के समान व्यवहार करता है।
public class Foo {
int field1, field2;
String field3;
public Foo(int i, int j, String k) {
field1 = i;
field2 = j;
field3 = k;
}
public static void main(String[] args) {
Foo foo1 = new Foo(0, 0, "bar");
Foo foo2 = new Foo(0, 0, "bar");
System.out.println(foo1.equals(foo2)); // prints false
}
}
भले ही foo1
और foo2
एक ही फ़ील्ड के साथ बनाए गए हैं, लेकिन वे दो अलग-अलग ऑब्जेक्ट्स को मेमोरी में इंगित कर रहे हैं। डिफ़ॉल्ट equals()
कार्यान्वयन इसलिए false
मूल्यांकन करता false
।
समानता के लिए किसी वस्तु की सामग्री की तुलना करने के लिए, equals()
को ओवरराइड करना पड़ता है।
public class Foo {
int field1, field2;
String field3;
public Foo(int i, int j, String k) {
field1 = i;
field2 = j;
field3 = k;
}
@Override
public boolean equals(Object obj) {
if (this == obj) {
return true;
}
if (obj == null || getClass() != obj.getClass()) {
return false;
}
Foo f = (Foo) obj;
return field1 == f.field1 &&
field2 == f.field2 &&
(field3 == null ? f.field3 == null : field3.equals(f.field3));
}
@Override
public int hashCode() {
int hash = 1;
hash = 31 * hash + this.field1;
hash = 31 * hash + this.field2;
hash = 31 * hash + (field3 == null ? 0 : field3.hashCode());
return hash;
}
public static void main(String[] args) {
Foo foo1 = new Foo(0, 0, "bar");
Foo foo2 = new Foo(0, 0, "bar");
System.out.println(foo1.equals(foo2)); // prints true
}
}
यहां ओवरराइड equals()
विधि तय करती है कि वस्तुएं समान हैं यदि उनके क्षेत्र समान हैं।
ध्यान दें कि hashCode()
विधि भी अधिलेखित थी। उस पद्धति का अनुबंध बताता है कि जब दो वस्तुएं समान होती हैं, तो उनके हैश मान भी समान होने चाहिए। यही कारण है कि एक साथ लगभग हमेशा hashCode()
और equals()
ओवरराइड करना चाहिए।
equals
पद्धति के तर्क प्रकार पर विशेष ध्यान दें। यह Object obj
, Foo obj
नहीं। यदि आप अपने तरीके से उत्तरार्द्ध डालते हैं, तो यह equals
पद्धति का ओवरराइड नहीं है।
अपनी कक्षा लिखते समय, समान equals()
और hashCode()
ओवरराइड करते समय आपको समान तर्क लिखना होगा। अधिकांश आईडीई स्वचालित रूप से आपके लिए इसे उत्पन्न कर सकते हैं।
एक equals()
कार्यान्वयन का एक उदाहरण String
क्लास में पाया जा सकता है, जो कोर जावा एपीआई का हिस्सा है। बल्कि संकेत की तुलना की तुलना में, String
वर्ग की सामग्री की तुलना String
।
जावा 1.7 ने java.util.Objects
क्लास की शुरुआत की, जो एक सुविधा पद्धति प्रदान करता है, जो equals
, जो दो संभावित null
संदर्भों की तुलना करता है, इसलिए इसका उपयोग equals
पद्धति के कार्यान्वयन को सरल बनाने के लिए किया जा सकता है।
@Override
public boolean equals(Object obj) {
if (this == obj) {
return true;
}
if (obj == null || getClass() != obj.getClass()) {
return false;
}
Foo f = (Foo) obj;
return field1 == f.field1 && field2 == f.field2 && Objects.equals(field3, f.field3);
}
कक्षा की तुलना
चूँकि समान पद्धति किसी भी वस्तु के विरुद्ध चल सकती है, पहली चीज़ जो विधि अक्सर करती है ( null
लिए जाँच करने के बाद) यह जाँचना है कि वस्तु के वर्ग की तुलना वर्तमान वर्ग से की जाती है या नहीं।
@Override
public boolean equals(Object obj) {
//...check for null
if (getClass() != obj.getClass()) {
return false;
}
//...compare fields
}
यह आमतौर पर कक्षा की वस्तुओं की तुलना करके ऊपर किया जाता है। हालाँकि, यह कुछ विशेष मामलों में विफल हो सकता है जो स्पष्ट नहीं हो सकता है। उदाहरण के लिए, कुछ चौखटे कक्षाओं की गतिशील परदे के पीछे उत्पन्न करते हैं और ये गतिशील परदे के पीछे वास्तव में एक अलग वर्ग हैं। यहां जेपीए का उपयोग करके एक उदाहरण दिया गया है।
Foo detachedInstance = ...
Foo mergedInstance = entityManager.merge(detachedInstance);
if (mergedInstance.equals(detachedInstance)) {
//Can never get here if equality is tested with getClass()
//as mergedInstance is a proxy (subclass) of Foo
}
उस सीमा के आसपास काम करने के लिए एक तंत्र instanceof
का उपयोग करके कक्षाओं की तुलना करना है
@Override
public final boolean equals(Object obj) {
if (!(obj instanceof Foo)) {
return false;
}
//...compare fields
}
हालांकि, वहाँ कुछ नुकसान है कि जब का उपयोग कर से बचना अनिवार्य हैं instanceof
। चूंकि फू में संभावित रूप से अन्य उपवर्ग हो सकते हैं और वे उपवर्ग equals()
हो सकते हैं equals()
आप एक ऐसे मामले में आ सकते हैं जहां एक Foo
एक FooSubclass
बराबर है लेकिन FooSubclass
Foo
बराबर नहीं है।
Foo foo = new Foo(7);
FooSubclass fooSubclass = new FooSubclass(7, false);
foo.equals(fooSubclass) //true
fooSubclass.equals(foo) //false
यह समरूपता और संक्रामकता के गुणों का उल्लंघन करता है और इस प्रकार equals()
पद्धति का एक अमान्य कार्यान्वयन है। नतीजतन, instanceof
, एक अच्छा अभ्यास equals()
विधि को final
बनाने के लिए equals()
उपरोक्त उदाहरण के रूप में)। यह सुनिश्चित करेगा कि कोई भी उपवर्ग equals()
नहीं equals()
और महत्वपूर्ण धारणाओं का उल्लंघन करता है।
हैशकोड () विधि
एक जावा वर्ग को ओवरराइड करता है जब equals
विधि, यह ओवरराइड करना चाहिए hashCode
विधि के रूप में अच्छी तरह से। जैसा कि विधि के अनुबंध में परिभाषित किया गया है :
- जब भी जावा एप्लिकेशन के निष्पादन के दौरान इसे एक से अधिक बार एक ही ऑब्जेक्ट पर लागू किया जाता है, तो
hashCode
विधि को लगातार एक ही पूर्णांक को वापस करना चाहिए, बशर्ते वस्तु पर तुलना में उपयोग की गई कोई भी जानकारी संशोधित न हो। इस पूर्णांक को एक एप्लिकेशन के एक निष्पादन से एक ही एप्लिकेशन के दूसरे निष्पादन के अनुरूप नहीं रहना चाहिए।- यदि दो ऑब्जेक्ट समान
equals(Object)
विधि के अनुसार समान हैं, तो दो ऑब्जेक्ट्स में से प्रत्येक परhashCode
विधि को कॉल करके एक ही पूर्णांक परिणाम का उत्पादन करना होगा।- यह आवश्यक नहीं है कि यदि दो वस्तुएं
equals(Object)
विधि के अनुसार असमान हैं, तो दो वस्तुओं में से प्रत्येक परhashCode
विधि को कॉल करके अलग पूर्णांक परिणाम उत्पन्न करना होगा। हालांकि, प्रोग्रामर को यह पता होना चाहिए कि असमान वस्तुओं के लिए अलग पूर्णांक परिणाम बनाने से हैश तालिकाओं के प्रदर्शन में सुधार हो सकता है।
हैश कोड का उपयोग हैश कार्यान्वयन में किया जाता है जैसे कि HashMap
, HashTable
और HashSet
। hashCode
फ़ंक्शन का परिणाम उस बाल्टी को निर्धारित करता है जिसमें कोई ऑब्जेक्ट डाला जाएगा। यदि उपलब्ध hashCode
कार्यान्वयन अच्छा हो तो ये हैश कार्यान्वयन अधिक कुशल होते हैं। अच्छे hashCode
कार्यान्वयन की एक महत्वपूर्ण संपत्ति यह है कि hashCode
मानों का वितरण एक समान है। दूसरे शब्दों में, एक छोटी सी संभावना है कि एक ही बाल्टी में कई उदाहरण संग्रहीत किए जाएंगे।
हैश कोड मान कंप्यूटिंग के लिए एक एल्गोरिथ्म निम्नलिखित के समान हो सकता है:
public class Foo {
private int field1, field2;
private String field3;
public Foo(int field1, int field2, String field3) {
this.field1 = field1;
this.field2 = field2;
this.field3 = field3;
}
@Override
public boolean equals(Object obj) {
if (this == obj) {
return true;
}
if (obj == null || getClass() != obj.getClass()) {
return false;
}
Foo f = (Foo) obj;
return field1 == f.field1 &&
field2 == f.field2 &&
(field3 == null ? f.field3 == null : field3.equals(f.field3);
}
@Override
public int hashCode() {
int hash = 1;
hash = 31 * hash + field1;
hash = 31 * hash + field2;
hash = 31 * hash + (field3 == null ? 0 : field3.hashCode());
return hash;
}
}
शॉर्ट कट के रूप में Arrays.hashCode () का उपयोग करना
जावा 1.2 और इसके बाद के संस्करण में, हैश कोड की गणना करने के लिए एल्गोरिथम विकसित करने के बजाय, किसी को java.util.Arrays#hashCode
का उपयोग करके उत्पन्न किया जा सकता है। किसी ऑब्जेक्ट या प्राइमेटिव सरणी की आपूर्ति करके java.util.Arrays#hashCode
को फ़ील्ड मानों से जोड़कर:
@Override
public int hashCode() {
return Arrays.hashCode(new Object[] {field1, field2, field3});
}
जावा 1.7 ने java.util.Objects
क्लास की शुरुआत की, जो एक सुविधा पद्धति, hash(Object... objects)
करता है, जो कि आपूर्ति की गई वस्तुओं के मूल्यों के आधार पर एक हैश कोड की गणना करता है। यह तरीका सिर्फ java.util.Arrays#hashCode
तरह काम करता है। java.util.Arrays#hashCode
।
@Override
public int hashCode() {
return Objects.hash(field1, field2, field3);
}
नोट: यह दृष्टिकोण अक्षम है, और हर बार आपके कस्टम hashCode()
विधि को कचरा ऑब्जेक्ट्स कहा जाता है:
- एक अस्थायी
Object[]
बनाई गई है। (Objects.hash()
संस्करण में, सरणी "varargs" तंत्र द्वारा बनाई गई है।) - यदि कोई भी फ़ील्ड आदिम प्रकार की हैं, तो उन्हें बॉक्सिंग किया जाना चाहिए और इससे अधिक अस्थायी ऑब्जेक्ट बन सकते हैं।
- सरणी को आबाद किया जाना चाहिए।
- सरणी को
Arrays.hashCode
याObjects.hash
विधि द्वाराArrays.hashCode
:Objects.hash
किया जाना चाहिए। -
Object.hashCode()
जोArrays.hashCode
याObjects.hash
को कॉल करना है (शायद)Objects.hash
नहीं हो सकता है।
हैश कोड की आंतरिक कैशिंग
चूंकि किसी वस्तु के हैश कोड की गणना महंगी हो सकती है, इसलिए पहली बार गणना की गई वस्तु के भीतर हैश कोड मान को कैश करना आकर्षक हो सकता है। उदाहरण के लिए
public final class ImmutableArray {
private int[] array;
private volatile int hash = 0;
public ImmutableArray(int[] initial) {
array = initial.clone();
}
// Other methods
@Override
public boolean equals(Object obj) {
// ...
}
@Override
public int hashCode() {
int h = hash;
if (h == 0) {
h = Arrays.hashCode(array);
hash = h;
}
return h;
}
}
यह दृष्टिकोण हैश कोड को कैश करने के लिए एक अतिरिक्त फ़ील्ड के ओवरहेड के खिलाफ हैश कोड की गणना (बार-बार) की लागत से ट्रेड करता है। क्या यह प्रदर्शन अनुकूलन के रूप में भुगतान करता है, इस बात पर निर्भर करेगा कि किसी दिए गए ऑब्जेक्ट को कितनी बार हैशेड (देखा गया) और अन्य कारक हैं।
आप यह भी देखेंगे कि अगर एक का सच hashCode ImmutableArray
शून्य (2 32 में एक मौका) होता है, कैश अप्रभावी है।
अंत में, यह दृष्टिकोण सही ढंग से लागू करने के लिए बहुत कठिन है यदि हम जिस वस्तु को हैशिंग करते हैं वह परिवर्तनशील है। हालाँकि, हैश कोड बदलने पर बड़ी चिंताएँ हैं; ऊपर अनुबंध देखें।
प्रतीक्षा () और सूचित () तरीके
wait()
और notify()
काम करते हैं - जब कोई थ्रेड किसी ऑब्जेक्ट पर wait()
कॉल करता है, तो वह थ्रेड तब तक ब्लॉक रहेगा जब तक कि कोई अन्य थ्रेड कॉल्स notify()
या notifyAll()
उसी ऑब्जेक्ट पर।
(यह भी देखें: प्रतीक्षा करें () / सूचना () )
package com.example.examples.object;
import java.util.concurrent.atomic.AtomicBoolean;
public class WaitAndNotify {
public static void main(String[] args) throws InterruptedException {
final Object obj = new Object();
AtomicBoolean aHasFinishedWaiting = new AtomicBoolean(false);
Thread threadA = new Thread("Thread A") {
public void run() {
System.out.println("A1: Could print before or after B1");
System.out.println("A2: Thread A is about to start waiting...");
try {
synchronized (obj) { // wait() must be in a synchronized block
// execution of thread A stops until obj.notify() is called
obj.wait();
}
System.out.println("A3: Thread A has finished waiting. "
+ "Guaranteed to happen after B3");
} catch (InterruptedException e) {
System.out.println("Thread A was interrupted while waiting");
} finally {
aHasFinishedWaiting.set(true);
}
}
};
Thread threadB = new Thread("Thread B") {
public void run() {
System.out.println("B1: Could print before or after A1");
System.out.println("B2: Thread B is about to wait for 10 seconds");
for (int i = 0; i < 10; i++) {
try {
Thread.sleep(1000); // sleep for 1 second
} catch (InterruptedException e) {
System.err.println("Thread B was interrupted from waiting");
}
}
System.out.println("B3: Will ALWAYS print before A3 since "
+ "A3 can only happen after obj.notify() is called.");
while (!aHasFinishedWaiting.get()) {
synchronized (obj) {
// notify ONE thread which has called obj.wait()
obj.notify();
}
}
}
};
threadA.start();
threadB.start();
threadA.join();
threadB.join();
System.out.println("Finished!");
}
}
कुछ उदाहरण आउटपुट:
A1: Could print before or after B1
B1: Could print before or after A1
A2: Thread A is about to start waiting...
B2: Thread B is about to wait for 10 seconds
B3: Will ALWAYS print before A3 since A3 can only happen after obj.notify() is called.
A3: Thread A has finished waiting. Guaranteed to happen after B3
Finished!
B1: Could print before or after A1
B2: Thread B is about to wait for 10 seconds
A1: Could print before or after B1
A2: Thread A is about to start waiting...
B3: Will ALWAYS print before A3 since A3 can only happen after obj.notify() is called.
A3: Thread A has finished waiting. Guaranteed to happen after B3
Finished!
A1: Could print before or after B1
A2: Thread A is about to start waiting...
B1: Could print before or after A1
B2: Thread B is about to wait for 10 seconds
B3: Will ALWAYS print before A3 since A3 can only happen after obj.notify() is called.
A3: Thread A has finished waiting. Guaranteed to happen after B3
Finished!
getClass () विधि
getClass()
विधि का उपयोग किसी ऑब्जेक्ट के रनटाइम क्लास प्रकार को खोजने के लिए किया जा सकता है। नीचे दिए गए उदाहरण देखें:
public class User {
private long userID;
private String name;
public User(long userID, String name) {
this.userID = userID;
this.name = name;
}
}
public class SpecificUser extends User {
private String specificUserID;
public SpecificUser(String specificUserID, long userID, String name) {
super(userID, name);
this.specificUserID = specificUserID;
}
}
public static void main(String[] args){
User user = new User(879745, "John");
SpecificUser specificUser = new SpecificUser("1AAAA", 877777, "Jim");
User anotherSpecificUser = new SpecificUser("1BBBB", 812345, "Jenny");
System.out.println(user.getClass()); //Prints "class User"
System.out.println(specificUser.getClass()); //Prints "class SpecificUser"
System.out.println(anotherSpecificUser.getClass()); //Prints "class SpecificUser"
}
getClass()
विधि सबसे विशिष्ट वर्ग प्रकार को anotherSpecificUser
, यही कारण है कि जब getClass()
को anotherSpecificUser
पर कॉल किया जाता है, तो रिटर्न मान class SpecificUser
क्योंकि यह User
तुलना में वंशानुक्रम का पेड़ कम होता है।
यह उल्लेखनीय है कि, जबकि getClass
विधि के रूप में घोषित किया गया है:
public final native Class<?> getClass();
getClass
को कॉल करके वास्तविक स्थिर प्रकार लौटाया गया है Class<? extends T>
जहां T
ऑब्जेक्ट का स्थिर प्रकार है जिस पर getClass
कहा जाता है।
अर्थात निम्नलिखित संकलन होगा:
Class<? extends String> cls = "".getClass();
क्लोन () विधि
किसी ऑब्जेक्ट की प्रतिलिपि बनाने और वापस करने के लिए clone()
विधि का उपयोग किया जाता है। इस पद्धति को तर्कपूर्ण रूप से टाला जाना चाहिए क्योंकि यह समस्याग्रस्त है और प्रतिलिपि बनाने वाले या प्रतिलिपि के लिए कुछ अन्य दृष्टिकोण का उपयोग clone()
पक्ष में किया जाना चाहिए।
विधि का उपयोग करने के लिए सभी वर्गों को कॉल करने की विधि को Cloneable
करने Cloneable
इंटरफ़ेस को लागू करना होगा।
Cloneable
इंटरफ़ेस स्वयं एक टैग इंटरफ़ेस है जिसका उपयोग native
clone()
पद्धति के व्यवहार को बदलने के लिए किया जाता है जो यह जांचता है कि क्या कॉलिंग ऑब्जेक्ट क्लास को लागू Cloneable
। यदि कॉलर इस इंटरफ़ेस को लागू नहीं करता है तो CloneNotSupportedException
को फेंक दिया जाएगा।
Object
वर्ग ही इस इंटरफ़ेस को लागू नहीं करता है तो एक CloneNotSupportedException
अगर बुला वस्तु वर्ग की है फेंक दिया जाएगा Object
।
किसी क्लोन के सही होने के लिए उसे उस वस्तु से स्वतंत्र होना चाहिए जिस पर से क्लोन किया जा रहा है, इसलिए वापस आने से पहले वस्तु को संशोधित करना आवश्यक हो सकता है। इसका मतलब यह है कि अनिवार्य रूप से किसी भी उत्परिवर्तित वस्तुओं को कॉपी करके एक "गहरी प्रतिलिपि" बनाना है जो ऑब्जेक्ट की आंतरिक संरचना को बंद कर देता है। यदि इसे सही ढंग से कार्यान्वित नहीं किया गया है, तो क्लोन की गई वस्तु स्वतंत्र नहीं होगी और उस वस्तु के रूप में उत्परिवर्तित वस्तुओं के समान संदर्भ होंगे, जिससे इसे क्लोन किया गया था। इसके परिणामस्वरूप असंगत व्यवहार होगा क्योंकि एक में उन लोगों के लिए कोई भी परिवर्तन दूसरे को प्रभावित करेगा।
class Foo implements Cloneable {
int w;
String x;
float[] y;
Date z;
public Foo clone() {
try {
Foo result = new Foo();
// copy primitives by value
result.w = this.w;
// immutable objects like String can be copied by reference
result.x = this.x;
// The fields y and z refer to a mutable objects; clone them recursively.
if (this.y != null) {
result.y = this.y.clone();
}
if (this.z != null) {
result.z = this.z.clone();
}
// Done, return the new object
return result;
} catch (CloneNotSupportedException e) {
// in case any of the cloned mutable fields do not implement Cloneable
throw new AssertionError(e);
}
}
}
अंतिम रूप () विधि
यह Object
क्लास का एक संरक्षित और गैर-स्थिर तरीका है। इस विधि का उपयोग किसी अंतिम ऑपरेशन को करने के लिए किया जाता है या मेमोरी से हटाए जाने से पहले किसी ऑब्जेक्ट पर संचालन को साफ करने के लिए।
डॉक के अनुसार, यह विधि किसी ऑब्जेक्ट पर कचरा संग्रहकर्ता द्वारा कॉल की जाती है जब कचरा संग्रह निर्धारित करता है कि ऑब्जेक्ट के लिए अधिक संदर्भ नहीं हैं।
लेकिन इस बात की कोई गारंटी नहीं है कि finalize()
विधि कहा जाता है यदि ऑब्जेक्ट अभी भी उपलब्ध है या ऑब्जेक्ट के योग्य होने पर कोई कचरा संग्राहक नहीं चलता है। इसलिए यह बेहतर है कि इस पद्धति पर भरोसा न करें।
जावा कोर पुस्तकालयों में कुछ उदाहरण उदाहरण मिल सकते हैं, उदाहरण के लिए FileInputStream.java
:
protected void finalize() throws IOException {
if ((fd != null) && (fd != FileDescriptor.in)) {
/* if fd is shared, the references in FileDescriptor
* will ensure that finalizer is only called when
* safe to do so. All references using the fd have
* become unreachable. We can call close()
*/
close();
}
}
इस मामले में यह संसाधन को बंद करने का अंतिम मौका है यदि उस संसाधन को पहले बंद नहीं किया गया है।
आमतौर पर इसे किसी भी तरह के अनुप्रयोगों में finalize()
पद्धति का उपयोग करने के लिए बुरा अभ्यास माना जाता है और इससे बचना चाहिए।
फाइनलर्स संसाधनों को मुक्त करने के लिए नहीं हैं (उदाहरण के लिए, फाइलें बंद करना)। कचरा इकट्ठा करने वाले को तब बुलाया जाता है जब (अगर!) सिस्टम ढेर स्थान पर कम चलता है। जब सिस्टम फ़ाइल हैंडल पर कम चल रहा हो या किसी अन्य कारण से आप इसे कॉल करने के लिए भरोसा नहीं कर सकते।
फाइनल करने वालों के लिए इच्छित उपयोग-मामला एक ऐसी वस्तु के लिए होता है, जिसे उसके आसन्न कयामत के बारे में किसी अन्य वस्तु को सूचित करने के लिए पुनः प्राप्त किया जाना है। एक बेहतर तंत्र अब उस उद्देश्य के लिए मौजूद है --- java.lang.ref.WeakReference<T>
वर्ग। अगर आपको लगता है कि आपको एक finalize()
विधि लिखने की आवश्यकता है, तो आपको इस बात पर ध्यान देना चाहिए कि क्या आप इसके बजाय WeakReference
का उपयोग करके उसी समस्या को हल कर सकते हैं। यदि वह आपकी समस्या का समाधान नहीं करेगा, तो आपको अपने डिजाइन को गहन स्तर पर फिर से सोचने की आवश्यकता हो सकती है।
आगे पढ़ने के लिए यहाँ यहोशू बलोच द्वारा "प्रभावी जावा" पुस्तक से finalize()
विधि के बारे में एक आइटम है।
ऑब्जेक्ट कंस्ट्रक्टर
जावा में सभी कंस्ट्रक्टर को Object
कंस्ट्रक्टर को कॉल करना होगा। यह कॉल super()
साथ किया जाता है। एक कंस्ट्रक्टर में यह पहली पंक्ति है। इसका कारण यह है कि वस्तु को वास्तव में ढेर पर बनाया जा सकता है इससे पहले कि कोई अतिरिक्त इनिशियलाइज़ेशन किया जाए।
यदि आप एक निर्माता में super()
को कॉल निर्दिष्ट नहीं करते हैं तो कंपाइलर इसे आपके लिए डाल देगा।
तो इन तीनों उदाहरण कार्यात्मक रूप से समान हैं
super()
कंस्ट्रक्टर को स्पष्ट कॉल के साथ
public class MyClass {
public MyClass() {
super();
}
}
super()
कंस्ट्रक्टर को निहित कॉल के साथ
public class MyClass {
public MyClass() {
// empty
}
}
निहित निर्माता के साथ
public class MyClass {
}
कंस्ट्रक्टर-चेनिंग के बारे में क्या?
अन्य रचनाकारों को एक निर्माता के पहले निर्देश के रूप में कॉल करना संभव है। जैसा कि एक सुपर कंस्ट्रक्टर को स्पष्ट कॉल और दूसरे कंस्ट्रक्टर को कॉल दोनों को पहले निर्देश होने चाहिए, वे पारस्परिक रूप से अनन्य हैं।
public class MyClass {
public MyClass(int size) {
doSomethingWith(size);
}
public MyClass(Collection<?> initialValues) {
this(initialValues.size());
addInitialValues(initialValues);
}
}
नए MyClass(Arrays.asList("a", "b", "c"))
को कॉल करके लिस्ट-तर्क के साथ दूसरे कंस्ट्रक्टर को कॉल करेंगे, जो पहले कंस्ट्रक्टर को प्रतिनिधि देगा (जो super()
को सुपरसिट करेगा super()
) और फिर सूची के दूसरे आकार के साथ addInitialValues(int size)
को कॉल करें। इसका उपयोग कोड दोहराव को कम करने के लिए किया जाता है जहां कई निर्माणकर्ताओं को समान कार्य करने की आवश्यकता होती है।
मैं एक विशिष्ट निर्माता कैसे कह सकता हूं?
ऊपर दिए गए उदाहरण को देखते हुए, कोई भी new MyClass("argument")
या new MyClass("argument", 0)
कह सकता है। दूसरे शब्दों में, विधि अधिभार की तरह, आप बस अपने चुने हुए निर्माता के लिए आवश्यक मापदंडों के साथ निर्माता को कॉल करते हैं।
ऑब्जेक्ट क्लास कंस्ट्रक्टर में क्या होगा?
सब-क्लास में इससे ज्यादा कुछ नहीं होगा जिसमें डिफॉल्ट खाली कंस्ट्रक्टर (माइनस टू कॉल टू super()
) हो।
डिफ़ॉल्ट खाली कंस्ट्रक्टर को स्पष्ट रूप से परिभाषित किया जा सकता है, लेकिन यदि कंपाइलर इसे आपके लिए नहीं डालेंगे, जब तक कि कोई अन्य कंस्ट्रक्टर पहले से परिभाषित न हो।
ऑब्जेक्ट में कंस्ट्रक्टर से ऑब्जेक्ट तब कैसे बनाया जाता है?
वस्तुओं का वास्तविक निर्माण जेवीएम के नीचे है। जावा में प्रत्येक कंस्ट्रक्टर <init>
नामक एक विशेष विधि के रूप में प्रकट होता है, जो उदाहरण के लिए प्रारंभिक है। यह <init>
विधि संकलक द्वारा आपूर्ति की जाती है और क्योंकि <init>
जावा में एक वैध पहचानकर्ता नहीं है, इसका उपयोग सीधे भाषा में नहीं किया जा सकता है।
जेवीएम इस
<init>
विधि को कैसे लागू करता है?
JVM invokespecial
इंस्ट्रक्शन का उपयोग करके <init>
मेथड को invokespecial
और इसे केवल uninitialized क्लास इंस्टेंसेस पर ही invokespecial
किया जा सकता है।
अधिक जानकारी के लिए JVM विनिर्देश और जावा भाषा विनिर्देश पर एक नज़र डालें:
- विशेष विधियाँ (JVM) - JVMS - 2.9
- कंस्ट्रक्टर्स - जेएलएस - 8.8