Why can't I have an private abstract method?

2019-08-07 01:19发布

问题:

Let's say I have my classic:

public abstract class Mammal {
    private int numLegs;
    private String voice;
    private Coat coat;

    public abstract void eat();

    public abstract void speak();
    public abstract void sleep();  


    private abstract void ingestFood(Food f);  //The abstract method ingestFood in type Mammal can only set a visibility modifier, one of public or protected
}

With these concrete implementations:

public class Dog extends Mammal {
     private int numLegs = 4;
     private String voice = "Woof!";
     private Coat coat = new Coat(COATTYPE.FUR, COATCOLOR.BROWN);

     @Override
     public void eat()
     { 
          Rabbit r = chaseRabbits(); 
          if (r != null) ingest(r); 
          else {
                   Garbage g = raidBin(); 
                   if (g!= null) ingest(g); 
               }


     }

     @Override
     private void ingest(Food f)
     {
         gobbleItAllUpInFiveSeconds(f); 
         stillFeelHungry(); 
     }
}

public class Human extends Mammal {
     private int numLegs = 2;
     private String voice = "Howdy!!";
     private Coat coat = new Coat(COATTYPE.SKIN, COATCOLOR.PINK);

     @Override
     public void eat()
     { 
          Food f = gotoSuperMarket();
          ingest(f); 


     }

     @Override
     private void ingest(Food f)
     {
         burp();  
     }
}

Now, I want a method in the Mammal class that is callable by all instances of the mammal, e.g.

public String describe() {
     return "This mammal has " + this.numLegs + "legs, a " + this.coat.getColor() + " " this.coat.getCoatType() + " and says " + this.voice;
}

My question is that, by making the Mammal class not abstract, is it possible to create a mammal by itself? E.g.

 Mammal me = new Mammal();

You shouldn't be able to do this.

However, I do want to have some public methods that are implemented by the parent class that all subclasses call, but that each call their own private method.

回答1:

You can totally have implemented methods in an abstract class:

"Abstract classes are similar to interfaces. You cannot instantiate them, and they may contain a mix of methods declared with or without an implementation."

https://docs.oracle.com/javase/tutorial/java/IandI/abstract.html



回答2:

Responding to the question in the title ("Why can't I have an private abstract method?") :

You can't have a private abstract method, because abstract methods need to be implemented in subclasses. But private methods are not visible in subclasses.

(If you want to have a method that is only visible in a subclass, and not publically, then you need to make the methods protected)

So you couldn't implement a private abstract method, ever. That's why Java doesn't allow them - they wouldn't make sense.



回答3:

Declare your unimplemented methods as abstract if you want them to behave differently on child classes, and the methods to be inherit leave them like a normal method. Also use protected instead of private to be accessible to inherited classes:

public abstract class Mammal
{
  protected int numLegs;
  protected String voice;
  protected Coat coat;

  abstract void eat();
  abstract void speak();
  abstract void sleep();

  public String describe()
  {
     return "This mammal has " + this.numLegs + "legs, a " 
     + this.coat.getColor() + " " this.coat.getCoatType() + " and says " + this.voice;
  }
}

And use constructors to initialize variables and implement abstract methods:

public class Dog extends Mammal
{
  public Dog(){
     this.numLegs = 4;
     this.voice = "Woof!";
     this.coat = new Coat(COATTYPE.FUR, COATCOLOR.BROWN);
  }
  void eat(){
    System.out.println("eating like a dog");
  }
  void speak(){
    System.out.println("speaking like a dog");
  }
  void sleep(){
    System.out.println("sleeping like a dog");
  }
}

public class Human extends Mammal
{
  public Human(){
     this.numLegs = 2;
     this.voice = "Howdy!!";
     this.coat = new Coat(COATTYPE.SKIN, COATCOLOR.PINK);
  }
  void eat(){
    System.out.println("eating like a human");
  }
  void speak(){
    System.out.println("speaking like a human");
  }
  void sleep(){
    System.out.println("sleeping like a human");
  }
}