So I have a super class and I want to instantiate multiple sub classes off of it. The sub classes will probably be multi-threaded.
E.g.:
public class Person() {
protected variables;
public/private methods ect.
}
public class Man() extends Person {
private variables;
public/private methods;
}
public class Woman() extends Person {
private variables;
public/private methods;
}
I want to instantiate Person then extend Man and Woman classes off of it.
Like:
Person A = new Person();
Man B = //some how extends A;
Woman C = //some how extends A;
Or are there other ways of achieving the same goal?
You are misunderstanding the difference between a class and an object. A class is the overall definition of how an object will be composed. An object is a specific instance.
So if you create an instance of Person then that's just that a single object instance of the Person class. You can't extend it dynamically to have it as a Man at runtime (there are patterns where you could sort of do this, but not inheritance). If you want a Man you have create an instance of one.
Maybe your real question is different. Maybe you want to use an instance of Person as the template to create new instances of Man and Woman.
Imagine this
class Person {
private String name;
public Person(String name) { ... }
}
and a prototype person:
Person kelly = new Person ("Kelly");
Maybe you want to make a copy of the generic "kelly" as a Man and as a Woman - two separate objects, that happen to have this gender-neutral name in common
Man kellyMan = new Man(kelly);
Woman kellyWoman = new Woman(kelly);
What are we seeing above? We're seeing a copy constructor pattern. The contents of the original Person object could be copied into a new Man or Woman object which would then go on to live lives of their own. Example:
class Man : extends Person {
public Man(Person template) {
super(template); // pass to superclass for copying
}
}
class Person {
...
public Person(Person template) {
this.name = template.name;
// etc
}
}
This is not an uncommon way to go about things. Dynamically changing the type of objects at runtime is not common at all... I tried it once. Don't do it!
If you want to inherit a class:
public class Child extends Parent { ...
You can have multiple child classes that inherit from the same parent, you just can't inherit from more than one class. Here are some examples of what you can use. Remember, when you write something like Person p = new Person(), you have p which is a reference to a Person object. Try messing around with mixing up object types with different references, and see what happens.
Related
I have a course project and I am not able to solve the following problem:
I need to create a linkedlist in which I can add a list of elements from a class called Person, and a list of elements from a class called Accounts using addAll()
List<Person> persons= new LinkedList<Person>();
List<Accounts> accounts= new LinkedList<Accounts>();
List<???> elements = new LinkedList<>();
elements.addAll(persons);
elements.addAll(accounts);
My teacher ordered to make a class ElementsOfTheBank to fill the place with ???, but I couldn't understand how to make it work :(
This is a kind of bad example, but your teacher probably wants you to use inheritance.
As a person and an account are both "elements of the bank", your classes can look like this:
class ElementsOfTheBank {
// common variables between Person and Account
}
class Person extends ElementsOfTheBank {
// ...
}
class Account extends ElementsOfTheBank {
// ...
}
Then you can add both types to your list:
List<ElementsOfTheBank> elements = new LinkedList<>();
elements.addAll(persons);
elements.addAll(accounts);
You need a common type that is shared by all elements of the bank. Trivially, java.lang.Object is common to them all, but perhaps you're being asked to make e.g. public interface ElementOfBank, so that you can then declare your Person class as class Person implements ElementOfBank {}.
Once you've done that, you can declare your list to be of that element: List<ElementOfBank> elements = ...;, and you could call .addAll(persons) on such a list. After all, every person instance is also an ElementOfBank, that's what class Person implements ElementOfBank means.
Don't use Collections just to combine correlated objects together.
It doesn't make much sense to create a List<Object> in order to Person and Account lists together. Introducing a common super of Person and Account doesn't seem to be a great idea as well. What is the advantage of binding through Inheritance a physical person and a bank account? I would rather suggest establishing the relationship between a person and their accounts through Composition (not Inheritance).
The better option would be to create a class, let's say Bank. That would encapsulate the two lists. I.e. you can introduce behavior for managing bank-clients and their accounts, and bank instance would become a single entry point for all operation you need to perform with them.
public class Bank {
private List<Person> persons= new LinkedList<>();
private List<Accounts> accounts= new LinkedList<>();
// constructors, getters
public boolean createAccount() {
// TO DO ...
return ...;
}
public Person findPerson(SomeProperty id) {
// TO DO ...
return ...;
}
}
This is a question I always had, but now is the time to solve it:
I'm trying to implement the composition of objects using public attributes like:
Person {
public Car car;
}
Owner {
public Person person;
public Car car;
}
Car {
public Person person;
}
Really my question is: Is a good practice to set that composition properties public or private?
The difference:
a) Public: doing public, the access is fast and not complicated, because I only need to reference the property directly with the instance like:
$instancePerson.car.getNumberOfGearsGood()
The problem: the car propertie is available to be modified by anybody from anywhere.
b) Private: doing private, the access if slow and is necessary to use methods to get these properties like:
$instancePerson.getCar().getNumberOfGearsGood()
When I say slow is because you need to do a method two method call, while in the Public solution only you need to do one.
I know many developers and software engineers here will prefer Private solution, but can you explain the performance there?
If you are doing OO, there should be no such thing as a "public" attribute. All the attributes are implementation details of the object, therefore are hidden from everybody. Only the methods associated with the object's responsibility are public.
So to answer the question:
All "attributes" should be private
And there should be no getter on a private attribute
Yes, there should be no
person.getCar().getNumberOfGears();
This is sometimes called the Law of Demeter. The person should have methods that do stuff connected to the responsibility of the Person class, therefore there is no performance penalty accessing attributes, because this access is always internal to the class and direct.
the short answer is that, except for very few cases, you want those variables to be private, and often technologies in the JVM will make access faster than you think it would be (and sometimes even faster than in C/C++).
For a bit more detailed answer:
The main question is: who should be able to modify those variables? for example, you may want Car to be created passing a Person to its constructor, and never allow the person to change (in a world where there is no market for used vehicles). In this case, if the field is public another object can modify it and change the owner of the car. But if you make the field private, and provide a getOwner() method, nobody can modify it. If the get method is final, and therefore can't be overridden in a subclass, the JVM might even transform internally any invocation of x.getOwner() in the equivalent of x.owner. In your example however it's not possible to pass all elements in the constructor, as they reference each other. In fact, it seems to me your model has one too many classes. Let's try to write it a bit differently:
Person {
public Car car;
}
Car {
public Person owner;
}
Now, with assuming that every car has an owner, and every person own a car, this model is dangerous, because you could do something like this:
Person p = new Person()
Car c = new Car();
p.car = c;
As you can see, I forgot to set c.owner = p.
Let's see how we can fix this:
Person {
private Car car;
public void setCar(Car c) {
if (car == c)
return;
car = c;
c.setOwner(this);
}
}
Car {
private Person owner;
public void setOwner(Person o) {
if (o == owner)
return;
owner = o;
o.setCar(this);
}
}
I can now do :
Person p = new Person();
Car c = new Car();
p.setCar(c);
or
Person p = new Person();
Car c = new Car();
c.setOwner(p);
and either way both relationship will be set correctly.
In other words, being forced to go through accessors allows to set more than just a simple field, which is useful to establish coherent state across model elements involved in a relationship.
I am not sure what the best practice for downcasting from parent to child or creating a B (extends A) out of A is.
As an example I have two classes:
The parent one:
public class SoccerPlayer {
private String name;
private SoccerShoe shoe;
private SoccerJersey jersey;
/* ... */
}
And the child one:
public class Goalkeeper extends SoccerPlayer {
private GoalkeeperGlove glove;
/* ... */
}
Now a regular soccer player wants to be a Goalkeeper. What can I do? Obviously the following would not work:
SoccerPlayerArrayOfTeamA[0] = new SoccerPlayer("Robert");
/*... new career path ...*/
SoccerPlayerArray[0] = (Goalkeeper) SoccerPlayerArray[0]
But that is what I would say "I want to do"...
The new Instance of the child class (Goalkeeper) should have all variable configurations as the old Instance of the parent class (SoccerPlayer). (e.g. name, jersey ...)
Is there an OOP way to do that I do I have to set every variable manually as in the following?
/*... new career path ...*/
SoccerPlayer temp = SoccerPlayerArray[0]
SoccerPlayerArray[0] = new Goalkeeper(temp.getName());
SoccerPlayerArray[0].setJersey(temp.getJersey());
Checkout Decorator Design Pattern. E.g. Java IO classes.
When any object dynamically wants to change its behavior then you can wrap that object with the desired object. Like if C wants to become B then B should have a constructor which accepts C and then the methods in B should use C where ever appropriate. Best example is when FileInputStream wants to become BufferedInputStream you can just create BufferedInputStream by passing FileInputStream in its constructor but it does not need to copy properties of FileInputStream.
Add a copy constructor to Goalkeeper that accepts SoccerPlayer as an argument.
I'm trying to get a clone of an object using copy-contructor, unfortunately seems that all the modification to the clone are reflected to the original object.
I have this interface
public interface Car{
public Car newInstance(Car c);
}
and various Object hat implements the interface in this way
public FerrariSpyder implements Car{
String name;
String description
ArrayList<Feature> featureList;
public FerrariSpyder(String name, String description, ArrayList<Feature> featureList){
this.name=name;
this.descripion=descripion;
this.featureList=featureList;
}
#Override
public Car newInstance(Car c) {
return FerrariSpyder.newInstance((FerrariSpyder) c);
}
public static FerrariSpyder newInstance(FerrariSpyder fs) {
return new FerrariSpyder(fs.getName(), fs.getDescription(), fs.getFeatureList());
}
}
Now assuming that I have a Car object named originalCar I try to clone this with
Car clone=originalCar.newIstance(originalCar);
If I add elements in featureList of the clone also the featureList in originalCar will be modified.
You create a new instance of your object, but the fields are shared.
Concerning name and description, there is no problem, because Java treat Strings as immutable. If you try to "modify" them, you will in fact change the reference to them.
Concerning featureList, that's another story. You currently have the same list instance in both objects. You need to create a new instance of the list when you call the constructor of your new object, like this:
public static FerrariSpyder newInstance(FerrariSpyder fs) {
return new FerrariSpyder(fs.getName(), fs.getDescription(), new ArrayList<>(fs.getFeatureList()));
}
Note: Be careful, there are now 2 lists, but they share the same objects. This means 2 things:
If you modify a Feature in one of the lists, you'll see modifications of that Feature in the other list.
If you add/remove an object from one list, the other list will not be affected.
If you want to be able to modify the Feature objects in the lists without affecting the other list, you'll have to do deep copies of these objects as well.
Side note: What you are doing here is basically writing a clone() method, which you named newInstance(). You should probably implement the Cloneable interface to do it the Java way ;-)
When i try to create an instance of a class and add this to my arraylist i can't call methods defined in the child.
How do i make this work?
List class:
import java.util.*;
public class List {
private ArrayList<Person> persons;
public List(){
persons = new ArrayList<Person>();
}
public void addAssistant(){
Person person = new Assistant();
persons.add(person);
if(person instanceof Assistant){
person.assist();
}
}
}
Person class:
public class Person {
public Person(){}
}
Assistant class:
public class Assistant extends Person {
public Assistant(){}
public void assist(){
System.out.println("I am assisting!");
}
}
Compiler:
line: person.assist(); within the addAssistant() method in the List class.
Compiler error:
The compiler cannot find symbol - method assist().
You need an explicit cast:
if(person instanceof Assistant){
((Assistant)person).assist();
}
However, I think this type of logic should generally be discouraged.
You need to make a cast for use a subclass method
if(person instanceof Assistant){
((Assistant)person).assist();
}
Person class does not have assist method defined so you must explicitly cast to Assistant class e.g.
if(person instanceof Assistant){
((Assistant)person).assist();
}
You have to cast your Person into an Assistant like this:
if(person instanceof Assistant){
((Assistant)person).assist();
}
This type of casting howerver is an indication of flawed application design I think.
Just a sidenote:
You should use interfaces instead of concrete implementations. So you should replace this:
private ArrayList<Person> persons;
with this:
private List<Person> persons;
If you want your Persons to do their specific work and an Assistants work is assisting than you can work around this by creating an abstract method in Person
public abstract void doYourWork();
and you can implement that in Assistant:
#Override
public void doYourWork(){
// doing something
}
In this case you don't have to explicitly cast your Person objects.
If Person ain't going to have any concrete implementations you can make it an interface instead.
I would code it this way
public void addAssistant(){
Assistant assistant = new Assistant();
assistant.add(person);
assistant.assist();
}
There is no point in abstracting yourself from the knowledge that your recently created object is in fact an Assistant.
Abstracting yourself from the concrete type is a good way of reduce coupling between two pieces of code and it is necessary for doing nice things like polymorphism... but in this particular example you are showing us you are already tightly coupled to an Assistant (in fact you are instantiating it just two lines above).
Another possible way to implement this is to use polymorphism, you can do that by adding the assist() method to the interface of your Person.
public class Person {
public Person(){}
public void assist() {
//I'm a just a person who doesn't assist anywhere
}
}
By doing so you are going to be able to do what you were trying:
public void addAssistant(){
Person person = new Assistant();
persons.add(person);
person.assist();
}
However I wouldn't recommend that, mostly because you will start filling your Person interface with responsibilities that are not correctly placed there. It's all matter of design, you need to choose the better (and of course, the most confortable) solution for your particular problem.
Good Luck
Claudio
The way Java language has been designed, this doesn't compile (as you've figured it out as well). Think of it this way, all assistants are persons, but not all persons are assistants. If you use an explicit cast, you can do what you want to achieve (as NPE mentioned in his answer).