Java递归与继承:子类重写父类递归方法的技术咨询
Hey there! Let’s dig into the recursion and inheritance quirks in your Java code, with clear fixes and explanations.
一、继承与方法重写的关键细节
You’ve got Dog extending Animal and overriding askForLocation()—here are some easy-to-miss points to watch for:
1. The value of @Override
Great call using the @Override annotation! It forces the compiler to verify that you’re actually overriding a parent class method correctly (matching method name, parameters, and return type). This prevents silent bugs from typos or mismatched signatures that would otherwise let your "override" fail quietly.
2. Unexpected recursion behavior with this
In Animal’s askForLocation(), you use this.askForLocation() to retry on empty input. Remember: this refers to the actual runtime object, not the parent class type. If a Dog instance triggers this code (even via super.askForLocation()), the recursive call will invoke Dog’s overridden method, not Animal’s original one. This might break your expected logic—keep this in mind when mixing inheritance and recursion.
3. Wasted resources from repeated Scanner creation
Both classes create a new Scanner every time askForLocation() runs. This wastes system resources and can cause input stream conflicts (multiple Scanners reading from the console at once can lead to garbled input). Instead, define Scanner as a class member variable so it’s reused across method calls.
二、 Recursion Issues & Optimizations
The recursive logic in Animal has some practical risks—let’s fix that:
1. Stack overflow danger
If a user keeps entering empty strings, the recursion will keep calling itself until Java runs out of stack space, throwing a StackOverflowError. Recursion works best for problems with limited depth; for input validation that might loop indefinitely, a while loop is safer and more efficient.
2. Optimized iterative alternative
Here’s how to rewrite the input logic with a loop instead of recursion, plus fixes for the Scanner and inheritance quirks:
import java.util.Scanner; public class Animal { // Reuse a single Scanner instance protected Scanner inFromConsole = new Scanner(System.in); public void askForLocation() { System.out.println("In animal"); String street; do { System.out.println("Street?"); street = inFromConsole.nextLine().trim(); // Trim whitespace to catch empty inputs with spaces if (street.isEmpty()) { System.out.println("Street can't be empty—please try again!"); } } while (street.isEmpty()); System.out.println("Street: " + street); } } public class Dog extends Animal { @Override public void askForLocation() { System.out.println("In dog"); // Add Dog-specific input logic first String city; do { System.out.println("City?"); city = inFromConsole.nextLine().trim(); if (city.isEmpty()) { System.out.println("City can't be empty—please try again!"); } } while (city.isEmpty()); System.out.println("City: " + city); // Call parent class's street input logic super.askForLocation(); } }
3. Quick note on when to use recursion
Reserve recursion for problems that naturally break into smaller identical subproblems (like tree traversals or divide-and-conquer algorithms). For user input validation or repetitive tasks with no fixed depth, iterative loops are always the more reliable choice.
内容的提问来源于stack exchange,提问作者mike

