Java学习---day07_继承及final、Object的介绍

Java学习—day07

简介:

java中存在继承的思想,来提高代码的复用性,代码的拓展性

程序中的继承,是类与类之间的特征和行为的一种赠予或获取。一个类可以将自己的属性和方法赠予其他的类,一个类也可以从其他的类中获取他们的属性和方法。

两个类之间的继承,必须满足is a 的关系

两个类之间,A类将属性和特征赠予B类。此时A类被称为是父类,B类被称为是子类,两者之间的关系是子类继承自父类。

final关键字

**定义:**在程序中只要被final修饰的内容是不能再被改变的。

int a = 5;		//这是定义了一个int型的变量a 赋值成5。如果我们给它加上修饰词final
final int a = 5; //这里a就相当于变成了常量,值一直是5,不能在被改变

可以修饰的内容:

  • 类:final修饰的类不能有子类
  • 成员变量:变量是一个终值,不能再被改变。所以在定义时必须先手动给一个值。
  • 局部变量:被final修饰的局部变量是一个终值,不能再被改变
  • 方法:final修饰的方法不允许重写
public class Demo6 {
    public static void main(String[] args) {
        Animal animal = new Animal();
        //name是常量,值不能改变.
        //animal.name = "chen";
    }
}
//1.类:final修饰的类不能有子类,外界只能用不能改
//final  class  Animal{
class  Animal{
    //2.成员变量:变量是一个终值,不能再被改变.所以在定义时必须先手动给一个值.
     final String name = "bing";
 
     //4.方法:final修饰的方法不允许重写
     public final   void  show(){
         //3.局部变量:被final修饰的局部变量是一个终值,不能再被改变
         final  int a = 4;
         //a++;
         System.out.println(a);
     }
}
空白final【了解】
  • 描述:修饰成员变量的一种形式
  • 如果是自定义的类可以在定义时先不给值,但是必须在构造方法中给值,即必须保证属性时被初始化了的,这种情况叫空白final
  • 优点:空白final在final的使用上提供了更大的灵活性,因为一个类中的final域可以做到根据对象而有所不同,却有保持其恒定不变的特性。
//接上面的代码
class  Bird extends  Animal{
  //这里暂时没有赋值
    final  String model;
    public Bird(String model){
        this.model = model;//这里完成赋值
    }
}

Object类【了解】

定义

Object类:是java继承体系中所有类的父类,Object类没有父类。(包含11个方法,相当于所有子类都默认有这些方法)

继承

父类的抽取:

将多个具体的类中相同的属性和行为提取出来到一个类中。

继承的特点(重点)

  • 产生继承关系后,子类可以使用父类中的属性和方法,也可以定义子类独有的属性和方法
  • Java是单继承,一个类有且只有一个直接的父类,可以有若干个间接的父类,一个父类可以有0个或多个子类,子类之间互不影响
  • 使用继承,可以简化代码,提高代码的复用性,提高代码的拓展性,增加代码的健壮性,最重要的使类与类之间产生了继承的关系,是多态的前提

继承的语法

  • 继承,需要使用关键字extends,在定义类的时候,使用子类extends父类的方式描述继承
  • Object类:是Java继承体系中所有类的父类,Object类没有父类。
/Phone类没有显示的父类,默认父类是Object类
class Phone {}
//Iphone类继承自Phone类
class Iphone extends Phone {
}

不可以被继承

  • 构造方法
    • 构造方法是为了创建当前类的对象的,不可以继承给子类
  • 私有成员
    • 私有成员只能在当前的类中使用,不可以继承给子类
    • 注意:父类的私有成员,在子类中可见不可用
  • 跨包子类
    • 默认的权限属性、方法,不可以继承给跨包子类

访问权限修饰符

访问权限修饰符,就是修饰类、属性的访问级别

当前类 同包其他类 跨包子类 跨包其他类
private × × ×
default(不能写出, 不写权限, 默认就是这个权限) × ×
protected ×
public

方法的重写【重点】

重写的原理
  • 当子类希望实现父类方法的功能之外的一些功能是,如何处理?

解决:子类可以继承到父类中的属性和方法,但是有些方法,子类的实现与父类的方法可能实现的不同。当父类提供的方法已经不能满足子类的需求时,子类中可以定义与父类相同的方法。

  • 当出现同名方法后,方法如何调用?

子类方法完成了对父类方法的覆盖,又叫重写(Override)

class  Phone extends  Object{
    String color;
    int model;
 
    public  void  callPhone(){
        System.out.println("打电话");
    }
    
    public void show(){
        return  null;
    }
}
class Iphone extends  Phone{
    String gui;
 
    public void  fangShui(){
        System.out.println("防水");
    }
 
    @Override
    public  void  callPhone(){
        //公共的功能
        //System.out.println("打电话");
        //通过super调用父类的callPhone方法
        super.callPhone();
        //自己的功能
        System.out.println("自己的功能");
    }
 
    //父类返回值是Phone,子类的show返回值是Iphone,重写时,程序允许返回值不同
    //重写的注意点:父类和子类的重写方法返回值可以不同,但是方法名,参数必须相同.返回值不同时,
    //必须保证父子类的重写方法的返回值有继承关系,并且子类中的返回值的类型是父类的返回值类型或者子类类型
    //在同一个类中不允许出现方法名,参数都相同,但是返回值不同的情况.
    public Iphone show(){
        return  null;
    }
}

@Override

一个注解,进行重写前的检验这个方法是否是开一个重写的方法。如果不是重写的方法,会直接报错。

重写的注意事项
  • 方法名字必须和父类方法名字相同
  • 参数列表必须和父类一致
  • 子类方法的访问权限需要大于等于父类的方法的访问权限,父类不能是private
  • 子类方法的返回值类型需要小于等于父类方法的返回值类型–这里说的是引用类型

super关键字

  • 有时候,子类重写父类方法的时候,并不是要对父类的实现全盘推翻,而是对父类方法进行拓展
  • 父类方法中的实现仍然需要,但是还需要在父类方法的基础上进行拓展的实现,此时就需要使用super关键字调用父类的方法
  • this和super的对比
    • this:是一种引用类型,代表当前对象,保存的是当前对象的地址
    • super:代表的是当前对象的父类,可以调用父类的成员,但是他不是引用数据类型
class Student {
    public void work() {
        System.out.println("学生在学习");
    }
}
class Monitor extends Student {
    @Override
    public void work() {
        super.work();   // 调用父类的实现
        System.out.println("班⻓收作业");
    }
}

继承中使用构造方法【重点】

基本使用:

  • 子类对象还实例化的时候,需要先实例化从父类继承到的部分。此时通过super()默认调用父类中的无参构造方法。
  • ps:super()方法是默认的,不需要显示写出来
class Animal {
    public Animal() {
        System.out.println("父类中的构造方法执行");
    }
}
class Dog extends Animal {
    public Dog() {
        //这里不显示写,也会默认有super(),调用的是父类的空参构造方法
        super();
        System.out.println("子类中的构造方法执行");
    }
}
  • 当我们创建构造方法的时候,为什么一定要调用super?
原因:父类中也有属性要进行初始化,而对象的属性必须由自己的构造方法进行初始化,所以必须调用super(),所以每个构造方法中都默认有一个super()
  • 如果父类中没有无参构造方法,对所有的子类对象实例化都会造成影响,导致子类对象无法实例化

(类中没有无参构造方法的情况:当我们在类中只写了有参构造方法时,系统不会再自动创建无参构造方法)

解决方案:

1.给父类添加无参构方法
2.在子类的构造方法中,使用super(参数列表),调用父类中的有参构造方法
总结:在继承体系中,作为父类最好的办法就是将无参构造方法和有参构造方法都写了
class Animal {
    String name;
    int age;
    public Animal(String name, int age) {
        this.name = name;
        this.age = age;
    }
    
    //1.给父类添加无参构造方法。
    public Animal(){
    }
}
class Dog extends Animal {
    public Dog(String name, int age) {
        super(name, age);   // 2.调用父类中存在的构造方法,实例化父类部分
    }
}
注意:

为什么要将super放在构造方法的第一行?

在子类的构造方法中有可能用到父类的属性,而属性在使用之前必须先进行初始化,否则无法使用。super的作用是初始化父类的属性,如果在super之前调用了其他的代码,有可能造成在未对父类属性初始化时使用了属性的错误情况发生,所以系统默认super前面不能放任何代码,this()用于构造方法调用时也要放在第一行是一个道理。
class  Animal{
    String name;
    //public Animal(){}
    public Animal(String name){
        super();
        this.name = name;
    }
}
 
class Dog extends  Animal{
    public Dog(){
        //super前不能写任何代码
        //System.out.println();
        super("bing");
    }
}

类与类之间的关系

共三种

1.继承---描述:谁是谁			例:人是动物
2.组合---描述:谁属于谁		    例:狗属于人/人拥有狗
3.传参
//创建测试类
public class Demo7 {
//人有一只狗
public static void main(String[] args) {
      Person per = new Person();
      per.name = "张三";
      per.dog = new Dog("拉布拉多");
        }
  
    public static void feedDog(Dog dog){//传参
    dog.eat();
    }
}
 
//创建的人类
class Person{
    String name;
    Dog dog;//组合
}
 
//创建动物类
class Animal{
        String name; 
}
//创建狗类
class  Dog extends Animal{//继承
    String name;//组合
    public Dog(String name){
         this.name = name;
    }
  
    public void eat(){
      System.out.println("吃⻣头");
    }
}
上一篇:封装、继承和重写、多态


下一篇:super详解