JavaTutorial之Interfaces and Inheritance

Interfaces

The Interface Body
The interface body can contain abstract methods, default methods, and static methods. An abstract method within an interface is followed by a semicolon, but no braces (an abstract method does not contain an implementation). Default methods are defined with the default modifier, and static methods with the static keyword. All abstract, default, and static methods in an interface are implicitly public, so you can omit the public modifier.

Interface里也可以定义变量All constant values defined in an interface are implicitly public, static, and final

public interface GroupedInterface extends Interface1, Interface2, Interface3 {

    // constant declarations
    
    // base of natural logarithms
    double E = 2.718282;
 
    // method signatures
    void doSomething (int i, double x);
    int doSomethingElse(String s);
}

Interfaces cannot be instantiated—they can only be implemented by classes or extended by other interfaces.(接口不能实例化它们只能由类实现或由其他接口扩展)

一个例子:

public interface OperateCar {

   // constant declarations, if any

   // method signatures
   
   // An enum with values RIGHT, LEFT
   int turn(Direction direction,
            double radius,
            double startSpeed,
            double endSpeed);
   int changeLanes(Direction direction,
                   double startSpeed,
                   double endSpeed);
   int signalTurn(Direction direction,
                  boolean signalOn);
   int getRadarFront(double distanceToCar,
                     double speedOfCar);
   int getRadarRear(double distanceToCar,
                    double speedOfCar);
         ......
   // more method signatures
}

这里方法是没有大括号的 { };

实现某个接口:

public class OperateBMW760i implements OperateCar {

    // the OperateCar method signatures, with implementation --
    // for example:
    public int signalTurn(Direction direction, boolean signalOn) {
       // code to turn BMW's LEFT turn indicator lights on
       // code to turn BMW's LEFT turn indicator lights off
       // code to turn BMW's RIGHT turn indicator lights on
       // code to turn BMW's RIGHT turn indicator lights off
    }

    // other members, as needed -- for example, helper classes not 
    // visible to clients of the interface
}

相当于具体的代码实现了。

一个更标准的interface的代码:

public interface GroupedInterface extends Interface1, Interface2, Interface3 {

    // constant declarations
    
    // base of natural logarithms
    double E = 2.718282;
 
    // method signatures
    void doSomething (int i, double x);
    int doSomethingElse(String s);
}

interface 可以 extend 其他的interface
方法和常量默认是public的
在这里插入图片描述
接口中的常量都是public,static,final

Using an Interface as a Type
将interface当作是一种类型(int)

If you define a reference variable whose type is an interface, any object you assign to it must be an instance of a class that implements the interface.(如果定义类型为接口的引用变量,则分配给它的任何对象都必须是实现该接口的类的实例。)

只要是实现了该接口的类的实例就行。因为是implement了该接口,则可以强制转型

public Object findLargest(Object object1, Object object2) {
   Relatable obj1 = (Relatable)object1;
   Relatable obj2 = (Relatable)object2;
   if ((obj1).isLargerThan(obj2) > 0)
      return object1;
   else 
      return object2;
}

These methods work for any “relatable” objects, no matter what their class inheritance is. When they implement Relatable, they can be of both their own class (or superclass) type and a Relatable type. This gives them some of the advantages of multiple inheritance, where they can have behavior from both a superclass and an interface.(不管它们的类继承是什么。当它们实现Relatable时,它们可以是自己的类(或超类)类型,也可以是Relatable类型。这给了它们多重继承的一些优点,它们可以同时拥有来自超类和接口的行为。)

Evolving Interfaces(接口是在不断变化的

public interface DoIt {
   void doSomething(int i, double x);
   int doSomethingElse(String s);
}

接口一开始是这样的

public interface DoIt {

   void doSomething(int i, double x);
   int doSomethingElse(String s);
   boolean didItWork(int i, double x, String s);
   
}

新加了一个,变成了如上,那么所有implement了这个接口的类怎么办?

public interface DoItPlus extends DoIt {

   boolean didItWork(int i, double x, String s);
   
}

新建一个接口,升级了老的接口

也可以:

public interface DoIt {

   void doSomething(int i, double x);
   int doSomethingElse(String s);
   default boolean didItWork(int i, double x, String s) {
       // Method body 
   }
   
}

也可以将新的弄成default,但是必须得实现这个default方法

下面展开讲一下default方法:

Default Methods

核心问题:interface要加入新的方法怎么办?改接口?大动干戈?
If they add them as static methods, then programmers would regard them as utility methods, not as essential, core methods.
如果将它们添加为静态方法,那么程序员会将它们视为实用方法,而不是基本的核心方法。
Default methods enable you to add new functionality to the interfaces of your libraries and ensure binary compatibility with code written for older versions of those interfaces.
默认方法使您能够向库的接口添加新功能,并确保与为这些接口的旧版本编写的代码的二进制兼容性。

方法:

public interface TimeClient {
    void setTime(int hour, int minute, int second);
    void setDate(int day, int month, int year);
    void setDateAndTime(int day, int month, int year,
                               int hour, int minute, int second);
    LocalDateTime getLocalDateTime();
    
    static ZoneId getZoneId (String zoneString) {
        try {
            return ZoneId.of(zoneString);
        } catch (DateTimeException e) {
            System.err.println("Invalid time zone: " + zoneString +
                "; using default time zone instead.");
            return ZoneId.systemDefault();
        }
    }
        
    default ZonedDateTime getZonedDateTime(String zoneString) {
        return ZonedDateTime.of(getLocalDateTime(), getZoneId(zoneString));
    }
}

Remember that an abstract method is a method declared without an implementation.
抽象方法是没有实现的方法,没有大括号{ }

方法名前加一个default关键字,以及进行实现。

With this interface, you do not have to modify the class SimpleTimeClient, and this class (and any class that implements the interface TimeClient), will have the method getZonedDateTime already defined
使用此接口,您不必修改SimpleTimeClient类,并且此类(以及实现接口TimeClient的任何类)将已定义getZoneDateTime方法

import java.time.*;
import java.lang.*;
import java.util.*;

public class TestSimpleTimeClient {
    public static void main(String... args) {
        TimeClient myTimeClient = new SimpleTimeClient();
        System.out.println("Current time: " + myTimeClient.toString());
        System.out.println("Time in California: " +
            myTimeClient.getZonedDateTime("Blah blah").toString());
    }
}

extend有default method的interface
三种类型:

  • Not mention the default method at all, which lets your extended interface inherit the default method.(不提及default method也就直接继承了原始的default method
  • Redeclare the default method, which makes it abstract.(重新声明默认方法,之后的类重新implement
  • Redefine the default method, which overrides it.(相当于提供了一个新的default method
public interface AnotherTimeClient extends TimeClient { }
public interface AbstractZoneTimeClient extends TimeClient {
    public ZonedDateTime getZonedDateTime(String zoneString);
}
public interface HandleInvalidTimeZoneClient extends TimeClient {
    default public ZonedDateTime getZonedDateTime(String zoneString) {
        try {
            return ZonedDateTime.of(getLocalDateTime(),ZoneId.of(zoneString)); 
        } catch (DateTimeException e) {
            System.err.println("Invalid zone ID: " + zoneString +
                "; using the default time zone instead.");
            return ZonedDateTime.of(getLocalDateTime(),ZoneId.systemDefault());
        }
    }
}

Extending Interfaces That Contain Default Methods

public interface AnotherTimeClient extends TimeClient { }
public interface AbstractZoneTimeClient extends TimeClient {
    public ZonedDateTime getZonedDateTime(String zoneString);
}
public interface HandleInvalidTimeZoneClient extends TimeClient {
    default public ZonedDateTime getZonedDateTime(String zoneString) {
        try {
            return ZonedDateTime.of(getLocalDateTime(),ZoneId.of(zoneString)); 
        } catch (DateTimeException e) {
            System.err.println("Invalid zone ID: " + zoneString +
                "; using the default time zone instead.");
            return ZonedDateTime.of(getLocalDateTime(),ZoneId.systemDefault());
        }
    }
}
  1. Not mention the default method at all, which lets your extended
    interface inherit the default method. 直接继承
  2. Redeclare the default method,which makes it abstract.重新声明
  3. Redefine the default method, which overrides it.重写

综上 Interface 中的default方法还是为了接口升级方便及确保与这些接口的旧版本的二进制兼容性

Static Methods

A static method is a method that is associated with the class in which it is defined rather than with any object. Every instance of the class shares its static methods.
静态方法是与定义它的类相关联的方法,而不是与任何对象相关联的方法。类的每个实例都共享它的静态方法。

可以方便在你的库中部署helper method

Integrating Default Methods into Existing Libraries

排序方法

myDeck.sort(
    (firstCard, secondCard) ->
        firstCard.getRank().value() - secondCard.getRank().value()
); 
myDeck.sort(
    Comparator
        .comparing(Card::getRank)
        .thenComparing(Comparator.comparing(Card::getSuit)));
myDeck.sort(
    Comparator.comparing(Card::getRank)
        .reversed()
        .thenComparing(Comparator.comparing(Card::getSuit)));

Inheritance

Java是单继承模式,最上层为Object类

子类可以直接继承父类的public或者protect方法,若在同一个包中则可以继承父类的 package-private 方法,不会直接继承父类private方法,但是如果超类具有访问其私有字段的公共或受保护方法,则子类也可以使用这些方法如通过nested class

Casting Objects

Object obj = new MountainBike();

隐式转换 obj既是一个Object类型的对象又是一个MountainBike对象;

MountainBike myBike = obj;

会编译报错 因为obj是一个Object类型不一定是MountainBike类型

MountainBike myBike = (MountainBike)obj;

但是我们可以告诉编译器我们准备给obj分配一个MountainBike类型

此强制转换插入一个runtime check运行时检查,确保obj被分配了一个MountainBike,以便编译器可以安全地假定obj是一个MountainBike。如果obj在运行时不是MountainBike,则会引发异常。

if (obj instanceof MountainBike) {
    MountainBike myBike = (MountainBike)obj;
}

也可以用上述代码避免异常抛出

Multiple Inheritance of State, Implementation, and Type 状态、实现和类型的多重继承

多重继承问题,若一个子类继承了多个父类,这些父类有一个名字共同的方法,这个子类改决定用哪个方法?
一个类可以实现多个接口,若default方法名字相同,java编译器可以通过某种手段保证不出错

Overriding and Hiding Methods

Instance Methods
对于父类中的普通方法,子类直接override父类方法。名称,参数,返回值都相同。

Static Methods
若子类定义了一个和父类一模一样的static方法,则子类将父类相应方法hide起来

hide a static meteod 和 override a instance method有以下启示:

被调用的重写实例方法的版本是子类中的版本。
调用的隐藏静态方法的版本取决于它是从超类还是子类调用的。

public class Animal {
    public static void testClassMethod() {
        System.out.println("The static method in Animal");
    }
    public void testInstanceMethod() {
        System.out.println("The instance method in Animal");
    }
}
public class Cat extends Animal {
    public static void testClassMethod() {
        System.out.println("The static method in Cat");
    }
    public void testInstanceMethod() {
        System.out.println("The instance method in Cat");
    }

    public static void main(String[] args) {
        Cat myCat = new Cat();
        Animal myAnimal = myCat;
        Animal.testClassMethod();
        myAnimal.testInstanceMethod();
    }
}
The static method in Animal
The instance method in Cat

Interface Methods
为了避免interface default method出现多重继承的问题,java做了一下规定:
Instance methods are preferred over interface default methods.

当父类和接口default方法相同时会优先选择父类方法。

public class Horse {
    public String identifyMyself() {
        return "I am a horse.";
    }
}
public interface Flyer {
    default public String identifyMyself() {
        return "I am able to fly.";
    }
}
public interface Mythical {
    default public String identifyMyself() {
        return "I am a mythical creature.";
    }
}
public class Pegasus extends Horse implements Flyer, Mythical {
    public static void main(String... args) {
        Pegasus myApp = new Pegasus();
        System.out.println(myApp.identifyMyself());
    }
}

I am a horse.

Methods that are already overridden by other candidates are ignored
interface method已经被其他接口实现了,就不选择了

public interface Animal {
    default public String identifyMyself() {
        return "I am an animal.";
    }
}
public interface EggLayer extends Animal {
    default public String identifyMyself() {
        return "I am able to lay eggs.";
    }
}
public interface FireBreather extends Animal { }
public class Dragon implements EggLayer, FireBreather {
    public static void main (String... args) {
        Dragon myApp = new Dragon();
        System.out.println(myApp.identifyMyself());
    }
}

I am able to lay eggs

若有多个接口拥有相同的default方法,则子类必须指明清楚具体实现哪个,不局限于一个,但必须得指明清楚。

public interface OperateCar {
    // ...
    default public int startEngine(EncryptedKey key) {
        // Implementation
    }
}
public interface FlyCar {
    // ...
    default public int startEngine(EncryptedKey key) {
        // Implementation
    }
}

public class FlyingCar implements OperateCar, FlyCar {
    // ...
    public int startEngine(EncryptedKey key) {
        FlyCar.super.startEngine(key);
        OperateCar.super.startEngine(key);
    }
}
public interface Mammal {
    String identifyMyself();
}
public class Horse {
    public String identifyMyself() {
        return "I am a horse.";
    }
}
public class Mustang extends Horse implements Mammal {
    public static void main(String... args) {
        Mustang myApp = new Mustang();
        System.out.println(myApp.identifyMyself());
    }
}

父类的优先级比接口的优先级高

注意:attention please:Static methods in interfaces are never inherited.接口的静态方法永远不会被继承

Modifiers
子类重写的方法只能比父类中的对应方法更开放,不能少
子类不能改变父类static 修饰的类方法,会compile-time error

Polymorphism多态

一个类的子类可以定义它们自己独特的行为,同时还可以共享父类的一些相同功能。

public void printDescription(){
    System.out.println("\nBike is " + "in gear " + this.gear
        + " with a cadence of " + this.cadence +
        " and travelling at a speed of " + this.speed + ". ");
}

父类bicycle中有此方法

public class MountainBike extends Bicycle {
    private String suspension;

    public MountainBike(
               int startCadence,
               int startSpeed,
               int startGear,
               String suspensionType){
        super(startCadence,
              startSpeed,
              startGear);
        this.setSuspension(suspensionType);
    }

    public String getSuspension(){
      return this.suspension;
    }

    public void setSuspension(String suspensionType) {
        this.suspension = suspensionType;
    }

    public void printDescription() {
        super.printDescription();
        System.out.println("The " + "MountainBike has a" +
            getSuspension() + " suspension.");
    }
} 
public class RoadBike extends Bicycle{
    // In millimeters (mm)
    private int tireWidth;

    public RoadBike(int startCadence,
                    int startSpeed,
                    int startGear,
                    int newTireWidth){
        super(startCadence,
              startSpeed,
              startGear);
        this.setTireWidth(newTireWidth);
    }

    public int getTireWidth(){
      return this.tireWidth;
    }

    public void setTireWidth(int newTireWidth){
        this.tireWidth = newTireWidth;
    }

    public void printDescription(){
        super.printDescription();
        System.out.println("The RoadBike" + " has " + getTireWidth() +
            " MM tires.");
    }
}
public class TestBikes {
  public static void main(String[] args){
    Bicycle bike01, bike02, bike03;

    bike01 = new Bicycle(20, 10, 1);
    bike02 = new MountainBike(20, 10, 5, "Dual");
    bike03 = new RoadBike(40, 20, 8, 23);

    bike01.printDescription();
    bike02.printDescription();
    bike03.printDescription();
  }
}

Bike is in gear 1 with a cadence of 20 and travelling at a speed of 10. 

Bike is in gear 5 with a cadence of 20 and travelling at a speed of 10. 
The MountainBike has a Dual suspension.

Bike is in gear 8 with a cadence of 40 and travelling at a speed of 20. 
The RoadBike has 23 MM tires.

JVM会保证调用合适对象的方法,方法是由对象决定而不是由变量类型决定
这个特性叫做virtual method invocation

Accessing Superclass Members

public class Superclass {

    public void printMethod() {
        System.out.println("Printed in Superclass.");
    }
}
public class Subclass extends Superclass {

    // overrides printMethod in Superclass
    public void printMethod() {
        super.printMethod();
        System.out.println("Printed in Subclass");
    }
    public static void main(String[] args) {
        Subclass s = new Subclass();
        s.printMethod();    
    }
}

通过super关键字访问父类中被子类重写的方法

Subclass Constructors

public MountainBike(int startHeight, 
                    int startCadence,
                    int startSpeed,
                    int startGear) {
    super(startCadence, startSpeed, startGear);
    seatHeight = startHeight;
}

子类构造函数在第一行调用父类构造函数,super()或super(parameter list)
会一直向上调用constructor chaining

Object as a Superclass

protected Object clone() throws CloneNotSupportedException
      Creates and returns a copy of this object.
public boolean equals(Object obj)
      Indicates whether some other object is "equal to" this one.
protected void finalize() throws Throwable
      Called by the garbage collector on an object when garbage
      collection determines that there are no more references to the object
public final Class getClass()
      Returns the runtime class of an object.
public int hashCode()
      Returns a hash code value for the object.
public String toString()
      Returns a string representation of the object.
public final void notify()
public final void notifyAll()
public final void wait()
public final void wait(long timeout)
public final void wait(long timeout, int nanos)

多线程相关

The clone() Method

如果调用clone()的对象实现了可克隆接口,则对象对clone()方法的实现将创建一个与原始对象具有相同类的对象,并初始化新对象的成员变量,使其具有与原始对象对应的成员变量相同的值。

克隆的对象可能包含其它对象的引用,所以clone需要重写以便于解耦

The equals() Method

The equals() method provided in the Object class uses the identity operator (==) to determine whether two objects are equal. For primitive data types, this gives the correct result. For objects, however, it does not. The equals() method provided by Object tests whether the object references are equal—that is, if the objects compared are the exact same object
通过 “= =”判断是否相同,对于基本数据类型,数值相同则相同,对于对象,比较的是对象引用,若指向同一个对象则相同

The finalize() Method

that may be invoked on an object when it becomes garbage GC所用

The getClass() Method
不可重写getClass方法

void printClassName(Object obj) {
    System.out.println("The object's" + " class is " +
        obj.getClass().getSimpleName());
}

The hashCode() Method
if two objects are equal, their hash code must also be equal 如果两个对象相同,则他们的hash code相同
If you override the equals() method, you change the way two objects are equated and Object’s implementation of hashCode() is no longer valid. Therefore, if you override the equals() method, you must also override the hashCode() method as well.

如果重写equals()方法,则会更改两个对象相等的方式,并且对象的hashCode()实现不再有效。因此,如果重写equals()方法,还必须重写hashCode()方法。

The toString() Method
应该总是去重写 toString()方法

The Object’s toString() method returns a String representation of the object, which is very useful for debugging
对于debug很有用

Writing Final Classes and Methods
有一些东西不希望被改变,不希望被子类重写
父类的构造函数一般弄成final,不然子类可能会乱改

class ChessAlgorithm {
    enum ChessPlayer { WHITE, BLACK }
    ...
    final ChessPlayer getFirstPlayer() {
        return ChessPlayer.WHITE;
    }
    ...
}

Abstract Methods and Classes
抽象类是由abstract的类
it may or may not include abstract methods
可包括或者不包括抽象方法

abstract void moveTo(double deltaX, double deltaY);

抽象方法的定义,没有{}大括号

若某个类包含抽象方法,则该类必须也定义为抽象类

public abstract class GraphicObject {
   // declare fields
   // declare nonabstract methods
   abstract void draw();
}

When an abstract class is subclassed, the subclass usually provides implementations for all of the abstract methods in its parent class

当抽象类被子类化时,子类通常为其父类中的所有抽象方法提供实现

with abstract classes, you can declare fields that are not static and final, and define public, protected, and private concrete methods.

With interfaces, all fields are automatically public, static, and final, and all methods that you declare or define (as default methods) are public.

In addition, you can extend only one class, whether or not it is abstract, whereas you can implement any number of interfaces.
主要是fields的修饰符不同,interface只能是 public static final

An Abstract Class Example

抽象类应用场景:某些类有一些共同的属性,但是还有一些具体的实现

abstract class GraphicObject {
    int x, y;
    ...
    void moveTo(int newX, int newY) {
        ...
    }
    abstract void draw();
    abstract void resize();
}
class Circle extends GraphicObject {
    void draw() {
        ...
    }
    void resize() {
        ...
    }
}
class Rectangle extends GraphicObject {
    void draw() {
        ...
    }
    void resize() {
        ...
    }
}
abstract class X implements Y {
  // implements all but one method of Y
  实现除一个方法外的所有方法
}

class XX extends X {
  // implements the remaining method in Y
}

抽象类也可以实现接口

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值