您好我想在构造函数中初始化内部类的最终变量,但编译器强制我在声明时初始化它为什么有任何想法?
我该如何处理这种情况?
public MainActivity extends Activity {
private class AcceptThread extends Thread {
private final BluetoothServerSocket mBluetoothServerSocket;
public AcceptThread() {
try {
mBluetoothServerSocket = mBluetoothAdapter.listenUsingRfcommWithServiceRecord("BT_SERVER", UUID.fromString("a60f35f0-b93a-11de-8a39-08002009c666"));
} catch (IOException e) { }
}
// Here methods
}
}
在这里看到谁回答了我的问题,这里看起来很奇怪
答案 0 :(得分:6)
问题不是你试图在构造函数中初始化字段,而是你没有在catch
块中初始化它。编译器必须确保在退出构造函数之前始终字段将被初始化。
不幸的是,简单地在catch
块中分配一个回退值是行不通的,因为当编译器看到这样的代码时:
try {
...
someFinalField = ...
...
} catch {
...
someFinalField = ...
...
}
...然后它看到字段初始化的可能性两次(一次在try
块中,第二次在catch
块中),这是final
字段非法。在你的简单情况下,我们清楚地看到这是不可能的,因为在try
块中初始化字段之前总会抛出异常,但遗憾的是编译器不够智能明白这一点。
您可以通过从catch
块中抛出异常来满足编译器,这可能是您案例中的首选选项:
catch (IOException e) {
throw new RuntimeException(e);
}
或使用非常受欢迎的guava library
catch (IOException e) {
throw Throwables.propagate(e);
}
如果您真的想要吞下异常,那么 - 为了确保该字段始终只被初始化一次,您必须将初始化移到try-catch
块之外:
private class AcceptThread extends Thread {
private final BluetoothServerSocket mBluetoothServerSocket;
public AcceptThread() {
BluetoothServerSocket localBluetoothServerSocket;
try {
localBluetoothServerSocket = ...
} catch (IOException e) {
localBluetoothServerSocket = ...
}
mBluetoothServerSocket = localBluetoothServerSocket;
}
}
答案 1 :(得分:2)
这是因为它在try-block中,因此在所有情况下都不会实例化最终变量。
修改后的答案:要求将对象作为参数。无论如何,在构造函数中完成工作通常都不是一个好主意。
答案 2 :(得分:1)
您的代码并不保证它初始化final
字段。如果发生异常,您会抓住并忽略它,然后您还没有为最终字段分配任何值。
将您的代码更改为:
public AcceptThread() throws IOException {
mBluetoothServerSocket = mBluetoothAdapter.listenUsingRfcommWithServiceRecord("BT_SERVER", UUID.fromString("a60f35f0-b93a-11de-8a39-08002009c666"));
}