java学习基础课之面向对象(渡一教育)【继承】(五)


类和类之间的关系

  • A is-a B:泛化(继承 实现)
  • A has-a B: 包含(组合 聚合 关联)
  • A use-a B: 依赖(依赖) (need-a)

一、继承 is-a

1.子类继承父类,通过一个关键字 extends
2.子类的对象可以调用父类中的(public protected)属性和方法 当做自己的来使用
3.子类可以添加自己独有的属性和方法的
4.子类从父类中继承过来的方法不能满足子类需要,可以在子类中重写(覆盖)父类的方法 更多指的是内容
5.每一个类都有继承类,如果不写extends关键字,默认继承Object,如果写了extends则继承后面那个父类
可以理解为Object类非常重要 是任何一个引用类型的父类(直接或间接的继承Object) Object类没有父类
6.Java中继承是单个存在的(单继承) 每一个类只能有一个继承类 (在extends关键字后面只能写一个类)
可以通过传递的方式实现多继承的效果 后续还会有多实现
7.继承在内存中的存储形式
8.关于this和super的使用

关于构造函数:
参考知识点
参考实例

1. 子类继承父类,通过一个**关键字** : extends ```java //父类 public class Animal { }
```java
//子类,继承了父类Animal
public class Person extends Animal{
}
  1. 子类的对象可以调用父类中的(public protected)属性和方法 ,当做自己的来使用。
    关于继承的构造函数理解
//基类:Animal  有两个方法一个属性
public class Animal {
	public String name;
    public void eat(){
        System.out.println("动物的吃饭方法");
    }
    public void sleep(){
        System.out.println("动物的睡觉方法");
    }
}

基类:Animal 有两个方法一个属性

//子类:Person中什么方法也没有定义,但是继承了父类Animal,所以可以使用父类Animal中的方法。
public class Person extends Animal {
}

子类:Person中什么方法也没有定义,但是继承了父类Animal,所以可以使用父类Animal中的方法。

//主方法,中创建Person类的对象,发现Person类中虽然没有方法和属性,但是Person类的对象可以使用Animal类中函数,因为Person继承了Animal,所以可以使用Animal中的方法和属性。
public class Test {
    public static void main(String[] args){
        Person p = new Person();
        p.name="郑中拓";
        p.eat();
        p.sleep();
    }
}

主方法,中创建Person类的对象,发现Person类中虽然没有方法和属性,但是Person类的对象可以使用Animal类中函数,因为Person继承了Animal,所以可以使用Animal中的方法和属性。

  1. 子类可以添加自己独有的属性和方法的。

父类Animal中不变

//子类
public class Person extends Animal {
    //添加一些独有的属性和方法
    public void study(){
        System.out.println("good good study,day day up");
    }
}

子类Person:添加一些独有的属性和方法

//主方法
public class Test {
    public static void main(String[] args){
        Person p = new Person();
        p.name="郑中拓";
        p.eat();
        p.sleep();
        p.study();//子类Person 独有的方法
    }
}

子类Person的对象可以使用,独有的方法

  1. 子类从父类中继承过来的方法不能满足子类需要,可以在子类中重写(覆盖)父类的方法 ,更多指的是内容
    方法的重写:override ,注意区分方法的重载。
//Person类中重写方法,原代码中加上下面这个新的重写方法
 //方法重写
    public void eat(){
        System.out.println("人类的吃饭方法 讲究色香味俱全");
    }

结果在主方法中调用p.eat()的时候,发现重写成功。输出:人类的吃饭方法 讲究色香味俱全。

方法重载和方法重写:

方法重写override方法重载overload
产生两个继承关系的类,子类重写父类的方法一个类中的一组方法
权限子类可以大于等于父类没有要求
特征final父类方法是final 子类不能重写没有要求
特征static父类方法是static 子类不存在没有要求
特征abstract父类方法是abstract 子类必须重写没有要求
返回值子类可以小于等于父类没有要求
名字子类与父类一致一个类中的好多方法名必须一致
参数子类与父类一致每一个方法的参数必须不一致(个数 类型 顺序)
方法体子类的方法内容与父类不一致每一个重载的方法 执行过程不一致
异常如果父类方法抛出运行时异常 ,子类可以不予理会。如果父类方法抛出编译时异常,子类抛出异常的个数少于等于父类,子类抛出异常的类型小于等于父类没有要求
方法体子类的方法内容与父类不一致执行过程不一致
  1. 每一个类都有继承类,如果不写extends关键字,默认继承Object,如果写了extends则继承后面那个父类。
    可以理解为Object类非常重要,是任何一个引用类型的父类(直接或间接的继承Object) ,Object类没有父类。
    Object类中的方法:
    hashCode()将对象在内存中的地址经过计算得到一个int整数
    equals() 用来比较两个对象的内容
    toString() 打印输出时将对象变成String字符串
    getClass() 获取对象对应类的类映射(反射)
    wait() 线程进入挂起等待状态 存在方法重载
    notify() 线程唤醒
    notifyAll() 唤醒所有
    finalize() 权限修饰符是protected 在对象被GC回收的时候 默认调用执行的方法
    clone() 权限修饰符是protected 为了克隆对象

  2. Java中继承是单个存在的(单继承) 每一个类只能有一个继承类 (在extends关键字后面只能写一个类)。
    可以通过传递的方式实现多继承的效果,后续还会有多实现。

  3. 继承在内存中的存储形式。剥洋葱。

//基类
public class Animal {
    public Animal(){
        System.out.println("animal中无参数的构造方法");
    }
    public void eat(){
        System.out.println("动物的吃饭方法");
    }
}
//子类:Person
public class Person extends Animal {
    public Person(){
     //隐藏一行代码 super();调用了父类的构造方法,所以执行了animal中无参数的构造方法
        System.out.println("person中的无参数构造方法");
    }
     //方法重写
    public void eat(){
        System.out.println("人类的吃饭方法 讲究色香味俱全");
    }
}
//主方法
public class Test {
    public static void main(String[] args){
        Person p = new Person();
    }
    p.hashcode();
    p.eat();
}

发现输出结果是:
animal中无参数的构造方法
person中的无参数构造方法
为什么会有:animal这个的构造函数呢???因为Person的构造函数,隐藏了一行:super();调用了父类的构造方法,所以执行了animal中无参数的构造方法。

在这里插入图片描述

主方法中执行过程:
加载类模板的过程,
Person类 Animal类 Object类,
Person p = new Person();创建一个Person类型的对象,
通过new, 堆内存中申请空间,然后创建了一个变量p,将地址传给了p,p指向了堆内存的那个空间。
假设继续执行p.hashcode()方法,如何执行的呢?首先通过p找到了堆内存,然后一层一层找,发现第一层没有hashcode()方法,在进入第二层,父类Animal那一层,发现也没有hashcode()方法,那就继续下一层Object类中找hashcode()方法,发现有,那么可以调用。
p.eat()执行,以后一个输出为:人类的吃饭方法 讲究色香味俱全。因为同样类似上面那种查找方式,发现第一层就找到了eat()方法,所以直接调用方法,不用再找第二层第三层了。

  1. 关于this和super的使用
public class Animal {

    public Animal(){
        System.out.println("animal中无参数的构造方法");
    }
    public void eat(){
        System.out.println("动物的吃饭方法");
    }
    public void sleep(){
	    this.eat();
        //?动物吃饭   人类重写的吃饭
        //代替是当前调用方法时的那个对象,不一定是当前类
        System.out.println("动物的睡觉方法");
    }
}
public class Person extends Animal{

    public Person(){
        //隐藏一行代码 super();调用了父类的构造方法,所以执行了animal中无参数的构造方法
        System.out.println("person中的无参数构造方法");
    }
    //方法重写
    public void eat(){
        System.out.println("人类的吃饭方法 讲究色香味俱全");
    }

    //添加一些独有的属性 或 方法
    public void study(){
        System.out.println("good good study,day day up");
    }
}
//主方法
public class Test {
    public static void main(String[] args){
        //加载类模板的过程
        //Person类  Animal类  Object类
        //创建一个Person类型的对象
        Person p = new Person();
        p.sleep();//从Animal类中继承过来的方法,问题在于Animal中this.eat();到底是调用动物的吃饭方法,还是人类重写的吃饭方法?this指的是当前的对象,当前的对象是人类的对象,所以this指的是人类的吃饭方法。
    }
}
//所以结果为:人类的吃饭方法 讲究色香味俱全

p.sleep();从Animal类中继承过来的方法,问题在于Animal中this.eat();到底是调用动物的吃饭方法,还是人类重写的吃饭方法?this指的是当前的对象,当前的对象是人类的对象,所以this指的是人类的吃饭方法。

那么有一个问题?我就想调用父类的eat的方法呢?这时就用到了super。
this和super都是指代词,代替的是对象。

  • this:代替的是当前执行方法时的那个对象 。不一定是当前类的
  • super:代替的是当前执行方法时的对象的父类对象,空间内部的那个
  • 都能调用一般属性 和 一般方法
    (1)可以放置在类成员的任意位置(属性 方法 构造 块)
    (2)注意调用一般方法的时候可以来回互相调用(写法 编译好用) 执行可能产生问题(StackOverflowError)
    (3)可以调用构造方法(放在构造方法的第一行)
    (4)this和super在构造方法中调用另一个类的构造方法不能同时出现在第一行。

类的个数变多啦—>需要管理类—>包package(可以理解为是一个文件夹)
在我们类的第一行会出现package关键字
如果package和import同时出现
先写package后写import

包含 has-a

包含关系(组合 聚合 关联)
从亲密程度来讲不太一样

  • 组合–>人和大脑 人和心脏的关系
    整体和部分的关系,不可分割,要出现都出现 要消亡都消亡
  • 聚合–>汽车和车轮子 电脑和主板
    整体和部分的关系,创建时有可能是分开的 ,没有组合那么紧密
  • 关联–>人有汽车 人有电脑
    整体和部分的关系,可以分割,后来形成在一起

从Java程序来描述这样的关系 : 通过一个类的对象当做另一个类的属性来存储
例子:车有轮子
建立Wheel.java

package contains;

public class Wheel {
    //属性
    public String brand;//品牌
    public int size;//尺寸
    public String color;//颜色

    //构造方法
    public Wheel(){}
    public Wheel(String brand,int size,String color){
        this.brand = brand;
        this.size = size;
        this.color = color;
    }

    //方法
    public void turn(){
        System.out.println("车轮子可以旋转");
    }
}

建立Car.java,使用了包含关系:public Wheel wheel;//车里面有一个轮子--->包含关系
想要使用Wheel的属性:wheel.brand
想要使用Wheel的方法:wheel.turn()

package contains;

public class Car {

    //属性
    public String brand;//汽车品牌
    public String type;//型号
    public String color;//颜色
    public Wheel wheel;//车里面有一个轮子--->包含关系

    //构造方法
    public Car(){}
    public Car(String brand,String type,String color,Wheel wheel){
        this.brand=brand;
        this.type=type;
        this.color=color;
        this.wheel=wheel;
    }
    //方法
    public void showCar(){
        System.out.println("这是一辆"+brand+"牌"+type+"型号"+color+"的小汽车");
        System.out.println("车上搭载着"+wheel.brand+"牌的"+wheel.size+"尺寸"+wheel.color+"颜色的车轮子");
        wheel.turn();//方法一定对象调用的 
    // 车轮子的方法肯定是车轮子对象调用   可以放置在任何地方
    }
}

设置一个主函数试验一下:

package contains;

public class Test {

    public static void main(String[] args){
        Car car = new Car;
        car.showCar();//展示汽车
    }
}

正常理解,是不应该有错的,但是运行时发现错误。错误指向:System.out.println("车上搭载着"+wheel.brand+"牌的"+wheel.size+"尺寸"+wheel.color+"颜色的车轮子"); 原因在于Wheel是一个空对象,空对象属性是空也不要紧,但是wheel.brand就不行,空对象加点就不可以。所以应当按照下面的样子赋值。

package contains;

public class Test {
    public static void main(String[] args){
        Car car=new Car();
        car.brand="宝马";
        car.color="宝石蓝";
        car.type="Z4";
        car.wheel=new Wheel();
        car.wheel.brand="米其林";
        car.wheel.color="酷黑";
        car.wheel.size=400;
//      Car car = new Car("宝马","Z4","宝石蓝色",new Wheel("米其林",400,"酷黑"));
//和上面那一段等价,
//可以用这一句也是因为我们自己定义了构造方法。
        car.showCar();//展示汽车
    }
}

依赖关系 use-a(need-a)

屠夫 杀 猪 ; 农夫 养 猪
一个类屠夫
可以做一件事情 ,杀猪
需要一头猪
不是整体和部分的关系,某一件事情产生了关系
临时组合在一起,这件事情一旦做完关系即解散
Java程序体现的形式为:
一个类的方法中使用到了另一个类的对象。

  • 第一个可以在方法中传递参数;
  • 第二个可以在方法中自己创建。

设计类的关系遵循的原则:高内聚低耦合
耦合度: 紧密 继承(实现) > 包含 > 依赖

例子:模拟刚刚我们讲过的农民养猪,屠夫杀猪
先写猪的java文件:

package rely;

public class Pig {//描述猪

    //属性
    private String name;//名字
    private int weight = 20;//体重

    //构造方法
    public Pig(){}
    public Pig(String name){
        this.name=name;
    }

    //方法
    //描述一个方法  表示小猪被杀啦
    public void beKilled(){
        System.out.println(this.name+"被杀啦,好惨呀");
    }

    //描述一个方法  让猪长肉
    //    每一个月涨到前一个月的两倍
    public void growUp(int month){
        for(int i=1;i<=month;i++){
            this.weight*=2;
        }
    }

    //描述一个方法  猪告知他的体重
    public int getWeight(){
        return this.weight;
    }
    public String getName(){
        return this.name;
    }
}

屠夫

package rely;

public class Butcher {//描述屠夫

    //属性  名字 有刀

    //方法
    //描述一个屠夫杀猪的方法   需要提供条件 一头猪
    public void killPig(Pig pig){
        Pig pig=new Pig("小花");
        System.out.println("屠夫执行了杀猪方法");
        String pigName = pig.getName();
        int pigWeight = pig.getWeight();
        System.out.println(pigName+"的体重为:"+pigWeight);
        pig.beKilled();
    }
}

主方法:

package rely;

public class Test {
    public static void main(String[] args){
        Butcher butcher = new Butcher();
        //屠夫做事--->杀猪
        butcher.killPig(pig);
    }
}

屠夫只负责杀猪,农夫才养猪,所以加一个农夫。
农夫:

package rely;

public class Farmer {//农夫

    //农夫养猪--->
    //    参数--->几个月    返回值-->是一头猪
    public Pig feedPig(int month){
        Pig pig = new Pig("小花");//依赖--->在屠夫的方法中使用到了猪的对象
        pig.growUp(month);//20 --> 640
        return pig;
    }
}

所以屠夫变为了:

package rely;

public class Butcher {//描述屠夫

    //属性  名字 有刀

    //方法
    //描述一个屠夫杀猪的方法   需要提供条件 一头猪
    public void killPig(Pig pig){
        System.out.println("屠夫执行了杀猪方法");
        String pigName = pig.getName();
        int pigWeight = pig.getWeight();
        System.out.println(pigName+"的体重为:"+pigWeight);
        pig.beKilled();
    }
}

主方法:

package rely;

public class Test {
    public static void main(String[] args){
        //创建农夫对象
        Farmer farmer = new Farmer();
        //农夫做一件事情--->养猪
        Pig pig = farmer.feedPig(5);
        //创建屠夫对象
        Butcher butcher = new Butcher();
        //屠夫做事--->杀猪
        butcher.killPig(pig);
    }
}

总结:

类和类的关系

  • is-a 继承 实现
    继承通过extends关键字 (单继承)
    实现通过implements关键字 (多实现 接口)
    注意方法重写 方法重载区别 注意Object类及方法 注意内存结构

  • has-a 组合 聚合 关联
    一个类的对象放置在另一个类中作为属性

  • use-a(need-a) 依赖
    一个类的方法中使用到了另外一个类的对象
    方法内部new 方法传递参数

    类关系的设计: 高内聚 低耦合 继承(实现) > 组合 > 聚合 > 关联 > 依赖

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值