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());
}
}
}
Related
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);
I was writing a program to return JSON object using gson and I discovered something peculiar. Basically when I wanted to convert following object to JSON it gave me null.
Customer customer = new Customer() {
{
setId(1);
setName("Foo bar");
setAddress("Some Address");
}
};
System.out.println(gson.toJson(customer));
where Customer looks like this
public class Customer{
int id;
String name;
String address;
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 String getAddress() {
return address;
}
public void setAddress(String address) {
this.address = address;
}
}
but when I created object properly like
Customer customer = new Customer();
customer.setId(1);
customer.setName("Foo bar");
customer.setAddress("Some Address");
System.out.println(gson.toJson(customer));
it worked perfectly fine and gave output as supposed to.
Why does it matter how I create my objects. Is there difference between two methods?
The reason the first case it is returning null because 'customer' object's class is an anonymous one which clazz.isAnonymousClass() return true
See below for GSon implementation
first time I've tried this. I need to be able to replace an email for subclass Student and sublass Teacher after an email has been inputted, I have a parent class and superclass which is where I believe I need to add my changeEmail method. I may be a way off here but can I use stringBuilder or is there an easier way? Real noob when it comes to this.
SUBCLASS -
public class Teacher extends Member
{
private String qualifications;
public Teacher(String name, String email, String qualifications)
{
super(name, email);
this.qualifications = qualifications;
}
public String getQualifications()
{
return qualifications;
}
public String toString()
{
StringBuffer details = new StringBuffer();
details.append(super.getName());
details.append(' ');
if(qualifications != null && qualifications.trim().length() > 0) {
details.append("(" + qualifications + ")");
details.append(' ');
}
details.append(super.getEmail());
return details.toString();
}
}
SUBCLASS -
public class Student extends Member
{
private int attendance;
public Student(String name, String email)
{
super(name, email);
this.attendance = 0;
}
public int getAttendance()
{
return attendance;
}
public void markAttendance(int attendance)
{
this.attendance += attendance;
}
public void print()
{
System.out.println(super.getName() + " (" + attendance + ")");
}
}
SUPERCLASS -
public class Member
{
private String email;
private String name;
public Member(String name, String email)
{
this.name = name;
this.email = email;
}
public String getEmail()
{
return email;
}
public String getName()
{
return name;
}
public String changeEmail()
{
//..........
}
}
Since changeEmail is a public method in the superclass, the subclasses can access it too. Student (as well as Teacher) is a Member.
public String changeEmail(String newEmailAddress) {
String old = email;
this.email = newEmailAddress;
return old;
}
What I changed was adding a parameter (String newEmailAddress) and then set the new value to the email instance field.
(EDIT: I updated the answer to return the old email address. I don't know why a method like this would return anything but anyways..)
That is called inheritance, basically if you have some shared variables, you can use some parent class and with the keyword extends create some subclasses.
All subclasses, which inherits the parent class, can have their own class variables, but also are having the parent variables.
In your case you can image the diagram like that- obvious, doesnt?
So...
Parent class member is having these class variables:
- String : mail
- String : name
You have two subclasses- Student and Teacher:
Teacher class variables:
qualifications
mail, name (inherited from parent!)
Student class variables:
attendance
mail, name (inherited from parent!)
Notice- with the keyword super you are calling the constructor (or simply "class" other methods) from the parent, so in Teacher and Student class, you will call exactly following:
public Member(String name, String email) {
this.name = name;
this.email = email;
}
To be able change the email, you need following
1) implement methods in parent class
2) optional- add call to child classes, and for usage outside the class also add some external method (without this you can still use public parent class methods)
Eg.
in parent
public void changeEmail(String newEmail) {
this.email = newEmail;
}
public String changeEmailWithReturnOld(String newEmail) {
String oldMail = this.email;
changeEmail(newEmail); //calling above
return oldMail;
}
In childs
public String changeTheMailWithReturnOld(String newMail) {
return super.changeEmailWithReturnOld(newMail); //super means super class, parent
}
Clear? :)
Then you can call following:
Teacher teacher1 = new Teacher("foo", "foo#foo.foo", "whateverFoo");
teacher1.changeEmail("someNewFoo#foo.foo"); //parent method
teacher1.changeEmailWithReturnOld("someNewFoo#foo.foo"); //Child method
I have a problem accessing the arraylist I created in a class. I tried going through the answers of questions similar to mine but unfortunately I was unable to solve the problem.
So I have two classes Student and Person and I want to iterate through the arraylist of Person in the class Student. (The code doesn't really make sense, I know. I just want to understand).
I tried two approaches :
1) creating a variable of type Person in Student class and calling the get method from person class.
2) creating a get method in the class person that returns arraylist.
Both are not working properly when i tried to call the isHere method in the main method.(false was printed instead of true)
I think my two approaches intialise a new array of type Person and not call the arraylist to which elements are already added. How can solve this?
import java.util.ArrayList;
public class Student {
private Person p;
private String name;
private int age;
private String address;
public Student() {
}
public Student(String name, int age, String address) {
this.name = name;
this.age = age;
this.address = address;
}
public boolean isHere(String name) {
p = new Person();
// I also tried for(Person per : p.getList)
for (Person per : this.getL()) {
if (per.getName().equals(name)) {
System.out.println("hi");
return true;
}
}
return false;
}
public ArrayList<Person> getL() {
return p.getList();
}
public Person getP() {
return p;
}
public void setP(Person p) {
this.p = p;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public String getAddress() {
return address;
}
public void setAddress(String address) {
this.address = address;
}
}
The Person class:
import java.util.ArrayList;
public class Person {
private String name;
private ArrayList<Person> list = new ArrayList<Person>();
Person() {
}
public Person(String name) {
this.name = name;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public ArrayList<Person> getList() {
return list;
}
public void setList(ArrayList<Person> list) {
this.list = list;
}
public void add(String name) {
list.add(new Person(name));
}
}
The statement p = new Person() in your isHere(..) method is creating a new Person object. When that Person object is created, the name in object p will be null and the list will be empty. So the for loop is never executed as the list is empty and hence it returns false.
If you ever want your code to run, you should not create the Person object and then immediately iterate through it because it will have nothing. You have to either add something to it or use a Person object which you believe will be populated before you run the isHere(..) method
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;
}
}