对象初始化 - 构造函数与 class 类型和方法访问的关系
Object initialisation - The relation of the constructor to class type and method access
我有以下代码:
package testapp;
class Calculation {
public Calculation(){}
public void addition(int x, int y) { }
public void Subtraction(int x, int y) { }
}
class My_Calculation extends Calculation {
public My_Calculation(){}
public void multiplication(int x, int y) { }
}
public class TestApp {
public static void main(String[] args) {
int a = 20, b = 10;
My_Calculation demo = new My_Calculation();
demo.addition(a, b);
demo.Subtraction(a, b);
demo.multiplication(a, b);
System.out.println(demo.getClass().getName());
Calculation d = new Calculation();
d.Subtraction(b, b);
d.addition(b, b);
// no multiplication
System.out.println(d.getClass().getName());
Calculation d2 = new My_Calculation();
d2.Subtraction(b, b);
d2.addition(b, b);
// no multiplication
System.out.println(d2.getClass().getName());
}
}
输出是这样的:
演示=testapp.My_Calculation
d = testapp.Calculation
d2 = testapp.My_Calculation
下面的语句是引用变量名d2到对象类型计算:
的声明
Calculation d2;
下面的语句是调用My_Calculation构造函数的初始化。
Calculation d2 = new My_Calculation();
当我 运行 以下代码时,输出表明 d2 是 class 类型 My_Calculation 但可以访问 Calculation class.
中的方法
System.out.println(d2.getClass().getName());
输出:testapp.My_Calculation
访问:加法;减法
现在,我的理解告诉我,如果调用 My_Calculation 构造函数,我应该:
1.仅访问乘法,或
2。访问加法、减法和乘法。
但是,我实际上得到了相反的结果:只能使用加法和减法。因此,我认为这是违反直觉的。
有人可以向我解释这里发生了什么,让我对为什么 类型的对象:My_Calculation 无法访问它的 自己的方法但是只能访问超级classes方法.
这里:
Calculation d2 = new My_Calculation();
您创建了一个类型为 My_Calculation
的对象,但您将其分配给了一个用超类型声明的变量!并且编译器不够聪明 "see" d2
实际上是子类型。因此,编译器 会阻止您调用在该子类型上定义的方法。因为对于编译器来说,d2
被认为是 Calculation
!
注意你可以cast告诉编译器"I know better":
( (My_Calculation) d2) ).multiplication(...
这在编译时和运行时都有效!
你的误解从这里开始:
Calculation d2 = new My_Calculation();
你在作业右侧所做的基本上是在下一行"forgotten"。然后编译器只知道你有一些d2
类型Calculation
!
最后:是的,在您的 specific 示例中,编译器可以轻松确定 real 类型的 d2
。但在很多情况下,这并不容易,甚至不可能。因此 Java 背后的人决定忽略这种潜力 "knowledge"。
Could someone explain to me what is happening here to give me a
coherent understanding of why an object of type: My_Calculation would
have no access to its own methods but access to only the superclasses
methods.
因为从编译器的角度来看,这不是访问方法的对象,而是引用那个的变量。
如果你声明:
Calculation d2 = new My_Calculation();
或者对象引用,如果你没有声明任何变量,例如:
new My_Calculation().doMethod();
编译器将 d2
视为 Calculation
,因此允许执行此 class 提供的操作。
这种做法被interface/supertype称为编程。这意味着您可以在实例化类型中传递任何实现,代码将始终有效。
例如,此更改:
Calculation d2 = new MyCalculationOtherSubclass();
如果 MyCalculationOtherSubclass
是 Calculation
的另一个子 class,则整个代码可以编译。
如果您需要使用特定的子类型,声明子类型是有意义的:
My_Calculation d2 = new My_Calculation();
左右垂头丧气吧:((My_Calculation)d2).invokeSubclassMethod();
.
类似地,String
是 CharSequence
的子 class,但如果您想使用 String
特有的 subString()
,则需要操作 String
:
所以你会声明它:String aString = "...";
而不是 CharSequence aString = "...";
.
这是因为,在编译时,您只能访问您正在处理的对象的静态类型(即您的变量的类型)中的方法和它的超类中的方法classes,接口和超级接口。 getClass
方法是可用的,因为它是在 Object
class 内部定义的,并且 Calculation
是从它继承的。因此,如果你想调用 multiplication
你必须将你的变量声明为 My_Calculation
.
然而,在运行时,调用的方法是来自动态类型的方法(您分配给变量的方法)。因此,如果您在 My_Calculation
中重写方法 addition
,即使静态类型是 Calculation
,该方法也会在运行时调用。
我有以下代码:
package testapp;
class Calculation {
public Calculation(){}
public void addition(int x, int y) { }
public void Subtraction(int x, int y) { }
}
class My_Calculation extends Calculation {
public My_Calculation(){}
public void multiplication(int x, int y) { }
}
public class TestApp {
public static void main(String[] args) {
int a = 20, b = 10;
My_Calculation demo = new My_Calculation();
demo.addition(a, b);
demo.Subtraction(a, b);
demo.multiplication(a, b);
System.out.println(demo.getClass().getName());
Calculation d = new Calculation();
d.Subtraction(b, b);
d.addition(b, b);
// no multiplication
System.out.println(d.getClass().getName());
Calculation d2 = new My_Calculation();
d2.Subtraction(b, b);
d2.addition(b, b);
// no multiplication
System.out.println(d2.getClass().getName());
}
}
输出是这样的:
演示=testapp.My_Calculation
d = testapp.Calculation
d2 = testapp.My_Calculation
下面的语句是引用变量名d2到对象类型计算:
的声明Calculation d2;
下面的语句是调用My_Calculation构造函数的初始化。
Calculation d2 = new My_Calculation();
当我 运行 以下代码时,输出表明 d2 是 class 类型 My_Calculation 但可以访问 Calculation class.
中的方法System.out.println(d2.getClass().getName());
输出:testapp.My_Calculation
访问:加法;减法
现在,我的理解告诉我,如果调用 My_Calculation 构造函数,我应该:
1.仅访问乘法,或
2。访问加法、减法和乘法。
但是,我实际上得到了相反的结果:只能使用加法和减法。因此,我认为这是违反直觉的。
有人可以向我解释这里发生了什么,让我对为什么 类型的对象:My_Calculation 无法访问它的 自己的方法但是只能访问超级classes方法.
这里:
Calculation d2 = new My_Calculation();
您创建了一个类型为 My_Calculation
的对象,但您将其分配给了一个用超类型声明的变量!并且编译器不够聪明 "see" d2
实际上是子类型。因此,编译器 会阻止您调用在该子类型上定义的方法。因为对于编译器来说,d2
被认为是 Calculation
!
注意你可以cast告诉编译器"I know better":
( (My_Calculation) d2) ).multiplication(...
这在编译时和运行时都有效!
你的误解从这里开始:
Calculation d2 = new My_Calculation();
你在作业右侧所做的基本上是在下一行"forgotten"。然后编译器只知道你有一些d2
类型Calculation
!
最后:是的,在您的 specific 示例中,编译器可以轻松确定 real 类型的 d2
。但在很多情况下,这并不容易,甚至不可能。因此 Java 背后的人决定忽略这种潜力 "knowledge"。
Could someone explain to me what is happening here to give me a coherent understanding of why an object of type: My_Calculation would have no access to its own methods but access to only the superclasses methods.
因为从编译器的角度来看,这不是访问方法的对象,而是引用那个的变量。
如果你声明:
Calculation d2 = new My_Calculation();
或者对象引用,如果你没有声明任何变量,例如:
new My_Calculation().doMethod();
编译器将 d2
视为 Calculation
,因此允许执行此 class 提供的操作。
这种做法被interface/supertype称为编程。这意味着您可以在实例化类型中传递任何实现,代码将始终有效。
例如,此更改:
Calculation d2 = new MyCalculationOtherSubclass();
如果 MyCalculationOtherSubclass
是 Calculation
的另一个子 class,则整个代码可以编译。
如果您需要使用特定的子类型,声明子类型是有意义的:
My_Calculation d2 = new My_Calculation();
左右垂头丧气吧:((My_Calculation)d2).invokeSubclassMethod();
.
类似地,String
是 CharSequence
的子 class,但如果您想使用 String
特有的 subString()
,则需要操作 String
:
所以你会声明它:String aString = "...";
而不是 CharSequence aString = "...";
.
这是因为,在编译时,您只能访问您正在处理的对象的静态类型(即您的变量的类型)中的方法和它的超类中的方法classes,接口和超级接口。 getClass
方法是可用的,因为它是在 Object
class 内部定义的,并且 Calculation
是从它继承的。因此,如果你想调用 multiplication
你必须将你的变量声明为 My_Calculation
.
然而,在运行时,调用的方法是来自动态类型的方法(您分配给变量的方法)。因此,如果您在 My_Calculation
中重写方法 addition
,即使静态类型是 Calculation
,该方法也会在运行时调用。