Abstract List<Person> - java

Update: My classes are more complex than this, I just am stuck on the ArrayList line
I have the following classes:
class CatList {
List<Cat> cats = new ArrayList<Cat>();
}
and
class DogList {
List<Dog> dogs = new ArrayList<Dog>();
}
Where Cat and dog are both data classes.
but I want to create an abstract class:
abstract class AnimalList {
List<???> animals;
AnimalList(Class animal) {
animals = new ArrayList<???>();
}
}
so that I can inherit my classes
AnimalList CatList = new AnimalList(Cat);
AnimalList DogList = new AnimalList(Dog);
AnimalList CowList = new AnimalList(Cow);
Hopefully that makes more sense. My question is therefore What are the ??? bits?

Using a type parameter might solve your problem - using the same class for different types - without inheritance:
public class AnimalList<T> {
private List<T> list = new ArrayList<T>();
public void add(T animal) {
list.add(animal);
}
// more methods
}
Now you can parametize instances for persons and animals:
AnimalList<Cat> catList = new AnimalList<Cat>();
catList.add(new Cat());
AnimalList<Dog> dogList = new AnimalList<Dog>();
dogList.add(new Dog());

My advice is, to create a base class for Dog and Cat, let's say Animal. This way you spare yourself some time, because you don't have to write the same methods and members in both classes, and it works like this:
public (abstract) class Animal
{
members and functions, that both Cats, and Dogs have...
}
then inherit from Animal like this:
public class Cat extends Animal
{
...
}
From now on you can create an ArrayList like this:
ArrayList<Animal> animals = new ArrayList<Animal>();
animals.add(new Cat());
animals.add(new Dog());
If you want to create an AnimalList anyway, then your best option is Andreas's solution, generics are meant for these kind of situation.
IF you know, how inheritance works, and you already considered building your application like this, then sorry for my post!

As was said, you might want to define a base class Animal for Cat and Dog and then:
class AnimalList<T extends Animal> {
private List<T> animals;
protected AnimalList() {
animals = new ArrayList<T>();
}
}
If you need to pass the Class you might wand to define yje constructor as:
AnimalList(Class<T> type) { … }
If you need to handle some AnimalList for some unknown Animal type you might use:
private AnimalList<? extends Animal> list;

Related

not able to add Animal object with wildcard super of Dog [duplicate]

This question already has answers here:
What is PECS (Producer Extends Consumer Super)?
(16 answers)
Closed 12 months ago.
Had seen many examples related to use of super wildcard. Majority of them are with Number and Integer classes. However for my understanding I was trying the below code:
package util;
import java.util.*;
class Animal{
void eat() {
System.out.println("animal eats");
}
}
class Dog extends Animal{
void eat() {
System.out.println("dog eats");
}
}
class Cat extends Animal{
void eat() {
System.out.println("cat eats");
}
}
public class Test {
public void addAnimal(List<? super Dog> list) {
list.add(new Animal());//******* getting error here
list.add(new Dog());
}
public static void main(String[] args) {
List<? super Dog> lsDogs = new ArrayList<Dog>();
List<? super Dog> lsAnimals = new ArrayList<Animal>();
}
}
as per the docs which I have understood super means we can add anything that is on right hand side or its super class. Here I created Dog class which extends Animal class. I can only add Dog type of objects and not Animal. Why is it not possible.. any specific reasons
List<? super Dog> says "this is a List that you can add a Dog to. You might be able to add a Dog because it is a List<Dog>, because it's a List<Animal>, or because it's a List<Object>."
You can't add an Animal to a List<? super Dog>, because your Animal could be any Animal subclass, e.g. a Cat, and then you may have a Cat in a List<Dog>.
class Animal { void sound() {}}
class Cat extends Animal {}
class Dog extends Animal {}
class Test {
public static void main(String[] args) {
List<Object> objects = new ArrayList<>();
List<Animal> animals = new ArrayList<>();
List<Dog> dogs = new ArrayList<>();
List<Cat> cats = new ArrayList<>();
add(objects);
add(animals);
add(dogs);
add(cats); // Error, must be a list we can add Dogs to
addAnimal(objects);
addAnimal(animals);
addAnimal(dogs); // Error, must be a list which can contain any Animal
useList(objects); // Error, must be a List of Animals
useList(animals);
useList(dogs);
useList(cats);
}
public static void add(List<? super Dog> list) {
list.add(new Dog());
}
public static void addAnimal(List<? super Animal> list) {
list.add(new Dog());
list.add(new Cat());
for (Animal a : list) { // error, ? can be Object
a.sound();
}
}
// If we're consuming items from the list we use extends
public static void useList(List<? extends Animal> list) {
list.add(new Animal()); // error, ? is a specific but unknown subclass of Animal
for (Animal a : list) {
a.sound();
}
}
}
The ? means that we don't know what the class is but it is a definite class.
? super of Dog means that ? is something that is a parent of dog. For your example you have { Object, Animal, Dog }. So your ? can be any of those 3 classes.
You can add to the list as long as what every you add can be cast to ?.
Can you add a Dog to the list? Yes because Dog can be cast to any Object, Animal, Dog.
Can you add an Animal to the list? No, because Animal cannot be cast to Dog.
Since Dog is the most specified it is the boundary that we compare against. You can add any Dog or class that extends Dog.

Can I call object methods without inheriting their classes

I implement an Array list in Zoo.java which doesn't inherit any other classes.I will add some objects to this
ArrayList al = new ArrayList();
al.add(new Cat());
al.add(new Dog());
I am unable to write logic which will tell me which type of object is called and using the methods of that class without using Inheritance and Generics.
so here can i use:
for(Animal a:al)
class <?> X = obj.getClass(a);
((X)a).somemethod();
You can create the array list of super class type.
You can do this.
ArrayList<Zoo> arrayList=new ArrayList<Zoo>();
The lesson to learn here is *polymorphism".
the classes Cat and Dog should implement a commont interface that declares methods available for them:
interface Animal {
void eat(SomeOtherInterface food);
void giveSound(BufferedWriter output);
void move();
}
class Cat implements Animal {
#Override public void eat(SomeOtherInterface food){
// consume the food
}
#Override public void giveSound(BufferedWriter output){
output.write("Meaw");
}
#Override public void move(){
// move within the world
}
}
class Dog implements Animal {
#Override public void eat(SomeOtherInterface food){
// consume the food
}
#Override public void giveSound(BufferedWriter output){
output.write("Woof");
}
#Override public void move(){
// move within the world
}
}
Then you give your collecton a generics parameter of the most generic common type providing the methods you want to access:
Collection<Animal> myAnimals = new ArrayList();
myAnimals.add(new Cat());
myAnimals.add(new Dog());
try( BufferedWriter output = new BufferedWriter(new OutputStreamWriter(System.out))){
for(Animal animal : animals)
animal.giveSound(output);
}
Without any instanceOf checks there is no other way to do it; unless your ArrayList::add has a definition that says to take some general Object and that Cat and Dog extends from. But still the only methods you would be able to call would be the methods from that Object, even if Cat or Dog have additional ones. You might see why generics are so handy in these cases...
I did some work on it. To access the methods of objects that are in the array list we can use java.lang.reflect package.
I can first get all the declared methods and then invoke them by using parameters.
so my program will be like:
public class Methodcall{
ArrayList <Object> al = new ArrayList<Object>();
al.add(new Cat());
al.add(new Dog());
for(Object a:al)
{
class ax = a.getClass();
Method[] methods=ax.getdeclaredMethods();
for(Method m:methods)
{
System.out.println(method.getName);
}
}
}
}
after this we can access methods by using other members of reflections.
Thank you all.

Why cannot write in covariance in Java? [duplicate]

This question already has answers here:
What is a difference between <? super E> and <? extends E>?
(10 answers)
Closed 4 years ago.
I have code like this:
class Scratch {
public static void main(String[] args) {
List<Cat> cats = new ArrayList<>();
List<? extends Animal> animals = cats;
animals.add(new Cat()); // compile error
Animal animal = animals.get(0);
}
}
class Animal {
}
class Cat extends Animal {
}
class Dog extends Animal {
}
Why cannot add a Cat instance to animals? Add Cat instance or Dog instance to animals, and read elements as animal is type safe. I know PECS (short for "Producer extends and Consumer super"), but I can't understand that why can't write in covariance and cant't read in contravariance in Java.
<? extends Animal> is not Cat, it can be any subclass ot Animal, for example:
List<? extends Animal> dogs = new ArrayList<Dog>();
dogs.add(new Cat()); // compile error
No matter what actually type <? extends Aminal> is, it can't add any subclass of Animal. Use List<Animal> instead of List<? extends Animal>.

ArrayList of Objects of different classes that belong to a superclass?

In the following code what should be put between '<' and '>' so that I will be able to add new object of each subclass of Animal superclass ?
package animal;
import javax.swing.JOptionPane;
import java.util.ArrayList;
public class Animal {
public static void main(String[] args) {
Animal createAnimals = new Animal();
createAnimals.userInputHandle();
ArrayList <> animalList = new ArrayList<>();
animalList.add(new Dog);
}
private String userInputHandle(){
String userInput;
userInput = JOptionPane.showInputDialog("Select animal from the "
+ "following list"
+ "\n1.Dog\n2.Cat\n3.Snake\n4.Frog"
+ "\n5.Human\n6.Shark\n7.Sea Gulls");
userInput = userInput.toLowerCase();
return userInput;}
}
class Fish extends Animal{
}
class Amphibians extends Animal{
}
class Reptiles extends Animal{}
class Birds extends Animal{}
So that I will make a method in Animal class and override it for each subclasses. For example for Amphibians--> Frog belongs to amphibian class and so on.
// this will work fine as 'Animal' will be base class for other class
ArrayList <Animal> animalList = new ArrayList<Animal>();
//
animalList.add(new Reptiles());
animalList.add(new Birds());
animalList.add(new Amphibians());
If you make the declaration
ArrayList <Animal> animalList = new ArrayList<Animal>();
then you'll be able to add any subclass of Animal to it.
Make your declaration on your ArrayList like this.
ArrayList <Animal> animalList = new ArrayList<Animal>();
To add subclasses of Animal.
animalList.add(new Monkey());
animalList.add(new Donkey());
and etc.
If you are using Java SE7 another way to instantiate a Generic(in your case an ArrayList) is to use a limited type inference like this.
ArrayList <Animal> animalList = new ArrayList<>();

Java Generics: adding wrong type in collection

Who could me explain this?
I have these couple of classes:
abstract class Animal {
public void eat() {
System.out.println("Animal is eating");
}
}
class Dog extends Animal {
public void woof() {
System.out.println("woof");
}
}
class Cat extends Animal {
public void meow() {
System.out.println("meow");
}
}
And this is the action:
import java.util.ArrayList;
import java.util.List;
public class TestClass {
public static void main(String[] args) {
new TestClass().go();
}
public void go() {
List<Dog> animals = new ArrayList<Dog>();
animals.add(new Dog());
animals.add(new Dog());
doAction(animals);
}
public <T extends Animal> void doAction(List<T> animals) {
animals.add((T) new Cat()); // why is it possible?
// Variable **animals** is List<Dog>,
// it is wrong, that I can add a Cat!
for (Animal animal: animals) {
if (animal instanceof Cat) {
((Cat)animal).meow();
}
if (animal instanceof Dog) {
((Dog)animal).woof();
}
}
}
}
This example compile without errors, and output is:
woof
woof
meow
But how can I add in list of Dog a Cat? And how the Cat is casted to Dog?
I use:
java version "1.6.0_24". OpenJDK Runtime Environment (IcedTea6 1.11.1) (6b24-1.11.1-4ubuntu3)
Ok here's the deal with generics (anything that uses casting hackery might not be safe at runtime, because generics work by erasure):
You can assign a subtype parameterised the same way e.g
List<Animal> l = new ArrayList<Animal>();
and you can add items that are the type of this parameter or its subclasses e.g
l.add(new Cat());
l.add(new Dog());
but you can only get out the type of the parameter:
Animal a = l.get(0);
Cat c = l.get(0); //disallowed
Dog d = l.get(1); //disallowed
Now, you can use a wild card to set an upper bound on the parameter type
List<? extends Animal> l = new ArrayList<Animal>();
List<? extends Animal> l = new ArrayList<Cat>();
List<? extends Animal> l = new ArrayList<Dog>();
But you can't add new items to this list
l.add(new Cat()); // disallowed
l.add(new Dog()); // disallowed
In your case you have a List<T> so it has a method add(T t) so you can add if you cast to T. But T has type bounded above by Animal so you shouldn't even be trying to add to this list, but it is treated as a concrete type and that's why it allows the cast. However this may throw a ClassCastException.
And you can only retrieve items that are the upper bound type
Animal a = l.get(0);
Cat c = l.get(0); //disallowed
Dog d = l.get(1); //disallowed
Or you can set the lower bound parameter type
List<? super Animal> l1 = new ArrayList<Object>();
List<? super Animal> l1 = new ArrayList<Animal>();
List<? super Cat> l2 = new ArrayList<Animal>();
List<? super Cat> l2 = new ArrayList<Cat>();
List<? super Dog> l3 = new ArrayList<Animal>();
List<? super Dog> l3 = new ArrayList<Dog>();
And you can add objects that are subtypes of the lower bound type
l1.add(new Cat());
l1.add(new Dog());
l1.add(new Object()); //disallowed
But all objects retrieved are of type Object
Object o = l1.get(0);
Animal a = l1.get(0); //disallowed
Cat c = l2.get(0); //disallowed
Dog d = l3.get(0); //disallowed
Do not expect generics to perform runtime type checking. During compilation, Java performs all the type inference, instantiates all the types, ... and then erases all trace of generic types from the code. At runtime, the type is List, not List< T > or List< Dog >.
The main question, why it allows you to cast new Cat() to type T extends Animal, with only a warning about unchecked conversions, is valid. Certain unsound features of the type system make legalizing such dubious casts necessary.
If you want the compiler to prevent the addition of anything to the list, you should use a wildcard:
public void doAction(List< ? extends Animal > animals) {
animals.add(new Cat()); // disallowed by compiler
animals.add((Animal)new Cat()); // disallowed by compiler
for (Animal animal: animals) {
if (animal instanceof Cat) {
((Cat)animal).meow();
}
if (animal instanceof Dog) {
((Dog)animal).woof();
}
}
}
P.S. The dubious downcasts in the loop body are a perfect example of how lame Java is for disjoint sum (variant) types.
This is related to type erasure. The type is not preserved at runtime. Really, List becomes List of Type Object at runtime. This is why you're getting a compiler warning or should be on animals.add((T) new Cat()); At compile time, Cat does extend animal which is of type T. However, it cannot enforce that a Dog is in the list at that time, therefore the compiler warning.
Generics only work for compile time safety. In your case, how can the compiler know that something bad will happen? It assumes your type definitions, and proceeds off of that. To do more would mean much more elaborate work for the compiler, but there are extended static checkers and other tools that could catch this pre-runtime.
Suffice it to say that there is such a T for which the cast can succeed. As for compiled code, it will be exactly the same as if you wrote animals.add((Animal)new Cat());
Your function doAction is parametrized by a type T that extends the class Animal. So it can be either an object of type Dog or Cat.
You should also note the difference between formal parameter and effective parameter. The formal parameter is the one you use when defining your method, which in your case is List <T> (using it as a shortcut). The effective parameter is the one you "give" to your method when call it, here List<Dog>. .
Lets take a look at animals.add((T) new Cat()) in doAction(). animals is a list which elements are of type T which is either Dog or Cat, so there is no mistake, since that's the type of the formal parameter.
So that's the reason. It is one of the benefits of using parametrize classes.

Categories