我目前正在将AspectJ应用于我们的项目,我发现了一种对我来说有点奇怪的行为。
Q1: 我使用inter-type声明向我当前的类添加了一个新的构造函数,并发现如果使用新的构造函数来实例化我的类,则不会初始化类的成员变量。
例如:
我将添加一个新构造函数的类:
public class Child {
public String name = "John";
public Child(String desc) {
// TODO Auto-generated constructor stub
}
}
aspectJ代码:
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”
结果:
子名称:null
这是AspectJ的限制吗?无论如何都有解决这个问题的方法吗?
我真的不想将成员变量初始化的代码添加到新的构造函数中。
Q2: 似乎在新添加的构造函数中, super.method()无法正确解析。
我将添加一个新构造函数的类:
public class Child extends Parent{
public String name = "John";
public Child(String desc) {
}
}
儿童扩展父。 父的方法是 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)
我的解决方法是为我的班级孩子定义另一种方法,并在该方法中间接调用super.method()
例如,为儿童
添加一个名为 super.init()的新方法public void Child.initState()
{
super.init();
}
现在,我可以在新添加的构造函数中调用initState(),如下所示:
public aspect MyTest {
public Child.new(String desc, int num) {
this.initState();
}
}
这是AspectJ的限制吗?这是解决此问题的唯一方法吗?
谢谢大家的时间:)
答案 0 :(得分: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);
}
}
答案 1 :(得分:1)
对于第二个问题,我认为这是aspectJ的一个错误。 反编译编织目标字节代码将发现将插入方法“com.test2.Child.ajc $ superDispatch $ com_test2_Child $ init()V”。这意味着这个方法应该由aspectJ生成,但字节代码中没有这样的方法。
答案 2 :(得分:0)
ITD介绍的代码与您直接添加到类中的代码没有什么不同。因此,如果在引入的构造函数中没有成员初始化代码,成员当然将保持未初始化状态。因此,您需要在Q1中更改代码,如下所示。
public Child.new(String name, int age) {
this.name = name;
this.age = age;
System.out.println("Child Name:" + this.name);
}
对于Q2,它对我来说很好。
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
以外的其他方法也适用(以匹配您的代码)。
关于你的评论:我没看到你在Q1中有什么不同。对不起,我收不到。
对于评论的第2部分,构造函数的安排对我有用:
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