为什么编译器允许 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
甚至不知道转向是什么意思,所以他不会碰任何他不知道的控件。
您不能将 AdvancedDriver
与 Vehicle
相匹配,因为这个没有包含所需的转向方法。
如果 VehicleWithSteering
有更高级的改进,NoviceDriver
和 AdvancedDriver
仍然可以使用它来执行他们有限的任务,因为它仍然提供所需的基本功能。
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。
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
甚至不知道转向是什么意思,所以他不会碰任何他不知道的控件。
您不能将 AdvancedDriver
与 Vehicle
相匹配,因为这个没有包含所需的转向方法。
如果 VehicleWithSteering
有更高级的改进,NoviceDriver
和 AdvancedDriver
仍然可以使用它来执行他们有限的任务,因为它仍然提供所需的基本功能。
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。