没有为包含对象的引用的未分配数组元素引发异常
No exception raised for referenced unassigned array element containing an object
物料需求计划
class B {
static int v;
public B(int i) {
System.out.format("Constructor called with value %d\n", i);
v=i;
}
}
public class A {
static B[] c;
A(){
c=new B[5];
c[1]=new B(1);
for (int i=0; i<3; i++) {
System.out.format("c[%d] is %d\n", i, c[i].v);
}
c[2]=new B(2);
for (int i=0; i<3; i++) {
System.out.format("c[%d] is %d\n", i, c[i].v);
}
}
public static void main(String[] args) {
new A();
}
}
Output is:
Constructor called with value 1
c[0] is 1
c[1] is 1
c[2] is 1
Constructor called with value 2
c[0] is 2
c[1] is 2
c[2] is 2
期望通过引用未分配的数组元素引发异常,例如c[0].先前的赋值也错误地更改了数组值。 c[0] 从未被赋值,但在上面的输出中取值 1 和 2。
public class A {
static String[] c;
A(){
c=new String[5];
c[0]=new String("alpha");
for (int i=0; i<3; i++) {
System.out.format("c[%d] is %s\n", i, c[i]);
}
c[1]=new String("beta");
for (int i=0; i<3; i++) {
System.out.format("c[%d] is %s\n", i, c[i]);
}
}
public static void main(String[] args) {
new A();
}
}
Output for the above is:
c[0] is alpha
c[1] is null
c[2] is null
c[0] is alpha
c[1] is beta
c[2] is null
上例中的 String 对象有不同的行为。
所以问题是为什么当 c[i]
是 null
时 c[i].v
不会导致 NullPointerException
。
让我们从稍微简单一点的开始:
B b = null;
System.out.println(b.v);
这不会抛出 NullPointerException
。
为什么?
由于B
的v
字段是static
,我们不需要取消引用b
的值来获取v
的值. v
的值与 B
.
的任何特定实例无关
所以,事实上,b.v
和B.v
是等价的。
在更一般的情况下,考虑 <expr>
是一些静态类型为 B
的表达式。那么:
V v = <expr>.v
与以下效果相同:
B temp = <expr>;
V v = B.v;
换句话说,计算表达式并丢弃其值。然后获取静态字段的值。但是由于 temp
没有被取消引用(因为它不需要 ),在表达式计算为零的情况下不会有 NPE ...它在你的例子中。
您的字符串示例的不同之处在于您打印的是 String
实例的状态,而不是 static
字段的状态。并且在字符串连接中没有出现 NPE,因为 +
运算符将 null
映射到 "null"
而不是调用 null.toString()
.
这里的底线是使用实例引用访问静态字段不是一个好主意。因为语法不符合您的预期。
确实有些 Java 样式检查器/静态分析器会将其标记为糟糕的样式或可能的错误。
物料需求计划
class B {
static int v;
public B(int i) {
System.out.format("Constructor called with value %d\n", i);
v=i;
}
}
public class A {
static B[] c;
A(){
c=new B[5];
c[1]=new B(1);
for (int i=0; i<3; i++) {
System.out.format("c[%d] is %d\n", i, c[i].v);
}
c[2]=new B(2);
for (int i=0; i<3; i++) {
System.out.format("c[%d] is %d\n", i, c[i].v);
}
}
public static void main(String[] args) {
new A();
}
}
Output is:
Constructor called with value 1
c[0] is 1
c[1] is 1
c[2] is 1
Constructor called with value 2
c[0] is 2
c[1] is 2
c[2] is 2
期望通过引用未分配的数组元素引发异常,例如c[0].先前的赋值也错误地更改了数组值。 c[0] 从未被赋值,但在上面的输出中取值 1 和 2。
public class A {
static String[] c;
A(){
c=new String[5];
c[0]=new String("alpha");
for (int i=0; i<3; i++) {
System.out.format("c[%d] is %s\n", i, c[i]);
}
c[1]=new String("beta");
for (int i=0; i<3; i++) {
System.out.format("c[%d] is %s\n", i, c[i]);
}
}
public static void main(String[] args) {
new A();
}
}
Output for the above is:
c[0] is alpha
c[1] is null
c[2] is null
c[0] is alpha
c[1] is beta
c[2] is null
上例中的 String 对象有不同的行为。
所以问题是为什么当 c[i]
是 null
时 c[i].v
不会导致 NullPointerException
。
让我们从稍微简单一点的开始:
B b = null;
System.out.println(b.v);
这不会抛出 NullPointerException
。
为什么?
由于B
的v
字段是static
,我们不需要取消引用b
的值来获取v
的值. v
的值与 B
.
所以,事实上,b.v
和B.v
是等价的。
在更一般的情况下,考虑 <expr>
是一些静态类型为 B
的表达式。那么:
V v = <expr>.v
与以下效果相同:
B temp = <expr>;
V v = B.v;
换句话说,计算表达式并丢弃其值。然后获取静态字段的值。但是由于 temp
没有被取消引用(因为它不需要 ),在表达式计算为零的情况下不会有 NPE ...它在你的例子中。
您的字符串示例的不同之处在于您打印的是 String
实例的状态,而不是 static
字段的状态。并且在字符串连接中没有出现 NPE,因为 +
运算符将 null
映射到 "null"
而不是调用 null.toString()
.
这里的底线是使用实例引用访问静态字段不是一个好主意。因为语法不符合您的预期。
确实有些 Java 样式检查器/静态分析器会将其标记为糟糕的样式或可能的错误。