为什么会出现不可转换类型错误?

6
如果我使用这个类:
public class BooleanTest {
    public static void main(String args[]) {
        final Object[] objarray = new Object[2];
        try {
            objarray[0] = "Hello World!";
            objarray[1] = false;
        } catch (NullPointerException e) {
        }
        boolean bool = (boolean) objarray[1];
    }
}

这个程序很好运行,我可以轻松地分配那个boolean。但是为什么当要求用户输入密码时我不能做同样的事情呢?

final Object result[] = new Object[2];
try {
    java.awt.EventQueue.invokeAndWait(new Runnable() {
        @Override
        public void run() {
            JPanel panel = new JPanel();
            panel.setLayout(new GridLayout(3,0));
            JLabel label = new JLabel();

            label.setHorizontalAlignment(SwingConstants.LEADING);
            JTextField input = new JTextField();

            input.setHorizontalAlignment(SwingConstants.CENTER);
            JCheckBox checkbox = new JCheckBox("Pair with this device");
            checkbox.setHorizontalAlignment(SwingConstants.LEADING);
            panel.add(label);
            panel.add(input);
            panel.add(checkbox);
            if (wrong) {
                label.setText("Wrong password. Please enter the password from the other device:");
            } else {
                label.setText("Please enter the password from the other device:");
            }
            int response = JOptionPane.showConfirmDialog(SendGUI.this, panel, "Enter password", JOptionPane.OK_CANCEL_OPTION);
            if (response == JOptionPane.OK_OPTION) {
                result[0] = input.getText();
                result[1] = (boolean)checkbox.isSelected();
            } else {
                result[0] = null;
                result[1] = false;
            }
        }
    });
} catch (InterruptedException e) {
} catch (InvocationTargetException e) {
}
boolean pair = (boolean)result[1]; //inconvertible type, expected boolean found Object

据我所见,在这两种情况下,我都在做同样的事情,但第一个示例可以编译通过,而第二个示例则不能。

3
你能否发布一下你在最后一段代码中遇到的错误? - Miguel Prz
1
@MiguelPrz 这是我的代码问题,出现了“不可转换类型,期望布尔值但发现了对象”的错误。 - ldam
@JonSkeet 是的。我使用Netbeans 7.3作为我的集成开发环境,并且用它来编译这两个案例。在第二个案例中,当它警告我有编译器错误时,我仍然点击运行,但是当它最终到达该代码块时,我会得到Exception in thread "Thread-3" java.lang.RuntimeException: Uncompilable source code - inconvertible types required: boolean found: java.lang.Object - ldam
@LoganDam:首先,不要试图运行带有编译时错误的代码!你确定你的第一段代码没有编译错误吗? - Jon Skeet
@LoganDam:问题是,我希望它能够使用Java 6选项进行编译,但不能使用Java 7选项...这就是为什么我明确说“使用相同的选项”。 - Jon Skeet
显示剩余3条评论
5个回答

8

您正在使用不同的编译器选项。这是必须的。两个代码片段都符合Java 7规则编译; 在Java 6规则下,两者都无法编译。例如,以您的第一个代码片段为例(您说它可以编译):

c:\Users\Jon\Test>javac -source 1.7 BooleanTest.java

(No console output, i.e. no errors)

c:\Users\Jon\Test>javac -source 1.6 BooleanTest.java
warning: [options] bootstrap class path not set in conjunction with -source 1.6
BooleanTest.java:10: error: inconvertible types
        boolean bool = (boolean) objarray[1];
                                         ^
  required: boolean
  found:    Object
1 error
1 warning

编辑:我认为更改在JLS(强制转换)的第5.5节中。

Java 7版本包括:

强制转换上下文允许使用以下之一:

  • ...
  • 缩小引用转换(§5.1.6),后面可以选择跟随装箱转换(§5.1.8)或不受检查的转换(§5.1.9)

第三版JLS(基本上是Java 5和6)包括:

强制转换上下文允许使用以下之一:

  • ...
  • 缩小引用转换(§5.1.6),后面可以选择跟随不受检查的转换

请注意,这里没有“装箱转换”。


我忘记了在第二个例子中我是针对Java 6的,而我没有在第一个例子中进行更改。谢谢。 - ldam
当Jon Skeet告诉我我错了时,我就知道我肯定走错了完全的轨迹 :) 当然,当我实际在Eclipse中运行这两个代码片段时,我已经想出来了,但那时候Jon已经发布了正确的答案。 - durron597
如果你需要安慰的话,我只是因为几天前有一个类似的问题(但不是完全相同)才知道这个答案的 :) - Jon Skeet
@JonSkeet Java 5 引入了自动装箱,这是一个在 1.7 中修复的自动装箱错误吗?我很难描述我的意思,但这是否意味着在 1.7 之前我不能将 Object 强制转换为 int - Ruan Mendes
@JuanMendes:是的,自动装箱是在Java 5中引入的,但是自动装箱和拆箱的确切性质在Java 7中发生了变化。要么是语言规范发生了变化,要么是Java 6编译器中的一个错误。说实话,我不想说哪个是哪个,但我怀疑这是一项语言规范的变化。 - Jon Skeet
1
@JuanMendes:实际上,我认为这是JLS第5.5节的变更。我会在我的回答中说明区别。 - Jon Skeet

1
您遇到的问题与Java 1.6中的自动装箱有关。您将原始类型放入对象数组中。Java无法将原始类型与对象混合,因此它将该原始布尔值包装为布尔值。因此,您所做的无法表示为:boolean result = (boolean) Boolean.TRUE;解决方案如下:
  1. 使用布尔数组替换对象数组。
  2. 使用Boolean.TRUE.equals(result[1]);
  3. 转换到Java 1.7,如John在他的回答中指出的那样。

这并没有解释为什么我的第一个例子可以无错误地运行。 - ldam
@LoganDam 不应该出现这种情况。你确定它能正常工作吗?再试一次。 - Alex Kreutznaer
嗯,并不是每个人都有机会使用最新版本的Java进行工作。 - Alex Kreutznaer
@JonSkeet,稍作修改,我们又回到正轨了。你对不同编译器的处理很敏锐,好棒! - Damian Leszczyński - Vash
@JonSkeet 可能大多数Java 7在编译器/运行时中已经修复了这个问题。谁想要装箱和基本类型?恶心。更多信息:http://gbracha.blogspot.ru/2009/09/systemic-overload.html - mathk
@LoganDam,它解释了为什么你的第一个片段可以工作。这是由于自动装箱。而你的第二个片段由于编译器/运行时中的错误而无法工作。 - mathk

1

更改:

result[1] = (boolean)checkbox.isSelected();

至:

result[1] = Boolean.valueOf(checkbox.isSelected());

对于给我点踩的人,我的意思是要使用Boolean.valueOf而不是new Boolean。我只是在我的iPhone上打字不够快。 - Adam Gent

0
尝试通过Boolean更改布尔值,它是从java.lang.Object继承的类,您可以使用Boolean.TRUE和Boolean.FALSE。

0
请使用这个。
 Boolean pair = (Boolean)result[1];

这可能会解决问题,但我的问题不是如何修复它,而是为什么它首先成为了一个问题。 - ldam
你的第一个示例中存在相同的问题,即对象到基本类型转换错误。 - Biswajit

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接