ООП Java: может вернуть дочерний класс в родительский класс? - PullRequest
0 голосов
/ 20 февраля 2012

Я новичок в ООП, поэтому у меня есть один глупый вопрос о том, когда класс extends другой класс.

Вот мой пример:

public class Test {
    public Monitor getMonitor(){
        return new LCD();
    }

    class LCD extends Monitor {   NO-ERROR
    class LCD {                   ERROR at line `return new LCD` 
        //some other method or function not in Monitor Class. Example:
        boolean isSamsung;
        public LCD whatkindLCD(){           
        }       
    }
}

У меня есть один вопросдля приведенного выше кода: потому что LCD расширен от Monitor, а LCD имеет некоторые другие свойства / методы, которых нет у Monitor.Итак, LCD является потомком Monitor, верно?

Это означает, что вы пытаетесь положить «большую коробку» в «маленькую коробку».Итак, почему, когда я return new LCD, Eclipse не замечает ошибку, как когда я просто использую class LCD {.

Спасибо :))

Ответы [ 4 ]

5 голосов
/ 20 февраля 2012

Во втором (ошибочном) случае вы забыли объявить, что LCD действительно расширяет Monitor. Вы просто определяете «нормальный», автономный класс - и поэтому new LCD() является , а не экземпляром Monitor.

Компилятор должен быть счастлив, если вы объявите класс LCD следующим образом:

class LCD extends Monitor {
    //some other method or function not in Monitor Class. Example:
    boolean isSamsung;
    public LCD whatkindLCD(){           
    }       
}

Редактировать (в ответ на комментарий): не проблема, что класс LCD имеет дополнительные свойства / методы по сравнению с Monitor. Код, который будет вызывать getMonitor(), действительно заботится только о том, чтобы получить обратно Monitor, то есть что-то, что имеет все методы, свойства и поведение Monitor.

Так что, если у вас есть turnOff и displayBitmap(int[][] data) методы в вашем Monitor классе, то ваш LCD класс также будет иметь эти методы. Любой экземпляр LCD может вести себя как Monitor, когда он необходим - это основной принцип создания подклассов в ОО-языках. Поэтому, когда что-то хочет Monitor, вы можете вместо этого дать ему LCD, или экземпляр CRT или SamsungLCD, если у вас есть такие, и компилятор может быть уверен, что правильные методы / свойства будут существовать и можно назвать.

(Технически это принцип подстановки Лискова , если вам нравятся формальные определения, но вам не нужно разбираться в этом уровне детализации.)

3 голосов
/ 20 февраля 2012

Аналогия с коробкой неверна, вместо этого подумайте о is a.

В первом примере LCD extends Monitor, то есть LCD is a Monitor, поэтому в любом месте, где ожидается Монитор, ЖК-дисплей в порядке. Когда вы думаете в реальном выражении, а не смотрите на код, вы понимаете, что это правильно. Все, что можно ожидать от монитора в целом (например, отображать изображение), подойдет ЖК-монитор.

Во втором примере ЖК-дисплей не является монитором, поэтому вы получаете сообщение об ошибке.

1 голос
/ 20 февраля 2012

Понимать наследование как отношение "есть". Вот простой пример, который я использовал для понимания наследования в течение моих начинающих лет.

class Employee
{
    String name;
    int salary;

    Employee()
    {
        name = "Employee";
        salary = 5000;
    }
    public String getName()
    {
        return name;
    }
    public int getSalary()
    {
        return salary;
    }
}
class Manager extends Employee
{
    int bonus;
    int salary;

    Manager()
    {
        bonus = 1000;
        salary = 6000;
    }
    public int getBonus()
    {
        return bonus;
    }
    public int getSalary()
    {
        return salary;
    }   
}

class Test
{        
    public static void main(String[] args)
    {
        Employee e = new Employee();
        System.out.println(e.getName());
        //System.out.println(e.getBonus());
        System.out.println(e.getSalary());

        System.out.println();

        Manager m = new Manager();
        System.out.println(m.getName());
        System.out.println(m.getBonus());
        System.out.println(m.getSalary());

        System.out.println();

        Employee em = new Manager();
        System.out.println(em.getName());                   
        //System.out.println(em.getBonus());            
        System.out.println(((Manager)em).getBonus());
        System.out.println(em.getSalary());     
        }
}

Компилятор ищет тип ссылки перед вызовом любых операций с ним. em.getBonus () не работает, потому что у Employee нет бонусного метода. Но используя актерский состав, мы можем заставить его работать. ((Менеджер) эм.) GetBonus ()

Причина, по которой компилятор ищет ссылочный тип перед вызовом любой операции над ним, заключается в следующем:

Менеджер [] Менеджеры = Новый Менеджер [10];

Допустимо преобразовать этот массив в массив Employee []:

сотрудник [] персонал = менеджеры; // ОК

Конечно, почему бы и нет, вы можете подумать. В конце концов, если менеджер [i] является менеджером, он также является сотрудником. Но на самом деле происходит нечто удивительное. Имейте в виду, что менеджеры и персонал являются ссылками на один и тот же массив.

Теперь рассмотрим утверждение

staff [0] = new Employee ("John Eipe", ...);

Компилятор с радостью разрешит это назначение. Но сотрудники [0] и менеджер [0] - это одна и та же ссылка, поэтому, похоже, нам удалось втянуть в управление простого сотрудника занимает.

Это было бы очень плохо - вызывающие менеджеры [0] .setBonus (1000) пытались бы получить доступ к несуществующее поле экземпляра и приведет к повреждению соседней памяти. Чтобы избежать такого повреждения, все массивы запоминают тип элемента с которые они были созданы, и они отслеживают, что только совместимые ссылки хранятся в их. Например, массив, созданный как новый Менеджер [10], помнит, что это массив менеджеры. Попытка сохранить ссылку Employee вызывает ArrayStoreException.

0 голосов
/ 20 февраля 2012

Ваш метод getMonitor возвращает тип «Монитор».

Когда вы расширяете свой ЖК-монитор класса с помощью монитора, вы утверждаете, что LCD является монитором. При удалении extends класс LCD становится простым классом, а не типом Monitor. Если вы измените ваш getMonitor на

public LCD getMonitor(){
       // code here
}

Ошибка исчезнет.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...