Objects in Java ArrayList don't get updated
SOLVED:
This is what was wrong:
current.addFolder(folder); (in the final else clause of the if statement)
Added a new folder, but did not guarantee that the folder passed is the folder added, it may simply do nothing if the folder already exists, so to overcome this I changed addFolder to return the actual folder (for example if it already existed) and I assigned folder to that return value. And that did the trick, so now I've got:
folder = current.addFolder(folder);
current = folder;
Thanks a lot people, your help was much appreciated :)
This is going to be a very long post, hopefully you can understand what I'm talking about and I appreciate any help. Thanks
Basically, I've created a personal, non-commercial project (which I don't plan to release) that can read ZIP and RAR files. It can only read the contents in the archive, the folders inside, the files inside the folders and its properties (such as last modified date, last modified time, CRC checksum, uncompressed size, compressed size and file name). It can't extract files either, so it's really a ZIP/RAR viewer if you may.
Anyway that's slightly irrelevant to my problem but I thought I'd give you some background info.
Now for my开发者_如何学JAVA problem:
I can successfully list all the folders and files inside a ZIP archive, so now I want to take that raw input and link it together in some useful way. I made 2 classes: ArchiveFile (represents a file inside a ZIP) and ArchiveFolder (represents a folder inside a ZIP). They both have some useful methods such as getLastModifiedDate, getName, getPath and so on. But the difference is that ArchiveFolder can hold an ArrayList of ArchiveFile's and additional ArchiveFolder's (think of this as files and folders inside a folder).
Now I want to populate my raw input into one root ArchiveFolder, which will have all the files in the root dir of the ZIP in the ArchiveFile's ArrayList and any additional folders in the root dir of the ZIP in the ArchiveFolder's ArrayList (and this process can continue on like this like a chain reaction (more files/folders in that ArchiveFolder etc etc).
So I came up with the following code:
while (archive.hasMore()) {
String path = "";
ArchiveFolder current = root;
String[] contents = archive.getName().split("/");
for (int x = 0; x < contents.length; ++x) {
if (x == (contents.length - 1) && !archive.getName().endsWith("/")) { // If on last item and item is a file
path += contents[x]; // Update final path ArchiveFile
file = new ArchiveFile(path, contents[x], archive.getUncompressedSize(), archive.getCompressedSize(), archive.getModifiedTime(), archive.getModifiedDate(), archive.getCRC());
current.addFile(file); // Create and add the file to the current ArchiveFolder
}
else if (x == (contents.length - 1)) { // Else if we are on last item and it is a folder
path += contents[x] + "/"; // Update final path
ArchiveFolder folder = new ArchiveFolder(path, contents[x], archive.getModifiedTime(), archive.getModifiedDate());
current.addFolder(folder); // Create and add this folder to the current ArchiveFile
}
else { // Else if we are still traversing through the path
path += contents[x] + "/"; // Update path
ArchiveFolder folder = new ArchiveFolder(path, contents[x]);
current.addFolder(folder); // Create and add folder (remember we do not know the modified date/time as all we know is the path, so we can deduce the name only)
current = folder; // Update current ArchiveFolder to the newly created one for the next iteration of the for loop
}
}
archive.getNext();
}
Assume that root is the root ArchiveFolder (initially empty). And that archive.getName() returns the name of the current file OR folder in the following fashion: file.txt or folder1/file2.txt or folder4/folder2/ (this is a empty folder) etc. So basically the relative path from the root of the ZIP archive.
Please read through the comments in the above code to familiarize yourself with it. Also assume that the addFolder method in an ArchiveFile, only adds the folder if it doesn't exist already (so there are no multiple folders) and it also updates the time and date of an existing folder if it is blank (ie it was a intermediate folder we only knew the name of, but now we know its details). The code for addFolder is (pretty self-explanitory):
public void addFolder(ArchiveFolder folder) {
int loc = folders.indexOf(folder); // folders is the ArrayList containing ArchiveFolder's
if (loc == -1) {
folders.add(folder);
}
else {
ArchiveFolder real = folders.get(loc);
if (real.getTime() == null) {
real.setTime(folder.getTime());
real.setDate(folder.getDate());
}
}
}
So I can't see anything wrong with the code, it works and after finishing, the root ArchiveFolder contains all the files in the root of the ZIP as I want it to, and it contains all the direcories in the root folder as I want it to. So you'd think it works as expected, but no the ArchiveFolder's in the root folder don't contain the data inside those 'child' folders, it's just a blank folder with no additional files and folders (while it does really contain some more files/folders when viewed in WinZip).
After debugging using Eclipse, the for loop does iterate through all the files (even those not included above), so this led me to believe that there is a problem with this line of the code:
current = folder;
What it does is, it updates the current folder (used as an intermediate by the loop) to the newly added folder.
I thought Java passed by reference and thus all new operations and new additions in future ArchiveFile's and ArchiveFolder's are automatically updated, and parent ArchiveFolder's will be updated accordingly. But that does not appear to be the case?
I know this is a long ass post and I really hope anyone can help me out with this.
Thanks in advance.
Since you use eclipse, set a breakpoint and step through the method, it may take time but it helps with finding bugs. (check the object ids for example to see if the reference has changed).
Java does not actually pass references in the way you'd understand this in C++ for example. It passes by value, but all variables of non-primitive types are actually pointers to objects. So whenever you pass a variable to a method, you are giving or a copy of the pointer, meaning both variables point to the same object (change the object from one and the other will "see" the change. But assigning a different value to the pointer on caller or callee side will not change the other side's pointer.
Hope I'm clear?
I suspect you haven't overloaded equals() and hashCode() correctly on your ArchiveFolder class, and thus
folders.indexOf(folder)
in addFolder() is always returning -1.
精彩评论