Methods और Recursion
Method parameters लेता है, काम करता है, और (चाहे तो) एक value return करता है — इससे code repeat नहीं करना पड़ता।
Java "pass by value" follow करता है — method को values की copy मिलती है, original variable change नहीं होता (objects के case में reference की copy मिलती है)।
Recursion में एक method ख़ुद को call करता है — जैसे factorial(5) = 5 * factorial(4)... जब तक base case (factorial(1)=1) ना आए।
int factorial(int n) {
if (n <= 1) return 1;
return n * factorial(n - 1);
}- Method = reusable code block
- Pass by value — copy मिलती है
- Recursion = method ख़ुद को call करता है
Method signature उसका नाम + parameter types/order होता है (return type signature का part नहीं होता — इसी वजह से दो methods सिर्फ़ return type से differ नहीं कर सकते, overloading के लिए parameters ही differ करने चाहिए)।
void मतलब method कुछ return नहीं करता। अगर method कुछ return करता है (जैसे int, String, या कोई object), तो return statement ज़रूरी है हर possible code path में — compiler check करता है कि कोई भी path बिना return के method ख़त्म ना हो जाए, वरना "missing return statement" error।
... (three dots) से एक method variable number of arguments ले सकता है — internally ये एक array की तरह treat होता है method के अंदर। Caller flexibility से 0, 1, या जितने चाहो उतने arguments दे सकता है।
एक method में सिर्फ़ एक varargs parameter हो सकता है, और वो हमेशा सबसे *last* parameter होना चाहिए (अगर और normal parameters भी हैं)। System.out.printf() और String.format() जैसे built-in methods varargs ही use करते हैं।
int sum(int... nums) {
int total = 0;
for (int n : nums) total += n;
return total;
}
sum(1, 2, 3); // works
sum(1, 2, 3, 4, 5); // works bhi
sum(); // works, total = 0Java हमेशा pass-by-value है, चाहे primitive हो या object — ये एक बहुत common interview trick question है। Primitive के case में value की copy मिलती है (original change नहीं होता, method के अंदर कुछ भी करो)।
Object के case में "reference" (heap address) की copy मिलती है — मतलब दोनों (original variable और parameter) एक ही object को point करते हैं। इसलिए object के अंदर के fields change कर सकते हो (दिखेगा बाहर भी), लेकिन अगर तुम parameter को नए object से reassign करो (s = new Student()), तो सिर्फ़ local copy update होती है — original reference change नहीं होता।
void modify(Student s) {
s.name = "Changed"; // ye dikhega original object mein (same reference)
s = new Student(); // ye NAHI dikhega — sirf local copy reassign hui
}Factorial और Fibonacci classic recursion examples हैं। हर recursive method में दो चीज़ें ज़रूरी हैं: base case (जहाँ recursion रुके) और recursive case (जो problem को छोटा करके ख़ुद को call करे)।
बिना base case के method infinite बार ख़ुद को call करता रहेगा, जब तक StackOverflowError ना आ जाए — हर recursive call एक "stack frame" लेता है, और JVM का call stack fixed size का होता है।
Fibonacci का naive recursive version (जैसा नीचे है) बहुत inefficient है बड़े n के लिए — क्योंकि same values बार-बार calculate होती हैं (fibonacci(5) दो बार fibonacci(3) calculate करता है)। इसको fix करने के तरीक़े हैं "memoization" (results cache करना) या iterative approach।
int factorial(int n) {
if (n <= 1) return 1; // base case
return n * factorial(n - 1); // recursive case
}
int fibonacci(int n) {
if (n <= 1) return n;
return fibonacci(n-1) + fibonacci(n-2);
}