Java基础学习笔记-继承、super和final

继承

基本介绍

继承是 Java 中一般到特殊的关系,是一种子类到父类的关系

  • 被继承的类称为:父类/超类。
  • 继承父类的类称为:子类。

继承的作用:

  • 提高代码的复用,相同代码可以定义在父类中
  • 子类继承父类,可以直接使用父类这些代码(相同代码重复利用)
  • 子类得到父类的属性(成员变量)和行为(方法),还可以定义自己的功能,子类更强大

继承的特点:

  1. 子类的全部构造器默认先访问父类的无参数构造器,再执行自己的构造器
  2. 单继承:一个类只能继承一个直接父类
  3. 多层继承:一个类可以间接继承多个父类(家谱)
  4. 一个类可以有多个子类
  5. 一个类要么默认继承了 Object 类,要么间接继承了 Object 类,Object 类是 Java 中的祖宗类

继承的格式:

子类 extends 父类{

}

子类不能继承父类的东西:

  • 子类不能继承父类的构造器,子类有自己的构造器
  • 子类是不能可以继承父类的私有成员的,可以反射暴力去访问继承自父类的私有成员
  • 子类是不能继承父类的静态成员的,子类只是可以访问父类的静态成员,父类静态成员只有一份可以被子类共享访问,共享并非继承
public class ExtendsDemo {
    public static void main(String[] args) {
        Cat c = new Cat();
        // c.run();
        Cat.test();
        System.out.println(Cat.schoolName);
    }
}
class Cat extends Animal{
}
class Animal{
    public static String schoolName ="seazean";
    public static void test(){}
    private void run(){}
}

变量访问

继承后成员变量的访问特点:就近原则,子类有找子类,子类没有找父类,父类没有就报错

如果要申明访问父类的成员变量可以使用:super.父类成员变量,super指父类引用

public class ExtendsDemo {
    public static void wmain(String[] args) {
        Wolf w = new Wolf();w
        w.showName();
    }
}
class Wolf extends Animal{
    private String name = "子类狼";
    public void showName(){
        String name = "局部名称";
        System.out.println(name); // 局部name
        System.out.println(this.name); // 子类对象的name
        System.out.println(super.name); // 父类的
        System.out.println(name1); // 父类的
        //System.out.println(name2); // 报错。子类父类都没有
    }
}

class Animal{
    public String name = "父类动物名称";
    public String name1 = "父类";
}

方法访问

子类继承了父类就得到了父类的方法,可以直接调用,受权限修饰符的限制,也可以重写方法

方法重写:子类重写一个与父类申明一样的方法来覆盖父类的该方法

方法重写的校验注解:@Override

  • 方法加了这个注解,那就必须是成功重写父类的方法,否则报错
  • @Override 优势:可读性好,安全,优雅

子类可以扩展父类的功能,但不能改变父类原有的功能,重写有以下三个限制:

  • 子类方法的访问权限必须大于等于父类方法
  • 子类方法的返回类型必须是父类方法返回类型或为其子类型
  • 子类方法抛出的异常类型必须是父类抛出异常类型或为其子类型

继承中的隐藏问题:

  • 子类和父类方法都是静态的,那么子类中的方法会隐藏父类中的方法
  • 在子类中可以定义和父类成员变量同名的成员变量,此时子类的成员变量隐藏了父类的成员变量,在创建对象为对象分配内存的过程中,隐藏变量依然会被分配内存
public class ExtendsDemo {
    public static void main(String[] args) {
        Wolf w = new Wolf();
        w.run();
    }
}
class Wolf extends Animal{
    @Override
    public void run(){}//
}
class Animal{
    public void run(){}
}

面试问题

  • 为什么子类构造器会先调用父类构造器?

    1. 子类的构造器的第一行默认 super() 调用父类的无参数构造器,写不写都存在
    2. 子类继承父类,子类就得到了父类的属性和行为。调用子类构造器初始化子类对象数据时,必须先调用父类构造器初始化继承自父类的属性和行为
    3. 参考 JVM → 类加载 → 对象创建
    class Animal{
        public Animal(){
            System.out.println("==父类Animal的无参数构造器==");
        }
    }
    class Tiger extends Animal{
        public Tiger(){
            super(); // 默认存在的,根据参数去匹配调用父类的构造器。
            System.out.println("==子类Tiger的无参数构造器==");
        }
        public Tiger(String name){
            //super();  默认存在的,根据参数去匹配调用父类的构造器。
            System.out.println("==子类Tiger的有参数构造器==");
        }
    }
  • 为什么 Java 是单继承的?

    答:反证法,假如 Java 可以多继承,请看如下代码:

    class A{
    	public void test(){
    		System.out.println("A");
    	}
    }
    class B{
    	public void test(){
    		System.out.println("B");
    	}
    }
    class C extends A , B {
    	public static void main(String[] args){
    		C c = new C();
            c.test(); 
            // 出现了类的二义性!所以Java不能多继承!!
    	}
    }

super

继承后 super 调用父类构造器,父类构造器初始化继承自父类的数据。

总结与拓展:

  • this 代表了当前对象的引用(继承中指代子类对象):this.子类成员变量、this.子类成员方法、**this(...)**可以根据参数匹配访问本类其他构造器。
  • super 代表了父类对象的引用(继承中指代了父类对象空间):super.父类成员变量、super.父类的成员方法、super(...)可以根据参数匹配访问父类的构造器

注意:

  • this(...) 借用本类其他构造器,super(...) 调用父类的构造器。
  • this(...) 或 super(...) 必须放在构造器的第一行,否则报错!
  • this(...) 和 super(...) 不能同时出现在构造器中,因为构造函数必须出现在第一行上,只能选择一个。
public class ThisDemo {
    public static void main(String[] args) {
        // 需求:希望如果不写学校默认就是”张三“!
        Student s1 = new Student("天蓬元帅", 1000 );
        Student s2 = new Student("齐天大圣", 2000, "清华大学" );
    }
}
class Study extends Student {
   public Study(String name, int age, String schoolName) {
        super(name , age , schoolName) ; 
       // 根据参数匹配调用父类构造器
   }
}

class Student{
    private String name ;
    private int age ;
    private String schoolName ;

    public Student() {
    }
    public Student(String name , int age){
        // 借用兄弟构造器的功能!
        this(name , age , "张三");
    }
	public Student(String name, int age, String schoolName) {
        this.name = name;
        this.age = age;
        this.schoolName = schoolName;
    }
// .......get + set
}

final

基本介绍

final 用于修饰:类,方法,变量

  • final 修饰类,类不能被继承了,类中的方法和变量可以使用
  • final 可以修饰方法,方法就不能被重写
  • final 修饰变量总规则:变量有且仅能被赋值一次

面试题:final 和 abstract 的关系是互斥关系,不能同时修饰类或者同时修饰方法!


修饰变量

静态变量

final 修饰静态成员变量,变量变成了常量

常量:有 public static final 修饰,名称字母全部大写,多个单词用下划线连接。

final 修饰静态成员变量可以在哪些地方赋值:

  1. 定义的时候赋值一次

  2. 可以在静态代码块中赋值一次

public class FinalDemo {
//常量:public static final修饰,名称字母全部大写,下划线连接。
    public static final String SCHOOL_NAME = "张三" ;
    public static final String SCHOOL_NAME1;

    static{
        //SCHOOL_NAME = "java";//报错
        SCHOOL_NAME1 = "张三1";
        //SCHOOL_NAME1 = "张三2"; // 报错,第二次赋值!
    }
}

实例变量

final 修饰变量的总规则:有且仅能被赋值一次

final 修饰实例成员变量可以在哪些地方赋值 1 次:

  1. 定义的时候赋值一次
  2. 可以在实例代码块中赋值一次
  3. 可以在每个构造器中赋值一次
public class FinalDemo {
    private final String name = "张三" ;
    private final String name1;
    private final String name2;
    {
        // 可以在实例代码块中赋值一次。
        name1 = "张三1";
    }
	//构造器赋值一次
    public FinalDemo(){
        name2 = "张三2";
    }
    public FinalDemo(String a){
        name2 = "张三2";
    }

    public static void main(String[] args) {
        FinalDemo f1 = new FinalDemo();
        //f1.name = "张三1"; // 第二次赋值 报错!
    }
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值