What happens when parent class object is assigned child class object? - java

This following code gives the output as :
Output:
Animal
Dog
Animal
I'm confused why "a.type" outputs as "Animal" even after the assignment "a=b". Why is it so?
Another observation was when I don't declare variable - "String type" inside Dog class. Then I get the output as :
Output:
Dog
Dog
Dog
My code:
//Parent class
class Animal {
String type;
public Animal(){
this.type= "Animal";
}
}
//Child class
class Dog extends Animal {
String type;
public Dog(){
this.type ="Dog";
}
}
//Main Class To Test
class TestDog{
Animal a = new Animal();
Dog b = new Dog();
Animal c = new Dog();
a = b;
System.out.println(a.type);
System.out.println(b.type);
System.out.println(c.type);
}

First a didactic point. You state in your tile:
What happens when parent class object is assigned child class object?
Please understand that you're assigning a child class object to a parent type variable. This may seem picky, but it's an important distinction and gets to the core of how Java implements OOPs and uses reference variables. Also the parent type might not even be a class, but could be an interface (a "pure" type).
As for your confusion, you're adding a type field to both the parent and the child class. Don't, since fields aren't overridden. Add it to the Parent only. Make it protected or give it getters and setters.
For example:
class Animal {
private String type;
public Animal() {
this.type = "Animal";
}
public String getType() {
return type;
}
public void setType(String type) {
this.type = type;
}
}
// Child class
class Dog extends Animal {
String type;
public Dog() {
setType("Dog");
}
}
// Main Class To Test
class TestDog {
public static void main(String[] args) {
Animal a = new Animal();
Dog b = new Dog();
Animal c = new Dog();
a = b;
System.out.println(a.getType());
System.out.println(b.getType());
System.out.println(c.getType());
}
}

Related

Java generics restrictions with interfaces

abstract class
public abstract class Animal {
private int id;
private String name;
public Animal(int id, String name) {
this.id = id;
this.name = name;
}}
_child of animal 1
public class Tiger extends Animal implements Dangerous {
public Tiger(int id, String name) {
super(id, name);
} }
_child of animal 2
public class Panda extends Animal implements Harmless{
public Panda(int id, String name){
super(id, name);
}}
_
Two attribute interfaces
public interface Dangerous {}
public interface Harmless {}
public class Zoo {
public static <T extends Animal & Harmless> void tagHarmless(Animal animal) {
System.out.println("this animal is harmless");
}
public static <T extends Animal & Dangerous> void tagDangerous(Animal animal) {
System.out.println("this animal is dangerous");
}}
public class App {
public static void main(String[] args) {
Animal panda = new Panda(8, "Barney");
Animal tiger = new Tiger(12, "Roger");
Zoo.tagHarmless(panda);
Zoo.tagHarmless(tiger);
}}
-result
this animal is harmless
this animal is harmless
Process finished with exit code 0
i try to restrict the methods of the class "zoo" with the interfaces "Dangerous" and "Harmless".
with the code
public static <T extends Animal & Harmless> void tagHarmless(Animal animal).
The Tiger doesnt have this Interface, so it actually should not work, does it?
But the tiger can also be added into this method tagHarmless.
I don't see the mistake.
Thanks for help.
You are declaring a generic type parameter T, but your method is never using it. Your method accepts an Animal argument, which means any Animal is acceptable.
It should be:
public static <T extends Animal & Harmless> void tagHarmless(T animal) {
System.out.println("this animal is harmless");
}
As for your main method, you are assigning the Panda and Tiger instances to Animal variables. Therefore, changing tagHarmless as I suggested means that neither the panda nor the tiger variables can be passed to tagHarmless (since an Animal doesn't implement Harmless).
If you change your main to:
Panda panda = new Panda(8, "Barney");
Tiger tiger = new Tiger(12, "Roger");
Zoo.tagHarmless(panda);
Zoo.tagHarmless(tiger);
The call to Zoo.tagHarmless(panda); will pass compilation, and the call to Zoo.tagHarmless(tiger); will not.

Creating Child Object, Child Constructor Not Used OOP

I'm a beginner to java, and I'm having issues creating an object that is a child of a parent class. I can't share source code, because it is for a school project; and I don't want to get dinged for cheating. But, I can write similar code; so that I can gain a fundamental understanding to the concepts that I am not grasping.
Java Environment: Eclipse
When I am attempting to create an child object in my Test class, I'm getting an error (that red symbol in the line numbers).
The error message that I'm receiving is "The constructor Animal(Long, String, Float, String, String) is undefined. Then the suggestions offer two options, modify the Animal constructor to include the child Dog class parameters. Or, create a new Animal constructor with the Animal and child Dog class parameters.
I'm not sure why this is happening. I've double checked and I'm not getting errors at the child constructors; and I'm using "super()". I thought that OOP and Java would automatically create a child object with the matching parameter pattern. Any help would be appreciated.
Parent Class
pubic class Animal {
Long id;
String section;
Float price;
public Animal (Long id, String section, Float price){
this.id = id;
this.section = section;
this.price = price;
}
}
1st Child Class
public class Dog extends Animal {
String name;
String favoriteToy;
public Dog (Long id, String section, Float price, String name, String favoriteToy){
super(id, section, price);
this.name = name;
this.favoriteToy = favoriteToy;
}
}
2nd Child Class
public class Bird extends Animal {
String name;
Integer wingSpan;
public Dog (Long id, String section, Float price, String name, Integer wingSpan){
super(id, section, price);
this.name = name;
this.wingSpan = wingSpan;
}
}
Test Class
public class Test {
public static void main(String[] args) throws java.lang.Exception{
//I get error here
Animal animal1 = new Animal (Long.valueOf(76532), "Canine", 99.95, "Sparky", "tennis ball");
}
}
Your Animal class has exactly one constructor
public Animal (Long id, String section, Float price){
but you're calling a constructor
new Animal (Long.valueOf(76532), "Canine", 99.95, "Sparky", "tennis ball");
This constructor does not exist for Animal. It is exactly what the compiler told you with "The constructor Animal(Long, String, Float, String, String) is undefined". What exists is
public Dog (Long id, String section, Float price, String name, Integer wingSpan){
that is a constructor of your Dog class. You probably want to call that like
new Dog (Long.valueOf(76532), "Canine", 99.95, "Sparky", "tennis ball");
As Dog inherits from Animal, i.e. Dog is an Animal, you can store a Dog reference in a variable of type Animal like
Animal animal1 = new Dog (Long.valueOf(76532), "Canine", 99.95, "Sparky", "tennis ball");

Java: make package level constructor in a class accessible for outer packages. Allow only certain classes inside project access to constructor

I'm developing a library and trying to keep everything organized. Thus, I have nested package structure and a single class that is supposed to have access to constructors to all other classes:
This is my project structure:
src
main
java
main
Main.java
zoo
Zoo.java
animals
Animal.java
mammals
Dog.java
fish
Salmon.java
birds
Falcon.java
This is the code I have in a main method:
Main.java:
Zoo zoo = new Zoo(password);
Animal dog = zoo.getDog(name);
Animal salmon = zoo.getSalmon(name);
Animal falcon = zoo.getFalcon(name);
I want to prevent a user from being able to create an animal directly (from outside of the zoo package):
Animal dog = new Dog("Charlie"); //error - constructor isn't public
However I'm not sure how to accomplish it. I could put all classes inside the zoo package and make animal constructors only package-level accessible. However, I would have to sacrifice the package structure and I'd rather not do that.
Zoo.java:
public class Zoo {
private String password;
public Zoo(String password) {this.password = password;}
public Dog getDog(String name) {return new Dog(name);}
public Salmon getSalmon(String name) {return new Salmon(name);}
public Falcon getFalcon(String name) {return new Falcon(name);}
}
Animal.java:
public abstract class Animal {
protected String name;
public Animal(String name) {this.name = name;}
}
animals:
public class Dog extends Animal {
public Dog(String name) {super(name);}
}
public class Salmon extends Animal {
public Salmon(String name) {super(name);}
}
public class Falcon extends Animal {
public Falcon(String name) {super(name);}
}
So what can be done to accomplish the above? Pehaps there exists some pattern for it?
To preserve package structure and make sure the user will instantiate animals using Zoo instance,
you probably have to use private Factories in Zoo class. However this seems to be a very awkward solution:
public class Falcon extends Animal {
protected Falcon() {
}
protected static Falcon create() {
return new Falcon();
}
}
---
public class Dog extends Animal {
protected Dog() {
}
protected static Dog create() {
return new Dog();
}
}
---
public class Zoo {
public Falcon getFalcon() {
return new FalconFactory().get();
}
public Dog getDog() {
return new DogFactory().get();
}
private static class FalconFactory extends Falcon {
private Falcon get() {
return create();
}
}
private static class DogFactory extends Dog {
private Dog get() {
return create();
}
}
}
I don't think this is a good desing, but indeed this force user to use Zoo instance to create animals.
Of course a user still may create her own Factory that inherits from Falcon or Dog.

Abstract class values are null after calling super

I have the following program:
public class Driver {
public static void main(String[] args) {
Animal dog = new Dog("larry");
dog.speak();
}
}
public abstract class Animal {
private String name;
public Animal(String name) {
this.name = name;
}
public abstract void speak();
}
public class Dog extends Animal {
private String name; // is this even needed?
public Dog(String name) {
super(name);
}
#Override
public void speak() {
System.out.println("I am " + name);
}
}
Running this program prints I am null, which is not what I want.
Why doesn't it just use the Animal variable defined name and print out larry?
What is the proper way to do this?
If I remove the name from the Dog class, is it possible to reference the Animal name variable while still keeping it private?
If so, how?
The name variable used in
System.out.println("I am " + name);
is the one defined in the Dog class. It is never set, hence null is printed.
There is no need to define name in both Animal and Dog. My suggestion would be to:
remove name from Dog
change the visibility of name in Animal to protected
If you want to keep the access to name as private, add a "getter" method for name to Animal, thus:
public class Animal {
private String name;
public String getName() { return name; }
}
public class Dog {
#Override
public void speak() {
System.out.println("I am " + getName());
}
}
You don't need the variable name in Dog; it is a separate variable from the one in Animal. The Animal constructor initializes the name in Animal correctly, but the speak method in Dog refers to the uninitialized name variable in Dog; the variable in Dog is the one that is in scope inside the Dog class code. Delete the name variable in Dog to avoid confusion.
But to keep name private in Animal and access it in a subclass, provide a getter method in Animal.
public String getName() { return name; } // or protected
Then you can call it in Dog:
System.out.println("I am " + getName());
Output:
I am larry

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.

Categories