Battleship Game in Java
Thanks for sharing your code.

what I like


you follow the Java Naming conventions
you resist to solve the problem based on an array


what I dislike

violation of encapsulation / information hiding

You access directly properties of an object and (even worse) their properties too like this:


x == ship.shipGeographic.x &amp;&amp; ship.shipGeographic.y &lt;= y



But the code using an object should not know anything about the internal implementation pf this object. The using code should only call (public) methods on on an object. This enables both: polymorphism and improving the internal implementation without affecting the calling code. The getters and setters you mention are not a solution to this problem.

The names for this "code smells" is feature envy: the calling code does something what should better be done inside the object by applying the "tell, don't ask" principle.

separation of concerns - intermix of user IO and business logic

In your code the Board class is responsible for the user IO and also does game logic. This reduces the  re-usability of the game logic. I.e.: you have to do a complete rewrite if you want to change the User interface to  graphics instead of a command line. You should learn about the Model-View-Controller concept (MVC) and its relatives MCP, MVVC and MVVM.

unnecessary mutability

Your ship objects are mutable, this means their properties could be changed at any time during the game. But in practice the properties never change after initialization. Therefore your should pass all the properties as constructor parameters and store them in final declared properties.

incomplete OO approach.

IMHO you stopped doing an OO approach half way.  

Holding a list of ships which know their positions is a good first step. But you could walked that path further.

E.g. The list of ships could only hold unsunk ones. Then the check for the end of the game would change from a loop to a simple statement: 

boolean allShipsSank() {
    return listOfShips.isEmpty();    
}


Next possibility could be the "ship hit" logik.

For once the ship should know itself if being hit:

class Ship {
  //...
  boolean isHitBy(int x, int y) {
    // logic here
  }
  //...
}


but instead of doing a calculation here I'd go the "collection" approach again. 

First we need to introduce another class:

class BordPosition{ // this is a DTO and has no business logik
   final int x;
   final int y;
   BordPosition(int x, int y){
     this.x = x;
     this.y = y;
   }
   // implement equals() and hascode()
}


and we need to enhance the Orientation enum:

enum Orientation {
    HORIZONTAL{
        public BordPosition translate(BordPosition startPoint, int stepsToMove){
           return new BordPosition(startPoint.x+stepsToMove, startPoint.y);
        }
    }, 
    VERTICAL{
        public BordPosition translate(BordPosition startPoint, int stepsToMove){
           return new BordPosition(startPoint.x, startPoint.y+stepsToMove);
        }
    };
    abstract public BordPosition translate(BordPosition startPoint, int stepsToMove);
}


then class Ship would change to this

class Ship {
  private final Collection&lt;BordPosition&gt; occupiedFields = new HashSet&lt;&gt;();
  private final Collection&lt;BordPosition&gt; hitFields = new HashSet&lt;&gt;();
  Ship(BordPosition startPoint, Orientation orientation, int size){
    for (int stepsToMove = 0; stepsToMove&lt;size; stepsToMove++) {
        occupiedFields.add(orientation.translate(startPoint,stepsToMove));
    }
  }

  boolean isHitBy(BordPosition missleTarget) {
    if(occupiedFields.contains(missleTarget)){
      hitFields.add(missleTarget);
      if (hitFields.size()==occupiedFields.size()){
       // deregister from ship list via Listener pattern
      }
      return true;
    } else {
      return false;
    } 
  }
  //...
}