我反编译了Java(实际上是Dalvik)字节码。在方法开始时,我直接访问实例成员的字段(即,不通过getter进行访问)。
似乎Java调用Object.getClass()
了访问的实例成员(mOther
),但未在任何地方使用结果。这是某种检查吗?为什么需要这个电话?我怀疑这是因为我直接访问一个字段(在该类中定义),但是看不到连接。
Java代码和反编译的字节码如下。
(请注意,最后一条指令加载lifeTime
为常量,0x0001
因为在中MyOtherClass
,我有lifeTime
一个public final
字段,并且当前是从代码初始化的。)
MyOtherClass other = mOther;
if (mAge >= other.lifeTime) { // lifeTime is initialized to 0x0001
end();
return;
}
.line 53
move-object/from16 v0, p0
iget-object v0, v0, Lcom/example/engine/MyClass1;->mOther:Lcom/example/engine/MyOtherClass;
move-object/from16 v16, v0
.line 54
.local v16, other:Lcom/example/engine/MyOtherClass;
move-object/from16 v0, p0
iget v0, v0, Lcom/example/engine/MyClass1;->mAge:I
move/from16 v18, v0
// Why is Object->getClass() called?
invoke-virtual/range {v16 .. v16}, Ljava/lang/Object;->getClass()Ljava/lang/Class;
const/16 v19, 0x0001
在评论中有人要求我提供该方法的完整源代码。请注意,这mOther
是最后一个字段(出于性能原因)。您在这里:
@Override
public void doStep() {
MyOtherClass other = mOther;
if (mAge >= other.lifeTime) {
end();
return;
}
mAge += TICK_TIME;
boolean isSurrounded = false;
if (mAge > mLastSurroundTime + other.surroundingTime) {
int distance = (int)other.maxSurroundDistance;
for (int bx = bx0; bx <= bx1; ++bx) {
if (bx < 0 || bx >= mSize) { continue; }
for (int by = by0; by <= by1; ++by) {
if (by < 0 || by >= mSize) { continue; }
ArrayList<WorldObject> candidates = getCandidatesAtPos(bx, by);
for (int i = 0; i < candidates.size(); ++i) {
WorldObject obj = candidates.get(i);
if (mSelf!= obj && mSelf.getDistanceFrom(obj) <= other.maxSurroundDistance) {
obj.notifyDangerImminent(mSelf);
isSurrounded = true;
}
}
}
}
if (isSurrounded) { mLastSurroundTime = mAge; }
}
}
我假设lifeTime是在声明时分配的最终字段:
final int lifeTime = 0x0001;
如果是这样,则按以下方式优化字节码(它与VM几乎没有关系,纯编译器不可思议):
一个简单的例子:
class Test {
private final int myFinalField = 1;
int test(Test t) {
return t.myFinalField;
}
}
如果我们看一下test()方法的字节码(这次是JVM,但是如果您将其转换为Dalvik,则本质上是相同的),这也是对getClass()的调用:
// access flags 0x0
test(LTest;)I
L0
LINENUMBER 5 L0
// load t
ALOAD 1
// if (t == null) throw new NullPointerException(); compressed in only two instructions
INVOKEVIRTUAL java/lang/Object.getClass ()Ljava/lang/Class;
POP
// the actual value of myFinalField
ICONST_1
IRETURN
L1
LOCALVARIABLE this LTest; L0 L1 0
LOCALVARIABLE t LTest; L0 L1 1
MAXSTACK = 1
MAXLOCALS = 2
问题内容: 在大学里学习时,我不得不做一些难看的Java基础知识,例如不使用封装就可以工作,同一类中的主要方法等。(我不想在Java样式指南上展开讨论,我只是想澄清一下,我不会在大学以外写这样的东西) 我偶然发现了一种我无法向自己解释的行为: 为什么这段代码可以编译并正确运行?我怎么可能访问私有字段?由于主类位于同一类中,因此行为异常? 问题答案: 由于静态方法是类的成员,因此可以访问中的任何私有
我的问题是为什么找不到“name”字段?
我正在修改我以前使用的Visitor模式。我们有基类Element,它有虚拟方法接受(Visitor),并且这个方法在继承自Element的所有类中都被重写。在任何派生类中,接受()所做的就是调用visitor- 为什么客户不能直接打电话给访客- 调用元素中有哪些有用的信息。接受(访客),然后依次呼叫访客。参观(元素)?这使得Visitor模式的使用很麻烦,并且在所有元素类的层次结构中都需要额外的
问题内容: 为什么Java编译器不会让我把成,是8位长,而这正大小的数据类型。 有人可以解释为什么1有效,为什么2不有效吗? 编辑 我读了答案,声称0xff是255,怎么办?不是吗,是什么导致0xff,-128或255或其他原因。为什么不将其视为字节,而不是将该字节的8位视为1。 问题答案: 在Java 类型是一个8位有符号整数类型与在范围内的值来。文字表示哪个超出了该范围。 在第一个示例中,您试
问题内容: 当我从中读取源代码时,我很困惑为什么它编写了这样的代码: 为什么使用别名而不是直接使用field变量,如下所示: 有人可以给出合理的解释吗? 问题答案: 如果您是从上下文中看这段代码,那么对于“别名”将没有很好的解释。它仅仅是冗余代码或不良的代码样式。 但是上下文是可以被子类化的类,它需要在多线程上下文中工作。 线索是,在宣布IS 。这意味着子类有可能进入并分配给。考虑到这种可能性,实