Способы создания объекта класса, реализующего интерфейс

Правильно ли я понимаю, что при создании объекта класса, который реализует интерфейс, я могу использовать разные варианты (создания этого самого объекта). Например:

interface B {
    int methodB(int i);
}

class A implements B {   
    public int methodB(int i) {
        return i + 2;
    }
}
 
public class MainClass {
    public static void main(String[] args) {
        
        B b = new A(); //1 вариант
        A a = new A(); //2 вариант
        
         
        System.out.println(b.methodB(2));
    }
}

Я не могу разобраться, являются ли эти два способа создания объектов, просто альтернативными (с одинаковой логикой) или каждый из них имеет специфическую логику и дают разный результат?


Ответы (2 шт):

Автор решения: had0uken

Разная логика создания объектов. Создавая объект а, как объект класса А, вы жестко привязываетесь к реализации. Это плохо, зачастую. ВСЕГДА нужно стремиться к тому, чтобы програмировать на уровне интерфейсов, а не реализаций. Поэтому старайтесь использовать данный вариант:

B b = new A(); //1 вариант

В таком случае вы получаете ряд преймуществ и куда большее пространство для маневра. Код выйдет куда более универсальным, менее связным, более годным к обслуживанию и т.д. В рамках одного ответа очень трудно описать все преимущества, которые вы получите при таком использовании. Для этого могу посоветовать книгу Head First. Паттерны проектирования. Там на идеальных примерах разобрано как вам это поможет в коде. И какие проблемы (порой нерешаемые) вы получите используя другой вариант создания объектов.

→ Ссылка
Автор решения: Зонтик

Это два разных способа и только один из них вам следует использовать. Дело в том, что в этом случае вы просто создаёте объект класса:

A a = new A(); //Просто объект класса A

Это просто объект класса A. Он ссылается только на класс A. Во втором же случае вы используете полиморфизм:

B b = new A(); //Используется полиморфизм

Переменная декларирована изначально как B, но создаётся объект класса A и это важно. Ведь только при использовании полиморфизма можно будет сделать это:

interface B{

  public int methodB(int i);
  
}

public class A implements B{

  public static void main (String [] args) {
  
     B b = new A();
     b = new SomeClass(); //Так можно будет сделать только при изначальном объявлении переменной как B
     
  }
  
  @Override
  public int methodB(int i){
     return i + 2;
  }
  
}

class SomeClass implements B{ //Важно! Этот класс тоже реализует интерфейс!

  @Override
  public int methodB(int i){
     return i + 5; //Здесь другая реализация
  }

}

Но!

interface B{

  public int methodB(int i);
  
}

public class A implements B{

  public static void main (String [] args) {
  
     B b = new A();
     b.someMethod();//Ошибка!Этот метод - не переопределённый метод из интерфейса B!
  }
  
  @Override
  public int methodB(int i){
     return i + 2;
  }
  
  public void someMethod(){

  }
}

То есть к собственным методам у такого объекта доступа не будет, ведь он декларирован изначально как B. То есть такой объект может вызывать только переопределённые методы интерфейса!

Какой вариант использовать? Если вам нужно вызвать переопределённый метод, то следует использовать полиморфизм, это даёт больше возможностей. Ну а если вы хотите вызывать собственные методы класса, то придётся создавать обычный объект.

Рекомендую посмотреть вот это, чтобы лучше понять вышесказанное.

→ Ссылка