1. 基础语法

在Java中,使用extends关键字来声明一个类继承自另一个类。例如,如果有一个Animal类,并希望创建一个Dog类作为其子类,语法如下:

public class Animal {
    public void eat() {
        System.out.println("动物正在进食");
    }
}

// Dog类继承自Animal类
public class Dog extends Animal {
    public void bark() {
        System.out.println("狗在叫");
    }
}

2. 方法继承与重写

子类自动获取父类的方法,但如果子类需要提供自己版本的方法实现,可以通过@Override注解重写父类的方法:

public class Animal {
    public void sound() {
        System.out.println("动物发出声音");
    }
}

public class Dog extends Animal {
    @Override
    public void sound() {
        System.out.println("狗发出的声音是汪汪!");
    }
}

3. 访问限制与封装

子类无法访问父类中private修饰的属性和方法,但可以访问publicprotected以及默认访问级别的成员。若想要访问private成员,可以通过父类提供的公有方法。

4. 构造函数与初始化

子类不能继承父类的构造函数,但可以通过super()显式调用父类构造器来初始化继承的成员变量。

public class Animal {
    private String name;

    public Animal(String name) {
        this.name = name;
    }
}

public class Dog extends Animal {
    public Dog(String name) {
        super(name); // 显式调用父类构造器
    }
}

5. final修饰符

  • final类不能被继承。
  • final方法不能被子类重写。

6. 多级继承

尽管Java不支持多重继承,但可以实现多级继承,即一个类可以继承另一个继承了某个类的类。

class Animal {}
class Mammal extends Animal {}
class Dog extends Mammal {}

7. Java继承的注意事项

在使用Java中的继承时,有几个关键点需要特别注意:

  1. 私有成员的继承:子类不能继承父类的私有成员(包括私有方法和私有变量)。私有成员只能在其父类的内部被访问和修改。
    // 父类
    public class Parent {
        private String secret = "秘密数据"; // 私有变量,子类无法直接访问
    
        protected void displayProtectedData() { // 受保护的方法,子类可以访问
            System.out.println("受保护的数据");
        }
    }
    
    // 子类,尝试访问父类的私有成员
    public class Child extends Parent {
        public void attemptToAccessSecret() {
            // 下面的行将导致编译错误,因为secret是私有的
            // System.out.println(secret); // 错误: 'secret' has private access in 'Parent'
            
            this.displayProtectedData(); // 正确: 子类可以访问受保护的方法
        }
    }
  2. 默认访问权限的继承:如果子类和父类不在同一个程序包中,子类无法继承父类中使用默认访问权限(即没有指定访问修饰符的成员)的成员。 
    // 父类,在com.parent包中
    package com.parent;
    public class Parent {
        void displayDefaultData() {
            System.out.println("默认访问级别的数据");
        }
    }
    
    // 子类,在com.child包中
    package com.child;
    import com.parent.Parent; // 导入父类
    
    public class Child extends Parent {
        public void attemptToAccessDefaultData() {
            // 下面的行将导致编译错误,因为默认访问权限的方法不在同一包内
            // this.displayDefaultData(); // 错误: 'displayDefaultData()' has package access in 'com.parent.Parent'
        }
    }
  3. 构造方法的调用:子类的构造方法不会继承父类的构造方法,但在子类的构造方法中可以通过super关键字显式调用父类的构造方法。如果父类中没有无参构造方法,子类的构造方法中必须显式调用父类的有参构造方法。 
    // 父类Vehicle定义了一个车辆的基本属性:品牌
    public class Vehicle {
        // 私有变量,用于存储车辆的品牌
        private String brand;
    
        // 构造方法,初始化Vehicle对象的brand属性
        public Vehicle(String brand) {
            // this关键字代表当前对象,此处用brand参数初始化brand属性
            this.brand = brand;
        }
    }
    
    // 子类Car,继承自Vehicle,代表汽车,具有额外的属性:车门数量
    public class Car extends Vehicle {
        // 私有变量,用于存储汽车的车门数量
        private int numberOfDoors;
    
        // 构造方法,初始化Car对象的numberOfDoors属性,同时调用父类构造方法初始化brand属性
        public Car(String brand, int numberOfDoors) {
            // super关键字用于调用父类Vehicle的构造方法,初始化brand属性
            super(brand);
            // 初始化numberOfDoors属性
            this.numberOfDoors = numberOfDoors;
        }
    }

  4. 方法重写:子类可以重写父类的方法,但重写的方法必须符合特定的规则,包括方法名、参数列表和返回类型必须与父类中被重写的方法相同。子类方法的访问权限不能低于父类被重写方法的访问权限。 
    // 父类Animal定义了一个所有动物共有的行为:发出声音
    public class Animal {
        // 公有方法,表示动物发出声音
        public void sound() {
            // 打印出动物发出声音的默认描述
            System.out.println("动物发出声音");
        }
    }
    
    // 子类Cat继承自Animal,代表猫,覆写sound方法以提供猫特有的行为
    public class Cat extends Animal {
        // 使用@Override注解表明此方法是覆写父类的方法
        @Override
        public void sound() {
            // 覆写父类Animal的sound方法,提供猫发出声音的描述
            System.out.println("猫喵喵叫");
        }
    }
  5. final方法的重写:不能重写父类中被声明为final的方法。 
    // 父类FinalExample定义了一个final方法,不可被覆写
    public class FinalExample {
        // final修饰的方法不能在子类中被覆写
        public final void finalMethod() {
            // 打印出final方法的描述
            System.out.println("Final method from parent");
        }
    }
    
    // 子类ChildOfFinalExample继承自FinalExample
    public class ChildOfFinalExample extends FinalExample {
        // 下面的代码尝试覆写父类的final方法,但是这将引起编译错误
        // 编译错误: cannot override final methods
        // @Override
        // public void finalMethod() {
        //     // 尝试改变final方法的行为,但这违反了Java的final方法规定
        //     System.out.println("Attempt to override final method");
        // }
    }
  6. 构造方法中的super和this:在子类的构造方法中,super和this关键字不能同时出现,且super必须是构造方法中的第一条语句。 
    // 子类构造示例
    public class Subclass {
        public Subclass() {
            super(); // 必须是第一条语句
            this(); // 错误: this()和super()不能在同一构造方法中
        }
    }
  7. 继承层次:Java不支持多重继承,即一个类只能继承自一个父类,但可以实现多个接口。 
  8. 初始化顺序:在继承关系中,父类的静态成员和静态初始化块先于子类执行,然后是父类的实例成员和实例初始化块,最后是子类的静态成员、静态初始化块、实例成员和实例初始化块。 
    // 父类Base,定义了静态和实例初始化块
    public class Base {
        // 静态初始化块,仅运行一次,在类加载时执行
        static {
            // 打印消息,指示静态初始化块的执行
            System.out.println("Base static block");
        }
    
        // 实例初始化块,每次创建对象时都会执行
        {
            // 打印消息,指示实例初始化块的执行
            System.out.println("Base instance block");
        }
    }
    
    // 子类Derived,继承自Base
    public class Derived extends Base {
        // 静态初始化块,仅运行一次,在类加载时执行
        static {
            // 打印消息,指示静态初始化块的执行
            System.out.println("Derived static block");
        }
    
        // 实例初始化块,每次创建对象时都会执行
        {
            // 打印消息,指示实例初始化块的执行
            System.out.println("Derived instance block");
        }
    }
  9. 避免过度继承:继承层次不宜过深,以免增加代码的复杂性和维护成本。 
  10. 向上转型和向下转型:向上转型是安全的,但向下转型需要进行类型检查,否则可能会抛出ClassCastException异常。
    // 基类Animal,表示所有动物
    public class Animal {
        // Animal类的具体实现
    }
    
    // 子类Cat,继承自Animal,表示猫
    public class Cat extends Animal {
        // Cat类的具体实现
    }
    
    // 向上转型:将Cat类型的对象赋值给Animal类型的引用
    // 这是安全的,因为Cat是Animal的一种
    Animal animal = new Cat();
    
    // 向下转型:将Animal类型的引用强制转换为Cat类型
    // 需要类型检查,确保animal确实是指向一个Cat实例
    Cat cat = (Cat) animal;
     
  11. 使用组合代替继承:在某些情况下,使用组合(通过包含其他类的对象来实现功能)可能比继承更灵活和合适。 
    public class Engine {}
    public class Car {
        private Engine engine;
    }
  12. 父类和子类的修改:对父类的修改要非常谨慎,因为这可能会影响到所有继承自该父类的子类。

点赞(0) 打赏

评论列表 共有 0 条评论

暂无评论

微信公众账号

微信扫一扫加关注

发表
评论
返回
顶部