I have a basic assignment to do but am very new to OOP and struggling with it. Other online resources are starting to add to my confusion.
I am required to:
Write code for a class Person. A Person object is to have attributes name, age and address.
Write code for a class Dog. A Dog object is to have attributes name and age.
Give any additional code in the Person and Dog classes that is required to setup a bidirectional association between a Person object and a Dog object. A Person object acts as an owner for a Dog object and the Dog object acts as a pet for the Person object.
Modify your Person class so that a Person object can act as owner for up to 20 Dog objects.
Obviously this is a very simple example.
My code so far:
Person Class :
public class Person
{
// instance variables - replace the example below with your own
private String name;
private int age;
private String address;
/**
* Constructor for objects of class Person
*/
public Person()
{
this.name = name;
this.age = age;
this.address = address;
}
//Set Methods:
public void setName () {
this.name = name;
}
public void setAge () {
this.age = age;
}
public void setAddress () {
this.address = address;
}
//Get Methods:
public String getName () {
return name;
}
public int getAge () {
return age;
}
public String getAddress () {
return address;
}
}
Dog Class:
public class Dog
{
// instance variables - replace the example below with your own
private String name;
private int age;
public Dog()
{
this.name = name;
this.age = age;
}
//Set Methods:
public void setName () {
this.name = name;
}
public void setAge () {
this.age = age;
}
//Get Methods:
public String getName () {
return name;
}
public int getAge () {
return age;
}
}
Main:
public class Main
{
//Blank
}
I know this code is currently useless and doesn't do anything but I am unsure of how to 'associate' the objects & where to do it. The assignment spec specifies a person acts as an 'owner' for the dog.
This is where my problem lies. Setting up the relationship between the objects.
The main problem here is consistency: if a Dog d1 is a pet for a Person p1, then p1 must be owner of d1, and vice versa. If, as many suggested, we have 2 methods (Person.addDog() and Dog.setOwner()), then a user can easily make a mistake and fail to call both methods (or call with wrong arguments). Since a Dog can have only one owner, a simple and safe interface would be using single method Dog.setOwner(Person p), where p may be null if we want the dog to have no owner. This method, besides setting the field Dog.owner, must remove this dog from the pet list of previous owner and (if p != null) add itself to the pet list of the new owner. The methods of class Person to add and remove pets should be visible for the class Dog but not visible to the user (they should be package private), while the method Dog.setOwner should be public.
UPDT
We can consider value of Dog.owner as a primary datum, and value of Person.dogs as secondary data, similar to database indexes.
This is a common problem with bidirectional relationships; you can't pass them in the constructor because one will not exist yet when the other is initialised. For this reason you must "wire them up from the outside"
Your mention of 20 dogs suggests they want you to use an array to hold the dogs, but an arraylist would be better. I will use the arraylist but can show you how this would work with an array if you'd like
public class Person
{
ArrayList<Dog> dogs=new ArrayList<Dog>(); //this will hold all the dogs that the Person has as pets
public void giveDog(Dog dog){
dogs.add(dog)
}
.....
.....
Equally the dog class is given an owner
public class Dog
{
Person owner;
public void setOwner(Person owner){
this.owner=owner;
}
.....
.....
Using these two methods you can create the bidirectional relationship.
Notes
This is obviously an assignment so you have no choice but for the future; bidirectional relationships like this can be useful. But they are also dangerous when used incorrectly; the most important thing is that after initialisation an object must work without error. It must not rely on setOwner() or giveDog() being called: in other words a petless person and an ownerless dog must behave "correctly" (what ever that means in this context. Failing to achieve this can lead to bug prone code. If this is impracticle then it must be impossible for ownerless dogs or dogless people to be exposed to the rest of the program; factory methods can be useful for this, but that is beyond the scope of this question
Because both objects can't be created at the same time you can't pass references to each other in the constructor. You must create getter and setter methods so you can create this relationship after the objects are created. An example of this is as follows:
public class Person
Set<Dog> dogs = new HashSet<Dog>();
public void addDog(Dog dog){
if(dogs.size()>20){
throw new IllegalArgumentException("exceeded the limit: ");
}
dogs.add(dog);
}
}
public class Dog
{
Person person;
public void setPerson(Person person){
this.person=person;
}
}
What you are required to do looks like a circular dependency issue. So what you can do is to use the object composition.
Simply add to your classes a instance variable of the second type:
public class Person
{
private Dog myDog;
private String name;
private int age;
private String address;
...etc.
and respectively in the Dog class, every Dog will have its owner:
public class Dog
{
private Person myOwner;
private String name;
private int age;
Don't forget setters and getters.
As for the point 4):
4) Modify your Person class so that a Person object can act as owner for up to 20 Dog objects.
Instead of having every Person object have one Dog member, use an array, or some Collection (List, Set, etc.):
So instead of
private Dog myDog;
do
private Dog[] dogArray = new Dog[20];
OR
private Collection<Dog> dogList = new ArrayList(20); //for example
Try this one:
Person person = new Person();
Dog dog1 = new Dog();
dog1.setAge(12);
Dog dog2 = new Dog();
dog2.setAge(34);
person.addDog(dog1); //dog 1
person.addDog(dog2); //dog 2
person.listDogs(); //list of all dogs
//PERSON
public class Person {
// instance variables - replace the example below with your own
private String name;
private int age;
private String address;
private ArrayList<Dog> dogs = new ArrayList<Dog>();
/**
* Constructor for objects of class Person
*/
public Person()
{
this.name = name;
this.age = age;
this.address = address;
}
public void addDog(Dog dog) {
this.dogs.add(dog);
}
public void listDogs() {
for(Dog item : this.dogs) {
System.out.println(item.getAge());
}
}
//Set Methods:
public void setName () {
this.name = name;
}
public void setAge () {
this.age = age;
}
public void setAddress () {
this.address = address;
}
//Get Methods:
public String getName () {
return name;
}
public int getAge () {
return age;
}
public String getAddress () {
return address;
}
}
//DOG
public class Dog {
// instance variables - replace the example below with your own
private String name;
private int age;
public Dog()
{
this.name = name;
this.age = age;
}
//Set Methods:
public void setName () {
this.name = name;
}
public void setAge (int age) {
this.age = age;
}
//Get Methods:
public String getName () {
return name;
}
public int getAge () {
return age;
}
}
Related
public class MainClass {
ArrayList<Man> mans = new ArrayList<Man>();
// I'm filling in this arraylist, but I'm not writing those parts because I want to summarize the
//code.
}
public class Man {
int index_father, index_son;
String name;
public Man(String name){
this.name = name;
}
}
Some guys in this community of men have a father-son relationship. My question is that:
I'm looking for a neater way to build this father-son relationship.
I tried to establish this relationship with integers (example: which_father shows the directory where the man's father is in the 'mans' list) but this has some disadvantages:
1-When creating objects, I always have to create sons after fathers. because:
private void createMan() {
Man man = new Man("Ethan");
man.index_father = 4;
mans.add(man);
mans.get(4).index_son = mans.indexOf(man);
}
If we haven't created the father yet, the 4th element of mans will not have been created yet.
2- In cases where I delete an element from the mans arraylist, which_fathers will not show the correct father man.
I may not know enough about Java, but there must be an easy way to establish a connection between objects (like the father-son relationship in this example), right?
You can add a List<Man> to represent sons in Man class:
public class Man {
String name;
List<Man> sons = new ArrayList<>();
public Man(String name){
this.name = name;
}
}
EDIT:
I think OOP can help to simplify things:
public class Person {
Sex sex;
String name;
List<Person> children = new ArrayList<>();
Person partner; // husband/wife
public Person(String name, Sex sex){
this.name = name;
this.sex = sex;
}
public void marryTo(Person person){
this.partner = person;
person.setPartner(person);
}
public void setChildFromMarriage(Person child){
children.add(child);
partner.getChildren().add(child);
}
public enum Sex {
MAN, WOMAN
}
}
You can keep a List<Person>.
Usage:
List<Person> people = Arrays.asList(
new Person("Jordan", Person.Sex.MAN),
new Person("Tim", Person.Sex.MAN),
new Person("Sarah", Person.Sex.WOMAN)
);
// Let's marry Jordan to Sarah
Person jordan = getPersonByName(people, "Jordan");
Person sarah = getPersonByName(people, "Sarah");
jordan.marryTo(sarah);
Person child = new Person("Jordan Jr", Person.Sex.MAN);
// We can add the child to people list if we want
jordan.setChildFromMarriage(child);
// Let's change their child name using Sarah's reference.
getPersonByName(sarah.getChildren(), "Jordan Jr").setName("Bob");
System.out.println(child.getName()); // Bob
private static Person getPersonByName(List<Person> people, String name) {
return people.stream()
.filter(person -> person.getName().equals(name))
.findFirst()
.get();
}
Output:
Bob
So what I have to do is use references instead of integers.
I thought that the objects we created were not references, but the object itself. I thought that when we assign an object to an object, the object on the left takes all the properties of the object on the right and we have two independent objects. But what actually happens is that the object reference on the left takes the object reference on the right, and we have two references and one object.
So the only way to actually create an object is to use new Constructor().
I changed the code to:
public class Person {
String Name;
Gender gender;
Person father;
Person mother;
Person partner;
ArrayList<Person> childs = new ArrayList<Person>();
public enum Gender {
MAN, WOMAN
}
public Person(String name, Gender gender){
this.Name = name;
this.gender = gender;
}
public void marryTo(Person person){
this.partner = person;
person.partner = this;
}
public void setChildFromMarriage(Person child){
childs.add(child);
partner.childs.add(child);
}
}
..........................................................................................
..........................................................................................
public class MainClass {
public static void main (String[] args)
{
try {
MainClass obj = new MainClass ();
obj.run ();
} catch (Exception e) {
e.printStackTrace ();
}
}
ArrayList<Person> persons = new ArrayList<Person>();
public void run () {
Person p;
p = new Person("Jordan", Person.Gender.MAN);
persons.add(p);
p = new Person("Sarah", Person.Gender.WOMAN);
persons.add(p);
persons.get(0).marryTo(persons.get(1));
p = new Person("Jordan Jr", Person.Gender.MAN);
persons.add(p);
persons.get(0).setChildFromMarriage(persons.get(2));
persons.get(1).childs.get(0).Name = "Bob";
System.out.println(persons.get(2).Name);
}
}
Output:
Bob
I have the following parent class:
public class Employee {
private String name;
public Employee(String name) {
this.name = name;
}
public String getName() {
return name;
}
}
And 2 child class which extends parent:
public class FullTimeEmployee extends Employee {
private double salary;
public FullTimeEmployee(String name, double salary) {
super(name);
this.salary = salary;
}
public double getSalary() {
return salary*2;
}
}
public class PartTimeEmployee extends Employee {
private double salary;
public PartTimeEmployee(String name, double salary) {
super(name);
this.salary = salary;
}
public double getSalary() {
return salary;
}
}
The scenario:
I am using an ArrayList to contain information about employees. The ArrayList is created at the start of the program, and the type of employee being added into the Arraylist is a child extending parent and only known at runtime through user's input
public class EmployeeApplication {
public static void displayInfo(Employee employee) {
// How do I access the method getSalary() that belong to the specific type determined on runtime?
System.out.println(employee.getSalary()); // <--- ???
}
public static void main(String[] args) {
Scanner keyboardInput = new Scanner(System.in);
System.out.println("Type of employee to add into arraylist: ");
String userInput = keyboardInput.nextLine();
// ArrayList to contain information about employees
ArrayList<Employee> employeeAL = new ArrayList<Employee>();
// Type of employee being created and added into ArrayList is dynamic and only known at run time based on user input
if(userInput.equals("full")) {
employeeAL.add(new FullTimeEmployee("John", 1000));
}
else {
employeeAL.add(new PartTimeEmployee("John", 500));
}
displayInfo(employeeAL.get(0));
keyboardInput.close();
}
}
Now the question:
how do I access the method getSalary() belonging to the specific child type that was determined on runtime? Since the object retrieved from the ArrayList is a parent type. Please note that the salary attribute only belongs to the child class.
My current implementation has me checking for the child type, typecasting it into that child type, and finally accessing the method belonging to the child.
I am trying to avoid typecasting because I believe I am doing things wrongly with regards to good Java coding practise. I'm missing something here but I just don't know what
Another method which I have thought about is to implement the method getSalary() in the parent class and overriding it in the child class, this way, I don't have to typecast but I don't know if this is the right practice since the salary attribute has got no relation with Employee at all:
// Parent
public class Employee {
private String name;
public Employee(String name) {
this.name = name;
}
public String getName() {
return name;
}
// ADDED THIS <----
public double getSalary() {
return 0.0;
}
}
// Child
public class FullTimeEmployee extends Employee {
private double salary;
public FullTimeEmployee(String name, double salary) {
super(name);
this.salary = salary;
}
// ADDED THIS <----
#Override
public double getSalary() {
return salary*2;
}
}
what am I doing wrongly and what is the best Java coding practice?
You can implement Employee as abstract and add getSalary() as an abstract method which forces subclasses of Employee to implement that method
public abstract class Employee {
private String name;
public Employee(String name) {
this.name = name;
}
public String getName() {
return name;
}
abstract protected double getSalary();
}
So if I have a class of Person, where you can define their name, age and date of birth.
public class Person
{
private String name;
private int age;
private String dOB;
public Person (String name, int age, String dateOfBirth)
{
this.name = name;
this.age = age;
dOB = dateOfBirth;
}
}
Then in another class of Memberships, I have an arrayList called Members. I know how to add a Person by:
import java.util.ArrayList;
public class Memberships
{
private ArrayList<Person> members;
public Memberships()
{
members = new ArrayList<Person>();
}
public void addMember(Person person)
{
members.add(person);
}
}
However how do I add a member without separately creating an instance of Person.
So starting with:
public void addMember(String name, int age, String dOB)
{
}
This is where I get stuck I have no idea how to take these values to create a Person to add to my members ArrayList.
#dehlen Sorry!
public void addNewMember(String name, int age, String dOB)
{
Person p = new Person(name, age, dOB);
for (Person pers : members)
{
if (pers.getName().equals(name))
{
System.out.print("This member is already included.");
}
else
{
members.add(p);
}
}
}
So I did this, however the Person is never added? I'm confused as to why?
You need to create an instance of Person, since this is what your ArrayList expects.
Here is how you can complete your task:
public void addMember(String name, int age, String dOB)
{
Person p = new Person(name,age,dOB);
members.add(p);
}
To make sure you do not add duplicates to your ArrayList you could iterate over your ArrayList and look if there is a Person object with the same values already in it.
public void addMember(String name, int age, String dOB)
{
//Create a new Person instance with given parameters
Person p = new Person(name,age,dOB);
//Loop through existing Person instances in ArrayList
for (Person pers : members){
//If there exists a Person with the same name
if (pers.getName().equals(name)) {
//We can stop searching for a duplicate and leave the method
return;
}
}
//Since we did not exit the method above we did not found any duplicate, therefore it is safe to add our Person instance to our ArrayList
members.add(p);
}
Of course this only checks whether there is a Person with the same name. But I with the help of this code you can accomplish also to check further properties.
Also I use a method called getName() which is called a getter. This method has to be specified in your Person model class:
public String getName() {
return name;
}
As #BorisTheSpider pointed out correctly there is a better approach to test equality.
You can/should override the equals() method of your model class like so:
#Override
public boolean equals(Object person)
{
boolean same = false;
if (person != null && person instanceof Person)
{
same = this.name == ((Person) person).name;
}
return same;
}
Then you can use use the contains() method as following:
members.contains(p);
To check your other properties too you should implement the logic in the overidden equals() method.
Simply create a Person instance, and then you can pass it into your existing addMember method that takes a person.
public void addMember(String name, int age, String dateOfBirth) {
this.addMember(new Person(name, age, dateOfBirth);
}
There is an interface like this:
public interface Person {
public String getName();
}
and then there is a class Student which implements Person:
public class Student implements Person {
private int id;
private String name;
public setId(int id) {
this.id = id;
}
public getId() {
return id;
}
public setName(String name) {
this.name = name;
}
public getName() {
return name;
}
}
What would an instance of Person look like at runtime? How do I instantiate?
You can't instantiate an interface.
What you can do is instantiate an implementation of an interface - in your case, Student.
Person s = new Student();
In this case, s will implement Person and you can check it with:
boolean isPerson = (s instanceof Person);
which will be evaluated to true
You cannot instantiate Person it is interface
you can only instantiate Student like
Person p1= new Student();
or
Student S1 = new Student();
You can never instantiate an interface in java. You can, however, refer to an object that implements an interface by the type of the interface. For example,
Person test = new Student();
As already stated in other answers, Person is an interface so can't be instantiated. Therefore it is useful to include the arguments in the constructor of the implementing class since the latter's setters will not be directly accessible from a Person reference
public Student(int id, String name) {
this.id = id;
this.name = name;
}
so as to initialize
Person s = new Student(1, "Jon Smith");
I'm having trouble accessing a superclass data member from it's subclass.
So I have a superclass Store like this
public class Store {
protected ArrayList<Audiobooks> ab;
public Store(ArrayList<Audiobooks> ab)
{
this.ab = ab;
}
...
}
ab is initialized and everything, then we have a subclass like this
public class Customer extends Store {
...
public Customer(String id, String name, String address)
{
this.id = id;
this.name = name;
this.address = address;
}
public void printAb(){
for(int i = 0; i<ab.size(); i++){
System.out.println(ab.get(i).toString());
}
}
}
I end up getting a null pointer exception error. When the function is placed in the store class it works fine, but when its in the subclass Customer the null pointer exception occurs.
I tried to get it by using super.ab.... but no success.
Thanks for any insight.
Your Customer constructor does not call you Store constructor, so the ab list is never instantiated.
To solve this, you either need to have your customer constructor call the store constructor:
public Customer(String id, String name, String address) {
super(new ArrayList<Audiobooks>());
this.id = id;
this.name = name;
this.address = address;
}
Or have your customer constructor instantiate the list. You also must have more than one constructor for the store class, otherwise the compiler would force you to call the constructor you are showing. You may want to consider getting rid of the empty constructor that you apparently have on the store class if it does not put the class into a valid state.
You access the ab property properly (otherwise you would have a compiler error).
Most likely you are not creating the object anywhere, try doing
protected ArrayList<Audiobooks> ab = new ArrayList<Audiobooks>();
Also, it would be better if you use the most generic interface List
protected List<Audiobooks> ab = new ArrayList<Audiobooks>();
Try doing this.
public class Customer extends Store {
...
public Customer(ArrayList<Audiobooks> a,String id, String name, String address)
{
super(a);
this.id = id;
this.name = name;
this.address = address;
}
public void printAb(){
for(int i = 0; i<ab.size(); i++){
System.out.println(ab.get(i).toString());
}
}
}
or do this
public class Customer extends Store {
...
public Customer(String id, String name, String address)
{
a=new ArrayList<Audiobooks>(/*initial size*/);
this.id = id;
this.name = name;
this.address = address;
}
public void printAb(){
for(int i = 0; i<ab.size(); i++){
System.out.println(ab.get(i).toString());
}
}
}