首页 > 编程语言 >Java 委托和继承(Delegation and Inheritance)

Java 委托和继承(Delegation and Inheritance)

时间:2023-07-04 17:55:06浏览次数:34  
标签:bar Inheritance void private public Delegation Java foo class

https://blog.csdn.net/Seriousplus/article/details/80462722

委派和继承都是为了提高代码的复用性,只是方式不同。

  • 委派:一个对象请求另一个对象的功能,捕获一个操作并将其发送到另一个对象。
  • 继承:利用extends来扩展一个基类。

Delegation(委托)

委托依赖于动态绑定,因为它要求特定的方法可以在运行时调用不同的代码段,可以看下面代码:

public class A {
    void foo() {
        this.bar(); 
    }
    void bar() { 
        System.out.println("a.bar");
    }
}

在B类中,不使用继承,而是利用委托结合A,达到复用A类中代码的效果:

public class B {
    private A a;
    public B(A a) {
        this.a = a; 
    }
    void foo() {
        a.foo(); // call foo() on the a-instance }
    }
    void bar() {
        System.out.println("b.bar");
    }
}

考虑下面代码的输出:

A a = new A();
B b = new B(a); 
b.foo();
b.bar();

可以很容易地看出来结果:

a.bar
b.bar

这就是一种简单的委派机制。

此外,还有另一种委派的方式:
首先写一个接口,如下:

public interface List<E> { 
    public boolean add(E e); 
    public E remove(int index);
    public void clear();
    …
}

如果我们想在每次调用方法前,在控制台输出点提示信息,那么就可以这样做:

public class LoggingList<E> implements List<E> {
    private final List<E> list;
    public LoggingList<E>(List<E> list) { 
        this.list = list; 
    } 
    public boolean add(E e) { 
        System.out.println("Adding " + e); 
        return list.add(e); 
    } 
    public E remove(int index) { 
        System.out.println("Removing at " + index); 
        return list.remove(index); 
    }
    …
}

 

相当于重写了add方法,但是是实现接口而没有使用继承。

委派的几种类型归纳

  • Use (A use B)

  • Composition/aggregation (A owns B)

  • Association (A has B)

Dependency(依赖): 临时性的delegation

  • 在这种关系中,一个类使用另一个类而不将其作为一个属性。
  • 两类之间的这种关系称为“uses-a”关系。例如,它可以是一个参数,或者在一个方法中本地使用,参考下面的代码:

首先新建一个课程类:

public class Course {}

在课表类总使用课程类:

public class CourseSchedule {
    List<Course> courses = new ArrayList<>();
    public void add (Course c) {
        courses.add(c);
    }
    public void remove (Course c) {
        courses.remove(c);
    }
}

 

在这里,并没有将Course类作为CourseSchedule类的属性来使用,而是作为迭代器中的元素和方法中的参数来使用。

Association(关联): 永久性的delegation

  • 关联是类之间的持久关系,允许一个对象实例让另一个对象实例代表它自己做其他事。
  • 这种关系属于has-a的关系,是结构化的,因为它指定了一种对象与另一种对象相连接,并且不代表行为,即不在该类的方法中使用另一个类的方法,只是简单的将不同的对象连接起来。

下面展示一下关联的代码:

class Teacher {
    private Student [] students; 
}

 

class Student {
    private Teacher teacher;
    Course[] selectedCourses;
}

 

可以看到,在两个类中(Student和Teacher)互相都有彼此的实例,而且没有使用继承,就直接将这几个不同的类相连接,这就是利用了Association方式。

Composition: 更强的delegation

  • 组合是将简单对象或数据类型组合成更复杂的方法的一种方法。
  • 这种关系是a-part-of关系,一个类有另一个属性或实例变量——实现了一个对象包含另一个对象。

let`s show 代码:

class Heart {}
class Person { 
    private Heart heart = new Heart();
    public void operation () { 
        heart.operation(); 
    }
}
  • 这种方式理解起来就很简单了,直接在该类中实例化一个其他类,然后该调用方法调用方法,对这个实例想怎么用怎么用,十分灵活。
  • 不过需要注意的是:
  • 这里的实例是private的,也就是说,外界访问不到,这样的话,更改其值只能在该方法中;而且每次创建该类的对象时,就已经创建好这个类中的实例;也就是说一旦创建好该类的对象,其中的属性指向便已经创建好。

Aggregation

  • 聚集:对象存在于另一个之外,是在外部创建的,所以它作为一个参数传递给构造函数。
  • 这种关系是has-a的关系,区别于

    让我们看一个这个例子的代码:

class Student {}
class Course { 
    private Student[] students; 
    public addStudent (Student s) { 
        studtents.append(s); 
    } 
}

 

可以看到,在这里,内部的属性是可以在外部指定的,而不是完全依赖该类。

Composition vs. Aggregation

组合和聚集是最常用的两种delegation方式,可以说,其中的使用包括了依赖和关联方式,并在其上做了进一步的扩展。二者很相似,但又有很多不同之处,这里举一个例子看一下二者的最大不同之处:

public class WebServer { 
    private HttpListener listener; 
    private RequestProcessor processor; 
    public WebServer(HttpListener listener, RequestProcessor processor) {
        this.listener = listener;
        this.processor = processor;
    } 
}
public class WebServer { 
    private HttpListener listener; 
    private RequestProcessor processor; 
    public WebServer() { 
        this.listener = new HttpListener(80); 
        this.processor = new RequestProcessor(“/www/root”);
    } 
} 

 

可以看到,第一个代码是聚集的方式,第二个代码是组合的方式,这是为什么呢?

  • 在组合中,当拥有的对象被销毁时,所包含的对象也是如此。
    比如:
    一所大学拥有不同的部门,每个部门都有许多教授,因为是大学创建了这些部门,所以如果大学关闭,这些部门将不复存在,但这些部门的教授将继续存在。

  • 但是在聚集中,这并不一定是正确的:
    大学可以被看作是部门的组成,而院系则是教授的集合。一个教授可以在一个以上的部门工作,但是一个部门不能成为一所大学的一部分,部门是在大学外创建的,故大学倒闭,部门还在。

Inheritance(继承)

继承就很好说了,直接是一个类利用extends扩展其父类,而且一个类只能扩展一个父类,但是可以多层扩展。
参考下面的代码:

public class A {
    public void foo() {
        this.bar(); 
    }
    void bar() {
        System.out.println("A.bar");
    }
}

public class B extends A{
    public B() {}
    @Override
    public void foo() { 
        super.foo();
    }
    public void bar() {
        System.out.println("B.bar");
    }
}

 

可以猜一下下面代码的输出的结果,比较有趣:

B b = new B();
b.foo();

 

我这里运行的结果是

B.bar

可以看到,在继承中,子类拥有父类所有的方法,而且还可以继续增加父类中没有的方法。

适用于不同场合

总而言之,委派和继承都是为了代码复用,只是方式不同。

  • 委托可以被看作是对象级别的重用机制,而继承是类级别的重用机制。
  • 此外,如果子类只需要复用父类中的一小部分方法,可以不需 要使用继承,而是通过委派机制来实现

标签:bar,Inheritance,void,private,public,Delegation,Java,foo,class
From: https://www.cnblogs.com/bluestorm/p/17526436.html

相关文章

  • java 组合>聚合>关联>依赖 的区别
    出处:https://zhuanlan.zhihu.com/p/359672087简单来讲,组合是一种较为紧密的关系,从生命周期上看,部分和整体是共存亡的关系。聚合则是一种较为松散的关系,部分和整体的生命周期未必一致。在实际代码中:组合关系中,部分的实例化在整体中进行。聚合关系中,部分的实例化过程在整体外进行,......
  • Java反射
    原文:https://www.cnblogs.com/chanshuyi/p/head_first_of_reflection.html Appleapple=newApple();//直接初始化,「正射」apple.setPrice(4);上面这样子进行类对象的初始化,我们可以理解为「正」。而反射则是一开始并不知道我要初始化的类对象是什么,自然也无法使用new......
  • java、vue基于hutool的aes指定秘钥加密(前后端aes加解密)
     后端代码//加密data对称AESKeybyte[]key=getBytes("._^BV67nW6ck8fwg",16);//秘钥长度最好是16位SymmetricCryptoaes=newSymmetricCrypto(SymmetricAlgorithm.AES,key);Stringjsondata=aes.encryptHex("中国test");System.out.println(jsondata);//......
  • Java获取CPU占用率、内存占用率
    @TestpublicvoidtestSystemUsage(){finallongGB=1024*1024*1024;while(true){OperatingSystemMXBeanoperatingSystemMXBean=ManagementFactory.getOperatingSystemMXBean();StringosJson=JSON.toJSO......
  • 七月四号Java学习
    今天在Java中学习到字面量和变量   ......
  • Java-基本语法回顾总结[25-36]
    常用的JVM启动参数有哪些?线程安全的理解?守护线程的理解?threadlocal的底层原理(25)常用的JVM启动参数有哪些?(26)线程安全的理解?(27)守护线程的理解?(28)threadlocal的底层原理(29)并发、并行与串行之间的区别?(30)Java死锁应如何避免?(31)......
  • java后台删除当前节点及其子节点-递归
    一、表设计 二、entityimportcom.fasterxml.jackson.annotation.JsonIgnore;importcom.joyoung.cloud.security.common.entity.BaseEntity;importio.swagger.annotations.ApiModel;importio.swagger.annotations.ApiModelProperty;importlombok.Data;importlombok......
  • Java数组
    Java数组数组概述1.数组概述1.相同类型变量的有序集合2.数组的声明和创建1.dataType[]arrayRefVar2.dataType[]arrayRefVar=newdataType[arraySize]内存分析1.声明数组int[]array=null;在栈中声明了array2.创建数组array=newint[10];在......
  • java+geotools (geotools for java)
    geotools所需的依赖,在pom.xml引入;<dependencies><!--forgeotoolsbegin--><!--处理空间数据--><!--geotools主要依赖--><dependency><groupId>org.geotools</groupId><artifa......
  • java工具类static静态方法读取yml配置
    当我们需要在工具类中获取yml配置的时候,由于变量是staic导致获取不到yml配置因为spring加载静态方法比IOC早,所以不能直接使用@Value注解读取yml配置,读取结果是null。@ComponentpublicclassTestUtil{//使用@Value注解读取yml配置的数据@Value("${test.url}")......