多重继承java_Java中的多重继承

多重继承java

Today we will look into Multiple Inheritance in Java. Sometime back I wrote few posts about inheritance, interface and composition in java. In this post, we will look into java multiple inheritance and then compare composition and inheritance.

今天,我们将研究Java中的多重继承。 有时我写了几篇有关Java 继承接口组成的文章。 在本文中,我们将研究Java多重继承,然后比较组成和继承。

Java中的多重继承 (Multiple Inheritance in Java)

multiple inheritance in java

Multiple inheritance in java is the capability of creating a single class with multiple superclasses. Unlike some other popular object oriented programming languages like C++, java doesn’t provide support for multiple inheritance in classes.


Java中的多重继承是创建具有多个超类的单个类的能力。 与其他一些流行的面向对象的编程语言(如C ++)不同, java不提供对类中多重继承的支持

Java doesn’t support multiple inheritances in classes because it can lead to diamond problem and rather than providing some complex way to solve it, there are better ways through which we can achieve the same result as multiple inheritances.

Java不支持类中的多重继承,因为它可能导致菱形问题 ,而不是提供一些复杂的方法来解决它,而是有更好的方法来实现与多重继承相同的结果。

Java中的钻石问题 (Diamond Problem in Java)

To understand diamond problem easily, let’s assume that multiple inheritances were supported in java. In that case, we could have a class hierarchy like below image.

为了轻松理解钻石问题, 我们假设java中支持多个继承 。 在这种情况下,我们可以像下面的图像那样有一个类层次结构。

Let’s say SuperClass is an abstract class declaring some method and ClassA, ClassB are concrete classes.

假设SuperClass是一个抽象类,声明了一些方法,而ClassA,ClassB是具体类。

SuperClass.java

SuperClass.java

package com.journaldev.inheritance;

public abstract class SuperClass {

	public abstract void doSomething();
}

ClassA.java

ClassA.java

package com.journaldev.inheritance;

public class ClassA extends SuperClass{
	
	@Override
	public void doSomething(){
		System.out.println("doSomething implementation of A");
	}
	
	//ClassA own method
	public void methodA(){
		
	}
}

ClassB.java

ClassB.java

package com.journaldev.inheritance;

public class ClassB extends SuperClass{

	@Override
	public void doSomething(){
		System.out.println("doSomething implementation of B");
	}
	
	//ClassB specific method
	public void methodB(){
		
	}
}

Now let’s say ClassC implementation would be something like below and it’s extending both ClassA and ClassB.

现在,让我们说ClassC的实现类似于下面的内容,它扩展了ClassA和ClassB。

ClassC.java

ClassC.java

package com.journaldev.inheritance;

// this is just an assumption to explain the diamond problem
//this code won't compile
public class ClassC extends ClassA, ClassB{

	public void test(){
		//calling super class method
		doSomething();
	}

}

Notice that test() method is making a call to superclass doSomething() method. This leads to the ambiguity as the compiler doesn’t know which superclass method to execute. Because of the diamond-shaped class diagram, it’s referred to as Diamond Problem in java. The diamond problem in Java is the main reason java doesn’t support multiple inheritances in classes.

注意, test()方法正在调用超类doSomething()方法。 由于编译器不知道要执行哪个超类方法,因此这导致了歧义。 由于菱形类图,在Java中被称为Diamond Problem。 Java中的菱形问题是Java不支持类中的多个继承的主要原因。

Notice that the above problem with multiple class inheritance can also come with only three classes where all of them has at least one common method.

请注意,具有多个类继承的上述问题也可能只出现在三个类中,它们全部具有至少一个通用方法。

Java接口中的多重继承 (Multiple Inheritance in Java Interfaces)

You might have noticed that I am always saying that multiple inheritances is not supported in classes but it’s supported in interfaces. A single interface can extend multiple interfaces, below is a simple example.

您可能已经注意到,我一直在说类不支持多重继承,但接口则支持多重继承。 单个接口可以扩展多个接口,下面是一个简单的示例。

InterfaceA.java

InterfaceA.java

package com.journaldev.inheritance;

public interface InterfaceA {

	public void doSomething();
}

InterfaceB.java

InterfaceB.java

package com.journaldev.inheritance;

public interface InterfaceB {

	public void doSomething();
}

Notice that both the interfaces are declaring the same method, now we can have an interface extending both these interfaces like below.

注意,两个接口都声明了相同的方法,现在我们可以拥有一个扩展这两个接口的接口,如下所示。

InterfaceC.java

InterfaceC.java

package com.journaldev.inheritance;

public interface InterfaceC extends InterfaceA, InterfaceB {

	//same method is declared in InterfaceA and InterfaceB both
	public void doSomething();
	
}

This is perfectly fine because the interfaces are only declaring the methods and the actual implementation will be done by concrete classes implementing the interfaces. So there is no possibility of any kind of ambiguity in multiple inheritances in Java interfaces.

这很好,因为接口仅声明方法,并且实际实现将由实现接口的具体类完成。 因此,Java接口中的多重继承不存在任何歧义。

That’s why a java class can implement multiple interfaces, something like below example.

这就是为什么Java类可以实现多个接口的原因,例如下面的示例。

InterfacesImpl.java

InterfacesImpl.java

package com.journaldev.inheritance;

public class InterfacesImpl implements InterfaceA, InterfaceB, InterfaceC {

	@Override
	public void doSomething() {
		System.out.println("doSomething implementation of concrete class");
	}

	public static void main(String[] args) {
		InterfaceA objA = new InterfacesImpl();
		InterfaceB objB = new InterfacesImpl();
		InterfaceC objC = new InterfacesImpl();
		
		//all the method calls below are going to same concrete implementation
		objA.doSomething();
		objB.doSomething();
		objC.doSomething();
	}

}

Did you noticed that every time I am overriding any superclass method or implementing any interface method, I am using @Override annotation. Override annotation is one of the three built-in java annotations and we should always use override annotation when overriding any method.

您是否注意到,每次我重写任何超类方法或实现任何接口方法时,我都使用@Override注释。 覆盖注释是三个内置的Java注释之一在覆盖任何方法时 ,我们都应始终使用覆盖注释

救援人员组成 (Composition for the rescue)

So what to do if we want to utilize ClassA function methodA() and ClassB function methodB() in ClassC. The solution lies in using composition. Here is a refactored version of ClassC that is using composition to utilize both classes methods and also using doSomething() method from one of the objects.

那么如果我们想在ClassC利用ClassA函数methodA()ClassB函数methodB() ClassC 。 解决方案在于使用组合 。 这是ClassC的重构版本,它使用合成来利用两个类方法以及一个对象中的doSomething()方法。

ClassC.java

ClassC.java

package com.journaldev.inheritance;

public class ClassC{

	ClassA objA = new ClassA();
	ClassB objB = new ClassB();
	
	public void test(){
		objA.doSomething();
	}
	
	public void methodA(){
		objA.methodA();
	}
	
	public void methodB(){
		objB.methodB();
	}
}

组合与继承 (Composition vs Inheritance)

One of the best practices of Java programming is to “favor composition over inheritance”. We will look into some of the aspects favoring this approach.

Java编程的最佳实践之一是“偏向于继承而不是继承”。 我们将研究有利于这种方法的某些方面。

  1. Suppose we have a superclass and subclass as follows:

    ClassC.java

    package com.journaldev.inheritance;
    
    public class ClassC{
    
    	public void methodC(){
    	}
    }

    ClassD.java

    The above code compiles and works fine but what if ClassC implementation is changed like below:

    ClassC.java

    package com.journaldev.inheritance;
    
    public class ClassC{
    
    	public void methodC(){
    	}
    
    	public void test(){
    	}
    }

    Notice that test() method already exists in the subclass but the return type is different. Now the ClassD won’t compile and if you are using any IDE, it will suggest you change the return type in either superclass or subclass.

    Now imagine the situation where we have multiple levels of class inheritance and superclass is not controlled by us. We will have no choice but to change our subclass method signature or its name to remove the compilation error. Also, we will have to make a change in all the places where our subclass method was getting invoked, so inheritance makes our code fragile.

    The above problem will never occur with composition and that makes it more favorable over inheritance.

    ClassC.java

    ClassD.java

    package com.journaldev.inheritance;
    
    public class ClassD extends ClassC{
    
    	public int test(){
    		return 0;
    	}
    }

    上面的代码可以编译并正常工作,但是如果ClassC实现更改如下:

    ClassC.java

    请注意,子类中已经存在test()方法,但返回类型不同。 现在,ClassD将无法编译,并且如果您使用的是任何IDE,它将建议您更改超类或子类中的返回类型。

    现在想象一下我们具有多个级别的类继承和超类不受我们控制的情况。 我们别无选择,只能更改子类方法签名或其名称以消除编译错误。 同样,我们将必须在所有调用子类方法的地方进行更改,因此继承会使我们的代码易碎。

    上面的问题永远不会在组合中发生,这使其比继承更有利。

  2. Another problem with inheritance is that we are exposing all the superclass methods to the client and if our superclass is not properly designed and there are security holes, then even though we take complete care in implementing our class, we get affected by the poor implementation of the superclass.

    Composition helps us in providing controlled access to the superclass methods whereas inheritance doesn’t provide any control of the superclass methods, this is also one of the major advantages of composition over inheritance.

    组合可以帮助我们提供对超类方法的受控访问,而继承不提供对超类方法的任何控制,这也是组合优于继承的主要优势之一。

  3. Another benefit with composition is that it provides flexibility in the invocation of methods. Our above implementation of ClassC is not optimal and provides compile-time binding with the method that will be invoked, with minimal change we can make the method invocation flexible and make it dynamic.

    ClassC.java

    package com.journaldev.inheritance;
    
    public class ClassC{
    
    	SuperClass obj = null;
    
    	public ClassC(SuperClass o){
    		this.obj = o;
    	}
    	public void test(){
    		obj.doSomething();
    	}
    	
    	public static void main(String args[]){
    		ClassC obj1 = new ClassC(new ClassA());
    		ClassC obj2 = new ClassC(new ClassB());
    		
    		obj1.test();
    		obj2.test();
    	}
    }

    Output of above program is:

    This flexibility in method invocation is not available in inheritance and boosts the best practice to favor composition over inheritance.

    ClassC实现不是最佳的,它提供了与将要调用的方法的编译时绑定,只需进行很小的更改,我们就可以灵活地使方法调用并使之动态。

    ClassC.java

    package com.journaldev.inheritance;
    
    public class ClassC{
    
    	SuperClass obj = null;
    
    	public ClassC(SuperClass o){
    		this.obj = o;
    	}
    	public void test(){
    		obj.doSomething();
    	}
    	
    	public static void main(String args[]){
    		ClassC obj1 = new ClassC(new ClassA());
    		ClassC obj2 = new ClassC(new ClassB());
    		
    		obj1.test();
    		obj2.test();
    	}
    }

    上面程序的输出是:

    这种方法调用的灵活性在继承中不可用,并提倡了最佳实践,即在继承方面偏向于组合。

  4. Unit testing is easy in composition because we know what all methods we are using from superclass and we can mock it up for testing whereas in inheritance we depend heavily on superclass and don’t know what all methods of superclass will be used, so we need to test all the methods of superclass, that is an extra work and we need to do it unnecessarily because of inheritance.

    单元测试很容易组合,因为我们知道超类中正在使用的所有方法,并且可以对其进行模拟,而在继承中,我们很大程度上依赖于超类,并且不知道将使用所有超类方法,因此我们需要要测试超类的所有方法,这是一项额外的工作,由于继承,我们不需要这样做。

That’s all for multiple inheritances in java and a brief look at composition.

这就是java中的多个继承以及对组合的简要介绍。

翻译自: https://www.journaldev.com/1775/multiple-inheritance-in-java

多重继承java

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值