Java入门 第八节面向对象(二)

1. 啥是继承?

  1. 继承是java面向对象核心思想之一,它可以 创建分等级层次的类
  2. 那什么是继承? 类和类之间是有关联的,子类自动具备来自于父类的属性和行为。从已有的类中派生出新的类,新的类能吸收已有类的数据属性和行为,并能扩展新的能力。
    • 例如: 儿子,继承父亲的一些能力(方法),基本特征(属性),并且儿子可能会有自己的新能力(唱,跳 ,rap)。
  3. 代码分析:
    
    class Student{
    //继承只能继承 private 以外的东西 私有话只能本类。
    	String name; //先不要私有化属性。
    	int age;
    public void study(){
    	System.out.println("学习");
    }
    
    
    class Teacher{
    	String name;
    	int age;
     public void study(){
     	System.out.println("学习");
    	}
    }
    
    ....
    
    //还有 Worker ... 等等都具有名字和学习。
    //这样的代码重复度很高。那么怎么解决这么多相似度的问题? 
    // 所以,就抽取相同的属性和行为,向上抽象类,得到了Person类
    
    class Person{
    	String  name;
    	int age;
    
    	public void Study(){
    		System.out.println("学习");
    	}
    }
    

1.1 语法结构

  1. 使用关键字 extends

    //父类
    public class Animal{
    	
    }
    //子类 
    public class Tiger{
    	
    }
    
    //继承语法结构
    public class Tiger extends Animal{
    	
    }
    
  2. 父类是动物类,食肉动物和食草动物都具备动物的一些属性和特征,父类的特点是通用,子类特点是 更加具体

    • is--a 的结构,继承关系。如: Tiger is a Animal。
    • 但是子类会有父类的一般性,也会具有自身特性。
      在这里插入图片描述

1.2 入门练习

  1. 继承的优点:提高代码的复用性(减少代码冗余,相同代码重复利用)。
    • 使类与类之间产生了关系。复用和设计分离,即使以后有100个 只要继承父类就可以了。
  2. 思考一个问题: 不能使用 private 修饰的属性和方法;为什么?
  • Animal 类:

    public class Animal {
        String food;
    
        public void call(){
            System.out.println("发出声音");
        }
    
        public void eat(){
            System.out.println("吃 "+food);
        }
    }
    
  • EatMeat 类

    public class EatMeat extends Animal{
    
         int age; //自己的属性年龄
        /*
            介绍自己
         */
        public void introduce(){
            System.out.println("我是食肉动物");
        }
    }
    
  • Tiger 类

    public class Tiger  extends EatMeat{
    
    }
    
  • 测试类 Test_Extends

    public class Test_Extends{
        public static void main(String[] args) {
            Tiger t = new Tiger();
            System.out.println(t.age);//拿到了父类EatMeat
            t.introduce();
    
            //通过继承关系,拿到了食肉动物Animal属性和方法。
            t.food="食草动物";
            t.eat();
            t.call();
        }
    }
    

1.3 继承的特点

  1. 关键字 extends 相当于子类把父类的功能复制了一份。
  2. 继承可以传递 (动物,食肉动物, 老虎之间关系 Animal 3.0 )。
  3. 重点:java只支持单继承,不可以多继承。(可以多重继承,Animal3.0)
  4. 继承用于功能修改,子类可以拥有父类功能的同时,并进行功能拓展。
  5. is-a关系 面向对象继承 例如:Tiger is a EatMeat , 体现了 狮子继承了食肉动物,二者有父子关系。

2. 继承类型关系图

  1. 继承也要灵活使用,千万不能为了继承而继承,就为了减少代码而继承,这就是错误的体现。
  2. 一定要,真正存在关系时而去使用继承。

在这里插入图片描述

2.1 继承关系案例

  1. 父类 又称之为 超类或者基类。
  2. 子类又叫做 派生类。
    //1. 私有化属性,需要通过Get和Set访问。
     public class Fu { //父类, (超类,基类)
        private String name; //姓名
    
        public String getName() {
            return name;
        }
        public void setName(String name) {
            this.name = name;
        }
    
     //介绍自己的名字
        public void speak(){
            System.out.println("I am "+name);
        }
    }
    
  • 子类 Zi 和 测试类:

    //子类
    public class Zi extends Fu{ //子类 (派生类)
    
        // 扩展自己特有的方法
        public void say(){
            System.out.println("My father is "+ getName());//调用父类方法,因为啥?
        }
    }
    
    // 测试类
    class Demo{
        public static void main(String[] args) {
            Zi zi = new Zi();
            zi.speak(); // 来子父类的方法
    
            //1. 父类私有属性,可以通过父类对外的访问方法设置。
            zi.setName("张三");
            zi.speak();
    
            zi.say();
        }
    }
    
    
  • 输出结果:

    I am null
    I am 张三
    My father is张三
    

3. super 关键字

  1. 通过super关键字,可以使用父类内容。
    • 区分 父类与子类同名 变量。
    • 调用 父类的构造函数。
  2. super代表父类的一个引用对象,如果使用必须放在第一位。

3.1 区别同名变量

  1. super 关键字,在继承中区别同名变量的使用。
  • 父类: Animal :

    public class Animal {
        String name = "超类,基类";
    }
    
  • 子类: Cat:

    public class Cat extends Animal {
       String name="派生类";
    
       public void show (){
          String name = "局部变量 name";
          System.out.println(this.name); //使用谁的? 子类本身
          //这里的super 我们可以理解为 Animal a = new Animal();  a相当于super
          System.out.println(super.name);// 使用的是谁的? 父类
          System.out.println(name);  // 使用谁的? 方法里受局部变量影响
       }
    }
    
    // 测试类 Demo
    class Demo{
       public static void main(String[] args) {
          // 匿名对象使用 ,只调用一次 。
          new Cat().show();
       }
    }
    
  • 输出结果:

    派生类
    超类,基类
    局部变量 name
    

3.2. 构造方法使用

  1. 创建子类的对象时,默认会先调用父类无参构造器。
  2. 父类的构造函数是不能够被继承。
    • 为什么构造方法不能被继承? 因为构造方法必须与类名相同!
  1. 看下列图片,为什么会报错!?
    • 因为子类继承父类之后,获取到了父类的内容(属性/字段),而这些内容在使用之前必须先初始化,所以 必须先调用父类的构造函数进行内容的初始化 。

在这里插入图片描述
在这里插入图片描述

  1. 解决上面图片的办法,如下面案例。
  • 父类: Father

    public class Father {
    
        // 父类 属性
        String name;
        int age;
    
        // 无参数构造 TODO ... ...
     //  public Father() {}
    
        // 构造函数
        public Father(String name) {
            this.name = name;
        }
    
        // 构造函数
        public Father(String name, int age) {
            this.name = name;
            this.age = age;
        }
    
        // 显示方法
        public void show(){
            System.out.println("name :"+name+"\n"+"age :"+age);
        }
    }
    
    
  • 子类: Son

    public class Son extends  Father {
    
        String address; //自己属性
        
    // 如果父类没有空参构造方法。子类必须调用父类构造方法,不管调用哪个 ,但必须调用一个。
        public Son() {
            // super();    //默认调用父类空参构造(前提父类有空参构造)
           // super("你好");
            super("jay",20);
            System.out.println("子类构造函数");
        }
    
     //注意:如果非得,想使用子类构造方法
        public Son(String address) {
            // super(); //第一行都是默认调用父类空参构造函数;(如果没有就必须调用别的。)
            super("张"); //如果没有空参构造,就必须调用含参数构造。
            this.address = address;
        }
    }
    
    
    class Test{
    
        public static void main(String[] args) {
            Son s = new Son();
             s.show();
    		System.out.println("--------华丽的分割线--------------");
            Son s2 = new Son(""); //调用子类含参构造
            s2.show()
    
    
    	
        }
    }
    
  • 输出结果:

    子类构造函数
    name :jay
    age :20
    --------华丽的分割线--------------
    name :张
    age :0
    

4. 方法重写

4.1 Override 重写

  1. 就是在子类中的把 父类方法重写一遍,前体是需要 修改或者扩展的方法,但是要遵循以下几点:

    • 首先继承后,子类就拥有了父类的功能,如果子类方法名称和父类完全一样(包括方法的返回值,方法名和参数列表,完全一致),就会发生重写,标识符 Override
    • 重写意义在于,外壳不变,核心重写, 可以添加子类特有的功能也可以修改父类的原有功能。
  2. 方法重写时需要,参照以下几点

    • 当父类方法无法满足子类需求的时候,需要方法重写;
    • 构造方法不能被重写;为什么?
    • 父类的私有方法不能被重写; 即:private 修饰符
    • 子类重写父类方法时,修饰符要大于等于父类修饰符的权限。private<默认(不写)<protected<public

4.2 重写 父类方法

  1. 古语有云:龙生九子,各有不同。
    • 重写父类方法并扩展功能。
  • 父类 Dragon
public class Dragon {
    private  String  food; //属性

    public String getFood() {
        return food;
    }

    public void setFood(String food) {
        this.food = food;
    }

    //1,权限protected
    protected void function(){
        System.out.println("控雨");
    }

    public void eat(){
       System.out.println("喜欢吃"+food);
   }

}


子类 Unicorn

public class Unicorn extends Dragon {
    //1.重新父类方法要求完全一致
    @Override
    public void function() {
        super.function();// 调用父类功能

        //1.扩展自己的功能
        System.out.println("喜欢和人类交朋友");
    }
}

class  Demo{
    public static void main(String[] args) {
        Unicorn u = new Unicorn();
        u.setFood("玉米");
        u.eat();
        u.function();
    }
}
  • 输出结果:

    喜欢吃玉米
    控雨
    喜欢和人类交朋友
    

5. 继承中的用法

5.1 成员变量的使用

  1. 就近原则 局部 < 成员< 父类。
public class Person {
    int age = 30;
}
public class Teacher extends Person {
    int age ;  //子类属性

    public  void show (){
        int age = 50;  // 局部方法 age
        System.out.println(age); //使用的局部age
        // 想使用父类
        System.out.println(super.age); // 如果想使用父类 age
        System.out.println(this.age); // 如果想使用本类 age
    }
}

class Demo{
    public static void main(String[] args) {
        int  age = 40;  // 没有一毛钱关系
        Teacher teacher = new Teacher();
            teacher.show();
    }
}

输出代码:

50
30
0

5.2 成员方法的使用

  1. 继承,特有,重写方法
public class Teacher  {


    // 普通方法
    public void show(){
        System.out.println("自我介绍");
    }

    public void eat(){
        System.out.println("印度美食,干净又卫生");
    }
}

public class Students extends Teacher {

    // 普通方法,或者 特有方法
    public void  showMe(){
        super.show(); // 可以使用父类的介绍方法
        System.out.println("唱,跳,rap");//加一些自己独特方法
    }

    // 如果想扩展自己的独特的吃饭,用到了重写
    @Override
    public void eat() {
        //TODO 加一些逻辑上的处理
        //... ...
        System.out.println("老八秘制小汉堡!");
    }

}

class Demo {

    public static void main(String[] args) {
        Students s = new Students();
        s.showMe(); // 在父类方法上进行扩展
        s.eat();  // 使用自己的方法
    }
}

输出结果:

自我介绍
唱,跳,rap
老八秘制小汉堡!

5.3 构造方法的使用

  1. 子类创建对象时,默认去访问父类的无参数构造方法;
  2. 在子类所有构造方法中, 第一行都有默认的语句super();写不写都存在!
  3. 父类没有无参构造,可以用 super调用其他构造方法,不然报错!~!
public class Person {
    String name;
    public  Person(String name){
        //sout(“”);可以什么都不输出!
        System.out.println("父类:"+name);
    }

    //    public Person(){
//        System.out.println("Person");
//    }
}
public class ZhangSan extends Person{

    public ZhangSan(){
        // 第一种:调用父类其他构造
        super("周杰伦");
       //  this("许嵩"); //突发奇想,是否可以用this(参数),调用本类的带参数!?
        System.out.println("ZhangSan");
    }
    public  ZhangSan(String name){
        //super(name); // 调用父类含参数 构造
        this(); //调用本类
        System.out.println(name);
    }
}

class Demo2{
    public static void main(String[] args) {
        //new ZhangSan();  // 打印  Person   ZhangSan?说明了有儿子的时候必须先有父亲
        new  ZhangSan("jjj");
    }
}
  • 提问: 如果父类中没有空参构造方法?子类继承会报错?如何解决?

6. 拓展

6.1 this 和 super 区别

  1. this代表 本类对象的引用,super代表 父类对象的引用。
    • this用于区分 局部变量和成员变量。 this.成员变量 this.成员方法() this(【参数】)代表调用本类内容
    • super用于区分 本类变量和父类变量。super.成员变量 super.成员方法() super(【参数】),代表调用父类内容。
  2. super的前提条件式必须有继承, 不然没有super。
  3. this和super不可以同时出现在同一个构造方法里
    • 因为语法要求this或者super都必须放在第一行,如果同时出现的话,到底第一行放谁呢。

6.2 重写 和 重载的区别

  1. 意义不同。

    • 重写:是在建立了继承关系之后,如果子类想扩展父类方法,进行重写。在不修改源码的情况下,进行功能的修改与拓展。
    • 重载:主要是方便程序调用,可以提供多种参数传递的选择。
  2. 创建语法结构不一样。

    • 重写(Override):是指建立了继承关系以后,遵循方法名和返回值相同,权限大于重写父类权限原则。
    • 重载(OverLoad):在一个类中 方法名必须相同 参数列表可以不相同(参数列表不同,参数个数,甚至顺序不同)则看作为重载!
  3. 注意: 重载对返回类型没有要求,可以相同也可以不同,对权限修饰也没有要求,但不能通过返回类型是否相同来判断重载。

public class Animal{

    public void eat(Dog dog){
        System.out.println("吃骨头");
    }
    public String eat(){

        return "吃";
    }
    public void eat(Cat cat){
        System.out.println("吃小鱼干"); 
    }
}

7.简单介绍: 继承关系中的内存图

public class Fu {
    int num = 10;
    public Fu(){
        System.out.println(num);
    }

    public void eat(){
        System.out.println(" fu eat()");
    }

}

public class Zi extends  Fu {

    int num = 20 ;
    public Zi(){
        super(); //1,初始化父类对象
        System.out.println(num);
    }
    public void show(){
        int num = 30;
        System.out.println(num);
        System.out.println(this.num);
        System.out.println(super.num);
    }

    @Override
    public void eat() {
        System.out.println("zi eat()");
    }
}

class Demo2{
    // 所有的方法执行都是加载到栈内存中!
    public static void main(String[] args) {
        Zi zi = new Zi();// 第一步 做了什么? 10 20 ;
        zi.show(); // 30 20  10 ;
        zi.eat(); //重写了父类方法, 找的方式如同!
    }
}

在这里插入图片描述

  • 1
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

吴琼老师

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值