0

I am trying to retrieve certain values from multiple objects under the same class. I have used a for each loop to iterate through each object, and would like to create an aggregated total, representing the rating and the cost of the item from the objects.

The For Each loop in my parent class:

for (Song songObj : Song.returnSongs()) {
    totalSongCost += Double.parseDouble(songObj.getPrice());
    totalSongRating += Integer.parseInt(songObj.getRating());
}

The Child class ArrayList meant to store objects:

private int rating;
private String title;
private double price;
private boolean favorite;
private static int counter = 0;
private static ArrayList songArray = new ArrayList();

/**
 * Constructor for objects of class Song
 */
public Song()
{
    // initialise instance variables
    rating = 0;
    title = "";
    price = 0.0;
    counter++;
    songArray.add(this);
}
public static ArrayList returnSongs() {
    return songArray;
}

When I compile the code I get an error message saying that an object cannot be converted to song. Is there a way to fix this, or an easier way to accomplish the same task?

nbrooks
  • 18,126
  • 5
  • 54
  • 66
GracefulLemming
  • 153
  • 2
  • 10
  • You should probably have another class like "Album" that has the arrayList of Songs, because your current implementation won't work. You can't add the object that contains the list (i.e. Song) to the list (which is in Song). – Benjamin Lowry Oct 13 '16 at 05:44
  • @BenjaminLowry The object doesn't contain the list, because it's `static` and therefore not owned by any object. – ajb Oct 13 '16 at 05:47
  • @ajb Ah yes, my bad, didn't see that it was static. – Benjamin Lowry Oct 13 '16 at 05:49

3 Answers3

1

If you've ever read the docs, you will know that ArrayList is actually a generic class. That means you can give ArrayList a type.

The type of stuff that an array list can store depends on what type you gave it. But if you don't give it any type, it stores Objects! Here,

for (Song songObj : Song.returnSongs()) {

you want to get Song objects from an array list of Object objects, which makes no sense to the compiler. As a result, the error appears.

The solution to this problem is of course, give the array list a type so that it knows what type it should store.

Change this

private static ArrayList songArray = new ArrayList();

to this:

private static ArrayList<Song> songArray = new ArrayList<>();

and change this:

public static ArrayList returnSongs() {

to this:

public static ArrayList<Song> returnSongs() {
Sweeper
  • 213,210
  • 22
  • 193
  • 313
0

ArrayList is a generic class. This means you can specify what class type it is meant to work with. if you change this:

private static ArrayList songArray = new ArrayList();

to this:

private static ArrayList<Song> songArray = new ArrayList<Song>();

Then the ArrayList class will understand that you're working with instances of Song.

Edit: as Jim Garrison pointed out, your returnSongs() method should also be changed to specify the class type in the same way.

public static ArrayList<Song> returnSongs() { ...
  • 1
    Don't forget to also change `public static ArrayList returnSongs() ` to `public static ArrayList returnSongs() ` and the generic type at the point where `returnSongs()` is invoked. – Jim Garrison Oct 13 '16 at 05:52
0

It's a little unusual to have the Song class be responsible for keeping track of all of the songs within the application. That seems outside of the responsibility of that class, and perhaps better suited to be handled within a different class, either within your parent class or a new type specially defined.

Additionally, be careful when using types like List and ArrayList. As your compiler will warn you, these require type parameters in angle brackets (i.e. List<Type>). You should make it a habit of addressing all compiler warnings, and of always specifying type parameters for generic types like List. In cases where you don't define your types correctly, things start to default to Object, which leads to the issue you faced here.

Below is an example of what this could look like, restructured to keep the Song class solely for attributes of the song itself:

import java.util.ArrayList;
import java.util.List;

public class Parent {
    private static List<Song> songs = new ArrayList<Song>();
    private static double totalSongCost = 0.0;
    private static int totalSongRating = 0;

    public static void main(String[] args) {
        populateSongs();

        for (Song song : songs) {
            totalSongCost += songObj.getPrice();
            totalSongRating += songObj.getRating();
        }
    }

    private void populateSongs() {
        songs.add(new Song(5, "Hey Jude", 12.5));
        songs.add(new Song(4, "Angie", 11.5));
        songs.add(new Song(0, "Other", 10.5));
    }
}

Your song class would simply be this:

public class Song {
    private int rating = 0;
    private String title = "";
    private double price = 0.0;

    public Song(int rating, String title, double price) {
        this.rating = rating;
        this.title = title;
        this.price = price;
    }

    // Compressed for brevity
    public int getRating() { return rating; }
    public String getTitle() { return title; }
    public double getPrice() { return price; }
}
nbrooks
  • 18,126
  • 5
  • 54
  • 66