多维数组常见误区解析
1. 多维数组长度可以不一致
Java中多维数组的每一维长度可以不同,这与许多初学者认为的"规则矩形"概念不同。例如:
int[][] arr = {{1}, {2,3}, {4,5,6}}; // 合法
2. 数组是复杂数据类型
常见误区认为数组是简单数据类型,实际上数组属于复杂数据类型,与指针、结构体并列。Java数组是对象,具有length属性。
3. 数组初始化方式
多维数组初始化有两种方式:
// 方式1:直接初始化
int[][] arr1 = {{1,2}, {3,4}};
// 方式2:先声明再分配
int[][] arr2 = new int[2][];
arr2[0] = new int[3];
arr2[1] = new int[1]; // 第二维长度可以不同
4. 数组越界问题
Java数组索引从0开始,访问arr[arr.length]会导致ArrayIndexOutOfBoundsException,这是运行时异常而非编译时错误。
接口继承常见误区解析
1. 接口与抽象类的区别
- 接口:只能包含抽象方法(Java 8前)、默认方法、静态方法和常量,是对行为的抽象
- 抽象类:可以包含普通方法、抽象方法和成员变量,是对类的抽象
2. 多重继承的实现
Java类只能单继承,但可以通过接口实现多重继承的效果。例如:
class MyClass extends Parent implements Interface1, Interface2 {...}
3. 成员变量"覆盖"误区
当子类定义了与父类同名的成员变量时,实际上是"隐藏"而非"覆盖"。父类变量依然存在,可通过super访问。例如:
class A { int i=1; }
class B extends A { int i=2; }
B b = new B();
System.out.println(b.i); // 输出2
System.out.println(((A)b).i); // 输出1
4. 构造方法调用顺序
子类构造方法中会隐式调用super(),如果父类没有无参构造,必须显式调用父类构造方法。例如:
class Parent {
Parent(int x) {...}
}
class Child extends Parent {
Child() {
super(10); // 必须显式调用
}
}
5. 方法重写规则
重写父类方法时需要遵守:
- 方法名、参数列表必须相同
- 返回类型可以是父类方法返回类型的子类
- 访问权限不能比父类更严格
- 不能抛出比父类更宽泛的异常
6. private成员不可继承
常见误区认为子类继承了父类所有成员,实际上private成员对子类不可见。子类只能通过父类提供的public/protected方法访问private成员。
综合案例分析
案例1:成员变量隐藏
abstract class A {
int i=1;
public void printI() {
System.out.println("i="+i);
}
}
class B extends A {
int i=2;
public static void main(String[] args) {
B b=new B();
b.printI(); // 输出i=1而非i=2
}
}
解析:printI()方法中访问的是A类的i,因为方法在A类中定义,使用的是A类的视角。
案例2:接口默认方法冲突
interface I1 { default void foo() { System.out.println("I1"); } }
interface I2 { default void foo() { System.out.println("I2"); } }
class C implements I1, I2 {
@Override
public void foo() { // 必须重写
I1.super.foo(); // 显式选择I1的实现
}
}
解析:当实现多个含有同名默认方法的接口时,必须重写该方法。
复习建议
- 理解继承中"is-a"关系与组合中"has-a"关系的区别
- 掌握super关键字的三种用法:
- 访问父类成员变量:super.var
- 调用父类方法:super.method()
- 调用父类构造器:super(params)
- 区分重写(Override)与重载(Overload):
- 重写:继承关系中,方法名和参数列表相同
- 重载:同一类中,方法名相同但参数列表不同
- 记住Object类中的重要方法:equals(), hashCode(), toString()等
通过理解这些常见误区,可以避免在实际编程和考试中犯类似错误,写出更健壮、符合Java规范的代码。