I know several programming languages. Most of them are scripting languages like lua, perl, JS, ruby, etc.
But recently, I started programming in Java, which works quietly. So I have been thinking of a certain function that exists in JS. The prototype of constructors, that is. For further understanding of what my question really is, I will make an example in JS. Let's say you want to create an application of dogs.
function dog (){
this.property1 = value;
this.propertr2 = value2;
this.propertyN = valueN;
//etc.
}
//now, I will create several instances of the constructor in JS
var snoopy = new dog();
var buddy = new dog();
and the awesome part, that I know about JS is that you can dynamically change the information of the constructor and all of the instances that is of the constructor (as it is called in JS) with the prototype keyword like this:
dog.prototype.bark = function () {
console.log("Woof!");
};
and THIS, does not only change the information about the constructor so that every dog that will ever be created with the constructor will know how to bark, it also changes so that all of the instances of the constructor gets the information of the prototype insertion which in this case teaches the dogs how to bark. which we can see in the next example:
var someOtherDog = new dog ();
someOtherDog.bark(); //output will be: Woof!
snoopy.bark(); //output will also be: Woof!
buddy.bark(); //you guessed it! it will also be: Woof!
So with this prototype keyword in JS I can manipulate constructors and their instances. Now, my question is:
HOW can I manipulate the classes and their instances in java? And is that even possible?
and if so; what should I do in order to do anything like that in java?
class dog
{
private String hairColor;
public dog ()
{
hairColor = "Brown";
}
public static void main (String args[])
{
dog snoopy = new dog ();
dog buddy = new dog ();
//now, how do I manipulate the class like I did in JS?
}
}
The thing is that both lua and JavaScript are prototype based, Java is not. You can use reflection to accomplish something similar, but not at the level of JavaScript. Reflection
Inheritance in JavaScript is accomplished by the prototype chain. Basically, when bark is not found in the snoopy object, it is looked up in its prototype snoopy.prototype. If it is found there, that version is used. If not (for example when calling bark.toString()), the prototype chain is traversed until a prototype is found which has that member. The prototype itself is shared between all 'instances' and since it's just a normal object, you can add or remove members to it later on.
Inheritance in Java is class-based. You cannot add or remove members from a class definition at run time unless you recompile and reload the whole class. It's a different programming paradigm which means that you'll have to program (slightly) differently for it using other techniques and patterns.
You can create anonymous classes on the fly if you want.
Say you have a class:
class Dog {
String name;
Dog(String name) { this.name = name; }
void bark() { System.out.println(name + " says 'woof!'"); }
public static void main(String...args) {
Dog snoopy = new Dog("snoopy");
snoopy.bark();
}
}
Here's the result
c:\files\j>javac Dog.java
c:\files\j>java Dog
snoopy says 'woof!'
Now buddy he doesn't say woof - he says ruff! So we create one on the fly like so
class Dog {
String name;
Dog(String name) { this.name = name; }
void bark() { System.out.println(name + " says 'woof!'"); }
public static void main(String...args) {
Dog snoopy = new Dog("snoopy");
snoopy.bark();
Dog buddy = new Dog("buddy") {
#Override void bark() { System.out.println(name + " says 'ruff!'"); }
};
buddy.bark();
}
}
Which results in
c:\files\j>javac Dog.java
c:\files\j>java Dog
snoopy says 'woof!'
buddy says 'ruff!'
If you wanted to permanently change every dog, that becomes more difficult, but can be done via the strategy pattern.
Let's say we have the following
abstract class BarkingStrategy {
public abstract void doBark(Dog dog);
}
class TypicalBarkingStrategy extends BarkingStrategy {
public void doBark(Dog dog) { System.out.println(dog.getName() + " says 'woof!'"); }
}
class AggressiveBarkingStrategy extends BarkingStrategy {
public void doBark(Dog dog) { System.out.println(dog.getName() + " says 'Rrrruff!'"); }
}
class Dog {
// notice this is static - that means it belongs to the class itself, not
// any particular instance of it - similar to prototype
static BarkingStrategy bark = new TypicalBarkingStrategy();
String name;
Dog(String name) { this.name = name; }
String getName() { return name; }
void bark() { bark.doBark(this); }
}
Then you can do the following
public static void main(String...args) {
Dog snoopy = new Dog("snoopy");
snoopy.bark();
Dog.bark = new AggressiveBarkingStrategy();
snoopy.bark();
}
This results in
c:\files\j>javac Dog.java
c:\files\j>java Dog
snoopy says 'woof!'
snoopy says 'Rrrruff!'
Related
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.
I have a task that needs to be done but I am really stuck.
Basically, I've some inheritance relations like this:
Animal
Pet WildAnimal
Bird Cat Dog Fish ||Snake Eagle
Animal is the parent of Pet and Wild Animal.
Pet is the parent of Bird, Cat, Dog, Fish.
WildAnimal is the parent of Snake and Eagle.
The task wants me to read inputs from a file which is "input.txt" and create Animal objects.
"input.txt" is like:
kiwi Bird
charlie Eagle
mango Fish
pepper Dog
angle Cat
tweety Bird
bob Dog
ziggy Snake
I can get all of the names but I couldn't figure out how to understand which kind of object every single name represent.
Here is the main method:
public static void main(String[] args) throws IOException {
String s ="";
int nameCounter = 0;
Animal[] animals = new Animal[100];
try{
Scanner input = new Scanner(Paths.get("input.txt"));
while (input.hasNext()) {
s = input.next();
Animal animal = new Animal(s);
animals[nameCounter] = animal;
nameCounter += 2;
}
}catch(Exception e){
e.printStackTrace();
}
}
Here is the animal class:
public class Animal {
private String name;
private int numberOfLegs;
private int numberOfWings;
public Animal(String name){
this.name = name;
numberOfLegs = 4;
numberOfWings = 0;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getNumberOfLegs() {
return numberOfLegs;
}
public void setNumberOfLegs(int numberOfLegs) {
this.numberOfLegs = numberOfLegs;
}
public int getNumberOfWings() {
return numberOfWings;
}
public void setNumberOfWings(int numberOfWings) {
this.numberOfWings = numberOfWings;
}
public void talk(){
System.out.printf("<Silence>");
}
public void fly(){
System.out.printf("%s cannot fly", getName());
}
public void run(){
System.out.printf("%s is running", getName());
}
}
I can add all the other classes if you want but i don't think you're gonna need them.
You have to instantiate objects of your specific class; based on the incoming string.
Example: if the class name from the file is Bird ... then you have to call new Bird() somehow.
There are two ways to get there:
Using reflection (you can actually instantiate classes "by string"; without knowing anything about that class)
By using a switch statement
Reflection is more of an "advanced" topic (and very easy to use the wrong); so I really do recommend you to go for option 2, like:
private Animal createAnimalFor(String className, String animalName) {
switch (className) {
case "Bird": return new Bird(animalName);
...
default: throw new IllegalArgumentException("Dont know how to create object for unknown class: " + className);
}
}
(the above code is meant as "fyi" - I didn't run it through the compiler; it is meant to give you one idea how this could be done).
Some notes beyond that:
Consider using a final field for those properties of your objects that can't change. You don't need a setter for the name then; just give the name as parameter to the constructor. In other words: only make those fields "changeable" that make sense to be changed. Anything else should better be final.
Instead of using an array with 100 empty slots, you could use a java.util.ArrayList and just add as many new animals as you find in that file.
Consider adding equals/hashCode methods to your Animal class (not mandatory, but you should read why that makes sense very often).
Probably most importantly: consider not putting all those different methods directly into your base class. It might make more sense to create either abstract subclasses that add certain functions, or use interface, like interface FlyingAnymal { void fly() }; which your specific subclasses would then implement. It is not really good practice to put a lot of methods on your base class ... that simply dont make sense for all of the sub classes.
If you really want to use reflection to do so (which I would also discourage), here's sample code :
String name = input.next();
String className = input.next();
// apply transformations to className as needed
Class<Animal> c = (Class<Animal>) Class.forName(className);
Constructor<Animal> constr = c.getDeclaredConstructor(String.class); // retrieves the Animal(String name) constructor
Animal a = constr.newInstance(name);
I don't think the code is so complex, but few people have ever used reflection so they'll have problems maintaining it, and it is tightly coupled with your classes definitions so it will probably have to be maintained a lot.
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();
}
I have 3 classes. Class A ,Class B and class C.
I have a class A and i want to pass same instance of A into class B and class C,ca n i found a way when i delete class A(instance used in C and B) that set to null in C and B by reference without need to set use setA(null).
Use WeakReferences.
In B and C, make your references to A like this:
public class B {
private final WeakReference<A> myA;
public B (A aToUse) {
myA = new WeakReference<A>(aToUse);
}
private void doSomethingWithMyA() {
A aToUse = myA.get(); // This returns null when the instance has been GC'd
}
}
Now, if the instance to A that you're deleting is the only instance of A that isn't a WeakReference, then that instance of A becomes eligible for garbage collection. Once it is garbage collected your WeakReferences will return null;
According to my understanding if you are passing the instance of Class A into B and C and you want that after deleting it this reference is set to null.
Note that first all the classes are loaded by class loader so at compile time the references are checked and if you delete the class A and surely you have declare the reference of A in B and C, so it gives you the compilation error type is missing something like that
No, If i am not wrong , You want that You want that after deleting Class A, Class Band C Should to Run assigning null to the Instance of A used,
You Can not do that, Basically when you use a class say Class A in another class say Class B , the Class Loader for the Class A, if it is found then JVM proceeds to another steps, But if you have Deleted that class , the Class Loader will not be able to find that , and will throws exception , Class Not Found Exception, or something Like that,
You need some managing mechanism, if you want to control links to your instance.
Without 3rd party solutions, easiest way to do it, is to provide intermidiate container object, which will control access to your instance.
Here is a basic example:
public static void main (String[] args) {
DogContainer dc = new DogContainer(new Dog("Scooby-Doo"));
Person shaggy = new Person("Shaggy");
shaggy.setDogContainer(dc);
Person dafna = new Person("Dafna");
dafna.setDogContainer(dc);
System.out.println(shaggy.getName() + " -> " + shaggy.getDogName());
System.out.println(dafna.getName() + " -> " + dafna.getDogName());
// Something happened with Scooby here. Say, a bus factor.
dc.setDog(null);
System.out.println(shaggy.getName() + " -> " + shaggy.getDogName());
System.out.println(dafna.getName() + " -> " + dafna.getDogName());
}
static class Dog {
private String name;
public Dog(String name) { this.name = name; }
public String getName() { return name; }
}
static class DogContainer {
private Dog dog;
public DogContainer(Dog dog) { this.dog = dog; }
public Dog getDog() { return dog; }
public void setDog(Dog dog) { this.dog = dog; }
}
static class Person {
private String name;
private DogContainer dogContainer;
public Person(String name) { this.name = name; }
public String getName() { return name; }
public void setDogContainer(DogContainer dc) { this.dogContainer = dc; }
public String getDogName() {
Dog dog = dogContainer.getDog();
return dog == null ? "Sorry, this person is not a dog owner" : dog.getName();
}
}
Here we have three entities: a dog, a person and a dog container.
The person is the dog owner. But he has no direct link to the dog. It can interact with the dog only through the container.
So if you change link into container it will affect all persons.
The output is:
Shaggy -> Scooby-Doo
Dafna -> Scooby-Doo
Shaggy -> Sorry, this person is not a dog owner
Dafna -> Sorry, this person is not a dog owner
P.S. Also using of nulls is a bad practice, so it's better to use Special Case pattern to provide Null Object.
Suppose you have a class Dog, that has
public class Dog {
private String name;
private double age;
// some setters
// some getters
Additionally, you have a class DogHandler, that makes an instance of the Dog d and passes it to Owner
I suppose, i can
... make a copy of a Dog before passing it to Owner, but that's an expensive operation and i'd rather avoid it.
... come up with an interface that Dog implements which contains getters only, cast Dog to that interface and pass the result along
... initialize settable variables in a constructor and simply not allow changes for this instance of an object
Are there any other ways to make sure receiver of the object cant modify it?
How do you take a simple bean containing some data and make it read-only?
This can be achieved in few ways, I can propose you 2 of them:
a) interface with getters is good idea
b) create derived class from Dog which has setters method blocked, like this:
class UnmodifiedDog extends Dog {
public UnmodifiedDog(double age, String name) {
super.setAge(age);
super.setName(name);
}
#Override
public void setAge(double age) {
throw new UnsupportedOperationException();
}
#Override
public void setName(String name) {
throw new UnsupportedOperationException();
}
}
In DogHandler:
Dog createDog() {
return new UnmodifiedDog(10, "Fido");
}
and you can pass this to the Owner:
owner.receiveDog(dogHandler.createDog());
The approaches you mention in the question are pretty much the standard steps to take to make Dog immutable. The only other tip would be to mandate that Dog cannot be overridden by declaring the class to be final.
Among the solutions mentioned here, you can also take advantage of visibility modifiers. If Dog and Owner are in separate packages, you can set the visibility of the mutators to default (package) scope or protected scope.
This will allow you to keep Dog and DogHandler in the same package (and therefore allow them both to mutate the Dog object accordingly), while keeping Owner objects separate (and therefore preventing them from making any modification to the Dog objects).
Here is an example using an interface and package access setters.
package blah.animal;
public interface Dog
{
double getAge();
String getName();
}
package blah.animal;
public class DogImpl implements Dog
{
private double age; // double seems wrong for age.
private String name;
... getters (defined by Dog interface)
// package access setters.
void setAge(double newValue)
{
age = newValue;
}
void setName(String newValue)
{
name = newValue;
}
package blah.animal;
public class DogHandler
{
public static Dog newDog(double age, String name)
{
Dog returnValue = new DogImpl();
returnValue.setAge(age);
returnValue.setName(name);
return returnValue;
}
}
package.blah.somethingelse;
public class Blam
{
private Dog myDog;
public Blam()
{
myDog = DogHandler.newDog(1.4D, "Tippy");
}
}