通过UML类图认识Java继承、聚合、合成(组合)、关联、依赖关系

本文将通过如下所示类图,在IDE中建一个工程,编写对应代码,在实际操作中认识Java的继承、聚合、合成(组合)、关联、依赖关系,在动手完成这个项目后,对这几个关系的认识会有深刻体会,以后如果别人给你一个类图也就知道如何动手了,画类图也自然不在话下。
在这里插入图片描述

继承

这里面继承最多,分为继承类和接口,先将动物类、鸟类、大雁、鸭类、企鹅类、飞翔接口、讲人话接口创建好,并将继承关系一一实现。类图和代码的类转换关系如下:
在这里插入图片描述
在这里插入图片描述

将其中已有属性和方法实现,各个类中与其他关系有关的方法暂时不实现。其中需要说的是这个鸟类本身有个下蛋行为(方法),继承它的大雁、鸭子、企鹅类中的下蛋行为(方法)其实是对鸟类这个父类下蛋行为的重写。

重写有关继承的多态性,重写也叫作方法覆盖,常常与方法重载进行区分,容易混淆。
重载:在同一个类中,方法名字相同(出现同名方法),由参数列表区别具体调用哪个方法。
覆盖:在类层次结构中,如果子类中的一个方法与父类中的方法有相同的方法名、相同的返回值类型并具有相同数量和类型的参数列表,这种情况称为方法覆盖。当一个覆盖方法通过父类引用被调用,Java根据当前被引用对象的类型来决定执行哪个版本的方法。
引用父类成员的形式为super关键字来引用:
super.成员变量或super.成员方法(参数)
对于构造方法而言,引用方式为: super(参数)

class SuperClass {
    int a;
    SuperClass(){ 
      a = 10; 
    }
    public void printA() {
      System.out.println("父类中a ="+a);}
    }
class SubClass extends SuperClass {
      int a;
      SubClass(int a) { 
           this.a = a;  
      }
      public void printA() { 
            System.out.println("子类中a = "+a); 
      }
}
public class OverrideDemo {
   public static void main(String args[]) {
      SubClass s1 = new SubClass(10);
 	   s1.printA();
   }
}

如上所代码结果将调用子类的printA方法。

如果子类中的方法,仅方法名、返回类型与父类方法一致,但参数列表有区别,则子类中此类情况算方法的重载,而不是覆盖。
覆盖时:子类中与父类同名的成员变量时注意“继承自父类的那些方法,只能操作父类的成员变量。子类中的成员变量与父类中定义的成员变量同名,子类在引用这个变量时,默认是引用它自己定义的成员变量,将从父类那里继承而来的成员变量“覆盖”,覆盖的涵义为隐藏父类同名成员。
关于多态性注意事项我有这些总结:
1、成员变量没有多态性
2、子类与父类对象可以完成类型转换
3、从子类引用的角度看待多态性,主要是理解成员变量和成员方法如何完成覆盖。
4、从父类引用调用子类对象的角度看待多态性,会发现即使父类引用指向的子类对象,父类引用和父类的成员方法依然只能直接操作父类自己的成员变量。父类引用必须调用子类方法才能间接操作子类成员变量(这里的方法必须是子类覆盖了父类的方法,不能是子类新增的方法)。一个重要用法:动态绑定方法。最后注意关键字instanceof。

这里关于Java多态性多说了点,从父类引用调用子类对象的角度看待多态性在本实例中没有体现,所以讲得较少,只有最后一段总结提了一下。继续本实例。

依赖关系

顾名思义,依赖关系是A做xx需要B,如这里的实例中动物的新陈代谢需要氧气和水,是借用关系,成为A依赖B,当B改变时可能A也会被要求改变。表现在代码上,为依赖的类的某个方法以被依赖的类作为其参数,或者是class A 的某个方法创造了 class B 的实例,或对class B的静态方法的调用。
在这里插入图片描述
那么本实例的依赖关系就可以这样实现(当然我这只是一种方法,自己想的,还有其他很多种方法,如果有新的想法可以自己思考)

Animal.java

public class Animal {
	public char living;   //是否有生命
	
	public void  metabolism(Oxygen oxygen,Water water) {              //新陈代谢
		System.out.print("进行新陈代谢   ");
		oxygen.needOxygen();
		water.needWater();
	}
	public void reproduce() {
		System.out.print("我是可以繁殖的!");      //繁殖
	}

Oxygen.java

package edu.hut.software.zqh;
class Oxygen{                                 //依赖关系空气
	public void needOxygen() {
		System.out.print("被依赖类氧气   ");
	}
}

class Water{                                  //依赖关系水
	public void needWater() {
		System.out.print("被依赖类水   ");
	}
}

关联关系

关联体现的是两个类、或者类与接口之间语义级别的一种强依赖关系,它使得一个类知道另外一个类的属性和方法,这种关系很强烈,比依赖更强,不是偶然性的,也不是临时性的,而是一种长期性,相对平等的关系,表现在代码层面,为被关联的类B以类属性的形式出现在类A中,也可能是关联类A引用了被关联类B的全局变量。如本实例中企鹅和气候,他们是关联关系,那企鹅类里就应该有气候类的类属性,他们是一种“拥有”的关系。
在这里插入图片描述
实现代码就是:

Climate.java

package edu.hut.software.zqh;

public class Climate {
	public void changeClimate() {
		System.out.print("关联关系“天气”");
	}
}

Penguin.java
package edu.hut.software.zqh;

public class Penguin extends Bird{
	private Climate climate;         //关联关系
	
	public Penguin(Climate climate) {
		this.climate=climate;
	}
	public void layEggs() {
		System.out.print("我是企鹅所以我生企鹅蛋    ");
		climate.changeClimate();
	}
}

关联关系

聚合是关联关系的特例,是强的关联关系,聚合是整个与个体的关系,此时整体和部分是可以分离的,他们具有各自的生命周期,部分可以属于多个对象,也可以被多个对象共享;比如计算机和CPU,公司与员工的关系;在代码层面聚合与关联是一致的,只能从语义上来区分。
聚合关系也是使用实例变量来实现的,在java语法上区分不出关联和聚合,关联关系中类出于一个层次,而聚合则明显的在两个不同的层次。
如本实例中的雁群和大雁,多个个体大雁组成了雁群,大雁离开了雁群,两者都能独立存在。
在这里插入图片描述
实现代码:

WideGoose.java

package edu.hut.software.zqh;
public class WideGoose extends Bird implements Fly{
	public void layEggs() {
		System.out.print("我是大雁所以我生大雁蛋");
	}
	public void fly() {
		System.out.print("我能够飞翔");
	}
}

WideGooseAggregate.java

package edu.hut.software.zqh;
public class WideGooseAggregate {
	private WideGoose[] arrayWideGoose;   //这里暂时不知道应该怎么给那些属性赋值,感觉没太大用,就不赋值了
	public void horizontalFly() {	
		System.out.printf("雁群一字型飞行队列");
	}
	public void vFiy() {
		System.out.printf("雁群一字型飞行队列");
	}
}

从通过Java实现的代码上看的确和关联区分不了,但是两个类不在一个层次。

扫描二维码关注公众号,回复: 9883132 查看本文章

合成(组合)关系

组合也是关联关系的一种特例,比聚合更强,是一种强聚合关系。它同样体现整体与部分的关系,但此时整体与部分是不可分的,整体生命周期的结束也意味着部分生命周期的结束,反之亦然。如大脑和人类,也如本例中的鸟和翅膀,鸟没了翅膀还存在就真的太恐怖了。
在这里插入图片描述
实现代码如下:

Wing.java
package edu.hut.software.zqh;
public class Wing {
	public void wing() {
		System.out.print("合成关系“有翅膀”");
	}
}

Animal.java
package edu.hut.software.zqh;
public class Bird extends Animal{
	public int feather;   //是否有羽毛
	public int mouse;     //嘴巴是否是有角质喙而没有牙齿
	private Wing wing;
	
	public Bird() {
		wing=new Wing();
		wing.wing();
	}
	public void layEggs() {                    //下蛋
		System.out.print("不同种类的鸟下蛋种类不同!");
	}	
}

也和关联在代码上没啥区别

最后

在过程中我已经给了大部分代码,剩下的是实现继承的类,如下:

package edu.hut.software.zqh;

public class DonaldDuck extends Duck implements Speak{
	public void speak() {
		System.out.print("大家好,我是唐老鸭,我和其他鸭子不一样的是我继承了讲人话接口,会说话");
	}
}

package edu.hut.software.zqh;

public class Duck extends Bird{
	public void layEggs()
	{
		System.out.print("我是鸭子所以我生鸭蛋");
	}
}

package edu.hut.software.zqh;

public interface Speak {
	public abstract void speak();
}

interface Fly{
	public abstract void fly();
}
public static void main(String args[]) {            //调用继承的方法并输出相关语句验证各种关系是否实现
		Penguin penguin=new Penguin(new Climate());   
		System.out.print("  ");
		penguin.layEggs();
		System.out.print("  ");
		penguin.metabolism(new Oxygen(), new Water());
		System.out.print("  ");
		penguin.reproduce();
		System.out.println();
		DonaldDuck donaldduck=new DonaldDuck();
		System.out.print("  ");
		donaldduck.layEggs();
		System.out.print("  ");
		donaldduck.metabolism(new Oxygen(), new Water());
		System.out.print("  ");
		donaldduck.reproduce();
		System.out.print("  ");
		donaldduck.speak();
		System.out.println();
		WideGoose widegoose=new WideGoose();
		System.out.print("  ");
		widegoose.layEggs();
		System.out.print("  ");
		widegoose.metabolism(new Oxygen(), new Water());
		System.out.print("  ");
		widegoose.reproduce();
		System.out.print("  ");
		widegoose.fly();
	}
}

所有代码都已经上传,运行后可以看到执行顺序
在这里插入图片描述

发布了21 篇原创文章 · 获赞 2 · 访问量 3354

猜你喜欢

转载自blog.csdn.net/weixin_44164333/article/details/104820494