How do I establish a link/relationship between objects? - java

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

Related

In Java, how do you create an ArrayList, with one element of that list being another ArrayList, that is unique for each element?

So for example.
I have an ArrayList of people. Created through a people object that contains a name, address, age, etc.
How would I then add another list to that, allowing a unique list of hobbies for each person?
So I could have:
James, 32, England, (Football, Tennis)
Chloe, 21, Wales, (Art)
Tried a few things and struggling with it.
import java.util.ArrayList;
public class People {
int id;
String name;
ArrayList<String> hobbies;
public People(int id, String name, ArrayList<String> hobbies) {
this.id = id;
this.name = name;
this.hobbies = hobbies;
}
public People(String name) {
this.name = name;
}
public People() {
// TODO Auto-generated constructor stub
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
#Override
public String toString() {
return "People [id=" + id + ", name=" + name + ", hobbies=" + hobbies + "]";
}
}
import java.util.ArrayList;
public class Runner {
public static void main(String[] args) {
// TODO Auto-generated method stub
ArrayList<People> arrayPeople = new ArrayList<>();
ArrayList<String> hobbies = new ArrayList<>();
hobbies.add("Football");
hobbies.add("Tennis");
arrayPeople.add(new People(1,"Paul", hobbies));
hobbies.add("Golf");
arrayPeople.add(new People(2,"James", hobbies));
System.out.println(arrayPeople);
}
}
This creates a hobby list that is the same for each person, not unique.
This creates a hobby list that is the same for each person, not unique.
That's because member hobbies in [Paul] People object has same value as member hobbies in [James] People object, since they are assigned the same value in method main of class Runner. Hence when you change hobbies variable, in method main of class Runner, you are changing for both Paul and James.
The simplest solution is to change the class constructor so that it creates a copy of the hobbies parameter and assigns the copy to the hobbies member:
public People(int id, String name, List<String> hobbies) {
this.id = id;
this.name = name;
this.hobbies = new ArrayList<>(hobbies);
}
However, I suggest that you add methods to class People to manipulate hobbies member, including:
addHobby for adding a hobby
removeHobby for removing a hobby
clearHobbies for removing all hobbies
getHobbies that returns a copy of hobbies (so that code that calls the method cannot change hobbies)
Below code demonstrates.
Note that you should always use the interface – in this case java.util.List – rather than the implementation – in this case ArrayList – in the API so that you can change class People without having to change its API. If you change the API of class People then all other classes that use class People – like class Runner in the code in your question – will need to be changed as well.
import java.util.ArrayList;
import java.util.List;
public class People {
private int id;
private String name;
private List<String> hobbies;
public People(int id, String name, List<String> hobbies) {
this.id = id;
this.name = name;
this.hobbies = new ArrayList<>(hobbies);
}
public People(int id, String name) {
this(id, name, new ArrayList<String>());
}
public People() {
this(0, "");
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public void addHobby(String hobby) {
if (!hobbies.contains(hobby)) {
hobbies.add(hobby);
}
}
public void clearHobbies() {
hobbies.clear();
}
public List<String> getHobbies() {
return List.of(hobbies.toArray(new String[]{}));
}
public void removeHobby(String hobby) {
if (hobbies.contains(hobby)) {
hobbies.remove(hobby);
}
}
#Override
public String toString() {
return "People [id=" + id + ", name=" + name + ", hobbies=" + hobbies + "]";
}
public static void main(String[] args) {
List<People> arrayPeople = new ArrayList<>();
People paul = new People(1,"Paul");
paul.addHobby("Football");
paul.addHobby("Tennis");
People james = new People(2,"James");
james.addHobby("Football");
james.addHobby("Tennis");
james.addHobby("Golf");
arrayPeople.add(paul);
arrayPeople.add(james);
System.out.println(arrayPeople);
}
}
Running the above code prints the following:
[People [id=1, name=Paul, hobbies=[Football, Tennis]], People [id=2, name=James, hobbies=[Football, Tennis, Golf]]]
The question seemed unclear to me, however I assume that you created lists such as
[name,age,location]
However, this is not an object. If you create a person object, you can add features inside it. So that when you create a person object, then you will have access to add/edit new features. In your case, your features must be:
Name
Age
Location
List (Whatever you name it, type of it must be an arraylist).
To have a list of people:
class Person{
String name;
int age;
String Address;
...
}
and
ArrayList<Person>
For the people class, if you need each hobby in hobbies to be unique you can have a Set class to store hobbies.
class Person{
String name;
int age;
String address;
Set<String> hobbies;
...
}
If the order does not matter you can use HashSet To maintain the order you can use TreeSet or LinkedHashSet.
class person{
String name;
int age;
String address;
TreeSet<String> hobbies;
...
}
class Person{
String name;
int age;
String address;
LinkedHashSet<String> hobbies;
...
}
To add a hobby to a person.
String hobby = "a hobby";
person.add(hobby);
To add hobbies to a person;
String hobby1 = "hobby1";
String hobby1 = "hobby2";
...
Set<String> hobbies = new TreeSet(); // or Set<String> hobbies = new LinkedHashMap();
hobbies.add(hobby1);
hobbies.add(hobby2);
...
person.addAll(hobby);
For another person with the same hobbies, you need to copy the hobbies, then modifying the hobbies of the second person will not affect the hobbies of the first person.
Set<String> new_hobbies = new TreeSet(old_hobbies); // or new LinkedHashSet(old_hobbies);
another_person.addAll(new_hobbies);

How to set / get a name to "ford" - instance of class Car I have created in main method of class Vehicle?

As you can see I am stuck in part where I should set a name an owner of ford... Thanks for help.
public class Vehicle {
Person owner;
long motorSerialNo;
String registerNo;
public static void main(String[] args) {
//an example, create an object instance of class Car
Car ford = new Car();
ford.model = "Focus";
ford.motorSerialNo = 123456;
ford.registerNo = "CA-126-65";
//and here is a problem
ford.owner.setName("John Croul");
}
}
class Car extends Vehicle {
String model;
}
class Person {
public Person(String name){
this.name = name;
}
String name;
String lastname;
String address;
String getName() {
return name;
}
void setName() {
this.name = name;
}
}
Firstly, your setter should look like
public void setName(String name) {
this.name = name;
}
Then you have to initialize the instance variable person before calling its method setName(), otherwise you will get the NullPoiterException.
Person owner = new Person();
or in the main method, as you did for other variables
ford.owner = new Person();

From UML to Java, Simple association

This is the Image that I'm going to transfer from UML to Java, I don't know how to lock them together and i don't know how to make one bankAccount locked to only one person.
How do i connect the 2 classes??
Here is my code so far
My main method
public class Upp5 {
public static void main(String[] args) {
Person2 david = new Person2();
BankAccount acc1 = new BankAccount();
BankAccount acc2 = new BankAccount();
david.setName("David");
david.setPnr("551012-8978");
acc1.setBnr("37");
acc2.setBnr("38");
System.out.println("Namn: " + david.getName() + " \nPersonnummer:" + david.getPnr());
System.out.println(acc1.getBnr() + "\n" + acc2.getBnr());
}
}
BankAccount.java:
public class BankAccount {
private String bnr;
private double balance;
public void credit() {
}
public void withdraw(){
}
public String getBnr(){
return bnr;
}
public void setBnr(String newAccount){
bnr = newAccount;
}
public void createAccount(String newNbr){
bnr = newNbr;
}
}
and Person2.java
public class Person2 {
private String pnr;
private String name;
//Koppla konto till pnr
public void addAccount(BankAccount a){
}
//Skapa Pnr och Namn
public void setPnr(String newPnr) {
pnr = newPnr;
}
public void setName(String newName){
name = newName;
}
// Hämta Pnr och Namn
public String getPnr(){
return pnr;
}
public String getName(){
return name;
}
}
You need to define a List<BankAccount> to your Person2 entity:
public class Person2 {
private String pnr;
private String name;
// list of bank accounts (from 0 to n) the Person can have.
private List<BankAccount> accounts;
//Koppla konto till pnr
public void addAccount(BankAccount a){
if (accounts = null) accounts = new ArrayList<BankAccount>();
accounts.add(a);
}
//Skapa Pnr och Namn
public void setPnr(String newPnr) {
pnr = newPnr;
}
public void setName(String newName){
name = newName;
}
// Hämta Pnr och Namn
public String getPnr(){
return pnr;
}
public String getName(){
return name;
}
// include getters setters
}
EDIT1: as suggested by #NathanCastlehow if you want double relationship, BankAccount.java must have a Person2 attibute
public class BankAccount {
private String bnr;
private double balance;
// one bank account can only be owned by a single Person
private Person2 person;
public void credit() {
}
public void withdraw(){
}
public String getBnr(){
return bnr;
}
public void setBnr(String newAccount){
bnr = newAccount;
}
// generate getters setters
public Person2 getPerson(){
......
}
}
You didn't put any arrows in your diagram, so we don't know if the bankaccount knows the person it is linked to. The most logical thing to do is; let the Person have a List which you always initiate in the Person's constructor.
If you want the bankaccount to know the person that owns him (which seems logical to me), let the Bankaccount have the property "Person owner" and let the constructor be require a Person to exist. I don't understand why you have made a Person2 instead of a Person class.
Tips for you: Never (!!!) use parameters like; 'a' or properties like 'nBr' because other people wanna see in an instance what they are instead of guessing. :-) And try to make some security rules (that's why I put booleans in the classes).
Solution:
Person:
public class Person {
List<BankAccount> bankAccounts;
private String name;
private String pNbr;
public Person(String name, String pNbr) {
this.name = name;
this.pNbr = pNbr;
}
public void addAccount(BankAccount newAccount){
bankAccounts.Add(newAccount);
}
}
Bankaccount:
public class BankAccount {
private String nBr; //maybe make this final?
private double balance;
private Person owner;
public BankAccount(String nbr, Person owner) {
this(nbr, 0, owner); // If you also want to support new empty accounts
}
public BankAccount(String nbr, double balance, Person owner) {
this.name = name;
this.pNbr = pNbr;
this.owner = owner;
}
public boolean Credit(double amount)
{ // TODO: write code
boolean result = false;
return result;
}
public boolean Withdraw(double amount)
{ // TODO: write code
boolean result = false;
return result;
}
}
So generally when this is done in models such as a relational model you would have an association class. So a class that has like an ID from a bank account and an ID of the person. You can lock variables using the final keyword in front of them which forces them to only be initialized once.
The easiest way to "link" classes in java is to add one of said classes as an attribute. For example:
// Make it private to maintain encapsulation
private BankAccount myBankAccount;
But this only works if you have a 1..1 (One to one) relationship.
Your UML diagram indicates a 1..n (One to many) relationship between Person and BankAccount classes. In other words,
A Person may have multiple BankAccounts.
This means you'll a have to use a structure to "keep" multiple BankAccounts in a single Person. Java already provides you with some handy classes:
ArrayList: Easy, quick, insertion-ordered list. Allows as many itens as you need.
Hashmap: Hash implementation of the Map interface. Provides a way to find itens using a "key" (Ex: An account's number). Very efficient.
A suggest reading some of those classes documentation. And you can always look for some neat examples on the internet ;)

How to set up bidirectional association between two objects in OO Java

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;
}
}

Java: Best way to store and access a list of objects

What i want to do is store some instances of my class on a list and get a specific instance from that list.
This is an example of a custom class
public class Person
{
private String name;
//Several unrelevant fields here
public Person(String name)
{
this.name = name;
}
public String getName()
{
return name;
}
//Several unrelevant methods here
}
And this is the code i'm currently using to get one of the instances on the list, that is on the main class.
public class Main
{
private List<Person> people = new ArrayList<Person>();
//More unrelevant fields here
public Person getPerson(String name)
{
for (Person p : people)
if (p.getName().equalsIgnoreCase(name))
return p;
return null;
}
//More unrelevant methods here
}
My question is if there's any other way to write this to increase the performance.
Use a Map whose keys are the names and whose values are the people.
HashMap is case sensitive. If you wanted case-insensitive lookups, you could use a TreeMap. My example demonstrates that people with the same name (case insensitively) overwrite each other.
import java.util.Map;
import java.util.TreeMap;
public class SoMain {
Map<String, Person> nameToPersonMap =
new TreeMap<String, Person>(String.CASE_INSENSITIVE_ORDER);
public static void main(String[] args) {
new SoMain().run(args);
}
private void run(String[] args) {
addPerson(new Person("Jim McDonald", 1));
addPerson(new Person("Jim Mcdonald", 2));
addPerson(new Person("John Smith", 3));
System.out.println("Number of people: "
+ nameToPersonMap.entrySet().size());
System.out.println("Jim McDonald id: "
+ getPerson("Jim McDonald").getPersonId());
System.out.println("John Smith id: "
+ getPerson("john smith").getPersonId());
}
private void addPerson(Person p) {
nameToPersonMap.put(p.getName(), p);
}
private Person getPerson(String name) {
return nameToPersonMap.get(name);
}
public static class Person {
private String name;
private int personId;
public Person(String name, int personId) {
this.name = name;
this.personId = personId;
}
public int getPersonId() {
return personId;
}
public String getName() {
return name;
}
}
}
As Eric mentions, you should use a HashMap, the reasoning for this is because you can look up and add data to one very quickly (on average).
Here is a code example of how to use HashMap using Person.name as the key, this assumes that there is never a person with the same name.
public class Main
{
private HashMap<String, Person> people = new HashMap<String, Person>();
public void addPerson(Person person)
{
people.put(person.getName(), person);
}
public Person getPerson(String name)
{
// get returns null when not found
return people.get(name);
}
}

Categories

Resources