在匿名内部类中使用final对象会导致null

时间:2009-11-23 10:56:24

标签: java

我有一个包含以下代码的方法:

public void myMethod(){
    final MyDto expectedtDto = new MyDto();

    MyRepository reposWithMock = new MyRepository(){
        protected MyDao createDao(){

            return new MyDao() {
                public MyDto someMethod(){
                   return expectedtDto;
                }
            };

        }
    };

  reposWithMock.doSomethingWithDao();
}
MyRepository.createDao()的构造函数调用

MyRepository。 从MyDao.someMethod()调用MyRepository.doSomethingWithDao()

但是,MyDao().someMethod()会返回null而不是expectedDto

知道为什么会这样吗?

澄清一些实际工作代码:

package nl.tests;

public class TestAnon {
  static class MyDao {
    private int value;

    public MyDao(int value) {
        this.value = value;
    }

    public int getValue() {
        return value;
    }
  }

  static class Repository {
    private MyDao dao;

    public Repository() {
        dao = createDao();
    }

    protected MyDao createDao(){
        return new MyDao( 4 );
    }

    public MyDao getDao(){
        return dao;
    }
  }

  public static void main(String[] args) {
    final MyDao testDao = new MyDao(8);

    Repository repos = new Repository() {
        protected MyDao createDao() {
            if ( testDao == null ) {
                System.out.println( "Error ");
                return new MyDao(0);
            }
            return testDao;
        }
    };

    System.out.println( "Dao :" + repos.getDao().getValue() );
  }
}

这导致:

Error 
Dao :0

一些其他信息:我目前(必须)使用java 1.4。 我的开发环境是Rational Application Developer 7。

附录,给定(和接受的答案)。对于下面的代码,我将createDao()方法设为public:

public static void main(final String[] args) {        
    final MyDao testDao = new MyDao(8);    


    Repository repos = new Repository() {
        public MyDao createDao() {

            if ( testDao == null ) {
                System.out.println( "Error ");
                return new MyDao(0);
            }
            return testDao;
        }
    };

    System.out.println( "Dao :" + repos.getDao().getValue() );
    System.out.println( "Dao :" + repos.createDao().getValue() );
}

返回:

Error
Dao :0
Dao :8

6 个答案:

答案 0 :(得分:4)

它在Java 1.4中失败,因为在执行Repository的超级构造函数时,尚未初始化包含局部变量的字段。

它适用于Java 1.5及更高版本,因为在调用超级构造函数之前,该字段已初始化。

通常,调用可能在构造函数的子类中重写的方法是不好的方式,因为它会导致这类问题。

答案 1 :(得分:2)

根据您提供的快速测试输出MyDto@190d11或类似内容。所以我敢打赌你遗漏了一些重要的代码,这些代码负责隐藏变量名称。

Test.java

public class Test {
  public static void main(String args[]) {
    new Test().myMethod();
  }
  public void myMethod() {
    final MyDto expectedtDto = new MyDto();

    MyRepository reposWithMock = new MyRepository() {
      @Override
      protected MyDao createDao() {
        return new MyDao() {
          @Override
          public MyDto someMethod(){
            return expectedtDto;
          }
        };
      }
    };
    reposWithMock.doSomethingWithDao();
  }
}

MyDto.java

public class MyDto {}

MyRepository.java

public abstract class MyRepository {
  protected abstract MyDao createDao();
  public void doSomethingWithDao() {
    System.out.println(createDao().someMethod());
  }
}

MyDao.java

public abstract class MyDao {
  public abstract MyDto someMethod();
}

答案 2 :(得分:0)

确保您实际上覆盖了您认为自己所采用的方法。您的IDE或@Override应该提供帮助。

答案 3 :(得分:0)

MyDtoMyDao的孩子吗? 当方法显示您返回MyDao时,您返回MyDto 也许这是一个问题。

第二种解决方案可能是:
将expectedtDto放在内部类而不是方法中。

马亭

答案 4 :(得分:0)

您的代码适合我。我可以看到expectedDto在匿名内部类中可能为null的唯一方法是,如果您在没有正确同步的情况下在另一个线程上引用它。

答案 5 :(得分:0)

您描述的测试用例对我来说很好。

您应该提供最小但完整的独立测试用例,以说明获得帮助的问题。