简体   繁体   中英

looping over different objects (that extends common super class) in one collection of superclasses

I struggle with inheritance in java. I have many elements that have similar properties like fe id , name or date . This elements have also specified parameters that belongs only to them, for example: email , address .

I would like to keeps this different elements in collection. And then display them in console, using loop. But when I put element like email (which is specified for concrete class User ) it gives me an error:

value email is not a member of Person

Here is code:

public class Person {
  int id;
  String name;
  Date date;
}
public class User extends Person {
  String email;
  String login;
  String password;
}
public class Contact extends Person {
  Address address;
}

public class Customer {
  List<Person> persons;

  // AND NOW I WOULD LIKE TO PRINT THIS
  public void print() {
    for(Person person: this.persons) {
      System.out.println(person.id + " " + person.email);
    }
  }
}

I have many many similar problems with inheritance in Java. I don't know how to carry on with it? How to implement classes, that I could make it work.

Can You give me some good Design Pattern or clues?

I am looking for something advance, that will allow me to work with parameters that occurs only in extended classes. I would like to call them by parameter name. I've tried already to implement print method for each extending class, but it is to general. I have to have access to parameters.

Your specific example is easy to solve. In order to print an object of a class, override toString for that class.

Then your print method becomes :

  public void print() {
    for(Person person: this.persons) {
      System.out.println (person);
    }
  }

Each class knows how its String representation should look like. For example, in the User class :

public class User extends Person
{
    @Override
    String toString ()
    {
        return this.id + " " + this.email;
    }
}

EDIT:

If you wish to access a member of a sub-class from a variable whose type is the super-class (for example accessing the email property from a Person variable), you must first cast the variable to the type of the sub-class (User in your example), and make sure that this cast is valid (by using instanceof to verify, for example, that person instanceof User ).

Sometimes can't avoid such casts, but too many casts often suggest that your design is flawed. When you process a Collection of Persons, you should avoid accessing specific properties defined only in some of the sub-classes. You should try to call only methods of the Person class, and those methods can be overridden in sub-classes to provide different behavior.

So lets look at your Code. Your Collection can have Objects of all classes that extend Person in itself. This means, that there might be some Objects of Person, some of User and so on. The Collection itself can't really be sure about which Objects of a certain Class it contains. We can see that your Superclass Person doesn't have the attribute email. Only the class User has (and all classes that might extend from it). So on an Obejct of the Superclass Person, you wouldn't be able to receive data from an attribute "email" simply because it doesn't have that member. A Collection of the Base Type Person can't Access the attribute email, even if it might be available in the subclasses because it cannot be ensured that the call will not fail on all Objects that might be put into the collection.

What workarounds might be available:

  • simplest, dont try to acess a member which isn't available in the base type of the collection
  • as mentioned above, define the toString() Method in the classes. Then you can see the value of the member email in Objects of the Class user.
  • if you know your collection will only have User Objects in itself, just Change the bastype
  • ClassX instanceof ClassY returns true of false depending on wether or not ClassX is a subclass of ClassY. So you can put it in an if statement. If something is instanceof a User you can then acess the member email without any problems. Remember to cast to User in the body of the if-statement though.

In programming you rarely have one size fits all. IMO not even with design patters. In your case I'd do something like:

for(Person person: this.persons) {
   if (person typeof User) 
      System.out.println(person.id + " " + ((User)person).email);
}

Hope someone else can come up something fancier :-)

That is simple. email is a member of User not Person.So you can not compile this code.

Remove email from User and add it to Person class.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM