Java ArrayList 中的对象不会更新
已解决:
这是错误的:
current.addFolder(folder); (in the final else clause of the if statement)
添加了一个新文件夹,但不保证传递的文件夹是添加的文件夹,如果该文件夹已经存在,它可能只是不执行任何操作,因此为了克服这个问题,我更改了addFolder 返回实际文件夹(例如,如果它已经存在),并将文件夹分配给该返回值。这就成功了,所以现在我得到了:
folder = current.addFolder(folder);
current = folder;
非常感谢大家,非常感谢您的帮助:)
这将是一篇很长的文章,希望您能理解我在说什么,我感谢您的帮助。谢谢
基本上,我创建了一个可以读取 ZIP 和 RAR 文件的个人非商业项目(我不打算发布)。它只能读取存档中的内容、其中的文件夹、文件夹中的文件及其属性(例如上次修改日期、上次修改时间、CRC 校验和、未压缩大小、压缩大小和文件名)。它也不能提取文件,所以如果可以的话,它实际上是一个 ZIP/RAR 查看器。
无论如何,这与我的问题有点无关,但我想我应该给你一些背景信息。
现在我的问题是:
我可以成功列出 ZIP 存档中的所有文件夹和文件,所以现在我想获取原始输入并以某种有用的方式将其链接在一起。我创建了 2 个类:ArchiveFile(代表 ZIP 中的文件)和 ArchiveFolder(代表 ZIP 中的文件夹)。它们都有一些有用的方法,例如 getLastModifiedDate、getName、getPath 等。 但区别在于 ArchiveFolder 可以保存 ArchiveFile 和附加 ArchiveFolder 的 ArrayList(将其视为文件夹内的文件和文件夹)。
现在,我想将原始输入填充到一个 root ArchiveFolder 中,该文件夹将包含 ArchiveFile 的 ArrayList 中 ZIP 根目录中的所有文件以及 ArchiveFile 的 ArrayList 中 ZIP 根目录中的所有其他文件夹。 ArchiveFolder 的 ArrayList(这个过程可以像连锁反应一样继续下去(ArchiveFolder 中的更多文件/文件夹等)。
所以我想出了以下代码:
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();
}
假设 root 是根 ArchiveFolder (最初为空)。 archive.getName() 按以下方式返回当前文件或文件夹的名称:file.txt 或folder1/file2.txt 或folder4/folder2/(这是一个空文件夹)等。所以基本上是来自的相对路径ZIP 存档的根目录。
请仔细阅读上述代码中的注释以熟悉它。还假设 ArchiveFile 中的 addFolder 方法仅添加尚不存在的文件夹(因此不存在多个文件夹),并且如果现有文件夹为空(即它是一个文件夹),它还会更新该文件夹的时间和日期。我们只知道中间文件夹的名称,但现在我们知道它的详细信息)。 addFolder 的代码是(非常不言自明的):
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());
}
}
}
所以我看不出代码有什么问题,它可以工作,完成后,根 ArchiveFolder 包含 ZIP 根目录中的所有文件,正如我想要的那样,并且它包含我想要的根文件夹中的所有目录。所以你会认为它按预期工作,但根文件夹中的 ArchiveFolder 不包含这些“子”文件夹中的数据,它只是一个空白文件夹,没有其他文件和文件夹(虽然它确实包含更多文件和文件夹)在 WinZip 中查看时的文件/文件夹)。
使用 Eclipse 进行调试后,for 循环确实会遍历所有文件(甚至是上面未包含的文件),因此这让我相信这行代码存在问题:
current = folder;
它所做的是更新当前文件夹(用作循环的中间体)到新添加的文件夹。
我认为Java通过引用传递,因此未来ArchiveFile和ArchiveFolder中的所有新操作和新添加都会自动更新,并且父ArchiveFolder将相应更新。但事实似乎并非如此?
我知道这是一篇很长的文章,我真的希望有人能帮助我解决这个问题。
提前致谢。
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 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.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(3)
例如,Java 实际上并不以您在 C++ 中理解的方式传递引用。它按值传递,但所有非基本类型的变量实际上都是指向对象的指针。因此,每当您将变量传递给方法时,您都会给出指针或指针的副本,这意味着两个变量都指向同一个对象(从一个对象更改对象,另一个将“看到”更改。但是为调用方或被调用方的指针不会改变另一方的指针。
希望我清楚了?
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?
我怀疑您没有在 ArchiveFolder 类上正确重载 equals() 和 hashCode() ,因此
在 addFolder() 中始终返回 -1。
I suspect you haven't overloaded equals() and hashCode() correctly on your ArchiveFolder class, and thus
in addFolder() is always returning -1.
由于您使用 eclipse,设置断点并逐步执行该方法,这可能会花费一些时间,但它有助于查找错误。 (例如,检查对象 ID 以查看引用是否已更改)。
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).