java 运行 对象_java实例对象的编译时类型和运行时类型

为什么要区分编译时类型和运行时类型?

看这样一句代码:Person p=new Women()(Women类继承自Person类)那么,假如p的属性修饰符为public 访问属性时得到的是Person类的属性还是Women类的属性,方法调用又是哪个类?答案:会得到Person类的属性,调用Women类的方法。为什么会这样呢?这里就需要知道什么是编译时类型和运行时类型,Java程序状态会分为编译和运行这两种状态,编译时,JVM会在栈中静态创建基本数据变量,和引用数据变量的引用,回到刚刚那句代码,显然,p这个引用就是在编译时创建的,那么,p的编译时类型就是Person了,当运行这句java代码时,JVM在堆中为p新建一块内存,对应new Women()这句代码,所以p的运行时类型就是Women。有这样一条规则,对象调用编译时类型的属性和运行时类型的方法。下面先用代码表示这样的结果,然后再说明我个人的一些理解。

code1

public class TestDemo1 {

public static void main(String[] args) {

// TODO Auto-generated method stub

Person p=new Women();

System.out.println("p.name:"+p.name);

p.show();

}

}

class Person{

public String name;

public Person()

{

name="person";

}

public void show()

{

System.out.println("class person's show()");

}

}

class Women extends Person

{

public String name;

public Women()

{

name="women";

}

public void show()

{

System.out.println("class women's show()");

}

}

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

结果如下

43990471e52d463fa2084a61d34e5b3e.png

从代码运行结果可以看出,p调用的属性属于Person类,而调用的方法是Women类的,验证了上面的规则–对象调用编译时类型的属性和运行时类型的方法

个人理解

这里属于我个人的理解,可能有错,以后发现会重新修正

根据上述规则

根据继承的特点我们可以知道,子类会继承父类非私有的属性和方法,也就是说,父类的(非私有)属性也会出现在子类中,当然,这是显而易见的,然而关键在于,如果子类重新定义了这一属性,会怎么样呢?实际上,父类的属性并不会被覆盖,为了方便起见,我把从父类继承来的属性记为–

属性 而自己重新定义的同名属性为–属性 这样,在子类中,会有两个属性 即:属性

属性,那么如何调用呢?–解答:<>中的内容对应着调用该属性的对象的编译时类型,编译时类型为父类,调用属性

,另一种情况就是调用子类的属性了。下面用图来表示:

75c39fd532b426ed93522832fd7285d8.png 

Class

A中定义属性a,Class B继承自A,重新定义了属性a,此时,B中有编译时类型为A的属性a和编译时类型为B的属性a,Class

C继承自B,自己重新定义了属性a,这时,C具有三种编译时类型的属性a。这样就好看多了,不知道应该调用的属性是哪个类的,就只要分析自己的编译时类型就可以了,调用方法其实不用在意,直接调用运行时类型的方法即可(运行时类型还是比较容易看的)。

就上图的例子我们用代码测试如下

code2

public class TestDemo2 {

public static void main(String[] args) {

// 编译时类型为A,输出应该是A

System.out.println("编译时类型为A,输出应该是A");

A a=new A();

System.out.println(a.name);

A ab=new B();

System.out.println(ab.name);

A ac=new C();

System.out.println(ac.name);

// 编译时类型为B,输出应该是B

System.out.println("编译时类型为B,输出应该是B");

B b=new B();

System.out.println(b.name);

B bc=new B();

System.out.println(bc.name);

// 编译时类型为C,输出应该是C

System.out.println("编译时类型为C,输出应该是C");

C c=new C();

System.out.println(c.name);

}

}

class A

{

String name="A";

}

class B extends A

{

String name="B";

}

class C extends B

{

String name="C";

}

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

运行结果如下

a2eab14a3b205d71c92d0cafd16f8a5f.png

根据运行结果上述解释应该是合理的!

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值