Я создал несколько классов с концепцией наследования, у меня есть основной класс для моего приложения, который называется модулем, который соответствует модулю, а также некоторые другие классы, называемые moduloLedRGB, ModuloSwitch и ModuloDimmer, все эти 3 класса расширяют класс по модулю, который имеет только общие аргументы для модулей, такие как id, name, Module type и ipAdress. Но когда я пытаюсь преобразовать модуль в один из этих трех дочерних классов, я получаю исключение, в котором говорится, что я не могу преобразовать Modulo в ModuloSitch или ModuloLedRGB ...

Вот где я получаю ошибку:

switch (modulo.getModulo()){
             case "RGB":
                 ModuloLedRGB rgb = (ModuloLedRGB) modulo;
    rgb.setProgress(c.getDouble(c.getColumnIndex("progress")));
    rgb.setProgressRed(c.getDouble(c.getColumnIndex("progressRed")));
    rgb.setProgressGreen(c.getDouble(c.getColumnIndex("progressGreen")));
    rgb.setProgressBlue(c.getDouble(c.getColumnIndex("progressBlue")));
                            break;
                 case "Dimmer":
    ModuloDimmer dimmer = (ModuloDimmer) modulo;
    dimmer.setProgress(c.getDouble(c.getColumnIndex("progress")));
                            break;
                        case"Switch":
                            ModuloSwitch sw = (ModuloSwitch) modulo;
                            break;   

Он говорит, что я не могу привести по модулю, что объект соответствует классу Modulo, к ModuloRGB. getModulo возвращает строку, в которой говорится, что это за модуль.

   package br.com.andrey.projetointegradoapp;

/**
 * Created by andrey on 04/08/2016.
 */
public class Modulo {
    private long id;
    private String nome;
    private String ModuleIpAdress;
    private String modulo;

    public String getModulo() {
        return modulo;
    }

    public void setModulo(String modulo) {
        this.modulo = modulo;
    }



    public String getModuleIpAdress() {
        return ModuleIpAdress;
    }

    public void setModuleIpAdress(String moduleIpAdress) {
        ModuleIpAdress = moduleIpAdress;
    }

    public long getId() {
        return id;
    }

    public void setId(long id) {
        this.id = id;
    }

    public String getNome() {
        return nome;
    }

    public void setNome(String nome) {
        this.nome = nome;
    }

}

Это класс Modulo.

А это класс ModuloLedRGB:

 package br.com.andrey.projetointegradoapp;

/**
 * Created by andrey on 16/12/2016.
 */

public class ModuloLedRGB extends Modulo {
    private double progress;
    private double progressRed;
    private double progressGreen;
    private double progressBlue;

    public double getProgressRed() {
        return progressRed;
    }

    public void setProgressRed(double progressRed) {
        this.progressRed = progressRed;
    }


    public double getProgress() {
        return progress;
    }

    public void setProgress(double progress) {
        this.progress = progress;
    }

    public double getProgressGreen() {
        return progressGreen;
    }

    public void setProgressGreen(double progressGreen) {
        this.progressGreen = progressGreen;
    }

    public double getProgressBlue() {
        return progressBlue;
    }

    public void setProgressBlue(double progressBlue) {
        this.progressBlue = progressBlue;
    }
    }

Есть идеи, почему я получаю это исключение? поскольку потомок расширяет основной класс, я думаю, что смогу его отбросить, не так ли?

1
Andrey Viktor Kandauroff 22 Дек 2016 в 07:44
1
Вы получаете ошибку компиляции или ошибку времени выполнения?
 – 
shmosel
22 Дек 2016 в 07:46
Вы можете сделать это ModuloRgb objectModuloRgb = new Modulo ();
 – 
Mr.Popular
22 Дек 2016 в 08:04
Я бы использовал оператор instanceof, который безопасен для ошибок.
 – 
Mordechai
22 Дек 2016 в 08:08
Как был создан modulo? Если он был создан с помощью new ModuloLedRGB() (или подкласса ModuloLedRGB), вы можете преобразовать его в ModuloLedRGB. В противном случае вы не сможете этого сделать, и попытка приведения приведет к исключению во время выполнения.
 – 
ajb
22 Дек 2016 в 08:20
Разве вы не должны где-нибудь установить modulo на "RGB"? Я не нашел этого в показанном вами коде.
 – 
Henry
22 Дек 2016 в 08:28

1 ответ

Лучший ответ

Судя по комментариям, вы неправильно понимаете природу кастинга.

Когда ты говоришь

class Modulo { ... }

class ModuloLedRGB extends Modulo { ... }

Создание подкласса определяет отношение is-a ; каждый ModuloLedRGB также является Modulo. Но это не работает в обоих направлениях.

Если вы создаете объект с

new Modulo()

Тогда это Modulo, но не ModuloLedRGB. Если вы создадите его с помощью

new ModuloLedRGB()

Это одновременно ModuloLedRGB и Modulo. Сказать, что это Modulo, означает, что вы можете присвоить ему переменную типа Modulo или использовать его как параметр Modulo:

ModuloLedRGB x = new ModuloLedRGB();
Modulo y = x;  // this is legal, but the object's class doesn't change

y - это ссылка на объект ModuloLedRGB. Но обратите внимание, что хотя y объявлен как Modulo, он по-прежнему относится к тому же объекту, чей класс - ModuloLedRGB, потому что таким образом создается объект.

Вот почему вы можете использовать понижающее приведение. Скажем, вы позже используете выражение

(ModuloLedRGB)y

На данный момент компилятор знает только, что y (если не ноль) является Modulo; это может быть объект класса Modulo, ModuloLedRGB, ModuloSwitch или что-нибудь еще. Таким образом, во время выполнения код проверяет, на какой именно объект он ссылается. Поскольку в приведенном выше примере y задано как объект, созданный как ModuloLedRGB, приведение выполняется успешно. Но если y был установлен на какой-то другой объект, который не был ModuloLedRGB, приведение выдает исключение.

Это приведение не меняет объект и не создает новый объект. Он просто говорит: «Убедитесь, что объект относится к классу ModuloLedRGB, а затем обработайте его как ModuloLedRGB, чтобы мы могли получить доступ к методам и переменным экземпляра, которые относятся к ModuloLedRGB».

Однако похоже, что вы пытаетесь преобразовать объект, изменив его класс. Вы создали объект, класс которого равен Modulo, и вы пытаетесь создать какой-то новый объект с классом ModuloLedRGB. Вы не можете этого сделать с гипсом. Если у вас есть Modulo и вы хотите создать ModuloLedRGB, вам нужно будет где-нибудь создать новый объект с new ModuloLedRGB(). Один из распространенных способов сделать это - написать конструктор:

class ModuloLedRGB extends Modulo {

    public ModuloLedRGB(Modulo m, maybe other parameters) {
        // copy the instance variables from "m"
        this.field = m.field;
        this.anotherField = m.anotherField;
        // set the new instance variables
        this.newField = maybe a parameter or some other computation;
        ...
    }

Или напишите статический фабричный метод для создания нового ModuloLedRGB из Modulo. Но вам придется его создать, и вам нужно будет написать код для его создания. Вы не можете "преобразовать" его из Modulo. В Java такого нет.

1
ajb 23 Дек 2016 в 09:29
Вот и все, я думаю, что понял проблему, поэтому, если я хочу использовать ModuloLedRGB, мне нужно создать новый ModuloLedRGB (); но я не смогу использовать его, если сделаю новый Modulo (); просто противоположное действительно. У меня есть этот метод в моей базе данных, который возвращает все Modulo моей системы, в этом методе я создаю новый Modulo, затем устанавливаю некоторые атрибуты, меняю регистр на тип Modulo, и в каждом случае я использую его для ModuloLedRGB, но это Modulo, а не ModuloLedRGB. Я новичок в O.O. мир спасибо за вашу помощь, я попробую некоторые изменения ...
 – 
Andrey Viktor Kandauroff
23 Дек 2016 в 21:14
... я думаю, что сначала могу создать новый Modulo (); проверьте, какой это тип модуля, и в каждом случае создайте новый ModuloLedRGB или что-то еще, установите специальные атрибуты, а затем приведите его, чтобы снова преобразовать его в Modulo, чтобы добавить в список, теряю ли я какие-либо данные с этой транзакцией? или мне, возможно, следует иметь разные методы в моем классе базы данных для каждого типа модуля в моей системе?
 – 
Andrey Viktor Kandauroff
23 Дек 2016 в 21:15
«У меня есть этот метод в моей базе данных, который возвращает все модули моей системы» - обычно такой метод может возвращать некоторые объекты класса ModuloLedRGB, ModuloSwitch или другие объекты других подклассов. Modulo[], или Set<Modulo>, или List<Modulo>, или другая коллекция часто будет иметь элементы разных подклассов Modulo - вот как работает Modulo. Но вы должны создавать их с помощью правильного класса при их создании. Это нет типичного объектно-ориентированного подхода для создания объектов базового класса (Modulo) и попытки получить реальный класс позже ...
 – 
ajb
23 Дек 2016 в 21:19
Фактически, в ситуации, подобной вашей, было бы более распространено сделать Modulo абстрактным классом, чтобы вы не могли прямо сказать new Modulo() но вам потребуется создать с помощью подкласса.
 – 
ajb
23 Дек 2016 в 21:20