java- calling sub-class from a list - java

I have this code:
public abstract class animal {
public final static int elephent = 1;
public final static int dog = 2;
and two sub-classes:
public class elephant extends animal {
public final static int type = animal.elephent;
public elephant (String name){
super(name);
}
}
public class dog extends animal {
public final static int type = animal.dog;
public dog (String name){
super(name);
}
}
now, say I have a list of Chars with the letters E- elephant and D- dog.
and an empty list of animals class of the same size.
and for every char on the first list I want to create a new instance of the right animal.
example: ["d","e","d"]
would give me a list of: [new dog, new elephant, new dog]
hope I made myself clear,
thanks in advance for the help.

This design is not optimal. You are indicating the type with an integer variable, which really is not a good idea.
First improvement: Make the type indication an enum.
public enum AnimalType {
ELEPHANT, DOG
}
Now add a type field in your animal class:
public abstract class Animal {
private final AnimalType type;
private final String name;
protected Animal(AnimalType type, String name) {
this.type = Objects.requireNonNull(type);
this.name = Objects.requireNonNull(name);
}
// more fields and methods here
}
An elephant then looks like that (dog is similar):
public class Elephant extends Animal {
public Elephant(String name) {
super(AnimalType.ELEPHANT, name);
}
// more fields and methods here
}
The main disadvantage: Each time you add a new animal type, you must add a new class and add a type to the enumeration. This is not the best design. Additionally, the type enum is not really needed, as the sub types already hold the type information
An instance of class Elephant is an elephant (dog the same). It does not need the type field.
Second improvement: Delete the type indication completely. No integers, no enums. Just have the abstract class and the sub classes.
Now your question, how to get the correct instance from any character input. This is called a mapping. You want to map
the character 'E' to the class Elephant.
the character 'D' to the class Dog.
This can be achieved by a Java Map:
Map<Character, Class<? extends Animal>> charToAnimal = new HashMap<>();
charToAnimal.put('E', Elephant.class);
charToAnimal.put('D', Dog.class);
Class<? extends Animal> animalClass = charToAnimal.get('E');
String name = ...;
Animal animal = animalClass.getConstructor(String.class).newInstance(name); // will be an Elephant instance
This map should be maintained in any class you need that behavior, or maybe in the main method if you are just learning how to do that.
Note, that I used a Java mechanism called reflection, just to create an instance, as there is no other generic way to handle the instantiation.
Another approach would be a method that does the same:
public Animal createAnimal(char c, String name) {
if (c == 'E') {
return new Elephant(name);
} else if (c == 'D') {
return new Dog(name);
} else {
throw new IllegalArgumentException(c);
}
}
Either way, you have to add not only a ne animal sub class, but you have to add an entry into the map (see above) or an if branch to the method.
EDIT, as I thought again over this scenario.
You could go with the enum approach and put the class instantiation into this enum. Take the animal classes as above and the following type enum (not checked):
public enum AnimalType {
ELEPHANT('E', Elephant.class),
DOG('D', Dog.class);
private static final Map<Character, Class<? extends Animal>> CHAR_TO_ANIMAL = new HashMap<>();
AnimalType(char c, Class<? extends Animal> animalClass) {
CHAR_TO_ANIMAL.put(c, animalClass)
}
public Animal createAnimal(char c, String name) {
if (c == 'E') {
return new Elephant(name);
} else if (c == 'D') {
return new Dog(name);
} else {
throw new IllegalArgumentException(c);
}
}
}

So one of the things you may want to consider is a switch-case statement. So in Java, you could do something like this:
// get a char from the list.
char animal;
switch(animal)
{
case'e':
Elephant varName = new Elephant("Dumbo");
newList.add(varName);
break;
}
I've not included everything here, but this should get you started. You will need to look up iterating (looping) through a data structure.
I will be honest, it's been a while since I've written any Java, but this is one way you could do this. There are other ways to do this as well, such as using an if block as well.
Hope this helps.

I think what u need is an static factory method returns an instance.Here is one way of doing it.
Abstract Class:
public abstract class animal {
public final static char elephent = 'E';
public final static char dog = 'D';
}
Elephant Class:
public class Elephant extends Animal {
private char myType;
private String name;
public Elephant(char type, String name) {
super();
this.myType = type;
this.name = name;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public char getMyType() {
return myType;
}
public void setMyType(char myType) {
this.myType = myType;
}
}
Dog Class:
public class Dog extends Animal {
private char myType;
private String name;
public Dog(char type, String name) {
super();
this.myType = type;
this.name = name;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public char getMyType() {
return myType;
}
public void setMyType(char myType) {
this.myType = myType;
}
}
Factory Class:
public class FactoryMethod {
static char getAnimalIndex(char type){
switch (type) {
case 'E':
case 'e':
return Animal.ELEPHANT;
case 'D':
case 'd':
return Animal.DOG;
default:
throw new IllegalArgumentException(String.valueOf(type));
}
}
public static Animal getInstance(char type, String name){
Animal myCategory = null;
switch (getAnimalIndex(type)) {
case Animal.ELEPHANT:
myCategory = new Elephant(type,name);
break;
case Animal.DOG:
myCategory = new Dog(type,name);
break;
}
return myCategory;
}
}
Usage:
if u need to use Animal class index or as u with the character from the list this factory method works.
To get instance:
//using Animal index
FactoryMethod.getInstance(Animal.ELEPHANT,"Elephant");
FactoryMethod.getInstance(Animal.DOG,"Dog");
//using characters in list
FactoryMethod.getInstance('character_in_list_here',"Name OF The Animal Here");
Since it is a static method u can use without using FactoryMethod instance.
I hope this is what u needed.

Related

Error when extending from abstract parent class

Error
public Cat (String nm, int legs, String sd, String col)
For this constructor I got following compiler error:
constructor Animal in class Animal cannot be applied to given types;
required: String, int
found: no arguments
reason: actual and formal arguments lists differ in length
Code
The parent class is right below the child class.
public class Cat extends Animal {
private String sound;
private String colour;
public Cat (String nm, int legs, String sd, String col) {
nm = super.getName();
legs = super.getNumOfLegs();
sound = sd;
colour = col;
}
public abstract class Animal {
protected String name;
protected int numOfLegs;
public Animal() {
}
public Animal(String nm, int legs) {
name = nm;
numOfLegs = legs;
}
public String getName() {
return name;
}
public int getNumOfLegs() {
return numOfLegs;
}
public abstract String display();
}
}
Should the parent abstract class be placed in a separate file instead?
I've tried that initially but it returned way more errors than it did now, especially from the abstract method display().
What is causing the error?
There are a couple of things you should change.
First of all, it is the best way to put the super class into a separate file. If you want to keep in one file you need drag it out of the Cat class and remove the scope (not public or private). But this is not a good coding style for a super class.
The next thing is, with the name/nm and legs/numOfLegs. Either you call the super constructor and provide the two variables (see my example) or you use name = nm; and numOfLegs = legs;
You should also reconsider if the name and numOfLegs varialbes need to be protected or if is fine to provide the access only through the getter.
If the number of legs, the name, sound and color will not change you could also make them immutable (with the key word final, e.g. private final String sound). If not you can make them accessible with a setter.
Finally you need to implement the abstract method in the Cat class...
public class Cat extends Animal {
private String sound;
private String colour;
public Cat(String nm, int legs, String sd, String col) {
super(nm, legs);
sound = sd;
colour = col;
}
#Override
public String display() {
return null;
}
}
abstract class Animal {
protected String name;
protected int numOfLegs;
public Animal(String nm, int legs) {
name = nm;
numOfLegs = legs;
}
public String getName() {
return name;
}
public int getNumOfLegs() {
return numOfLegs;
}
public abstract String display();
}

How to cast an object of an ArrayList of objects (of type superclass) to an object of type subclass

If I have a superclass, let's call it Car, with the constructor parameters String name, String color, double wheelSize, and a subclass of this, let's call it Truck, with the constructor parameters String name, String color, double wheelSize, and double truckBedArea, and in the subclass (Truck), I have a method called modifyCar with the paramaters Car car, String newName, String newColor, double newWheelSize, and double newTruckBedArea, how can I find a way to take that Car object and specify that it is indeed a Truck, so I can then use a Truck setter (setTruckBedArea) to set the new truck bed area? This example isn't a great comparison to my actual assignment, but I have an ArrayList field of my superclass (Cars) called "ArrayList cars" of "Car" objects, and I need to find a way to change that "Car" object in this ArrayList field, which I have already found a way of doing. I simply loop through each item in the ArrayList of "Cars" until it equals the instance of the Car put in as a parameter, and if it does, I then say "cars.get(i).//setter" (essentially). However, it would not work if I say "cars.get(i).setTruckBedArea(newTruckBedArea)". I am not sure how to cast the Car object within this list of Cars to a Truck specifically, so I can then access the setter I want to use. The main issue is that I am required to implement an interface (let's call it "Vehicle") wherein the ArrayList cars has to be of type cars, since it is specified to be that in the Vehicle interface (otherwise I would just change the ArrayList field to be ArrayList trucks).
Example:
public class Truck implements Vehicle { //have to implement this interface
//... other fields
private ArrayList<Car> cars;
//... other methods/constructors
public void modifyCar(Car car, String newName, String newColor, double newWheelSize, double newTruckBedArea) {
//have to have "Car car" as parameter for this method because of interface
for (int i = 0; i < cars.size(); i++) {
if (cars.get(i).equals(car)) {
cars.get(i).setColor(newColor);
cars.get(i).setName(newName);
cars.get(i).setWheelSize(newWheelSize);
cars.get(i).setTruckBedArea(newTruckBedArea); //will produce error
}
}
}
}
As far as I understand the question, you can use "instanceof" operator:
if(cars.get(i) instanceof Truck){
Truck truck = (Truck) cars.get(i);
truck.setTruckBedArea(newTruckBedArea);
}
instanceof operator returns a boolean value in result of whether an object is an instance of given type or not.
Vehicle should be an Abstract class.
Car Interface
public interface Car {
void modifyCar(Car car, String newName, String newColor, double newWheelSize, double newTruckBedArea);
}
Vehicle Abstract Class
public abstract class Vehicle implements Car {
String name;
String color;
double wheelSize;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getColor() {
return color;
}
public void setColor(String color) {
this.color = color;
}
public double getWheelSize() {
return wheelSize;
}
public void setWheelSize(double wheelSize) {
this.wheelSize = wheelSize;
}
}
Truck Class
public class Truck extends Vehicle {
double truckBedArea;
private ArrayList<Car> cars;
public double getTruckBedArea() {
return truckBedArea;
}
public void setTruckBedArea(double truckBedArea) {
this.truckBedArea = truckBedArea;
}
public ArrayList<Car> getCars() {
return cars;
}
public void setCars(ArrayList<Car> cars) {
this.cars = cars;
}
#Override
public void modifyCar(Car car, String newName, String newColor, double newWheelSize, double newTruckBedArea) {
for (int i = 0; i < cars.size(); i++) {
if (cars.get(i).equals(car)){
((Vehicle)cars.get(i)).setColor(newColor);
((Vehicle)cars.get(i)).setWheelSize(newWheelSize);
((Truck)cars.get(i)).setTruckBedArea(newTruckBedArea);
}
}
}
}
Run code.
public static void main(String[] args) {
// TODO code application logic here
Truck trucks = new Truck();
trucks.setColor("Red");
trucks.setName("Nissan");
trucks.setWheelSize(20.15);
trucks.setTruckBedArea(3.5);
ArrayList<Car> cars = new ArrayList<Car>();
cars.add(trucks);
trucks.setCars(cars);
trucks.modifyCar(trucks, "Kia", "Blue", 15.5, 14.0);
System.out.println(trucks.getTruckBedArea());
}

I need help creating constructors and returning boolean and strings

I need help fixing my code with the basic concepts listed above. To save from clutter, I took a screen shot of the directions here: https://imgur.com/SdiotUi
However, when I run my code it isn't working. I know there are a lot of errors but I'm having trouble fixing them even though I've spent the past few hours googling the correct way to do this.
When I create the first constructors I am not sure if I am assigning the name and legs correctly, I am having trouble returning "true", I get an error calling the parent class taking one argument, and I don't think I am overriding the abstract class correctly.
My code:
public class Animal1 {
private String animalName;
public int numberOfLegs;
public Animal1(String name){
name = animalName;
name = "John";
}
public Animal1(String name, int legs){
name = animalName;
legs = numberOfLegs;
name = "Jack";
legs = 4;
}
public String getName(){
return animalName;
}
public int getLegs(){
return numberOfLegs;
}
public void isAMammal(){
return true;
}
public void isCarnivorous(){
return true;
}
public abstract class getHello{
}
}
public class Cat1 extends Animal1{
public Cat1(String name){
Animal1.name;
}
public abstract class getHello{
return "Meow";
}
}
public class Dog1 extends Animal1{
public Dog1(String name){
Animal1.name;
}
public abstract class getHello{
return "Woof";
}
}
public abstract class Animal1 { // If you want to have an abstract method, declare the class as abstract
private final String animalName;
private final int numberOfLegs; // better of using private and make it final since it's not going to change.
public Animal1(final String name, final int legs){ //better making the input parameters final since they are not supposed to be changed
//name = animalName;
//legs = numberOfLegs;//it assigned the field to an input parameter. that will take no effect on the object created.
animalName = name;
numberOfLegs = legs;
}
public String getName(){
return animalName;
}
public int getLegs(){
return numberOfLegs;
}
public boolean isAnimal(){ //boolean function needs a return type too!!
return true;
}
public boolean isCarnivorous(){
return true;
}
public abstract String getHello(); // an abstract method has same requirement as a normal method besides the abstract modifier. it will need a return type. And it ends with a semicolon
}
public class Cat1 extends Animal1{
public Cat1(final String name){
super(name, 4); //use super to call parent constructor
}
#Override
public String getHello(){
return "Meow";
}
}
public class Dog1 extends Animal1{
public Dog1(final String name){
super(name, 4);
}
#Override
public String getHello(){
return "Woof";
}
}
First, it looks like a few of your methods are declared as classes. I assume you wanted to make them abstract methods. They need to be changed to:
public abstract String getHello();
Note that abstract methods can only be declared in an abstract class. So, you need to redefine Animal1 as abstract.
public abstract class Animal1
Next, when you implement the abstract method, you define it as
public String getHello()
If you are using an IDE like Eclipse it will automatically offer to generate this method.
Finally, when using your constructor in your child classes like Cat1, you are trying to set "name" as if it was a static variable and bypassing the constructor you already had set for Animal1. The best way to correct this is to change the constructor in Cat1 and Dog1 to call the super constructor.
public Cat1(String name){
super(name);
}

Trying to figure out Inheritance and polymorphism

I'm doing an exercise on Inheritance and polymorphism, I have 3 seperate clasees, my main class, a super Animal class, and a sub Cat class. I've made overloaded constructors, getters and setters, and toString() methods in both Animal and Cat classes. I think I have the inheritance part down. Now I need to make 2 Animal Object references, both an instance of Cat, example: one a type Siameese with a name Tobbie.
Could anyone give me an example of one of these object references? You can see I've attempted in my Main class there, but I'm not sure if that is correct.
Here are the three different classes I have currently.
public class Hw02 {
/**
* #param args the command line arguments
*/
public static void main(String[] args) {
Animal Siamese = new Cat("Tobbie");
}
}
Here's my Animal Class.
public class Animal {
private String name;
public Animal() {
this("na");
}
public Animal(String name) {
this.name = name;
}
/**
* #return the name
*/
public String getName() {
return name;
}
/**
* #param name the name to set
*/
public void setName(String name) {
this.name = name;
}
#Override
public String toString() {
return "Animal{"
+ "name="
+ name
+ '}';
}
}
And here is my Cat class.
public class Cat extends Animal {
private String type;
public Cat() {
}
public Cat(String type) {
this.type = type;
}
public Cat(String type, String name) {
this.type = type;
}
public String getType() {
return type;
}
public void setType(String type) {
this.type = type;
}
#Override
public String toString() {
return "Cat{"
+ "type="
+ type
+ '}';
}
}
// in main method
Animal tobbie = new Cat("siamese", "Tobbie")
Animal jackie = new Cat("tomcat", "Jackie")
// in Cat class
public Cat(String type, String name) {
super(name)
this.type = type;
}
A few comments:
It is not proper convention to have the name Siamese; variable names should be "camelCase" (start with a lower-case letter). Compiler will accept it is as you have written, but it is a bad practice.
Your Cat(String type, String name) constructor didn't invoke the proper superclass constructor, thus type was lost; same for the Cat(String type) constructor
I think I would make Animal abstract and its constructors protected. I think it is a bad practice to let clients directly instantiate Animals without specifying what kind of animals they are.
Edit:
Like this:
Animal animal = new Animal("What am I?")
However, I don't consider it a good practice to do this, probably what you want done is better achieved otherwise.
Edit:
Cat toString():
public String toString() {
return super.toString() + " Cat{type=" + type + "}";
}
With the code you have above, this is an example:
Animal animal0 = new Cat("Siamese", "Bob");
Animal animal1 = new Cat("Tomcat", "Frank");
Animal animal2 = new Cat("Tomcat", "George");
Animal animal3 = new Animal("Elephant");
System.out.print(animal0.toString());
System.out.print(animal1.toString());
System.out.print(animal2.toString());
System.out.print(animal3.toString());
Would produce the output:
Cat{type=Siamese}
Cat{type=Tomcat}
Cat{type=Tomcat}
Animal{name=Elephant}

Is it possible to use Enum constants as templates for instantiable classes in Java?

Sorry if my question is a bit unclear; I'm finding it a little tough to find the wording. I spent several hours screwing around in Eclipse, cruising the JavaDoc, and Google, as well as SO. I learned a lot, but didn't find an answer.
What I'd like to be able to do is define an Enum, eg.:
public enum Animals {
Cow,
Chicken,
Sheep,
Horse;
}
and have each enum constant define an instantiable class that's not a local class. Would the following work? And if not, why, and what would?
In some file:
abstract public class Animal {
private String nameString;
public String getName() {
return nameString;
}
}
In another:
public enum Animals {
Cow ((new Animal() {
private boolean hasMilk;
{
nameString = "Cow";
hasMilk = false;
}
public boolean hasMilk() {
return hasMilk;
}
}).getClass()),
Chicken ((new Animal() {
private boolean hasFeathers;
{
nameString = "Chicken";
hasFeathers = true;
}
public boolean hasFeathers() {
return hasFeathers;
}
}).getClass()),
Sheep ((new Animal() {
private boolean isShorn;
{
nameString = "Cow";
isShorn = false;
}
public boolean isShorn() {
return isShorn;
}
public void Shear() {
isShorn = true;
}
}).getClass()),
Horse ((new Animal() {
{
nameString = "Cow";
}
}).getClass());
private Class<? extends Animal> animalClass;
private Animals(Class<? extends Animal> a) {
animalClass = a;
}
public Class<? extends Animal> getAnimalClass() {
return animalClass;
}
}
And then, in some other method of some other class, be able to do this:
Animal farmAnimal;
farmAnimal = Animals.Sheep.getAnimalClass().newInstance();
boolean shorn = farmAnimal.isShorn();
(The value of shorn being false at this point);
farmAnimal.shear();
shorn = farmAnimal.isShorn();
(shorn == true)
farmAnimal = Animals.Sheep.getAnimalClass().newInstance();
shorn = farmAnimal.isShorn();
(shorn == false)
Obviously, this isn't the best way to do what I've done here, but that's not the point. I know I can specify behaviour for enum constants, but that doesn't make them multiply-instantiable as distinct instances. I want to be able to create multiple instances (or copies) of various enum constants, with different instance variables (and different quantities/types of instance variables), with different accessor methods, which I can then do stuff to (alter instance variables) without modifying the enum constant.
I get that enum constants are designed to be immutable. That doesn't clash with my idea; I want each enum constant to represent an immutable definition of a mutable class.
You can do something like this:
public enum AnimalType {
COW {
#Override
public Animal createNew() {
return new Cow();
}
},
HORSE {
#Override
public Animal createNew() {
return new Horse();
}
};
public abstract Animal createNew();
}
public abstract class Animal {
private final AnimalType type;
private final String nameString;
public Animal(final AnimalType type, final String nameString) {
super();
this.type = type;
this.nameString = nameString;
}
public String getName() {
return nameString;
}
public AnimalType getType() {
return type;
}
}
public class Horse extends Animal {
public Horse() {
super(AnimalType.HORSE, "Horse");
}
}
public class Cow extends Animal {
private boolean milk;
public Cow() {
super(AnimalType.COW, "Cow");
}
public boolean hasMilk() {
return milk;
}
public void setMilk(final boolean milk) {
this.milk = milk;
}
}
#Test
public void testEnum() {
Cow cow = (Cow) AnimalType.COW.createNew();
Horse horse = (Horse) AnimalType.HORSE.createNew();
System.out.println("cow : " + cow.getType() + ", has milk: " + cow.hasMilk());
System.out.println("horse: " + horse.getType());
}

Categories