What happens when we access the same variable defined in two interfaces implemented by same class?

  • Article
  • 4 minutes to read

An interface contains definitions for a group of related functionalities that a non-abstract class or a struct must implement. An interface may define static methods, which must have an implementation. An interface may define a default implementation for members. An interface may not declare instance data such as fields, auto-implemented properties, or property-like events.

By using interfaces, you can, for example, include behavior from multiple sources in a class. That capability is important in C# because the language doesn't support multiple inheritance of classes. In addition, you must use an interface if you want to simulate inheritance for structs, because they can't actually inherit from another struct or class.

You define an interface by using the interface keyword as the following example shows.

interface IEquatable<T> { bool Equals(T obj); }

The name of an interface must be a valid C# identifier name. By convention, interface names begin with a capital I.

Any class or struct that implements the IEquatable<T> interface must contain a definition for an Equals method that matches the signature that the interface specifies. As a result, you can count on a class that implements IEquatable<T> to contain an Equals method with which an instance of the class can determine whether it's equal to another instance of the same class.

The definition of IEquatable<T> doesn't provide an implementation for Equals. A class or struct can implement multiple interfaces, but a class can only inherit from a single class.

For more information about abstract classes, see Abstract and Sealed Classes and Class Members.

Interfaces can contain instance methods, properties, events, indexers, or any combination of those four member types. Interfaces may contain static constructors, fields, constants, or operators. Beginning with C# 11, interface members that aren't fields may be static abstract. An interface can't contain instance fields, instance constructors, or finalizers. Interface members are public by default, and you can explicitly specify accessibility modifiers, such as public, protected, internal, private, protected internal, or private protected. A private member must have a default implementation.

To implement an interface member, the corresponding member of the implementing class must be public, non-static, and have the same name and signature as the interface member.

Note

When an interface declares static members, a type implementing that interface may also declare static members with the same signature. Those are distinct and uniquely identified by the type declaring the member. The static member declared in a type doesn't override the static member declared in the interface.

A class or struct that implements an interface must provide an implementation for all declared members without a default implementation provided by the interface. However, if a base class implements an interface, any class that's derived from the base class inherits that implementation.

The following example shows an implementation of the IEquatable<T> interface. The implementing class, Car, must provide an implementation of the Equals method.

public class Car : IEquatable<Car> { public string? Make { get; set; } public string? Model { get; set; } public string? Year { get; set; } // Implementation of IEquatable<T> interface public bool Equals(Car? car) { return (this.Make, this.Model, this.Year) == (car?.Make, car?.Model, car?.Year); } }

Properties and indexers of a class can define extra accessors for a property or indexer that's defined in an interface. For example, an interface might declare a property that has a get accessor. The class that implements the interface can declare the same property with both a get and set accessor. However, if the property or indexer uses explicit implementation, the accessors must match. For more information about explicit implementation, see Explicit Interface Implementation and Interface Properties.

Interfaces can inherit from one or more interfaces. The derived interface inherits the members from its base interfaces. A class that implements a derived interface must implement all members in the derived interface, including all members of the derived interface's base interfaces. That class may be implicitly converted to the derived interface or any of its base interfaces. A class might include an interface multiple times through base classes that it inherits or through interfaces that other interfaces inherit. However, the class can provide an implementation of an interface only one time and only if the class declares the interface as part of the definition of the class (class ClassName : InterfaceName). If the interface is inherited because you inherited a base class that implements the interface, the base class provides the implementation of the members of the interface. However, the derived class can reimplement any virtual interface members instead of using the inherited implementation. When interfaces declare a default implementation of a method, any class implementing that interface inherits that implementation (You need to cast the class instance to the interface type to access the default implementation on the Interface member).

A base class can also implement interface members by using virtual members. In that case, a derived class can change the interface behavior by overriding the virtual members. For more information about virtual members, see Polymorphism.

An interface has the following properties:

  • In C# versions earlier than 8.0, an interface is like an abstract base class with only abstract members. A class or struct that implements the interface must implement all its members.
  • Beginning with C# 8.0, an interface may define default implementations for some or all of its members. A class or struct that implements the interface doesn't have to implement members that have default implementations. For more information, see default interface methods.
  • An interface can't be instantiated directly. Its members are implemented by any class or struct that implements the interface.
  • A class or struct can implement multiple interfaces. A class can inherit a base class and also implement one or more interfaces.

Java expands on the abstract method concept with its interfaces scheme. It’s often desirable to specify the prototypes for a set of methods and provide no implementation. In Java, this is called an interface. An interface defines a set of methods that a class must implement (i.e., some or all of the class’s behavior). A class in Java can declare that it implements an interface and then go about implementing the required methods. A class that implements an interface doesn’t have to inherit from any particular part of the inheritance hierarchy or use a particular implementation.

Interfaces are kind of like Boy Scout or Girl Scout merit badges. A scout who has learned to build a birdhouse can walk around wearing a little sleeve patch with a picture of one. This says to the world, “I know how to build a birdhouse.” Similarly, an interface is a list of methods that define some set of behavior for an object. Any class that implements each of the methods listed in the interface can declare that it implements the interface and wear, as its merit badge, an extra type—the interface’s type.

Interface types act like class types. You can declare variables to be of an interface type, you can declare arguments of methods to accept interface types, and you can even specify that the return type of a method is an interface type. In each of these cases, what is meant is that any object that implements the interface (i.e., wears the right merit badge) can fill that spot. In this sense, interfaces are orthogonal to the class hierarchy. They cut across the boundaries of what kind of object an item is and deal with it only in terms of what it can do. A class can implement as many interfaces as it desires. In this way, interfaces in Java replace the need for C++’s multiple inheritance (and all of its messy side effects).

An interface looks like a purely abstract class (i.e., a class with only abstract methods). You define an interface with the interface keyword and list its methods with no bodies, just prototypes:

interface Driveable { boolean startEngine( ); void stopEngine( ); float accelerate( float acc ); boolean turn( Direction dir ); }

The previous example defines an interface called Driveable with four methods. It’s acceptable, but not necessary, to declare the methods in an interface with the abstract modifier; we haven’t done that here. More importantly, the methods of an interface are always considered public, and you can optionally declare them as so. Why public? Well, the user of the interface wouldn’t necessarily be able to see them otherwise.

Interfaces define capabilities, so it’s common to name interfaces after their capabilities. Driveable, Runnable, and Updateable are good interface names. Any class that implements all the methods can then declare it implements the interface by using a special implements clause in its class definition. For example:

class Automobile implements Driveable { ... public boolean startEngine( ) { if ( notTooCold ) engineRunning = true; ... } public void stopEngine( ) { engineRunning = false; } public float accelerate( float acc ) { ... } public boolean turn( Direction dir ) { ... } ... }

Here, the class Automobile implements the methods of the Driveable interface and declares itself Driveable using an implements clause.

As shown in Figure 6.5, another class, such as Lawnmower, can also implement the Driveable interface. The figure illustrates the Driveable interface being implemented by two different classes. While it’s possible that both Automobile and Lawnmower could derive from some primitive kind of vehicle, they don’t have to in this scenario. This is a significant advantage of interfaces over standard multiple inheritance, as implemented in C++.

Figure 6-5. Implementing the Driveable interface

After declaring the interface, we have a new type, Driveable. We can declare variables of type Driveable and assign them any instance of a Driveable object:

Automobile auto = new Automobile( ); Lawnmower mower = new Lawnmower( ); Driveable vehicle; vehicle = auto; vehicle.startEngine( ); vehicle.stopEngine( ); vehicle = mower; vehicle.startEngine( ); vehicle.stopEngine( );

Both Automobile and Lawnmower implement Driveable, so they can be considered of that type.

Interfaces can be used to implement callbacks in Java. An object can, in effect, pass one of its methods to another object. The callback occurs when the other object subsequently invokes the method. In C or C++, this is prime territory for function pointers; Java uses interfaces instead.

Consider two classes: a TickerTape class that displays data and a TextSource class that provides an information feed. We’d like our TextSource to send any new text data. We could have TextSource store a reference to a TickerTape object, but then we could never use our TextSource to send data to any other kind of object. Instead, we’d have to proliferate subclasses of TextSource that dealt with different types. A more elegant solution is to have TextSource store a reference to an interface type, TextUpdateable:

interface TextUpdateable { void doTextUpdate( String text ); } class TickerTape implements TextUpdateable { public void doTextUpdate( String text ) { System.out.println("TICKER:\n" + text + "\n"); } } class TextSource { TextUpdateable receiver; TextSource( TextUpdateable r ) { receiver = r; } public void sendText( String s ) { receiver.doTextUpdate( s ); } }

The only thing the TextSource really cares about is finding the right method to invoke in order to output some text. Using an interface establishes a “well-known” name, doTextUpdate, for that method.

When the TextSource is constructed, a reference to the TickerTape (which implements the interface) is stored in an instance variable. This “registers” the TickerTape as the TextSource’s “output device.” Whenever it needs to output data, the TextSource calls the output device’s doTextUpdate( ) method.

Although interfaces mostly allow us to specify behavior without implementation, there’s one exception. An interface can contain constants (static final variables), which appear in any class that implements the interface. This feature enables predefined parameters for use with the methods:

interface Scaleable { static final int BIG = 0, MEDIUM = 1, SMALL = 2; void setScale( int size ); }

The Scaleable interface defines three integers: BIG, MEDIUM, and SMALL. All variables defined in interfaces are implicitly final and static; we don’t have to use the modifiers, but for clarity, we recommend you do. A class that implements Scaleable sees these variables:

class Box implements Scaleable { void setScale( int size ) { switch( size ) { case BIG: ... case MEDIUM: ... case SMALL: ... } } ... }

Sometimes, interfaces are created just to hold constants; anyone who implements the interfaces can see the constant names, as if they were included by a C/C++ include file. This is a somewhat degenerate, but acceptable, use of interfaces.

Sometimes completely empty interfaces serve as a marker that a class has a special property. The java.io.Serializeable interface is a good example. Classes that implement Serializable don’t add any methods or variables. Their additional type simply identifies them to Java as classes that want to be able to be serialized.

An interface can extend another interface, just as a class can extend another class. Such an interface is called a subinterface. For example:

interface DynamicallyScaleable extends Scaleable { void changeScale( int size ); }

The interface DynamicallyScaleable extends our previous Scaleable interface and adds an additional method. A class that implements DynamicallyScaleable must implement all the methods of both interfaces.

Note here that we are using the term "extends” and not “implements" to subclass the interface. Interfaces can’t implement anything! But an interface is allowed to extend as many interfaces as it wants. If you want to extend two or more interfaces, list them after the extends keyword, separated by commas:

interface DynamicallyScaleable extends Scaleable, SomethingElseable { ... }

Keep in mind that although Java supports multiple inheritance of interfaces, each class can extend only a single parent class.

Neuester Beitrag

Stichworte