How can I access gets and sets in a sub class? - java

In this application we have the Automovel class:
public class Automovel {
private String marca;
private String matricula;
private String anoConstrucao;
private Motor motor;
private int preco = 0;
}
(with their builders, getters and setters) and there is a class called Motor that is an attribute of the Automovel class.
Motor Class:
private int potencia;
public Motor() {}
public Motor(int potencia){
this.potencia = potencia;
}
public int getPotencia() {return this.potencia;}
public void setPotencia(int potencia) {
this.potencia = potencia
}
There are also 2 subclasses of this class (MotorEletrico and MotorCombustao):
Motor Elétrico:
public class MotorEletrico extends Motor {
private int autonomia;
public MotorEletrico() {}
public MotorEletrico(int potencia, int autonomia) {
super(potencia);
this.autonomia = autonomia;
}
public int getAutonomia() {
return autonomia;
}
public void setAutonomia(int autonomia) {
this.autonomia = autonomia;
}
}
Motor Combustão:
public class MotorCombustao extends Motor{
private int cilindrada;
private String combustivel;
public MotorCombustao(){}
public MotorCombustao(int potencia, int cilindrada, String combustivel){
super(potencia);
this.cilindrada = cilindrada;
this.combustivel = combustivel;
}
public int getCilindrada(){
return cilindrada;
}
public void setCilindrada(int cilindrada){
this.cilindrada = cilindrada;
}
public String getCombustivel(){
return combustivel;
}
public void setCombustivel(String combustivel){
this.combustivel = combustivel;
}
}
I store a car with an X engine in an array of Automovel objects, but when I try to access the getters and setters of the subclass (MotorCombustao / MotorEletrico), only the gets and sets of the mother class (Motor) appears. My problem is that I can't access the getters and setters of the motor subclasses.
Here's an example of what I tried:
Automovel arrayteste[] = new Automovel[49];
Motor motor1 = new MotorEletrico();
motor1.setPotencia(5);
Automovel automovel1 = new Automovel("Opel", "xx-12-xx", "2000", motor1, 2000);
arrayteste[0] = automovel1;
System.out.println(arrayteste[0].getMotor().getPotencia()); //Here, I can't Do .getAutonomia

Short answer
You need to cast
System.out.println(((MotorElettrico)(arrayteste[0].getMotor())).getAutonomia());
TL;DR
When you wrote
Motor motor1 = new MotorElettrico();
you are using polymorphism.
This is very useful when, for example you, have a list of Motor that contains more then one motor type and for all of this you want to print the potencia.
Then you can write something like this:
List<Motor> list = Arrays.asList(new MotorElectico(), new MotorCombustao());
// ----- some set
print(list);
where print method is something like this:
public void print(List<Motor> list){
for(Motor m : list){
System.out.println(String.format("Potencia %d", m.getPotencia()));
}
}
This happens because a MotorElectico IS A Motor and upcasting (casting to supertype) is always allowed.
In your case, you have to do downcasting: you are telling to a compilator that arraytest[0].getMotor() contains a Motor but this Motor is actually a MotorElectrico: you are asking to compilator to trust you. If at compile-time arraytest[0].getMotor() should not be a MotorElectrico you'd get a ClassCastException.

You need to cast the reference of the parent class to the corresponding child class if you want to access a method which is not inherited from the parent class e.g. the method, getAutonomia() is not inherited from Motor and therefore, you need to cast the reference of Motor to MotorEletrico before you can access getAutonomia(). Some more useful code is given below:
public class Main {
public static void main(String[] args) {
Automovel arrayteste[] = new Automovel[2];
Motor motor;
motor = new MotorEletrico(5, 10);
arrayteste[0] = new Automovel("Opel", "xx-12-xx", "2000", motor, 2000);
motor = new MotorCombustao(7, 4, "xx-yy-zz");
arrayteste[1] = new Automovel("Opel", "xx-08-xx", "1995", motor, 1995);
for (Automovel automovel : arrayteste) {
motor = automovel.getMotor();
if (motor instanceof MotorEletrico) {
System.out.println(((MotorEletrico) motor).getAutonomia());
}
if (automovel.getMotor() instanceof MotorCombustao) {
System.out.println(((MotorCombustao) motor).getCilindrada());
System.out.println(((MotorCombustao) motor).getCombustivel());
}
}
}
}
Output:
10
4
xx-yy-zz
[Update: the following update is based on your comment]
Another way to iterate arrayteste is as given below:
for (int i = 0; i < arrayteste.length; i++) {
if (arrayteste[i] != null) {
motor = arrayteste[i].getMotor();
if (motor instanceof MotorEletrico) {
System.out.println(((MotorEletrico) motor).getAutonomia());
}
if (arrayteste[i].getMotor() instanceof MotorCombustao) {
System.out.println(((MotorCombustao) motor).getCilindrada());
System.out.println(((MotorCombustao) motor).getCombustivel());
}
}
}

You are familiar with the Liskov substitution principle, I assume.
If you don't know the type of motor, you can write a statement that asks each instance of the Automovel array arraytest[i] what class it is.
For example:
List<Automovel> arrayteste = new ArrayList<>();
Motor motor1 = new MotorEletrico();
motor1.setPotencia(5);
Automovel automovel1 = new Automovel("Opel", "xx-12-xx", "2000", motor1, 2000);
arrayteste.add(automovel1);
Motor motor = new Motor();
String motorClass;
String[] motorTypes = {"MotorEletrico", "MotorCombustao"};
Set<String> motorClasses = new HashSet<>(Arrays.asList(motorTypes));
for (int i = 0; i < arrayteste.size(); i++)
{
motorClass = arrayteste.get(i).getMotor().getClass().getName();
if (motorClasses.contains(motorClass))
{
if (motorClass.equals("MotorEletrico"))
{
motor = (MotorEletrico)(arrayteste.get(i).getMotor());
}
else if (motorClass.equals("MotorCombustao"))
{
motor = (MotorCombustao)(arrayteste.get(i).getMotor());
}
System.out.println("Automovel #" + i + " : " + motor.getPotencia());
}
else
{
System.out.println("Não sei que classe de motor é esse . . .");
}
}
}
But it might be better to explore the class design more closely.
Possibly try to use interfaces.

Related

Java: how can I put new object into array of objects of its class inside a constructor function? Is it possible?

everyone! I'm total noob in Java and in programming in general and I want to implement CarBrand class with its' inner Model class (let there be no more than 4 models for each brand). For example:
public class CarBrand {
public String brand;
public Model[4] models;
public int curIndex = 0;
public CarBrand(String name) {
brand = name;
Model[] models = new Model[4];
}
public class Model {
public String modelName;
public Model(String name) {
modelName = name;
models[curIndex] = this;
curIndex = curIndex + 1;
}
}
}
I want to make new instance of CarBrand and its new Model (and add this model into models array of new instance of CarBrand) this way:
public class App {
public static void main(String args[]) {
CarBrand subaru = new Auto("Subaru");
CarBrand.Model legacy = subaru.new Model("Legacy");
System.out.println(subaru.models[0]);
}
}
But unfortunately running App finishes with error:
Exception in thread "main" java.lang.NullPointerException: Cannot store to object array because "<parameter1>.models" is null
What is the reason behind that? Is there a way to add a new model in brand's models array? I suppose, the object wasn't created yet, that's why there is an error. How far am I from the truth?
Your syntax is generally incorrect: you would need
public Model[] models; // not Model[4]
public int curIndex = 0;
public CarBrand(String name) {
brand = name;
models = new Model[4]; // not Model[]
}

Need explanation of this UML model

Please explain what "MANAGER static employee" means.
I did everything except changeManager, how can I implement it ?
public Employee(){
this.id=-1;
this.year=-1;
salary=-1;
name="NA";
department="NA";
}
public Employee(int id ,String name ,String depatment, int year,double salary){
Employee Employee=new Employee();
Employee.setid(id); Employee.setname(name); Employee.setdepartment(depatment); Employee.setyear(year); Employee.setsalary(salary);
}
As in Java a static attribute in UML is an attribute of the class itself, rather than an attribute of instance, that means there is only one manager 'shared' by all the instances. Of course its type is Employee, so in Java :
private static Employee MANAGER;
by default the class has no manager because MANAGER is null.
Note the presence of 'static' in the diagram is abnormal and does not follow the norm, like for the operation changeManager the line for the attribute is underlined, that is the way to say an attribute/operation is static in UML
The definition of isManager is trivial :
public boolean isManager() { return this == MANAGER; }
Note may be the class does not have yet a manager, in that case MANAGER is null, and to call isManager(null) is the way to check if the class has a manager
The definition of changeManager is also trivial :
public static void changeManager(Employee newManager) { MANAGER = newManager; }
Note that allows to have no manager calling that operation with null
Example with few methods/attributes :
Employee.java
class Employee {
private String name;
private int id;
private static Employee MANAGER;
public Employee(String n, int i) {
name = n;
id = i;
}
public boolean isManager() {
return this == MANAGER;
}
public static void changeManager(Employee e) {
MANAGER = e;
}
}
Main.java
class Main {
public static void main(String[] args) {
Employee e1 = new Employee("e1", 1);
Employee e2 = new Employee("e2", 2);
System.out.print("e1.isManager() = ");
System.out.println(e1.isManager());
System.out.print("e2.isManager() = ");
System.out.println(e2.isManager());
System.out.println("do 'Employee.changeManager(e1)'");
Employee.changeManager(e1);
System.out.print("e1.isManager() = ");
System.out.println(e1.isManager());
System.out.print("e2.isManager() = ");
System.out.println(e2.isManager());
System.out.println("do 'Employee.changeManager(e2)'");
Employee.changeManager(e2);
System.out.print("e1.isManager() = ");
System.out.println(e1.isManager());
System.out.print("e2.isManager() = ");
System.out.println(e2.isManager());
System.out.println("do 'Employee.changeManager(null)'");
Employee.changeManager(null);
System.out.print("e1.isManager() = ");
System.out.println(e1.isManager());
System.out.print("e2.isManager() = ");
System.out.println(e2.isManager());
}
}
Compilation, execution :
pi#raspberrypi:/tmp $ javac Main.java Employee.java
pi#raspberrypi:/tmp $ java Main
e1.isManager() = false
e2.isManager() = false
do 'Employee.changeManager(e1)'
e1.isManager() = true
e2.isManager() = false
do 'Employee.changeManager(e2)'
e1.isManager() = false
e2.isManager() = true
do 'Employee.changeManager(null)'
e1.isManager() = false
e2.isManager() = false
pi#raspberrypi:/tmp $

Assign unique ID for every new Class (not instance!)

I was wondering, whether it would be possible to assign a unique ID for every new class (not instance!).
Example of what I mean:
public class ChildObjectOne extends SuperClass {}
public class ChildObjectTwo extends SuperClass {}
public SuperClass {
private final int ID;
public SuperClass() {
this.ID = newID();
}
}
final ChildObjectOne childObjectOne = new ChildObjectOne();
final ChildObjectTwo childObjectTwo = new ChildObjectTwo();
System.out.println(childObjectOne.getID()); //prints 1
System.out.println(childObjectOne.getID()); //prints 2
childObjectOne = new ChildObjectOne();
childObjectTwo = new ChildObjectTwo();
System.out.println(childObjectOne.getID()); //prints 3
System.out.println(childObjectOne.getID()); //prints 4
What I want it to do instead is print 1 and 2 again. It should generate a new ID for every new class, but if I create a new instance of that class, I want the ID to stay the same.
I tried to achieve this using generics:
public SuperClass<T> {
private static int ID;
public SuperClass() {
this.ID = newID();
}
}
public class ChildObjectOne extends SuperClass<ChildObjectOne> {}
public class ChildObjectTwo extends SuperClass<ChildObjectTwo> {}
I was hoping, it would count passing a different T as a new class, but that didn't work. Instead the ID is the last one that was set.
How can I achieve this kind of ID system?
To expand upon my comment, the class name will give you an unique String ID. If you want that ID to be a number you could do something like this:
class IdGenerator{
private static int counter = 0;
private static HashMap<String,Integer> classIdMap = new HashMap<>();
public static synchronized int getId(Class clazz){
if (classIdMap.containsKey(clazz.getName())) {
return classIdMap.get(clazz.getName());
} else {
classIdMap.put(clazz.getName(), ++counter);
return counter;
}
}
}
And then from your class you would do:
IdGenerator.getId(this.getClass());
The generated IDs might not be the same every time you run your app, depending on how it is structured.
For example:
Scanner in = new Scanner(System.in);
if (in.nextInt() < 100) {
System.out.println("a = " + new Aclass().id); // a = 1
System.out.println("b = " + new Bclass().id); // b = 2
} else {
System.out.println("b = " + new Bclass().id); // b = 1
System.out.println("a = " + new Aclass().id); // a = 2
}
Class::getName
Each class in Java already carries a unique identifier: the fully-qualified name of the class. No need for you to add an identifier.
Access the fully-qualified name by calling Class::getName.
For a class:
String.class.getName()
"java.lang.String"
For an object (an instance), call Object::getClass, and then Class::getName.
customer.getClass().getName()
com.example.invoicing.Customer

Using a Java For-Each Loop to iterate over an ArrayList which has private access?

I have three classes: Labradors, Kennels and Show. The Kennel contains a private ArrayList of
Labradors. As shown:
Labradors.java:
public class Labradors {
private String name;
private String description;
public Labradors(String n, String d) {
name = n;
description = d;
}
public String getName() {
return name;
}
}
Kennel.java:
import java.util.ArrayList;
public class Kennel{
private ArrayList<Labradors> labs;
public Kennel() {
labs = new ArrayList<Labradors>();
}
public void addDog(Labradors l) {
labs.add(l);
}
}
and
Show.java
class Show
{
public static void main(String args[])
{
Labradors Dave = new Labradors("Dave", "Good dog!");
Labradors Bob = new Labradors("Bob", "Likes tummy rubs!");
Kennel niceHome = new Kennel();
niceHome.addDog(Dave);
niceHome.addDog(Bob);
for (Labradors lab: niceHome.labs ) {
System.out.println(lab.getName());
}
}
}
My for-each loop in Show gives me the following error:
Show.java:12: error: labs has private access in Kennel
for (Labradors lab: niceHome.labs ) {
^
1 error
Clearly one solution would be to make the ArrayList public, but my understanding of encapsulation is that best practice means it should be private and a Getter written. But how do I do this?
I feel this should have a really easy answer, but I'm having difficulty tracking it down...
NB - I'm using openjdk version 11.0.6 on Ubuntu 19.10.
Inside Kennel Class make a getter function
import java.util.ArrayList;
public class Kennel{
private ArrayList<Labradors> labs;
public Kennel() {
labs = new ArrayList<Labradors>();
}
public void addDog(Labradors l) {
labs.add(l);
}
public ArrayList<Labradors> getLabs(){
return this.labs;
}
}
Then access from main function like this
class Show
{
public static void main(String args[])
{
Labradors Dave = new Labradors("Dave", "Good dog!");
Labradors Bob = new Labradors("Bob", "Likes tummy rubs!");
Kennel niceHome = new Kennel();
niceHome.addDog(Dave);
niceHome.addDog(Bob);
for (Labradors lab: niceHome.getLabs()) {
System.out.println(lab.getName());
}
}
}

Java varargs to require indefinite number of variables

I am trying to apply varargs. I have declared a method which requires an indefinite amount of variables like this:
private Subject carMonitor;
public AdvancedMonitor(Subject ... carMonitors){
for (Subject carMonitor : carMonitors){
this.carMonitor = carMonitor;
carMonitor.registerObserver(this);
}
}
However, when I try to call it in my main method, I am not able to use anything other than one argument:
BigCar bigCar = new BigCar();
SmallCar smallCar = new SmallCar();
AdvancedMonitor doubleAdvancedDisplay1 = new AdvancedMonitor();
AdvancedMonitor doubleAdvancedDisplay2 = new AdvancedMonitor(bigCar);
AdvancedMonitor doubleAdvancedDisplay3 = new AdvancedMonitor(bigCar, smallCar);
Only the second one works. Why is this?
Is it related to my interface?
public interface Subject {
public void registerObserver(Observer o);
public void removeObserver(Observer o);
public void notifyObservers();
}
big car interface -- small car is pretty much the same for now :
public class BigCar implements Subject {
private ArrayList observers;
private int state;
public BigCar(){
observers = new ArrayList();
}
public void registerObserver(Observer o){
observers.add(o);
}
public void removeObserver(Observer o){
int i = observers.indexOf(o);
if (i >= 0){
observers.remove(i);
}
}
public void notifyObservers(){
for (int i = 0; i < observers.size(); i++){
Observer observer = (Observer)observers.get(i);
observer.update(state);
}
}
public void stateChanged() {
notifyObservers();
}
public void setState(int state){
this.state = state;
stateChanged();
}
}
I write following code:
public class Test {
public static class AdvancedMonitor {
private String carMonitor;
public AdvancedMonitor(String... carMonitors) {
for (String carMonitor : carMonitors) {
this.carMonitor = carMonitor;
System.out.println(this.carMonitor);
}
}
}
public static void main(String[] args) {
String bigCar = "bigCar";
String smallCar = "smallCar";
System.out.println("step 1");
AdvancedMonitor doubleAdvancedDisplay1 = new AdvancedMonitor();
System.out.println();
System.out.println("step 2");
AdvancedMonitor doubleAdvancedDisplay2 = new AdvancedMonitor(bigCar);
System.out.println();
System.out.println("step 3");
AdvancedMonitor doubleAdvancedDisplay3 = new AdvancedMonitor(bigCar, smallCar);
}
}
And I have following result:
step 1
step 2
bigCar
step 3
bigCar
smallCar
In my opinion, all correct. What is wrong in your case? Do you use logging or System.out.println to debug your problem? It's look like your problem isn't with Java varagrs, but you have some exception in carMonitor.registerObserver(this).
P.S. Also, you understand that every AdvancedMonitor has only a one varible carMonitor? And using new AdvancedMonitor(bigCar, smallCar); in result you have AdvancedMonitor only with smallCar in private String carMonitor;?
P.P.S. Also bad idea to use this in construstor, because object isn't really create when running construstor.
Actually the Constructor works.
Please check these statements:
SmallCar and BigCar both implements Subject
class AdvancedMonitor implements Observer
AdvancedMonitor doubleAdvancedDisplay is not declared several times but in your code it is. It should be smth like:
AdvancedMonitor doubleAdvancedDisplay1 = new AdvancedMonitor();
AdvancedMonitor doubleAdvancedDisplay2 = new AdvancedMonitor(bigCar);
AdvancedMonitor doubleAdvancedDisplay3 = new AdvancedMonitor(bigCar, smallCar);
I hope it'll help you

Categories