Abstract class values are null after calling super - java

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

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.

How to use function parameter: call specific getter

I have a Dog class with a name and a breed. I want to print either the dog's name or its breed depending on a method parameter passed to a printDog method. How do I do that?
class Dog {
private String name;
private String breed;
//constructor
public String getName() {
return name;
}
public String getBreed() {
return breed;
}
}
public void printDog(Dog dog, ?) {
System.out.println(dog.?);
}
Dog dog = new Dog("Buster", "Shepherd");
printDog(dog, dog::getName);
printDog(dog, dog::getBreed);
Use a Function<Dog, String>. This represents a function that takes a Dog and returns a String.
public void printDog(Dog dog, Function<Dog, String> propertySelector) {
System.out.println(propertySelector.apply(dog));
}
You can call this exactly the way you wanted:
Dog dog = new Dog("Buster", "Shepherd");
printDog(dog, dog::getName);
printDog(dog, dog::getBreed);

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.

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

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());
}
}

Trying to figure out Inheritance and polymorphism

I'm doing an exercise on Inheritance and polymorphism, I have 3 seperate clasees, my main class, a super Animal class, and a sub Cat class. I've made overloaded constructors, getters and setters, and toString() methods in both Animal and Cat classes. I think I have the inheritance part down. Now I need to make 2 Animal Object references, both an instance of Cat, example: one a type Siameese with a name Tobbie.
Could anyone give me an example of one of these object references? You can see I've attempted in my Main class there, but I'm not sure if that is correct.
Here are the three different classes I have currently.
public class Hw02 {
/**
* #param args the command line arguments
*/
public static void main(String[] args) {
Animal Siamese = new Cat("Tobbie");
}
}
Here's my Animal Class.
public class Animal {
private String name;
public Animal() {
this("na");
}
public Animal(String name) {
this.name = name;
}
/**
* #return the name
*/
public String getName() {
return name;
}
/**
* #param name the name to set
*/
public void setName(String name) {
this.name = name;
}
#Override
public String toString() {
return "Animal{"
+ "name="
+ name
+ '}';
}
}
And here is my Cat class.
public class Cat extends Animal {
private String type;
public Cat() {
}
public Cat(String type) {
this.type = type;
}
public Cat(String type, String name) {
this.type = type;
}
public String getType() {
return type;
}
public void setType(String type) {
this.type = type;
}
#Override
public String toString() {
return "Cat{"
+ "type="
+ type
+ '}';
}
}
// in main method
Animal tobbie = new Cat("siamese", "Tobbie")
Animal jackie = new Cat("tomcat", "Jackie")
// in Cat class
public Cat(String type, String name) {
super(name)
this.type = type;
}
A few comments:
It is not proper convention to have the name Siamese; variable names should be "camelCase" (start with a lower-case letter). Compiler will accept it is as you have written, but it is a bad practice.
Your Cat(String type, String name) constructor didn't invoke the proper superclass constructor, thus type was lost; same for the Cat(String type) constructor
I think I would make Animal abstract and its constructors protected. I think it is a bad practice to let clients directly instantiate Animals without specifying what kind of animals they are.
Edit:
Like this:
Animal animal = new Animal("What am I?")
However, I don't consider it a good practice to do this, probably what you want done is better achieved otherwise.
Edit:
Cat toString():
public String toString() {
return super.toString() + " Cat{type=" + type + "}";
}
With the code you have above, this is an example:
Animal animal0 = new Cat("Siamese", "Bob");
Animal animal1 = new Cat("Tomcat", "Frank");
Animal animal2 = new Cat("Tomcat", "George");
Animal animal3 = new Animal("Elephant");
System.out.print(animal0.toString());
System.out.print(animal1.toString());
System.out.print(animal2.toString());
System.out.print(animal3.toString());
Would produce the output:
Cat{type=Siamese}
Cat{type=Tomcat}
Cat{type=Tomcat}
Animal{name=Elephant}

Categories