Доступ к свойству подкласса

Я новичок в Java и изо всех сил пытаюсь понять, почему я продолжаю получать сообщение об ошибке в командной строке. У меня есть суперкласс Guest с переменными guestID, fName, lName и dateJoin. У меня также есть подкласс VIPGuest с дополнительными переменными VIPstartDate и VIPexpiryDate.

У меня есть гости ArrayList, в которых хранятся все гостевые объекты, которые есть в моих записях. Я хочу выполнить итерацию по ArrayList и записать каждого гостя в текстовый файл с каждым гостем в новой строке в форме guestID, fName, lName, dateJoin, разделенных запятыми (или guestID, fName, lName, dateJoin, VIPstartDate, VIPexpiryDate, если Гость — это VIP-гость).

Мой код ниже. Он отлично работает, когда я использую аналогичный код, чтобы сделать то же самое для ArrayList объектов класса без подклассов, но когда я пытаюсь обойти тот факт, что у некоторых гостей есть дополнительные переменные, возникает ошибка:

  HotelImpl.java:440: error: cannot find symbol
                    + "," + g.getVIPstartDate() + "," + g.getVIPexpiryDate());
                             ^
      symbol:   method getVIPstartDate()
      location: variable g of type Guest
    HotelImpl.java:440: error: cannot find symbol
                    + "," + g.getVIPstartDate() + "," + g.getVIPexpiryDate());
                                                         ^
      symbol:   method getVIPexpiryDate()
      location: variable g of type Guest
    2 errors

Я вижу, что у него проблемы с дополнительными переменными для объектов VIPGuest, но я думал, что исправил это с помощью if/else:

  public boolean saveGuestsData(String guestsTxtFileName){
    BufferedWriter writer;
    try{
      writer = new BufferedWriter(new FileWriter(guestsTxtFileName));
    } catch (IOException e){
      System.out.print("Invalid file.");
      return false;
    }
      try{
            for (Guest g : guests){
              if (!(g instanceof VIPGuest)){
                writer.write(
                g.getGuestID() + "," + g.getFName() + "," + getLName() 
                + "," + g.getDateJoin());

              }
              else {
                writer.write(
                g.getGuestID() + "," + g.getFName() + "," + 
                getLName() + "," + g.getDateJoin() + "," + 
                g.getVIPstartDate() + "," + g.getVIPexpiryDate());
              }
              writer.newLine();

            }
          writer.close();
          return true;
          } catch (FileNotFoundException ex) {
            System.out.print("File not found.");
            return false;
          } catch (IOException e){
            System.out.print("Invalid file.");
            return false;
          }
  }
g является гостем, а не VIP-гостем. Если вы хотите использовать методы класса VIPGuest, вам нужно привести g к VIPGuest, например. ((VIPGuest)g).getVIPstartDate()
Roddy of the Frozen Peas 11.03.2019 18:00

Это исправило это! Спасибо :)

Habilee 11.03.2019 18:03

@Habilee, я рекомендую вам использовать IDE, она объяснит вам этот тип ошибки.

vincrichaud 11.03.2019 18:03
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
Как вычислять биты и понимать побитовые операторы в Java - объяснение с примерами
Как вычислять биты и понимать побитовые операторы в Java - объяснение с примерами
В компьютерном программировании биты играют важнейшую роль в представлении и манипулировании данными на двоичном уровне. Побитовые операции...
Поднятие тревоги для долго выполняющихся методов в Spring Boot
Поднятие тревоги для долго выполняющихся методов в Spring Boot
Приходилось ли вам сталкиваться с требованиями, в которых вас могли попросить поднять тревогу или выдать ошибку, когда метод Java занимает больше...
Полный курс Java для разработчиков веб-сайтов и приложений
Полный курс Java для разработчиков веб-сайтов и приложений
Получите сертификат Java Web и Application Developer, используя наш курс.
1
3
48
3
Перейти к ответу Данный вопрос помечен как решенный

Ответы 3

В этом ответе я предполагаю, что VIPGuest расширяет Guest.

Прежде чем вы сможете использовать любой из методов VIPGuest на обычном Guest, вам нужно преобразовать гостя в VIP-гостя.

for (Guest g : guests){
  if (!(g instanceof VIPGuest)){
    // omitted for brevity
  } else {
    VIPGuest vip = (VIPGuest)g;
    writer.write(vip.getGuestID() + "," + vip.getFName() + "," + vip.getLName() + "," + 
                 vip.getDateJoin() + "," + vip.getVIPstartDate() + "," + vip.getVIPexpiryDate());
  }
  writer.newLine();

}

Хотя вы знаете, используя чек instanceof, что g на самом деле является VIP-гостем, ссылка на него относится только к гостю.

Обратите внимание, что если бы g на самом деле не было экземпляром VIPGuest, попытка приведения (VIPGuest)g, скорее всего, вызвала бы исключение ClassCastException.

Верно. Я собирался опубликовать аналогичный ответ;)

isapir 11.03.2019 18:05

Ваша переменная g имеет тип Guest, и хотя экземпляр является VIPGuest, метод getVIPstartDate недоступен.

Что вы должны сделать, это:

else
{
  VIPGuest vg;
  vg = (VIPGuest)g;
  writer.write(
    vg.getGuestID() + "," + vg.getFName() + "," + 
    getLName() + "," + vg.getDateJoin() + "," + 
    vg.getVIPstartDate() + "," + vg.getVIPexpiryDate());
}

Даже лучше:

Переопределите метод toString() как в Guest, так и в VIPGuest.
Последний вызывает super.toString() и добавляет дополнительную информацию.

Ответ принят как подходящий

g является ссылкой типа Guest, поэтому вы можете получить доступ только к членам Gusest из него. Если вы хотите получить доступ к членам VIPGuest, вам придется явно понизить его. Например.:

VIPGuest vg = (VIPGuest) g;
writer.write(g.getGuestID() + "," + 
             g.getFName() + "," + 
             g.getLName() + "," +
             g.getDateJoin() + "," + 
             vg.getVIPstartDate() + "," + 
             vg.getVIPexpiryDate());

Это должно работать, но это плохой дизайн, он вынуждает ваш метод saveGuestsData хорошо знать ваши реализации Guest. Более надежный дизайн состоит в том, чтобы перенести эту логику в классы Guest и заставить этот метод просто вызывать их:

public class Guest {
    @Override
    public String toString() {
        return getGuestID() + "," + getFName() + "," +  getLName() + "," + g.getDateJoin();
    }

    // other methods...
}

public class VIPGuest extends Guest {
    @Override
    public String toString() {
        return super.toString() + ", " + getVIPstartDate() + "," + getVIPexpiryDate());

    // other methods...
}

А затем просто вызовите этот метод:

for (Guest g : guests) {
    writer.write(g.toString());
}

Другие вопросы по теме