简体   繁体   中英

java- calling sub-class from a list

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.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM