Create a dynamic class in java - java

I'm working on a problem where different animal types implement the same talk() method from Animal interface.
If you look at getAnimal() method, you can see that, when a new kind of animal is added to the program, inside of that method has to be changed as well.
I want to add new animals just by subclassing Animal without changing anything in the already existing classes.
For example, add an animal "Dog", criteria="loyal"; talk="woof".
Could you tell me, how it is possible? Below is my code:
interface Animal {
public void talk();
}
class Lion implements Animal {
#Override
public void talk() {
System.out.println("ROARRRRR");
}
}
class Mouse implements Animal {
#Override
public void talk() {
System.out.println("SQUEEEEEAK");
}
}
class Bison implements Animal {
#Override
public void talk() {
System.out.println("BELLOWWWWW");
}
}
class AnimalType {
public static Animal getAnimal(String criteria) {
// I refactor this method
if (criteria.equals("small")) {
return new Mouse();
} else if (criteria.equals("big")) {
return new Bison();
} else if (criteria.equals("lazy")) {
return new Lion();
}
return null;
}
}
public class AnimalExamples {
public static void main(String[] args) {
AnimalType.getAnimal("small").talk();
AnimalType.getAnimal("big").talk();
AnimalType.getAnimal("lazy").talk();
// how to add an animal "Dog" here, criteria="loyal"; talk="woof"
AnimalType.getAnimal("loyal").talk();
try {
AnimalType.getAnimal("small").talk();
} catch (Exception ex) {
System.out.println("Animal does not exists");
}
}
}
I searched on google, understood it can be done by reflection. But do not know how. If possible, could you help me with this, please? Thanks in advance!

Just so you know runtime class generation is extremely complex and not something recommended for beginners to the language. This would be an excellent scenario to use a map an anonymous classes.
class AnimalType {
private static final Map<String, Animal> animals = new HashMap<String, Animal>();
static {
// Populating map with default animals
addAnimal("big","BELLOWWWWW"); // bison
addAnimal("small","SQUEEEEEAK"); // mouse
addAnimal("lazy","ROARRRRR"); // lion
addAnimal("loyal","WOOF "); // dog
}
public static void addAnimal(String criteria, final String sound) {
// Assigning a anonymous implementation of animal to the given criteria
animals.put(criteria, new Animal() {
#Override
public void talk() {
System.out.println(sound);
}
});
}
public static Animal getAnimal(String criteria) {
// Returning an animal from the animals map
return animals.get(criteria);
}
}
If you really do insist on true runtime class generation or if you're curious how it works, check out ByteBuddy.

Old question, but here is how to create class... For me the easy way is to use Javassist.
I created a small example here: http://hrabosch.com/2018/04/08/generate-class-during-runtime-with-javassist/
But here is main point:
public static Class generateClass(String className, String methodName, String methodBody)
throws CannotCompileException {
ClassPool pool = ClassPool.getDefault();
CtClass cc = pool.makeClass(className);
StringBuffer method = new StringBuffer();
method.append("public void ")
.append(methodName)
.append("() {")
.append(methodBody)
.append(";}");
cc.addMethod(CtMethod.make(method.toString(), cc));
return cc.toClass();
}
So what I did... Via Javassist I made a class in ClassPool. Also I added a method inside this class and via reflection I invoked it.
Hope it helps.
Just keep on mind whatever you want to use in generated class, there
are NOT imports, so you have to use fully-qualified names.

Java doesn't support creating a class at runtime. However there are really better ways of achieving what you want here. I'll propose two.
Firstly, you could create an AnimalType class that contains all the shared behaviour about a species. You could then have an Animal class that takes an AnimalType as a constructor parameter.
Secondly, you could use a prototype design pattern. In this case the Animal class would need a clone method to create a new animal from the prototype. The factory class could then have a list of the prototypes and use whatever logic you desire to choose the correct prototype to clone.
Comment below if you want further details or sample code for either of these options.

you have to define the dog class
class Dog implements Animal {
#Override
public void talk() {
System.out.println("woof");
}
}
and add the if else to AnimalType
} else if ("loyal".equals(criteria)) {
return new Dog();
}

Related

How to call a method created in an inline class [duplicate]

This question already has answers here:
Calling newly defined method from anonymous class
(6 answers)
Closed 1 year ago.
I just came to know that there is a process called in-line class with the help of which I can create a new object and modify its class methods on the fly. I don't know if I can create new methods and variables inside the in-line class and use them. So I did this experiment. My IDE did not show any error while creating a new method inside the in-line class. Now I don't know how to access the newly created method. My doubt is, can I create a new method while creating an in-line class?(If yes then how?) Or, in-line class is only for overloading the existing methods?
public class Main {
public static void main(String[] args) {
Animals cat = new Animals("Cat") {
#Override
public void makeNoise() {
System.out.println("MEOW MEOW");
}
public void color() {
System.out.println("Color is: white");
}
};
cat.makeNoise();
cat.color(); //this is showing error
}
}
Animal class
class Animals {
private String name;
public Animals(String name) {
this.name = name;
}
public void makeNoise() {
System.out.println("Sound of the animal");
}
}
The easiest change: use var:
public static void main(String[] args) {
var cat = new Animals("Cat") {
#Override
public void makeNoise() {
System.out.println("MEOW MEOW");
}
public void color() {
System.out.println("Color is: white");
}
};
cat.makeNoise();
cat.color();
}
This now works, because cat isn't an Animals, it's inferred as a more specific type than that - it's a class that doesn't have an accessible name, so you can't write it as an explicit variable.
In fact, you were able to access anonymous class methods prior to the introduction of var, in a way:
new Animals("Cat") {
// ...
public void color() { ... }
}.color();
This worked prior to var, because the expression new Animals("Cat") { ... } has a more specific type that Animals. The problem is, you can only invoke those extra methods directly on the new instance creation expression, because you can only assign it to a variable of type Animals (or a superclass), thus preventing the compiler from accessing the specific class methods.
An alternative would be to declare it as a named class.
The most similar to what you have here would be a local class, although they are pretty rarely used (if known about at all), in my experience:
public static void main(String[] args) {
class Cat extends Animals {
Cat() { super("Cat"); }
// ...
public void color() { ... }
}
Cat cat = new Cat();
cat.color();
}
This is sort-of what the var approach does; it just gives the type an explicit name. This approach would be good if you wanted to create more than one instance of Cat in that method.
But there's not an obvious reason why this would need to be a local class: you could alternatively declare it as a nested or inner class, or, of course, a top-level class.
You cannot do that.. The first thing is Animals class has no method name Color.

What is the difference between these two codes regarding interface?

I am currently learning java. I just don't understand the use of interface and I am really confused about it.
These two codes return the same answer, then what is the use of interface here?
interface Jumpable {
abstract int maxDistance();
}
class Animal implements Jumpable {
public int maxDistance() {
return 100;
}
}
public class Forest {
public static void main(String args[]) {
Animal lion = new Animal();
System.out.println(lion.maxDistance());
}
}
class Animal {
public int maxDistance() {
return 100;
}
}
public class Forest {
public static void main(String args[]) {
Animal lion = new Animal();
System.out.println(lion.maxDistance());
}
}
In the state your code is in right now, there is no difference, but that is not what it is about. Further down the line you will need to do things with your animals, without knowing what animals you have or what they can do.
Suppose you want to subclass your animals, into mammals, birds and insects. Some of them can jump, but not others. It will be very ugly code if you create specific classes or attributes for mammals that can jump etc. If you instead create an interface, you have lots of options. You can create a list of animals that can jump, and then tell them to jump, regardless of their type.
Later, you might want to add screaming to your animals. Just add an interface for that.

Class object as List's type

I have class Animal and two subclasses Tiger and Eagle. Both of subclasses have hunt method which is pretty much the same. The only difference between them is type of Victims. Method hunt is using generic class Field<T> for seekeing victims. It looks like this:
Tiger
void hunt(){
Field<Cattle> field = new Field<Cattle>();
List<Cattle> list = field.getObjects();
...
Eagle
void hunt(){
Field<Rabbit> field = new Field<Rabbit>();
List<Rabbit> list = field.getObjects();
...
Is there any way to perform something like that?
void hunt(Object type){
Field<type> field = new Field<type>();
List<type> list = field.getObjects();
I know that I can get list full of Object type and use instanceof later, but here we come to second question:
Is it possible to call if( object instanceof instanceOfSomeClass)?
You can use generics to achieve what you want:
public class AnimalsGenerics<E> {
public void Hunt(E prey){
...
}
}
and implement your animals specifying the prey:
public class Tiger extends AnimalsGenerics<Buffalo> {
}
But my personal implementation would be using interfaces to specify what does the animal do, for example: what happens if the animal is not a hunter, for example an herbivorous, would you need to implement your animal class again? follow the principle of leaving the implementation to the interfaces and not the heritance would help you to have a cleaner code, my dessign would be:
To design the behaviour:
public interface CollectFoodBehaviour<E> {
void collectFood(E prey);
}
Class animal would be:
public class Animal<E> {
CollectFoodBehaviour<E> collectFoodBehaviour;
public void goToGetFood(E food){
collectFoodBehaviour.collectFood(food);
}
}
Implementing the hunting behaviour:
public class HuntAnimalsBehaviour<E> implements CollectFoodBehaviour<E> {
#Override
public void collectFood(E prey) {
//implemenet the generic hunting process
}
}
and an animal instance as an example:
public class Dog extends Animal<Rabbit> {
public Dog(){
this.collectFoodBehaviour = new HuntAnimalsBehaviour<Rabbit>();
}
}
Is it possible to call if( object instanceof instanceOfSomeClass)?
No, instanceof tests if an object is an instance of a class, not an instance of an instance (as if the left side is a non-static reference and the right side is static reference); You can, however, not declare your instance
// JButton b = new JButton();
// if (b instanceof Component) can be replced with
if (JButton.class.newInstance() instanceof Component)
// or
if (new JButton() instanceof Component)
if for some odd reason you find this useful.
If I understood correctly, you can use a generic method using following code:
If you pass the object class, not the instance, you can construct a Field instance using the Class passed as parameter.
public class MyAnimal {
public <T> void hunt(Class<T> type) {
Field<T> field = new Field<>();
List<T> list = field.getObjects();
if (type == Cattle.class) {
System.out.println("Type is a Cattle");
} else {
System.out.println("Type is not a Cattle, is a " + type.getName());
}
}
public static void main(String[] args) {
new MyAnimal().hunt(Cattle.class);
new MyAnimal().hunt(new Cattle().getClass());
}
}
About your second question, if you have the Class type, you can ask with a simple: type == MyClass.class.

Avoid using instanceOf in observer method

I have the following system in Java:
public class Human {
public void drown(Animal animal) {
if (animal instanceOf Fish) {
return;
} else {
animal.die();
}
}
}
public abstract class LandAnimal extends Animal{...}
public class Tiger extends LandAnimal{...}
public abstract class Fish extends Animal {...}
public class Trout extends Fish {...}
I have thought of adding a method
public abstract boolean drownable() {...}
in class Animal but I don't have access to the code of Animal class.
As I know the use of instanceOf is considered bad OOP practice. How do I avoid the use of instanceOf in this case? Thanks.
The drown() method in Human should be (by the way, why do humans want to drown animals?):
public void drown(Animal animal) {
animal.drown();
}
And each Animal will know what to do, for example:
// in class Tiger
public void drown() {
die();
}
// in class Fish
public void drown() {
// do nothing, fish can't drown
}
You would declare Animal.drown() and override it in Fish, containing the appropriate 'kill code' :).
So you'd just need to call drown() on each animal and each instance will behave according to its type specific method implementation.
public class Human {
public void drown(Animal animal) {
animal.drown();
}
}
Methods can be overloaded based on their arguments. You can have two different methods:
public void drown(Fish f) {
return;
}
public void drown(LandAnimal a) {
a.drown();
}
However, it should be noted that this makes determining whether some animal will drown the responsibility of the Human class, which, as other answers show, is arguable.

Simple Object-oriented Programming Concepts

it may looks like a dummy question for you but I have difficulties solving this:
We have an abstract class Animal and Cat and Dog that extends it. In Animal we have a method produceSound(); that is abstract. As you can probably guess for Cat it should return "Mao" and for Dog - "Bao" or something like that. This is OK but now we must write a static method in the Animal class that returns Cat or Dog objects depending on their sound. For example: identifyAnimal("Mao") should return Cat.
Question: How to implement the identifyAnimal(String sound) method?
Here is some simple example of the hierarchy:
Animal class
public abstract class Animal {
protected abstract String produceSound();
protected static void identifyAnimal(String animalSound) {
// TODO
}
}
Cat class
public class Cat extends Animal{
#Override
protected String produceSound() {
return "Mao";
}
}
Dog class
public class Dog extends Animal{
#Override
protected String produceSound() {
return "Bao";
}
}
Test class
public class AnimalTest {
public static void main(String[] args) {
Animal.identifyAnimal("Bao");
}
}
In the AnimalTest class when calling the Animal.identifyAnimal("Bao"); we should get a Dog.
private static Class[] animalTypes = [Dog.class, Cat.class];
public static String identifyAnimal(String animalSound)
{
for (int i = 0; i < animalTypes.length; i++) {
Animal a = animalTypes[i].newInstance();
String s = a.produceSound();
if (animalSound.equals(s))
return animalTypes[i].getName();
}
return null;
}
So here a (terrible) way to do this. I actually twitched a little.
I don't know what language you are using, so I'm going with c++(sorry current mode) though you could replace maps with Dictionaries if we are in C#, whatever. This is a bad way to go about things, but should work(conceptually, anyway)
Again...Terrible...
public abstract class Animal {
protected abstract String produceSound();
protected static map<string, string> SoundList;
protected static bool registerSound(string sound, string type)
{
return (SoundList.insert( pair<string, string>(sound, type)))->second;//true if worked false if already there
}
protected static string identifyAnimal(string animalSound)
{
map<string,string>::iterator result = SoundList.find(sound);
if(result != SoundList.end())
return result->second;
else
return "What The Hell Is This!?";
}
}
Cat class
public class Cat extends Animal
{
Cat()
{
Animal::registerSound("Mao","Cat");
}
#Override
protected String produceSound() {
return "Mao";
}
}
abstract class Animal {
static Map<String,String> map = new HashMap<String,String>();
public Animal(String value) { map.put(produceSound(), value); }
protected abstract String produceSound();
protected static void identifyAnimal(String animalSound) {
System.out.println(map.get(animalSound));
}
}
class Cat extends Animal {
#Override
protected String produceSound() { return "Mao"; }
Cat(){ super("CAT"); }
}
class Dog extends Animal {
#Override
protected String produceSound() { return "Bao"; }
Dog(){ super("DOG"); }
}
class Test {
public static void main(String[] args) {
new Dog();
new Cat();
Animal.identifyAnimal("Bao");
}
}
Do a switch with the predefined sounds that you have and let each sound return a string with the name of the animal. For example "Mao" returns a string "Cat" and so on.
One more thing let ur identifyAnimal method returna string instead of void.
You could use reflection to get a list of all types that extend Animal, loop through them using Activator to create instances of each type running produceSound on each until you find the return value that matches animalSound, returning that instance. Slow, but effective if you want to avoid your Animal class being aware of what extends it.
What is the nature of the problem you are trying to solve? There is no 'right' way that is independent of the problem.
What does the consuming application need from the class Animal? What does your application need to do with the classes that it consumes? Nothing can be assumed unless these presumptions are clear.

Categories