This question already has an answer here:
Closed 10 years ago.
Possible Duplicate:
Regarding factory design pattern through reflection
I was doing R&D on factory pattern I have developed the below code. Right now I know the subclasses are Dog and Cat, but please advise me. What to do if I want to achieve the same thing through reflection by passing the class name in main.java?
Animal
public abstract class Animal {
public abstract String makeSound();
}
Dog
public class Dog extends Animal {
#Override
public String makeSound() {
return "Woof";
}
}
Cat
public class Cat extends Animal {
#Override
public String makeSound() {
return "Meow";
}
}
AnimalFactory
public class AnimalFactory {
public Animal getAnimal(String type) {
if ("canine".equals(type)) {
return new Dog();
} else {
return new Cat();
}
}
}
Main
public class Main {
public static void main(String[] args) {
AnimalFactory animalFactory = new AnimalFactory();
Animal a1 = animalFactory.getAnimal("feline");
System.out.println("a1 sound: " + a1.makeSound());
Animal a2 = animalFactory.getAnimal("canine");
System.out.println("a2 sound: " + a2.makeSound());
}
}
Please advise it how I can add reflection functionality into it so that I don't need to even determine the type, just pass the class name in the main java and object of that subclass gets created.
If you pass the fullyqualified name of the class, you can instantiate them as following:
return (Animal) Class.forName(fullyQualifiedClassName).newInstance();
To avoid ClassCastException, you could test that the returned class of Class.forName() is indeed a subclass of Animal before invoking newInstance(). Use isAssignableFrom for that.
public Animal getAnimal(String clName) {
try {
return (Animal) Class.forName(clName).newInstance();
} catch (Exception e) {
throw new RuntimeException(e);
}
}
Related
I am very new to reflections and I would like to get some advices/help. I am trying to get the subclass names using reflection in the base class. I have multiple subclasses (Cat, Dog, Frog etc..) and all of them extend the base class (Animal).
What I want to do is getting the class names from the subclasses themselves and pass them through the constructors so the Animal does not have to instantiate dozens of subclasses. Below is an example of what I am NOT trying to do.
If there is a way to just dynamically get the subclasses names without going through the pain of instantiating every single subclass, I would love to see it. Your help is much appreciated.
class Dog extends Animal {
private String s;
public Dog() {
s = "Bark";
}
public void method() {
System.out.println("Dogs " + s);
}
}
class Cat extends Animal {
private String s;
public Cat() {
s = "Meow";
}
public void method() {
System.out.println("Cats " + s);
}
}
class Animal {
public static void main(String args[]) throws Exception {
Dog dog = new Dog();
Cat cat = new Cat();
Class cls = dog.getClass();
System.out.println("The name of class is " + cls.getName());
Constructor constructor = cls.getConstructor();
System.out.println("The name of constructor is " + constructor.getName());
}
}
I do not see why you want the names of the subclasses. If the problem is to instantiate a class based on its name it would be better to use an Abstract Factory pattern. You can create an enumeration that contains the animal that you knows
enum ANIMALS {
DOG, CAT
}
You can create the Animal interface
public interface Animal {
}
the classes extending Animal as default classes
public class Dog implements Animal {
}
then finally the AnimalAbstractFactory as
public class AnimalAbstractFactory {
public enum ANIMALS {
DOG, CAT
}
public Animal createAnimal(ANIMALS animal) {
switch (animal) {
case DOG:
return new Dog();
case CAT:
return new Cat();
}
return null;
}
}
Notes that now you do not need to know the subclass to instantiate an animal. Note also that createAnimal returns an Animal not the subclass. I hope it helps.
Assume that I've the following classes:
1) Animal class, a base class
public abstract class Animal {
public abstract void Hello();
}
2) Dog class, extends from Animal class
public class Dog extends Animal {
#Override
public void Hello() {
System.out.println("I'm Dog");
}
}
3) Wolf class, extends from Animal class
public class Wolf extends Animal {
#Override
public void Hello() {
System.out.println("I'm Wolf");
}
}
In the Dog class's constructor or newInstance method, is there a way to switch/turn itself into a Wolf class under a certain condition, say during full moon? So, basically, if the caller does something like below, the variable "a" will be a Wolf object during full moon, instead of a Dog object.
Animal a = (Animal) Class.forName("Dog").newInstance();
You could use a wrapper for Animal to delegate to the actual Animal you wish to track and; then include in the delegator wrapper a method to swap delegates based on the class name of the Animal you want. Here is an example class:
public abstract class Animal {
public abstract String hello();
static class Dog extends Animal {
#Override
public String hello() {
return "I'm Dog";
}
}
static class Wolf extends Animal {
#Override
public String hello() {
return "I'm Wolf";
}
}
static class AnimalWrapper extends Animal {
private Animal delegate = new Dog();
public void delegateTo(String className) throws Exception {
this.delegate = (Animal) Class.forName(className).newInstance();
}
#Override
public String hello() {
return delegate.hello();
}
}
public static void main(String[] args) throws Exception {
AnimalWrapper animal = new AnimalWrapper();
System.out.println("Animal says: " + animal.hello());
animal.delegateTo(Wolf.class.getName());
System.out.println("Animal says: " + animal.hello());
animal.delegateTo(Dog.class.getName());
System.out.println("Animal says: " + animal.hello());
}
}
Complete code on GitHub
You cannot do that.
It looks like you need something like factory (search for factory design pattern) that will be responsible for creating instance of class you need.
This question already has answers here:
What does a "Cannot find symbol" or "Cannot resolve symbol" error mean?
(18 answers)
Closed 5 years ago.
I am only learning about polymorphism so be easy on me (literally copying from the book). I try to pass a class as an argument to a method. When I do that I can call the superclass methods, but not the actual subclass. Using the start() method, I try to make the wolf howl:
public class experiment {
public static void main(String[] args) {
PetOwner own = new PetOwner();
own.start();
}
}
//Trying polymorphic arguments
class Vet {
public void giveShot(Animal a) {
a.howl();
}
}
class PetOwner {
public void start() {
Vet v = new Vet();
Wolf w = new Wolf();
v.giveShot(w);
}
}
//Inheritance//
//Kingdom - Animal
class Animal {
public void move() {
System.out.println("*motions softly*");
}
}
//Family - canine
class Canine extends Animal {
public void bark() {
System.out.println("Woof!");
}
}
//Species - wolf
class Wolf extends Canine {
public void howl() {
System.out.println("Howl! Howl!");
}
}
If I pass the howl method to the superclass (Animal) it works fine. If I call it directly from the Wolf class - it works fine. The only instance where it doesn't work is if I try to pass the wolf class as an argument and call it from there.
Here is why I try it that way, quoted from Head First Java pg 187:
The Vet's giveShot() method can take any Animal you give it. As long
as the object you in as the argument is a subclass of Animal, it
will work
I am getting a "cannot find symbol symbol: method howl(), Location variable of type animal" error.
You're calling a.howl() while a is an instance of Animal class. Animal does not know how to howl. The only Wolf does.
You can defin a method say react() and then override it for any particular subclass of Animal;
You are calling the howl-Method inside the giveShot-Method. Animal doesn't have a howl method.
EDIT: If you cast animal to wolf inside the giveShot-Method it should work.
Yes, you could do something like:
class Vet {
public void giveShot(Animal a) {
a.makeNoise();
}
}
class Animal {
public void move() {
System.out.println("*motions softly*");
}
public void makeNoise() {
}
}
//Family - canine
class Canine extends Animal {
#Override
public void makeNoise() {
System.out.println("Woof!");
}
}
//Species - wolf
class Wolf extends Canine {
#Override
public void makeNoise() {
System.out.println("Howl! Howl!");
}
}
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?
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.
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();
}
}
}
I have the following interface and abstract class that implements it:
interface Walk {
String walk();
}
public abstract class Animal implements Walk {
abstract String MakeNoise();
}
And the following concrete implementations:
class Cat extends Animal {
String MakeNoise() {
return "Meow";
}
#Override
String walk() {
return "cat is walking";
}
}
class Dog extends Animal {
#Override
String walk() {
return "Dog is walking";
}
#Override
String MakeNoise() {
return "bark";
}
}
class Human {
public void Speak() {
System.out.println("...Speaking...");
}
}
Putting it all together:
class MainClass {
public static void main(String[] args) {
Random randomGen = new Random();
Animal[] zoo = new Animal[4];
zoo[0] = new Cat();
zoo[1] = new Dog();
zoo[2] = new Cat();
zoo[3] = new Cat();
// System.out.println(zoo[ randomGen.nextInt(2)].MakeNoise());
for (Animal animal : zoo) {
if (animal instanceof Dog) {
Dog jeffrey = (Dog) animal;
System.out.println(jeffrey.MakeNoise());
}
}
}
}
I get this error
"walk() in Cat cannot implement walk() in Walk " .
Any ideas? thanks
Methods in interfaces are implicitly public. However, methods in classes are package-visible by default. You cannot reduce the visibility of an overriden method, i.e. you can't do stuff like this:
class A {
public foo() {}
}
class B extends A {
private foo() {} // No!
}
class C extends A {
foo() {} // No! foo is package-visible, which is lower than public
}
In your case, the solution is to declare walk() as public in Dog and Cat.
The error eclipse gives is:
Cannot reduce the visibility of the inherited method from Walk
The method must be public, because it is defined in an interface.
Interface methods must be public. You need to declare walk() as a public method in Cat.
Make String walk() implementations public. That will fix it