简体   繁体   中英

Java: Creating object with String input of the object's name

I have two classes, Dog and Cat:

class Dog{
   public void speak(){
        System.out.print("Woof!");
   }
}

class Cat{
   public void speak(){
       System.out.print("Meow!");
   }
}

In my main, I take the name as String, either "Cat", or "Dog".

public static void main(String [] args){
    Scanner sc = new Scanner(System.in);
    String name = sc.next();

    Class<?> cls = Class.forName(name);
    Object object = cls.newInstance();
}

But now I want to be able to call the method "speak". But then I have to cast the object to either cat or dog, since "Object" obviously does not have built in "speak" method. So my solution was to make another class (I can't use if-statements btw):

class Animal{
    public void speak(){
    }
}

And then both "Cat" and "Dog" can extend Animal and override its methods. Is there any other way to do this WITHOUT making another method / using if-statements? (Including switch case, ternary operator). Thanks in advance.

ANOTHER QUESTION: If I take in the name of the METHOD in as an input as well, how would I call it? For example:

class Dog{
    public void speak(){}
    public void bark(){}
}

If I take in as a String either "speak" or "bark", how would I call the method without using if-statements?

You can do it with reflection using Class.getMethod and Method.invoke .

Creating an Animal class is really the cleanest way, though. What stops you from doing that?

You are on the right track. The easiest way is to create an animal class and have dog and cat inherit from it and make them both implement their own version of speak(). Is there a reason you don't want to create another class?

Alright, here are two methods ordered by preference:

abstract class Animal {
    public abstract void speak();
}

class Dog extends Animal {
    @Override
    public void speak() {
        System.out.println("Woof woof");
    }
}

class Cat extends Animal {
    @Override
    public void speak() {
        System.out.println("Miauw");
    }
}

public static void main(String[] args) {
    String type = "Dog";
    Class<?> clazz;
    try {
        clazz = Class.forName(type);
        Animal pet = (Animal) clazz.newInstance();
        pet.speak();
    } catch (Exception e) {
        e.printStackTrace();
    }
}

I'm using a baseclass since it can be assumed that an Animal will hold more fields that are shared by each animal (name, species, etc). If this isn't the case then you should go for an interface.

Or with reflection:

public class Test {
    public static void main(String[] args) {
        String type = "Dog";
        Class<?> clazz;
        try {
            clazz = Class.forName(type);
            for(Method method : clazz.getMethods()){
                if(method.getName().equals("speak")){
                    method.invoke(clazz.newInstance(), null);
                }
            }
        } catch (CException e) {
            e.printStackTrace();
        }
    }
}

You don't have to create class Animal - create an interface :

interface Animal{
    public void speak();
}

and have both Cat and Dog implement it. Then in main() :

Class<?> cls = Class.forName(name);
Animal animal = cls.newInstance();
animal.speak();

No need to cast or use if/else.

The only reason to use inheritance/abstract classes is when you want to reuse functionality (implement a method once and use it in a few classes). Otherwise - better use interfaces.

As for the method name, if you want the "wise-ass" solution: use switch (supported from Java 7). Otherwise, see @immibis's answer.

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