This question has been asked in a C++ context but I'm curious about Java. The concerns about virtual methods don't apply (I think), but if you have this situation:
abstract class Pet
{
private String name;
public Pet setName(String name) { this.name = name; return this; }
}
class Cat extends Pet
{
public Cat catchMice() {
System.out.println("I caught a mouse!");
return this;
}
}
class Dog extends Pet
{
public Dog catchFrisbee() {
System.out.println("I caught a frisbee!");
return this;
}
}
class Bird extends Pet
{
public Bird layEgg() {
...
return this;
}
}
{
Cat c = new Cat();
c.setName("Morris").catchMice(); // error! setName returns Pet, not Cat
Dog d = new Dog();
d.setName("Snoopy").catchFrisbee(); // error! setName returns Pet, not Dog
Bird b = new Bird();
b.setName("Tweety").layEgg(); // error! setName returns Pet, not Bird
}
In this sort of class hierarchy, is there any way to return this in a way that doesn't (effectively) upcast the the object type?
If you want to avoid unchecked cast warnings from your compiler (and don't want to #SuppressWarnings("unchecked")), then you need to do a little more:
First of all, your definition of Pet must be self-referential, because Pet is always a generic type:
abstract class Pet <T extends Pet<T>>
Secondly, the (T) this cast in setName is also unchecked. To avoid this, use the "getThis" technique in the excellent Generics FAQ by Angelika Langer:
The "getThis" trick provides a way to
recover the exact type of the this
reference.
This results in the code below, which compiles and runs without warnings. If you want to extend your subclasses, then the technique still holds (though you'll probably need to genericise your intermediate classes).
The resulting code is:
public class TestClass {
static abstract class Pet <T extends Pet<T>> {
private String name;
protected abstract T getThis();
public T setName(String name) {
this.name = name;
return getThis(); }
}
static class Cat extends Pet<Cat> {
#Override protected Cat getThis() { return this; }
public Cat catchMice() {
System.out.println("I caught a mouse!");
return getThis();
}
}
static class Dog extends Pet<Dog> {
#Override protected Dog getThis() { return this; }
public Dog catchFrisbee() {
System.out.println("I caught a frisbee!");
return getThis();
}
}
public static void main(String[] args) {
Cat c = new Cat();
c.setName("Morris").catchMice();
Dog d = new Dog();
d.setName("Snoopy").catchFrisbee();
}
}
How about this old trick:
abstract class Pet<T extends Pet>
{
private String name;
public T setName(String name) { this.name = name; return (T) this; }
}
class Cat extends Pet<Cat>
{
/* ... */
}
class Dog extends Pet<Dog>
{
/* ... */
}
No, not really. You could work around it by using covariant return types (thanks to McDowell for the correct name):
#Override
public Cat setName(String name) {
super.setName(name);
return this;
}
(Covariant return types are only in Java 5 and above, if that's a concern for you.)
It's a bit convoluted, but you can do this with generics:
abstract class Pet< T extends Pet > {
private String name;
public T setName( String name ) {
this.name = name;
return (T)this;
}
public static class Cat extends Pet< Cat > {
public Cat catchMice() {
System.out.println( "I caught a mouse!" );
return this;
}
}
public static class Dog extends Pet< Dog > {
public Dog catchFrisbee() {
System.out.println( "I caught a frisbee!" );
return this;
}
}
public static void main (String[] args){
Cat c = new Cat();
c.setName( "Morris" ).catchMice(); // error! setName returns Pet, not Cat
Dog d = new Dog();
d.setName( "Snoopy" ).catchFrisbee(); // error! setName returns Pet, not Dog
}
}
public class Pet<AnimalType extends Pet> {
private String name;
public AnimalType setName(String name) {
this.name = name; return (AnimalType)this;
}
}
and
public class Cat extends Pet<Cat> {
public Cat catchMice() {return this;}
public static void main(String[] args) {
Cat c = new Cat().setName("bob").catchMice();
}
}
Related
I am fairly new to coding please help me understand how to use inheritance in android with Java. Let me explain my question with an example :
Like there is a parent class called "Animal" which includes "name" and "age" and has two subclasses "Dog" and "Cat". The "Dog" class has "name", "age", "food" and the "Cat" class has "name", "age", "breed" as their attributes.
From my understanding the best practice is to make:
Animal class with the attribute of "name", "age" + constructor and getter and setter
public class Animal{
private String name;
private int age;
public Animal() {
this.name = name;
this.age = age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
}
Dog class extends of Animal class with an attribute of "food" and put getter and setter
private String food;
public String getFood() {
return food;
}
public void setFood(String food) {
this.food = food;
}
}
Cat class extends of Animal class with an attribute of "breed" and put getter and setter
private String breed;
public String getBreed() {
return breed;
}
public void setBreed(String breed) {
this.breed = breed;
}
}
MainActivity should be like
public class MainActivity extends AppCompatActivity {
ArrayList<Animal> mAnimal = new ArrayList<>();
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Dog dog = new Dog();
dog.setName("The Dog");
dog.setAge(2);
dog.setFood("Bone");
Cat cat = new Cat();
cat.setName("The Cat");
cat.setAge(1);
cat.setBreed("Persian");
mAnimal.add(dog);
mAnimal.add(cat);
}
}
Now Since there are three classes and each class has a different attribute, How to implement listview to show a list of all animals and their foods or breeds (depends on which one they have) in Mainactivity?
I would really appreciate your answers in advance
Your question Refers to Inheritance but also to polymorphism.
create a super class and sub classes
class Animal {
protected String name;
protected int age;
public void animalSound() {
System.out.print("The animal makes a sound");
}
}
class Cat extends Animal {
private boolean isLivesAtHome;
//getters & setters
//override function from super class
public void animalSound() {
System.out.print("The Cat says meow");
}
}
class Dog extends Animal {
private boolean isWasVaccinatedAgainstRabies;
//getters & setters
//override function from super class
public void animalSound() {
System.out.print("The dog says bow wow");
}
}
run this on Main function like this:
class Main {
public static void main(String[] args) {
Animal myAnimal = new Animal(); // Create a Animal object - Super Class
Animal myCat = new Cat(); // Create a Cat object
Animal myDog = new Dog(); // Create a Dog object
ArrayList<Animal> arr = new ArrayList<>();
arr.add(myCat);
arr.add(myDog);
arr.add(myAnimal);
//simple for loop
for (int i = 0; i < arr.size(); i++){
//if the object is a Cat instance
if(arr.get(i) instanceof Cat){
//change Cat instance variable
((Cat)arr.get(i)).setLivesAtHome(true);
System.out.println("I'm a Cat");
}
//print animalSound function
arr.get(i).animalSound();
}
}
}
This code print's:
I'm a Cat
The Cat says meow
The dog says bow wow
The animal makes a sound
This example show Polymorphism and inheritance concept using single ArrayList.
The list is of animals. Of the Super Class type.
A dog is also an animal, a cat is also an animal (by inheritance) so you can add them to the Animal List.
If you want to refer a particular object (like the Cat in the example code), you have to use 'instance of' operator for Casting.
for more info you can read about Inheritance and Polymorphism.
You can do like this or similar to this.
Models:
Animal:
public class Animal {
Dog dog;
Cat cat;
public Animal(Dog dog, Cat cat) {
this.dog = dog;
this.cat = cat;
}
public Animal() {
}
public Dog getDog() {
return dog;
}
public void setDog(Dog dog) {
this.dog = dog;
}
public Cat getCat() {
return cat;
}
public void setCat(Cat cat) {
this.cat = cat;
}
Dog:
public class Dog {
String name;
String age;
String food;
public Dog(String name, String age, String food) {
this.name = name;
this.age = age;
this.food = food;
}
public String getFood() {
return food;
}
public void setFood(String food) {
this.food = food;
}
Cat:
public class Cat {
String name;
String age;
String breed;
public Cat(String name, String age, String breed) {
this.name = name;
this.age = age;
this.breed = breed;
}
public String getBreed() {
return breed;
}
public void setBreed(String breed) {
this.breed = breed;
}
MainActivity.java:
public class TestActivity extends AppCompatActivity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_test);
Animal animal = new Animal();
animal.setDog(new Dog("tomi", "6","Roti"));
List<Animal> animals = new ArrayList<>();
animals.add(animal);
Log.d("Jay", animals.toString());
}
What you are askings reffers to polymorphism. It means subclass inherits everything from it's superclass.
To achieve what you want you would create your objects like:
Animal dog = new Dog();
((Dog) dog).setBreed("Terrier"); //This is called Casting
...
Animal cat = new Cat();
...
And then in your ListView when showing data you can check if your object is instance of particular object, like this:
if(dog instanceof Dog)
textView.setText(((Dog) dog).getBreed());
public class Pet
{
private String name;
private String type;
public Pet(String n, String t)
{
name = n;
type = t;
}
public String getType(){
return type;
}
public String getName(){
return name;
}
public void speak()
{
System.out.println("grr!");
}
public static void main(String[] args)
{
Pet p = new Pet("Sammy","hamster");
System.out.println(p.getType());
p.speak();
Dog d = new Dog("Fido");
System.out.println(d.getType());
d.speak();
//Cat c = new Cat("Fluffy");
//System.out.println(c.getType());
//c.speak();
}
}
class Dog extends Pet
{
public Dog(String name){
super(name);
}
public void speak(){
System.out.println("Woof");
}
}
// Add a Cat class
How do I add "type" to this without adding another String to my parameter?
I've tried other ways that obviously didn't work but I still tried anyway. So how do I add another object to my super class from Pet without adding more to my parameter?
Constructor with one parameter for the dog class:
public Dog(String name) {
super(name, "dog");
}
How can I access to members of each classes?
I have class Dog and Cat. They have different member variable of class.
I try to create one function "CommUtil.display()" to access many classes (Dog or Cat) and display all members of class.
I try to access from mainClass to access Dog or Cat class.
but it can't.
Anyone can help will be appreciated.
I have made an example below:
class Dog {
private String name = null;
private String weight = null;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getWeight() {
return weight;
}
public void setWeight(String weight) {
this.weight = weight;
}
}
class Cat {
private String name = null;
private String age = null;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getAge() {
return age;
}
public void setAge(String age) {
this.age = age;
}
}
class commUtil {
//TODO: output members of class
public void display (Object obj){
//Question: How to access members of each classes?
//code here...
}
}
class mainClass {
public static void main(String[] args) {
Dog d = new Dog();
commUtil.display(d);
or
Cat c = new Cat();
commUtil.display(c);
}
}
In case 1:
Dog d = new Dog();
d.setName("Lion");
d.setWeight("2Kg");
commUtil.display(d);
It will display Name and Weight of Dog
In case 2:
Cat c = new Cat();
c.setName("MiMi");
c.setAge("1");
commUtil.display(c);
It will display Name and Age of Cat
If the code can still change, you may be able to use java interface. The idea is that both Dog and Cat implements a common interface for output display. In practice though, it will have the same result as modifying toString() like the other comments already covered. Anyway, here is an example:
public interface AnimalInfo {
public String getInfo();
}
and then both Dog and Cat classes can implements this interface.
class Dog implements AnimalInfo {
...
public String getInfo() {
return "name="+name+", weight="+weight;
}
class Cat implements AnimalInfo {
...
public String getInfo() {
return "name="+name+", age="+age;
}
and then inside commUtil the argument can use the interface type AnimalInfo
public void display (AnimalInfo animal){
System.out.println("It will display " +
animal.getInfo() + " of " + animal.getClass().getSimpleName());
}
This is what inheritance is for, so you would make an abstract super class possibly called Animal in this case and then Dog and Cat would extend that class as subclasses. Here is a fairly simple tutorial about inheritance.
public abstract class Animal {
/** Common name property for all animals */
private String name;
/** Common age property for all animals */
private int age;
public Animal(String name, int age) {
this.name = name;
this.age = age;
}
public void setName(String name) {
this.name = name;
}
public String getName() {
return name;
}
public void setAge(int age) {
this.age= age;
}
public int getAge() {
return age;
}
/**
* Abstract method that will need to be implemented
* by a concrete class that inherits from this abstract class
*/
public abstract String getInfo();
public abstract String speak();
public abstract String getType();
}
public class Dog extends Animal {
/*
Any Dog specific properties would also go in here
*/
private boolean isPedigree = false;
/** Class Constructor */
public Dog(String name, int age, boolean isPedigree) {
super(name, age);
this.isPedigree = isPedigree;
}
public boolean isPedigree() {
return isPedigree;
}
#Override
public String getInfo() {
return "I am a Dog named " + name + " and I am " + age + " years old.";
}
#Override
public String speak() {
return "WOOF";
}
#Override
public String getType() {
return Dog.class.getSimpleName();
}
}
public class Cat extends Animal() {
/*
Any Cat specific properties would also go in here
*/
/** Class Constructor */
public Cat(String name, int age) {
super(name, age);
}
#Override
public String getInfo() {
return "I am a " + getType() + named " + name + " and I am " + age + " years old.";
}
#Override
public String speak() {
return "meow";
}
#Override
public String getType() {
return Cat.class.getSimpleName();
}
}
public class MyMainClass {
public static void main(String[] args) {
/*
Just creating a random array to show that
any animal whether Dog or Cat can be placed into
this array as they inherit from Animal
*/
List<Animal> animals = new ArrayList<>();
animals.add(new Dog("James", 5, true));
animals.add(new Cat("Treacle", 2));
for (Animal animal : animals) {
display(animal);
if (animal instanceof Dog) {
boolean isPedigree = ((Dog) animal).isPedigree();
System.out.println("Q: Am I a Pedigree? A: " + String.valueOf(isPedigree));
}
}
}
private void display(Animal animal) {
System.out.println("I'm an animal of type " + animal.getType() + " and I can say " + animal.speak());
System.out.println(animal.getInfo());
}
}
Our output would be:
I'm an animal of type Dog and I can say WOOF
I am a Dog named James and I am 5 years old.
Q: Am I a Pedigree? A: true
I'm an animal of type Cat and I can say meow
I am a Cat named Treacle and I am 2 years old.
This answer shows simple inheritance and polymorphism. This of the backbone of OOP (Object Orientated Programming) and when learning Java will be the essential basics you will need to learn and understand.
In my example getInfo() could actually just be a method in Animal as there is nothing specific it is doing per subclass. You could also move display into the Animal abstract class if you which, I only placed it here for the example.
There is no need for any CommonUtils class or anything like that here, everything you want can be done by simply learning about inheritance.
What we are saying in this example is Cat and Dog are Animals they inherit all the characteristics of any Animal. What you can't do though is create a random Animal object like Animal animal = new Animal("Paul", 4);, the Animal has to be of some sort of type whether that is of type Dog, Cat or some other Subclass of Animal you create (i.e. Bird, Fish or even Human).
You can have the CommonUtil class as shown below. Also, make the display method static as you are trying to access it using class name.
class CommUtil {
//TODO: output members of class
public static void display (Object obj){
//Question: How to access members of each classes?
//code here...
if(obj instanceof Dog) {
System.out.println(((Dog) obj).getName());
System.out.println(((Dog) obj).getWeight());
}
}
}
But as mentioned in the comments you can just override toString() method inside every class and display objects for all those classes.
public String toString() {
return "Cat [name=" + name + ", age=" + age + "]";
}
You can use Java reflection to get all fields from object, below is the example, you can achieve this by T parameter method in utility class
public class ArrayMain {
int x=10; String name="anil";
public static void main(String[] args) throws IllegalArgumentException, IllegalAccessException {
ArrayMain m = new ArrayMain();
m1(m);
SomeOther o = new SomeOther();
m1(o);
}
public int getX() {
return x;
}
public String getName() {
return name;
}
static <T> void m1(T type) throws IllegalArgumentException, IllegalAccessException {
Field[] f=type.getClass().getDeclaredFields();
for(Field f1:f) {
System.out.println(f1.getName());
System.out.println(f1.get(type));
}
}
}
Check if the object is an instance of Cat or Dog using the instanceof operator. Then you must perform a cast to access the object’s getter methods.
if(obj instanceof Cat){
Cat cat = ((Cat) obj);
System.out.println(cat.getName());
}
This question has been asked in a C++ context but I'm curious about Java. The concerns about virtual methods don't apply (I think), but if you have this situation:
abstract class Pet
{
private String name;
public Pet setName(String name) { this.name = name; return this; }
}
class Cat extends Pet
{
public Cat catchMice() {
System.out.println("I caught a mouse!");
return this;
}
}
class Dog extends Pet
{
public Dog catchFrisbee() {
System.out.println("I caught a frisbee!");
return this;
}
}
class Bird extends Pet
{
public Bird layEgg() {
...
return this;
}
}
{
Cat c = new Cat();
c.setName("Morris").catchMice(); // error! setName returns Pet, not Cat
Dog d = new Dog();
d.setName("Snoopy").catchFrisbee(); // error! setName returns Pet, not Dog
Bird b = new Bird();
b.setName("Tweety").layEgg(); // error! setName returns Pet, not Bird
}
In this sort of class hierarchy, is there any way to return this in a way that doesn't (effectively) upcast the the object type?
If you want to avoid unchecked cast warnings from your compiler (and don't want to #SuppressWarnings("unchecked")), then you need to do a little more:
First of all, your definition of Pet must be self-referential, because Pet is always a generic type:
abstract class Pet <T extends Pet<T>>
Secondly, the (T) this cast in setName is also unchecked. To avoid this, use the "getThis" technique in the excellent Generics FAQ by Angelika Langer:
The "getThis" trick provides a way to
recover the exact type of the this
reference.
This results in the code below, which compiles and runs without warnings. If you want to extend your subclasses, then the technique still holds (though you'll probably need to genericise your intermediate classes).
The resulting code is:
public class TestClass {
static abstract class Pet <T extends Pet<T>> {
private String name;
protected abstract T getThis();
public T setName(String name) {
this.name = name;
return getThis(); }
}
static class Cat extends Pet<Cat> {
#Override protected Cat getThis() { return this; }
public Cat catchMice() {
System.out.println("I caught a mouse!");
return getThis();
}
}
static class Dog extends Pet<Dog> {
#Override protected Dog getThis() { return this; }
public Dog catchFrisbee() {
System.out.println("I caught a frisbee!");
return getThis();
}
}
public static void main(String[] args) {
Cat c = new Cat();
c.setName("Morris").catchMice();
Dog d = new Dog();
d.setName("Snoopy").catchFrisbee();
}
}
How about this old trick:
abstract class Pet<T extends Pet>
{
private String name;
public T setName(String name) { this.name = name; return (T) this; }
}
class Cat extends Pet<Cat>
{
/* ... */
}
class Dog extends Pet<Dog>
{
/* ... */
}
No, not really. You could work around it by using covariant return types (thanks to McDowell for the correct name):
#Override
public Cat setName(String name) {
super.setName(name);
return this;
}
(Covariant return types are only in Java 5 and above, if that's a concern for you.)
It's a bit convoluted, but you can do this with generics:
abstract class Pet< T extends Pet > {
private String name;
public T setName( String name ) {
this.name = name;
return (T)this;
}
public static class Cat extends Pet< Cat > {
public Cat catchMice() {
System.out.println( "I caught a mouse!" );
return this;
}
}
public static class Dog extends Pet< Dog > {
public Dog catchFrisbee() {
System.out.println( "I caught a frisbee!" );
return this;
}
}
public static void main (String[] args){
Cat c = new Cat();
c.setName( "Morris" ).catchMice(); // error! setName returns Pet, not Cat
Dog d = new Dog();
d.setName( "Snoopy" ).catchFrisbee(); // error! setName returns Pet, not Dog
}
}
public class Pet<AnimalType extends Pet> {
private String name;
public AnimalType setName(String name) {
this.name = name; return (AnimalType)this;
}
}
and
public class Cat extends Pet<Cat> {
public Cat catchMice() {return this;}
public static void main(String[] args) {
Cat c = new Cat().setName("bob").catchMice();
}
}
This question has been asked in a C++ context but I'm curious about Java. The concerns about virtual methods don't apply (I think), but if you have this situation:
abstract class Pet
{
private String name;
public Pet setName(String name) { this.name = name; return this; }
}
class Cat extends Pet
{
public Cat catchMice() {
System.out.println("I caught a mouse!");
return this;
}
}
class Dog extends Pet
{
public Dog catchFrisbee() {
System.out.println("I caught a frisbee!");
return this;
}
}
class Bird extends Pet
{
public Bird layEgg() {
...
return this;
}
}
{
Cat c = new Cat();
c.setName("Morris").catchMice(); // error! setName returns Pet, not Cat
Dog d = new Dog();
d.setName("Snoopy").catchFrisbee(); // error! setName returns Pet, not Dog
Bird b = new Bird();
b.setName("Tweety").layEgg(); // error! setName returns Pet, not Bird
}
In this sort of class hierarchy, is there any way to return this in a way that doesn't (effectively) upcast the the object type?
If you want to avoid unchecked cast warnings from your compiler (and don't want to #SuppressWarnings("unchecked")), then you need to do a little more:
First of all, your definition of Pet must be self-referential, because Pet is always a generic type:
abstract class Pet <T extends Pet<T>>
Secondly, the (T) this cast in setName is also unchecked. To avoid this, use the "getThis" technique in the excellent Generics FAQ by Angelika Langer:
The "getThis" trick provides a way to
recover the exact type of the this
reference.
This results in the code below, which compiles and runs without warnings. If you want to extend your subclasses, then the technique still holds (though you'll probably need to genericise your intermediate classes).
The resulting code is:
public class TestClass {
static abstract class Pet <T extends Pet<T>> {
private String name;
protected abstract T getThis();
public T setName(String name) {
this.name = name;
return getThis(); }
}
static class Cat extends Pet<Cat> {
#Override protected Cat getThis() { return this; }
public Cat catchMice() {
System.out.println("I caught a mouse!");
return getThis();
}
}
static class Dog extends Pet<Dog> {
#Override protected Dog getThis() { return this; }
public Dog catchFrisbee() {
System.out.println("I caught a frisbee!");
return getThis();
}
}
public static void main(String[] args) {
Cat c = new Cat();
c.setName("Morris").catchMice();
Dog d = new Dog();
d.setName("Snoopy").catchFrisbee();
}
}
How about this old trick:
abstract class Pet<T extends Pet>
{
private String name;
public T setName(String name) { this.name = name; return (T) this; }
}
class Cat extends Pet<Cat>
{
/* ... */
}
class Dog extends Pet<Dog>
{
/* ... */
}
No, not really. You could work around it by using covariant return types (thanks to McDowell for the correct name):
#Override
public Cat setName(String name) {
super.setName(name);
return this;
}
(Covariant return types are only in Java 5 and above, if that's a concern for you.)
It's a bit convoluted, but you can do this with generics:
abstract class Pet< T extends Pet > {
private String name;
public T setName( String name ) {
this.name = name;
return (T)this;
}
public static class Cat extends Pet< Cat > {
public Cat catchMice() {
System.out.println( "I caught a mouse!" );
return this;
}
}
public static class Dog extends Pet< Dog > {
public Dog catchFrisbee() {
System.out.println( "I caught a frisbee!" );
return this;
}
}
public static void main (String[] args){
Cat c = new Cat();
c.setName( "Morris" ).catchMice(); // error! setName returns Pet, not Cat
Dog d = new Dog();
d.setName( "Snoopy" ).catchFrisbee(); // error! setName returns Pet, not Dog
}
}
public class Pet<AnimalType extends Pet> {
private String name;
public AnimalType setName(String name) {
this.name = name; return (AnimalType)this;
}
}
and
public class Cat extends Pet<Cat> {
public Cat catchMice() {return this;}
public static void main(String[] args) {
Cat c = new Cat().setName("bob").catchMice();
}
}