Java中variant_Java Covariants

问题

public class CovariantTest {

public A getObj() {

return new A();

}

public static void main(String[] args) {

CovariantTest c = new SubCovariantTest();

System.out.println(c.getObj().x);

}

}

class SubCovariantTest extends CovariantTest {

public B getObj() {

return new B();

}

}

class A {

int x = 5;

}

class B extends A {

int x = 6;

}

The above code prints 5 when compiled and run. It uses the covariant return for the over-ridden method.

Why does it prints 5 instead of 6, as it executes the over ridden method getObj in class SubCovariantTest.

Can some one throw some light on this. Thanks.

回答1:

This is because in Java member variables don't override, they shadow (unlike methods). Both A and B have a variable x. Since c is declared to be of type CovarientTest, the return of getObj() is implicitly an A, not B, so you get A's x, not B's x.

回答2:

Java doesn't override fields (aka. attributes or member variables). Instead they shadow over each other. If you run the program through the debugger, you'll find two x variables in any object that is of type B.

Here is an explanation on what is happening. The program first retrieves something that is implicitly of type A and then call for the x that is assumed to come from A. Even though it is clearly a subtype, in your example an object of type B is created through SubCovariantTest, it still assumes you return something in getObj() that is implicitly typed A. Since Java cannot override fields, the test will call A.x and not B.x.

CovariantTest c = new SubCovariantTest();

// c is assumed the type of CovariantTest as it is

// implicitly declared

System.out.println(c.getObj().x);

// In this method chain the following happens:

// c.getObj() will return object of type B

// BUT will assume it is an A

// c.getObj().x will return the x from A

// since in this context the compiler assumes

// it is an A and make the call to A.x

It seems like a mindboggling gotcha because methods are always overridden in Java (in comparison to C++ and C# in which they are not). You usually won't run into this problem because Java code convention tells you to never access fields directly. Instead make sure that fields are always accessed through accessor methods, i.e. getters:

class A {

private int x = 5;

public int getX() { //

return x;

}

}

class B extends A {

private int x = 6;

@override

public int getX() {

// will be called instead even though B is implied to be A

// @override is optional because methods in Java are always virtual

// thus are always overridden

return x;

}

}

Code to get this working is the following:

c.getObj().getX();

// Will now call getX() in B and return the x that is defined in B's context.

回答3:

Replace your A and B above with:

class A {

public int getX() { return 5; }

}

class B extends A {

public int getX() { return 6; }

}

That will probably answer your question about what is wrong ;-)

回答4:

There are two fields named x in the object, one from class A and one from class B,

which hides the one in A.

The field x referred to is the one in A, because of the declaration of c.

In practice this is not a problem, because it is very bad style to

hide a field in a subclass,

access a field directly instead of via a method.

回答5:

package ch2;

class CovariantTest

{

public A getObj()

{

return new A();

}

}

class SubCovariantTest extends CovariantTest

{

public B getObj()

{

return new B();

}

}

public class TestPrg

{

public static void main(String[] args)

{

CovariantTest c = new SubCovariantTest();

System.out.println("c.getObj().x :: "+c.getObj().x);

System.out.println("c.getObj().getX() :: "+c.getObj().getX());

}

}

class A

{

int x = 5;

int getX()

{

return x;

}

}

class B extends A

{

int x = 6;

int getX()

{

return x;

}

}

Simple... Polymorphism is only applicable for functions. Not variables.

Variables will be resolved during compile time.

回答6:

I was looking at your code and was having some trouble compiling it. Getting error

The return type is incompatible with

CovariantTest.getObj()

I made a small change.

class A {

int x = 5;

}

class B extends A {

int x = 6;

}

public class CovariantTest {

public A getObj() {

return new A();

}

public static void main(String[] args) {

CovariantTest c = new SubCovariantTest();

A a = c.getObj();

System.out.println(c.getObj().x);

}

}

class SubCovariantTest extends CovariantTest {

public A getObj() {

return new B();

}

}

Stick a breakpoint in at the system out line and look at the a variable. It contains two x members, with one set to 5 and one to 6.

Starblue's answer explains this behaviour.

回答7:

c is typed as CovariantTest at compile time and thus the call to c.getObj() is bound to the method CovariantTest.getObj() at compile time (and that can't be modified at runtime).

Also, x exists in both A and B (it is shadowed, not overridden). Because the method being called is CovariantTest.getObj() and that method works with A, the x being retrieved is A.x even though the actual object is of type B.

来源:https://stackoverflow.com/questions/404804/java-covariants

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值