Java 8 中的可能错误 Windows 8 上的更新 45
Possible bug in Java 8 Update 45 on Windows 8
此代码采用输入图像并生成尺寸两倍大的输出图像。内循环中的前四行写了四个相同大小的原始副本,最后四行应该用输入图像的一个副本覆盖小图像,该副本是原始图像的两倍。
代码在 Java 8 上编译和运行没有错误,在 Windows 8 上更新 45。结果图像不是预期的输入的一大副本。输出的下半部分符合预期,但上半部分由循环内前两行写入的输入的两个原始大小的副本组成。注释掉这两行会导致最初预期的结果,因此前两行似乎是最后执行的,而不是最先执行的,尽管在源代码中最先出现。
这是编译器错误、运行时竞争条件还是代表我的脑放屁?
如果需要,我会在某处提供示例。
import java.awt.image.*;
import java.io.*;
import javax.imageio.*;
class HelloWorldApp {
public static void main(String[] orgs) throws IOException {
BufferedImage pic = ImageIO.read(new File("cat.jpg"));
int w=pic.getWidth(),h=pic.getHeight();
BufferedImage out = new BufferedImage(w+w,h+h,pic.getType());
for (int y=0;y<h;y++) {
for (int x=0;x<w;x++) {
int pixel = pic.getRGB(x,y);
// write four small copies
out.setRGB(x ,y ,pixel); // these two lines apparently are
out.setRGB(x+w ,y ,pixel); // executed after the remaining six
out.setRGB(x ,y+h ,pixel);
out.setRGB(x+w ,y+h ,pixel);
// overwrite with one large copy
out.setRGB(x+x ,y+y ,pixel);
out.setRGB(x+x+1,y+y ,pixel);
out.setRGB(x+x ,y+y+1,pixel);
out.setRGB(x+x+1,y+y+1,pixel);
}
}
ImageIO.write(out, "bmp", new File("./cat.bmp"));
}
}
恐怕这是一个脑放屁。因为您在同一个循环中执行所有操作,所以在后面的迭代中执行最初的四行(小副本)最终会覆盖在前面的迭代中由最后四行(大副本)写入的像素。
我不确定我的措辞是否出色,但希望您能明白我的意思。
让我们尝试演示发生了什么。假设您的图像是:
┌───╥───┬───┐
│ ║ 0 │ 1 │
╞═══╬═══╪═══╡
│ 0 ║ A │ B │
├───╫───┼───┤
│ 1 ║ C │ D │
└───╨───┴───┘
对于x=0,y=0,前四行后:
┌───╥───┬───┬───┬───┐
│ ║ 0 │ 1 │ 2 │ 3 │
╞═══╬═══╪═══╪═══╪═══╡
│ 0 ║ A │ │ A │ │
├───╫───┼───┼───┼───┤
│ 1 ║ │ │ │ │
├───╫───┼───┼───┼───┤
│ 2 ║ A │ │ A │ │
├───╫───┼───┼───┼───┤
│ 3 ║ │ │ │ │
└───╨───┴───┴───┴───┘
最后四行之后:
┌───╥───┬───┬───┬───┐
│ ║ 0 │ 1 │ 2 │ 3 │
╞═══╬═══╪═══╪═══╪═══╡
│ 0 ║ A │ A │ A │ │
├───╫───┼───┼───┼───┤
│ 1 ║ A │ A │ │ │
├───╫───┼───┼───┼───┤
│ 2 ║ A │ │ A │ │
├───╫───┼───┼───┼───┤
│ 3 ║ │ │ │ │
└───╨───┴───┴───┴───┘
对于 x=1,y=0,在前四行之后:
┌───╥───┬───┬───┬───┐
│ ║ 0 │ 1 │ 2 │ 3 │
╞═══╬═══╪═══╪═══╪═══╡
│ 0 ║ A │ B │ A │ B │
├───╫───┼───┼───┼───┤
│ 1 ║ A │ A │ │ │
├───╫───┼───┼───┼───┤
│ 2 ║ A │ B │ A │ B │
├───╫───┼───┼───┼───┤
│ 3 ║ │ │ │ │
└───╨───┴───┴───┴───┘
最后四行之后:
┌───╥───┬───┬───┬───┐
│ ║ 0 │ 1 │ 2 │ 3 │
╞═══╬═══╪═══╪═══╪═══╡
│ 0 ║ A │ B │ B │ B │
├───╫───┼───┼───┼───┤
│ 1 ║ A │ A │ B │ B │
├───╫───┼───┼───┼───┤
│ 2 ║ A │ B │ A │ B │
├───╫───┼───┼───┼───┤
│ 3 ║ │ │ │ │
└───╨───┴───┴───┴───┘
对于 x = 0,y = 1,前四行:
┌───╥───┬───┬───┬───┐
│ ║ 0 │ 1 │ 2 │ 3 │
╞═══╬═══╪═══╪═══╪═══╡
│ 0 ║ A │ B │ B │ B │
├───╫───┼───┼───┼───┤
│ 1 ║ C │ A │ C │ B │
├───╫───┼───┼───┼───┤
│ 2 ║ A │ B │ A │ B │
├───╫───┼───┼───┼───┤
│ 3 ║ C │ │ C │ │
└───╨───┴───┴───┴───┘
最后四行:
┌───╥───┬───┬───┬───┐
│ ║ 0 │ 1 │ 2 │ 3 │
╞═══╬═══╪═══╪═══╪═══╡
│ 0 ║ A │ B │ B │ B │
├───╫───┼───┼───┼───┤
│ 1 ║ C │ A │ C │ B │
├───╫───┼───┼───┼───┤
│ 2 ║ C │ C │ A │ B │
├───╫───┼───┼───┼───┤
│ 3 ║ C │ C │ C │ │
└───╨───┴───┴───┴───┘
对于 x=1,y=1,前四行:
┌───╥───┬───┬───┬───┐
│ ║ 0 │ 1 │ 2 │ 3 │
╞═══╬═══╪═══╪═══╪═══╡
│ 0 ║ A │ B │ B │ B │
├───╫───┼───┼───┼───┤
│ 1 ║ C │ D │ C │ D │
├───╫───┼───┼───┼───┤
│ 2 ║ C │ C │ A │ B │
├───╫───┼───┼───┼───┤
│ 3 ║ C │ D │ C │ D │
└───╨───┴───┴───┴───┘
最后四行:
┌───╥───┬───┬───┬───┐
│ ║ 0 │ 1 │ 2 │ 3 │
╞═══╬═══╪═══╪═══╪═══╡
│ 0 ║ A │ B │ B │ B │
├───╫───┼───┼───┼───┤
│ 1 ║ C │ D │ C │ D │
├───╫───┼───┼───┼───┤
│ 2 ║ C │ C │ D │ D │
├───╫───┼───┼───┼───┤
│ 3 ║ C │ D │ D │ D │
└───╨───┴───┴───┴───┘
这不是您预期的结果,它源于这样一个事实,即在每次迭代中,您返回并覆盖四个像素。其中一些像素属于您的双像。
发生的情况是,小图像是同时从顶部和中间开始逐行写入的。大图也是从顶部开始,但是 "moves" 快了一倍。因此,上半部分的小 "slow" 图像覆盖了较早写入的快速大像素,而在下半部分,已经写入的 "small" 像素被稍后到达的快速前沿覆盖。
我上传了一个 animation on YouTube 显示过程。
(Phil 和 RealSkeptic 的回答都有助于找到解释。我选择 Phil 的回答是因为他的回答更接近于解释到底发生了什么。)
此代码采用输入图像并生成尺寸两倍大的输出图像。内循环中的前四行写了四个相同大小的原始副本,最后四行应该用输入图像的一个副本覆盖小图像,该副本是原始图像的两倍。
代码在 Java 8 上编译和运行没有错误,在 Windows 8 上更新 45。结果图像不是预期的输入的一大副本。输出的下半部分符合预期,但上半部分由循环内前两行写入的输入的两个原始大小的副本组成。注释掉这两行会导致最初预期的结果,因此前两行似乎是最后执行的,而不是最先执行的,尽管在源代码中最先出现。
这是编译器错误、运行时竞争条件还是代表我的脑放屁?
如果需要,我会在某处提供示例。
import java.awt.image.*;
import java.io.*;
import javax.imageio.*;
class HelloWorldApp {
public static void main(String[] orgs) throws IOException {
BufferedImage pic = ImageIO.read(new File("cat.jpg"));
int w=pic.getWidth(),h=pic.getHeight();
BufferedImage out = new BufferedImage(w+w,h+h,pic.getType());
for (int y=0;y<h;y++) {
for (int x=0;x<w;x++) {
int pixel = pic.getRGB(x,y);
// write four small copies
out.setRGB(x ,y ,pixel); // these two lines apparently are
out.setRGB(x+w ,y ,pixel); // executed after the remaining six
out.setRGB(x ,y+h ,pixel);
out.setRGB(x+w ,y+h ,pixel);
// overwrite with one large copy
out.setRGB(x+x ,y+y ,pixel);
out.setRGB(x+x+1,y+y ,pixel);
out.setRGB(x+x ,y+y+1,pixel);
out.setRGB(x+x+1,y+y+1,pixel);
}
}
ImageIO.write(out, "bmp", new File("./cat.bmp"));
}
}
恐怕这是一个脑放屁。因为您在同一个循环中执行所有操作,所以在后面的迭代中执行最初的四行(小副本)最终会覆盖在前面的迭代中由最后四行(大副本)写入的像素。
我不确定我的措辞是否出色,但希望您能明白我的意思。
让我们尝试演示发生了什么。假设您的图像是:
┌───╥───┬───┐ │ ║ 0 │ 1 │ ╞═══╬═══╪═══╡ │ 0 ║ A │ B │ ├───╫───┼───┤ │ 1 ║ C │ D │ └───╨───┴───┘
对于x=0,y=0,前四行后:
┌───╥───┬───┬───┬───┐ │ ║ 0 │ 1 │ 2 │ 3 │ ╞═══╬═══╪═══╪═══╪═══╡ │ 0 ║ A │ │ A │ │ ├───╫───┼───┼───┼───┤ │ 1 ║ │ │ │ │ ├───╫───┼───┼───┼───┤ │ 2 ║ A │ │ A │ │ ├───╫───┼───┼───┼───┤ │ 3 ║ │ │ │ │ └───╨───┴───┴───┴───┘
最后四行之后:
┌───╥───┬───┬───┬───┐ │ ║ 0 │ 1 │ 2 │ 3 │ ╞═══╬═══╪═══╪═══╪═══╡ │ 0 ║ A │ A │ A │ │ ├───╫───┼───┼───┼───┤ │ 1 ║ A │ A │ │ │ ├───╫───┼───┼───┼───┤ │ 2 ║ A │ │ A │ │ ├───╫───┼───┼───┼───┤ │ 3 ║ │ │ │ │ └───╨───┴───┴───┴───┘
对于 x=1,y=0,在前四行之后:
┌───╥───┬───┬───┬───┐ │ ║ 0 │ 1 │ 2 │ 3 │ ╞═══╬═══╪═══╪═══╪═══╡ │ 0 ║ A │ B │ A │ B │ ├───╫───┼───┼───┼───┤ │ 1 ║ A │ A │ │ │ ├───╫───┼───┼───┼───┤ │ 2 ║ A │ B │ A │ B │ ├───╫───┼───┼───┼───┤ │ 3 ║ │ │ │ │ └───╨───┴───┴───┴───┘
最后四行之后:
┌───╥───┬───┬───┬───┐ │ ║ 0 │ 1 │ 2 │ 3 │ ╞═══╬═══╪═══╪═══╪═══╡ │ 0 ║ A │ B │ B │ B │ ├───╫───┼───┼───┼───┤ │ 1 ║ A │ A │ B │ B │ ├───╫───┼───┼───┼───┤ │ 2 ║ A │ B │ A │ B │ ├───╫───┼───┼───┼───┤ │ 3 ║ │ │ │ │ └───╨───┴───┴───┴───┘
对于 x = 0,y = 1,前四行:
┌───╥───┬───┬───┬───┐ │ ║ 0 │ 1 │ 2 │ 3 │ ╞═══╬═══╪═══╪═══╪═══╡ │ 0 ║ A │ B │ B │ B │ ├───╫───┼───┼───┼───┤ │ 1 ║ C │ A │ C │ B │ ├───╫───┼───┼───┼───┤ │ 2 ║ A │ B │ A │ B │ ├───╫───┼───┼───┼───┤ │ 3 ║ C │ │ C │ │ └───╨───┴───┴───┴───┘
最后四行:
┌───╥───┬───┬───┬───┐ │ ║ 0 │ 1 │ 2 │ 3 │ ╞═══╬═══╪═══╪═══╪═══╡ │ 0 ║ A │ B │ B │ B │ ├───╫───┼───┼───┼───┤ │ 1 ║ C │ A │ C │ B │ ├───╫───┼───┼───┼───┤ │ 2 ║ C │ C │ A │ B │ ├───╫───┼───┼───┼───┤ │ 3 ║ C │ C │ C │ │ └───╨───┴───┴───┴───┘
对于 x=1,y=1,前四行:
┌───╥───┬───┬───┬───┐ │ ║ 0 │ 1 │ 2 │ 3 │ ╞═══╬═══╪═══╪═══╪═══╡ │ 0 ║ A │ B │ B │ B │ ├───╫───┼───┼───┼───┤ │ 1 ║ C │ D │ C │ D │ ├───╫───┼───┼───┼───┤ │ 2 ║ C │ C │ A │ B │ ├───╫───┼───┼───┼───┤ │ 3 ║ C │ D │ C │ D │ └───╨───┴───┴───┴───┘
最后四行:
┌───╥───┬───┬───┬───┐ │ ║ 0 │ 1 │ 2 │ 3 │ ╞═══╬═══╪═══╪═══╪═══╡ │ 0 ║ A │ B │ B │ B │ ├───╫───┼───┼───┼───┤ │ 1 ║ C │ D │ C │ D │ ├───╫───┼───┼───┼───┤ │ 2 ║ C │ C │ D │ D │ ├───╫───┼───┼───┼───┤ │ 3 ║ C │ D │ D │ D │ └───╨───┴───┴───┴───┘
这不是您预期的结果,它源于这样一个事实,即在每次迭代中,您返回并覆盖四个像素。其中一些像素属于您的双像。
发生的情况是,小图像是同时从顶部和中间开始逐行写入的。大图也是从顶部开始,但是 "moves" 快了一倍。因此,上半部分的小 "slow" 图像覆盖了较早写入的快速大像素,而在下半部分,已经写入的 "small" 像素被稍后到达的快速前沿覆盖。
我上传了一个 animation on YouTube 显示过程。
(Phil 和 RealSkeptic 的回答都有助于找到解释。我选择 Phil 的回答是因为他的回答更接近于解释到底发生了什么。)