为什么编译器允许 class "I" 的变量被分配给继承 "I" class 的 class "N" 的对象

Why is the compiler allowing the variable of class "I" to be assigned an object of class "N" which inherits the "I" class

class I {    
    String s="yes its me:I";

    void Mine(){
            System.out.println(s);
    }
}

class N extends I {
    String l="yes its me:N";

    void Mine(){
        System.out.println(l);
    }   
}


class T extends N{
    String m="yes its me:T";
    void Mine(){
        System.out.println(m);
    }
}

class Test{
    public static void main(String[] args) {
        I i=new I();
        N n=new N();
        T t=new T();
        I r; // r is a variable of class type I

        r=i; // fine here

        r.Mine(); //no doubt here

        r=n; // heres the problem

        r.Mine(); // these are working only 

        r=t; //with overriding methods existing & no other method exists in all classes

        r.Mine();
    }
}

另外请告诉我:如果我们声明一个class类型的变量,它是做什么的(我的意思是它会根据class的方法和实例变量的数量来识别吗?或仅方法或仅实例变量)。

考虑:

class MP3Player // any MP3 player
class IPod extends MP3Player // an iPod MP3 player
class IPodClassic extends IPod // an iPod Classic in particular

然后:

MP3Player m = new IPod();
m.playMp3();

是允许的,因为 iPod 是一个 MP3 播放器,可以做任何 MP3 播放器可以做的事情。

IPod i = new MP3Player(); // Not allowed
i.showAppStore(); // MP3Player might not have app store

不允许,因为并非所有 MP3 播放器都是 iPod。

IPodClassic ic = new IPod(); // Not allowed
ic.getHardDisk(); // Not all iPod objects have a hard disk.

不允许,因为并非所有 iPod 都是 iPod classics。

class Vehicle {
    Engine myEngine = new Engine();
    void start() {
        myEngine.start();
    }
    void stop() {
        myEngine.stop();
    }
}
class VehicleWithSteering extends Vehicle {
    Steering mySteering = new Steering();
    void start() {
        mySteering.reset();
        myEngine.start();
    }
    void steerLeft() {
        mySteering.left();
    }
    void steerRight() {
        mySteering.right();
    }
}

如您所见,VehicleWithSteering 确实具有基本 Vehicle 所没有的方法。它还会覆盖 void start() 方法,因为启动这个更复杂的车辆涉及不同的例程。

class NoviceDriver {
    Vehicle myVehicle;
    public NoviceDriver(Vehicle vehicle) {
        myVehicle = vehicle;
    }
    void doSomething() {
        myVehicle.start();
        myVehicle.stop();
    }
}
class AdvancedDriver {
    VehicleWithSteering myVehicle;
    public NoviceDriver(VehicleWithSteering vehicle) {
        myVehicle = vehicle;
    }
    void doSomethingElse() {
        myVehicle.start();
        myVehicle.steerLeft();
        myVehicle.stop();
    }
}

AdvancedDriver 需要基本 Vehicle 无法满足的附加功能,因此它总是需要 VehicleWithSteering.

的实例
class Test{
    public static void main(String[] args) {
        // Create one basic vehicle
        Vehicle a = new Vehicle();
        // And one more advanced
        VehicleWithSteering b = new VehicleWithSteering();

        // A novice driver is satisfied with having a basic vehicle
        NoviceDriver x = new NoviceDriver(a);

        // The advanced driver however needs more functionality
        AdvancedDriver y = new AdvancedDriver(b);

        // A novice driver can use the advanced vehicle as well
        // But he will not bother about the advanced functionality
        NoviceDriver z = new NoviceDriver(b);
    }
}

NoviceDriver 只知道如何访问 Vehicle 的方法。但由于这些方法也存在于 VehicleWithSteering 中,所以他也可以使用那个方法。 NoviceDriver 甚至不知道转向是什么意思,所以他不会碰任何他不知道的控件。

您不能将 AdvancedDriverVehicle 相匹配,因为这个没有包含所需的转向方法。

如果 VehicleWithSteering 有更高级的改进,NoviceDriverAdvancedDriver 仍然可以使用它来执行他们有限的任务,因为它仍然提供所需的基本功能。

NoviceDriver 可以访问原始 Vehicle 拥有的所有 public 方法和属性。它不知道以后添加的新方法或属性。在这种情况下,它可以看到 VehicleWithSteering 上继承的 Engine myEngine 属性,但看不到新的 Steering mySteering 属性.

关于你的最后一个问题:这取决于语言。

在Java中,每个class都有一个内部列表,包含其他继承的classes和它实现的接口。每当您将细化转换为更原始的类型时,Java 将检查原始类型是否在列表中。这种行为也用于其他严格类型的语言,例如 C++、C# 和许多其他语言。

另一个概念是 Duck-Typing。

When I see a bird that walks like a duck and swims like a duck and quacks like a duck, I call that bird a duck.

当一种语言使用 Duck-Typing 时,它会通过名称和签名在对象中查找请求的方法。这可能发生在编译时或运行时,在后一种情况下,大多数支持 Duck-Typing 的语言都会抛出异常。

某些语言(例如 PHP 和其他各种脚本语言同时具有严格的类型检查和 Duck-Typing 功能。这意味着您可以选择对继承的 classes 和实现的接口列表强制执行严格的类型检查,以及在省略该检查时默认为 Duck-Typing。