0

我目前正在将 AspectJ 应用到我们的项目中,我发现了一种对我来说有点奇怪的行为。

Q1: 我用inter-type声明给我当前的类增加了一个新的构造函数,发现如果用这个新的构造函数来实例化我的类,这个类的成员变量没有被初始化。

例如:

我将向其中添加新构造函数的类:

public class Child {

    public String name = "John";

    public Child(String desc) {
        // TODO Auto-generated constructor stub
    }
} 

方面J代码:

public aspect MyTest {
    public Child.new(String desc, int num) {
        System.out.println("Child Name:" + this.name);
    }
}

如果我用新的构造函数实例化 Child:

new Child("A child", 5)

成员变量this.name没有像原来的构造函数那样被初始化。

但是,如果我调用原始构造函数:

new Child("A child") 

成员变量this.name将像往常一样初始化为“John”

结果:

孩子姓名:空

这是 AspectJ 的限制吗?有没有办法解决这个问题?

我真的不想将成员变量初始化的代码添加到新的构造函数中。

Q2: 似乎在新添加的构造函数中,super.method()无法正确解析。

我将向其中添加新构造函数的类:

public class Child extends Parent{

    public String name = "John";

    public Child(String desc) {

    }
} 

Child扩展Parent父母有一个方法init()

public class Parent {

    public void init() {
        //....
    }

}

我在我的方面为Child添加了一个新的构造函数。

public aspect MyTest {
    public Child.new(String desc, int num) {
        super.init();
    }
}

上面的切面代码会触发异常。

Exception in thread "main" java.lang.NoSuchMethodError: com.test2.Child.ajc$superDispatch$com_test2_Child$init()V
    at MyTest.ajc$postInterConstructor$MyTest$com_test2_Child(MyTest.aj:19)
    at com.test2.Child.<init>(Child.java:1)
    at MainProgram.main(MainProgram.java:11)

我的解决方法是为我的类Child定义另一个方法,并在该方法中间接调用 super.method()

例如,为Child添加一个调用super.init()的新方法

public void Child.initState()
{
    super.init();
}

现在,我可以在新添加的构造函数中调用 initState(),如下所示:

public aspect MyTest {
    public Child.new(String desc, int num) {
        this.initState();
    }
}

这是 AspectJ 的限制吗?这是解决此问题的唯一方法吗?

谢谢大家的时间:)

4

3 回答 3

2

面对第一个问题,编译时似乎会出现 lint 警告:(除非您关闭 lint 警告)

“类型间构造函数不包含显式构造函数调用:目标类型中的字段初始值设定项将不会被执行 [Xlint:noExplicitConstructorCall]”

因此我会说这是AspectJ 的限制

最好的方法可能是在 AspectJ 添加的构造函数中调用Child的其他构造函数

例如:

public aspect MyTest {
    public Child.new(String desc, int num) {
        this("Hello"); // -> This will call the constructor of Child, and trigger fields initialization
        System.out.println("Child Name:" + this.name);
    }
}
于 2013-07-18T08:43:15.253 回答
1

对于第二个问题,我认为这是aspectJ的一个错误。反编译编织的目标字节码会发现会插入方法“com.test2.Child.ajc$superDispatch$com_test2_Child$init()V”。这意味着该方法应该由aspectJ生成,但字节码中没有这种方法。

于 2013-07-27T15:25:16.403 回答
0

ITD 介绍的代码与您直接添加到类的代码没有什么不同。因此,在您引入的构造函数中没有成员初始化代码,当然,成员将保持未初始化状态。因此,您需要按如下方式更改 Q1 中的代码。

public Child.new(String name, int age) {
    this.name = name;
    this.age = age;
    System.out.println("Child Name:" + this.name);
}

至于第二季度,它对我来说很好。

class Parent {
    public void init() {
    System.out.println("P.init");
}
}

class Child extends Parent {
}

aspect Intro {
    public void Child.init(){
        super.init();
        System.out.println("C.init");
    }
}

public class Main {
    public static void main(String[] args) {
        Child c = new Child();
        c.init();
    }
}

印刷:

P.init
C.init

将引入的方法更改为其他方法init也可以(以匹配您的代码)。

关于您的评论:我看不出您在第一季度有什么不同。对不起,我不明白。

至于您评论的 Q2 部分,构造函数安排对我有用:

class Parent {
    protected String name;

    public Parent(String name) {
        this.name = name;
    }
}

class Child extends Parent {
    int age;

    public Child(String name) {
        super(name);
    }
}

aspect Intro {
    public Child.new(String name, int age){
        super(name);
        this.age = age;
        System.out.println("this.name: " + this.name + " this.age: " + this.age);
    }
}

印刷this.name: myname this.age: 2

于 2013-07-15T17:54:12.280 回答