Instanceof com classe mae e classe filha {JAVA}

Olá! Tenho duas classes no meu projeto, a classe mãe A e filha B. Uso constantemente objetos dessas classes e para editá-los eu uso uma outra classe. Nessa classe eu preciso saber de qual instancia é o objeto que eu recebi pra saber como trata-lo mas o instanceof sempre t indica que o objeto é uma instancia da classe mãe (A) mesmo sendo um objeto da classe filha (B). Atualmente eu uso objeto.getClass().getSimpleName().equals("A") para saber de qual classe é o objeto que eu recebi. Essa é a maneira correta? caso não , qual seria ? Obrigado.

Vc descrevendo assim parece uma maneira errada, mas acho que depende, vc pode mostrar trechos de código que demonstrem o que vc precisa exatamente fazer? É que acredito que a simples herança já resolveria seu problema.

Essa solução parece gambiarra porque parará de funcionar caso você mude o nome da Classe “A”.

Se “B” extende “A”, você deve ser capaz de usar “B” em todos os lugares onde “A” é esperado, caso contrário, estará violando o Princípio de Substituição de Liskov (LSP).

Se em certos casos você precisa de “B” e não te serve “A”, você deveria declarar este Tipo “B” (seja em parâmetros, declaração de variáveis, etc.).

Se você recebe um Objeto Tipo “B” dentro de uma variável do Tipo “A”, como em um Parâmetro, você pode usar instanceof para fazer uma Conversão verificada, assim:

public void paint(Graphics g) { //Graphics é superclasse de Graphics2D
    if (g instanceof Graphics2D)
        Graphics2D g2 = (Graphics2D) g;
    else
        //Lança uma Exception ou faz outra coisa
}

Ainda existem os métodos “x.getClass().isAssignableFrom(y.getClass());” e “x.getClass().isInstance(y);” que lhe podem ser úteis.

1 curtida

Aqui está:
Esta é a classe que uso para editar os objetos das classe A e B, respectivos DebitoFixo e Debito onde Debito herda de DebitoFixo

Tenho dois objetos ja definidos na 3° classe das classes acima. Oque eu preciso é saber a forma certa de diferenciar um objeto do tipo Debito de um objeto do tipo DebitoFixo. Atualmente eu uso o codigo abaixo mas me parece gambiarra

 private DebitoFixo mDebitoFixo;
 private Debito mDebito; 
 private boolean isFixo;

 if (objeto.getClass().getSimpleName().equals("DebitoFixo")) {
        mDebitoFixo = (DebitoFixo) objeto;
        isFixo = true;
    } else {
        mDebito = (Debito) objeto;
    }
   //..... edito o objeto

Eu queria era saber o que vc faz depois dessa verificação, se não puder dizer não tem problema.

Mas vc realmente precisa saber o tipo do objeto? Vc não pode apenas sobreescrever os métodos relacionados e deixar o programa fazer o resto? Por exemplo:

class DebitoFixo {
    void fazAlgumaCoisa(DadoImportante dado) {
        System.out.println("Fazendo algo que só DebitoFixo sabe fazer!");
    }
}

class Debito extends DebitoFixo {
    @Override
    void fazAlgumaCoisa(DadoImportante dado) {
        System.out.println("Fazendo algo que só Debito sabe fazer!");
    }
}

E em outro lugar vc teria:

class Cliente {
    private DadoImportante dado;
    
    void metodoSuperImportante(DebitoFixo d) {
        d.fazAlgumaCoisa(dado);
    }
}

Não sei se ficou claro, mas cada classe saberia lidar com DadoImportante à sua própria maneira sem que vc se preocupe com qual delas é, entende? Será que seria possível algo assim no seu sistema?

Qualquer coisa dá mais detalhes (se puder) que a gente pensa em algo diferente.

Eu não conhecia o Princípio de Substituição de Liskov (LSP), dei uma lida mas n entendi uma coisa: Eu extendo “A” de “B” para aproveitar alguns comportamentos e atributos, no meu caso Debito tem todos os atributos de DebitoFixo e mais 3 atributos próprios. Como devo ser capaz de usar DebitoFixo em todos os lugares onde um Debito é aceito se caso eu precise de um atributo que só Debito tenha eu n vou poder obter de um DebitoFixo? , pra mim faz mais sentido se for ao contrario pois de um Debito eu posso obter todos os atributos de um DebitoFixo. Inclusive eu pensei em usar um objeto Debito na minha classe de edição oque me permitiria checar apenas uma vez qual tipo de objeto estava recebendo , se necessário converte-lo de DebitoFixo para Debito, artibui-lo ao meu objeto de instancia Debito na classe de edição e edita-lo mas depois achei melhor identificar os objetos.

Ahh! N tinha me dado conta do que vc queria… vamos lá!

eu posso usar um objeto debito na classe de edição mas preciso saber se estou manipulando um objeto Debito ou DebitoFixo pois preciso gerar a interface de formas diferentes pra cada objeto, exemplo: Tenho um checkbox na tela que diz se o usuari esta editando uma despesa fixa ou comum e preciso marcar esse checkbox(ou não) de acordo com o objeto que recebo, esses objetos tbm são salvos em tabelas diferentes do Banco de dados, por isso preciso saber o tipo. Obrigado.

Segue a Activity inteira (Estou desenvolvendo para android)

        public class EditarDebito extends AppCompatActivity implements View.OnClickListener,CompoundButton.OnCheckedChangeListener {
private TextInputEditText edtNome, edtValor, edtData, edtObservaçao, edtParcelas;
private Spinner spinner;
private CheckBox cbFixa, cbParcelas;
private RelativeLayout rlContainer;
private LinearLayout llContainer;
private AdView mAdView;
private Folha mFolha;
private Debito mDebito;
private DebitoFixo mDebitoFixo;
private CategoriaManager cManager;
private InputMethodManager imm;
private AppPatterns patterns;
private boolean isFixo;

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.act_add_debitos);
    // TODO: 17/04/2017 CORRIGIR ESSA GAMBIARRA E TENTAR PASSAR O DEBITO POR INTENT ,CHECAR  DEBTSFRAGMENT E DEBTSFIXSFRAGMENT
    if (InstanceHolder.debito.getClass().getSimpleName().equals("DebitoFixo")) {
        mDebitoFixo = (DebitoFixo) InstanceHolder.debito;
        isFixo = true;
    } else {
        mDebito = (Debito) InstanceHolder.debito;
    }


    mFolha = SheetManager.getInstancia().getFolhaAtual();
    cManager = new CategoriaManager();
    patterns = new AppPatterns();
    imm = (InputMethodManager) getSystemService(INPUT_METHOD_SERVICE);
    initComps();
    loadAd();
    new Handler().postDelayed(new Runnable() {
        @Override
        public void run() {
            changeDebtType(isFixo);
        }
    }, 1000);

}

private void changeDebtType(boolean isFixo) {
    ActionBar bar = getSupportActionBar();
    if (bar == null) return;
    if (isFixo) {
        bar.setTitle(getString(R.string.adicionar_debito_fixo));
        bar.setSubtitle(getString(R.string.debitos_fixos));
    } else {
        bar.setTitle(getString(R.string.adicionar_debito));
        bar.setSubtitle(mFolha.getNome());
    }
}

private void initComps() {
    mAdView = (AdView) findViewById(R.id.adView);
    edtNome = (TextInputEditText) findViewById(R.id.edtNome);
    edtValor = (TextInputEditText) findViewById(R.id.edtValor);
    edtData = (TextInputEditText) findViewById(R.id.edtData);
    edtObservaçao = (TextInputEditText) findViewById(R.id.edtObservaçao);
    spinner = (Spinner) findViewById(R.id.spinner);
    rlContainer = (RelativeLayout) findViewById(R.id.rlContainer);
    llContainer = (LinearLayout) findViewById(R.id.llContainer);
    cbFixa = (CheckBox) findViewById(R.id.cbFixa);
    cbParcelas = (CheckBox) findViewById(R.id.cbParcelas);
    ArrayList<Categoria> cArray = cManager.getCategorias();
    SpinnerAdapter adapter = new SpinnerAdapter(this, cArray);
    adapter.setDropDownViewResource(R.layout.view_item_categorias);
    spinner.setAdapter(adapter);

    cbFixa.setClickable(false);
    cbParcelas.setClickable(false);

    if (isFixo) loadFixoData();
    else loadData();

    edtValor.setOnClickListener(this);
    edtData.setOnClickListener(this);
    cbFixa.setOnCheckedChangeListener(this);
    cbParcelas.setOnCheckedChangeListener(this);
}

private void loadFixoData() {
    edtNome.setText(mDebitoFixo.getNome());
    edtValor.setText(patterns.toReal(mDebitoFixo.getValor()));
    edtData.setText(patterns.formatDate(mDebitoFixo.getData(), true));
    edtObservaçao.setText(mDebitoFixo.getObservaçao());

    cbFixa.setChecked(true);

    if (mDebitoFixo.getParcelas() != null && !mDebitoFixo.getParcelas().getParcelaAtual().isEmpty()) {
        addParcelasField(true);
        edtParcelas.setText(mDebitoFixo.getParcelas().getParcelaAtual());
        cbParcelas.setChecked(true);
    }
}

private void loadData() {
    edtNome.setText(mDebito.getNome());
    edtValor.setText(patterns.toReal(mDebito.getValor()));
    edtData.setText(patterns.formatDate(mDebito.getData(), true));
    edtObservaçao.setText(mDebito.getObservaçao());

    cbFixa.setChecked(false);

    if (mDebito.getParcelas() != null && !mDebito.getParcelas().getParcelaAtual().isEmpty()) {
        addParcelasField(true);
        edtParcelas.setText(mDebito.getParcelas().getParcelaAtual());
        cbParcelas.setChecked(true);
    }
}

private void loadAd() {
    if (Configuraçao.getValue(Key.IS_AD_ENABLED, true)) {
        AdRequest adRequest = new AdRequest.Builder().build();
        mAdView.loadAd(adRequest);
    } else {
        rlContainer.removeView(mAdView);
    }
}

private void addParcelasField(boolean b) {
    if (!b) llContainer.removeViewAt(4);
    else {

        int minHeight = (int) getResources().getDimension(R.dimen.input_view_min_height);
        int margin = (int) getResources().getDimension(R.dimen.input_view_margin);

        TableLayout.LayoutParams params = new TableLayout.LayoutParams();
        params.setMargins(margin, margin, margin, margin);

        edtParcelas = new TextInputEditText(this);
        edtParcelas.setHint(getString(R.string.Parcelas));
        edtParcelas.setMinHeight(minHeight);
        edtParcelas.setLayoutParams(params);
        edtParcelas.setInputType(InputType.TYPE_CLASS_NUMBER);
        edtParcelas.setTypeface(new FontManager(this).getCommom());
        MaskEditTextChangedListener maskParcel = new MaskEditTextChangedListener("##/##x", edtParcelas);
        edtParcelas.addTextChangedListener(maskParcel);
        llContainer.addView(edtParcelas, 4);
    }
}

@Override
protected void attachBaseContext(Context newBase) {
    super.attachBaseContext(CalligraphyContextWrapper.wrap(newBase));
}

@Override
public boolean onCreateOptionsMenu(Menu menu) {
    getMenuInflater().inflate(R.menu.menu_check, menu);
    return super.onCreateOptionsMenu(menu);
}

@Override
public boolean onOptionsItemSelected(MenuItem item) {
    if (item.getItemId() == R.id.concluir) {
        updateDebito();
    }
    return super.onOptionsItemSelected(item);
}

private void updateDebito() {
    if (!checkNome()) return;
    if (!checkValor()) return;
    if (!checkData()) return;
    if (cbParcelas.isChecked())
        if (!checkParcelas()) {
            return;
        } else {
            if (isFixo) {
                Parcela parcela = new Parcela(IDManager.createId(Parcela.class));
                parcela.setParcelaAtual(edtParcelas.getText().toString(), mDebitoFixo.getData());
                mDebitoFixo.setParcelas(parcela);
            } else {
                Parcela parcela = new Parcela(IDManager.createId(Parcela.class));
                parcela.setParcelaAtual(edtParcelas.getText().toString(), mDebito.getData());
                mDebito.setParcelas(parcela);
            }
        }
    if (isFixo) {
        mDebitoFixo.setNome(edtNome.getText().toString());
        mDebitoFixo.setObservaçao(edtObservaçao.getText().toString());
        mDebitoFixo.setCategoria((Categoria) spinner.getSelectedItem());
    } else {
        mDebito.setNome(edtNome.getText().toString());
        mDebito.setObservaçao(edtObservaçao.getText().toString());
        mDebito.setCategoria((Categoria) spinner.getSelectedItem());
    }


    if (isFixo) {
        if (!new DebitosManager().updateDebitoFixo(mDebitoFixo))
            Toast.makeText(this, getString(R.string.Erro), Toast.LENGTH_SHORT).show();
    } else {
        if (!mFolha.UpdateDebito(mDebito))
            Toast.makeText(this, getString(R.string.Erro), Toast.LENGTH_SHORT).show();
    }
    finishActivity();
}

private void finishActivity() {
    setResult(RESULT_OK);
    finish();
}


private boolean checkParcelas() {
    String parcelas = edtParcelas.getText().toString();
    if (parcelas.contains("/")) {
        if (parcelas.contains("x")) {
            parcelas = parcelas.replace("/", "").replace("x", "");
            if (parcelas.length() == 4) {
                try {
                    Integer.parseInt(parcelas);
                } catch (Exception e) {
                    AppPatterns.feedBackUser(edtParcelas);
                    return false;
                }

                int atual = Integer.parseInt(parcelas.charAt(0) + "" + parcelas.charAt(1));
                int total = Integer.parseInt(parcelas.charAt(2) + "" + parcelas.charAt(3));
                if (atual > total) {
                    Toast.makeText(this, getString(R.string.A_parcela_atual_nao_pode_ser_maior_do_que_o_total_de_parcelas), Toast.LENGTH_LONG).show();
                    AppPatterns.feedBackUser(edtParcelas);
                    return false;
                } else {
                    return true;
                }

            }

        }


    }
    AppPatterns.feedBackUser(edtParcelas);
    return false;

}

private boolean checkNome() {
    String nome = edtNome.getText().toString();
    // vejo se o usuario alterou o nome da despesa, caso n, n preciso checar os dados
    if (isFixo) {
        if (nome.equals(mDebitoFixo.getNome())) return true;
    } else if (nome.equals(mDebito.getNome())) return true;

    if (nome.isEmpty()) {
        AppPatterns.feedBackUser(edtNome);
        return false;
    }
    ArrayList<Debito> dArray = mFolha.getDebitos();

    for (int i = 0; i < dArray.size(); i++) {
        Debito debito = dArray.get(i);
        if (debito.getNome().equals(nome)) {
            Toast.makeText(this, getString(R.string.debito_id_repetida), Toast.LENGTH_LONG).show();
            AppPatterns.feedBackUser(edtNome);
            return false;
        }
    }
    // se for mDebito fixo checo nos debitos fixos em busca de id repetida
    if (cbFixa.isChecked()) {
        ArrayList<DebitoFixo> dfArray = new DebitosManager().getDebitosFixos();
        for (int i = 0; i < dfArray.size(); i++) {
            DebitoFixo debito = dfArray.get(i);
            if (debito.getNome().equals(nome)) {
                Toast.makeText(this, getString(R.string.debito_fixo_id_repetida), Toast.LENGTH_LONG).show();
                AppPatterns.feedBackUser(edtNome);
                return false;
            }
        }
    }
    return true;

}

private boolean checkValor() {
    if (isFixo) {
        if (mDebitoFixo.getValor() == null || mDebitoFixo.getValor().isEmpty()) {
            AppPatterns.feedBackUser(edtValor);
            return false;
        } else return true;
    } else {
        if (mDebito.getValor() == null || mDebito.getValor().isEmpty()) {
            AppPatterns.feedBackUser(edtValor);
            return false;
        } else return true;
    }
}

private boolean checkData() {
    if (isFixo) {
        if (mDebitoFixo.getData() == null || mDebitoFixo.getData().isEmpty()) {
            AppPatterns.feedBackUser(edtData);
            return false;
        } else return true;
    } else {
        if (mDebito.getData() == null || mDebito.getData().isEmpty()) {
            AppPatterns.feedBackUser(edtData);
            return false;
        } else return true;
    }
}

@Override
public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
    if (buttonView.getId() == R.id.cbFixa) {
        changeDebtType(isChecked);
        if (!isChecked) {
            cbParcelas.setChecked(false);
        }
    }
    if (buttonView.getId() == R.id.cbParcelas) {
        addParcelasField(isChecked);
        if (isChecked) {
            if (!cbFixa.isChecked()) cbFixa.setChecked(true);
        }
    }
}

@Override
public void onClick(View v) {
    if (v.getId() == R.id.edtValor) {
        imm.hideSoftInputFromWindow(edtNome.getWindowToken(), InputMethodManager.RESULT_UNCHANGED_SHOWN);
        new CustomKeyboard().bringItOn(this, edtValor.getText().toString(), new CustomKeyBoardCallBack() {
            @Override
            public void onResult(String realResult, String decimalResult) {
                if (isFixo) mDebitoFixo.setValor(decimalResult);
                else mDebito.setValor(decimalResult);
                edtValor.setText(realResult);
            }
        });
    } else if (v.getId() == R.id.edtData) {
        imm.hideSoftInputFromWindow(edtValor.getWindowToken(), InputMethodManager.RESULT_UNCHANGED_SHOWN);
        new PickData(this, new OnDataSet() {
            @Override
            public void onDataSet(String base, String s) {
                if (isFixo) mDebitoFixo.setData(base);
                else mDebito.setData(base);
                edtData.setText(s);
            }
        });
    }

}

}

Vou olhar o código melhor depois, só queria compartilhar agora essa idéia:

E se usasse Enum?

class DebitoFixo {
    enum Tipo { NORMAL, FIXO }
    private Tipo tipo;
    DebitoFixo(Tipo tipo) { this.tipo = tipo }
}

class Debito extends DebitoFixo {
    Debito() {
        super(NORMAL);
    }
}

Aí acho que o ideal seria criar uma classe Débito que será extendida por DebitoFixo e DebitoNormal.