JLS:
的最低优先级操作者是lambda表达式的箭头( - >) ,随后由赋值运算符。
遵循哪个方向(增加优先级,减少优先级)?-“跟随”是指分配的优先级较高还是较低(相对于箭头运算符)?我猜想,这是因为“最低”(箭头)表示绝对最低。
据我了解,箭头(->)应该位于此Princeton运算符优先级表的最底部(在所有赋值运算符的下方),因此箭头(->)的优先级为0(零)(根据该表)。
我的理解正确吗?
ExamTray似乎说箭头优先级至少与分配相同。此外,还阐明了箭头的关联性是Left-> To-> Right(与分配不同)。我没有找到JLS的箭头关联性报价。
我一直认为分配优先级原则上最低。
java specifications operator-precedence language-lawyer java-8
给定一个f1() + f2()*f3()带有3个方法调用的表达式,java首先计算加法运算(的操作数):
int result = f1() + f2()*f3();
f1 working
f2 working
f3 working
Run Code Online (Sandbox Code Playgroud)
我(错误地)期望f2()首先被呼叫,然后被呼叫f3(),最后被呼叫f1()。因为乘法应在加法之前求值。
所以,我在这里不了解JLS-我想念什么?
15.7.3。评估尊重括号和优先权
Java编程语言遵守 由括号显式表示和由运算符优先级隐式表示的评估顺序。
在此示例中,如何精确地遵守运算符优先级?
JLS在15.7.5中提到了一些例外。其他表达式(方法调用表达式(§15.12.4),方法引用表达式(§15.13.3))的评估顺序,但是我不能将这些异常中的任何一个应用于我的示例。
我知道JLS保证二进制运算的操作数从左到右求值。但是在我的示例中,为了了解方法调用顺序,有必要了解首先考虑哪个操作(及其两个操作数!)。我在这里错了-为什么?
更多示例:
int result = f1() + f2()*f3() + f4() + f5()*f6() + (f7()+f8());
Run Code Online (Sandbox Code Playgroud)
自豪地生产:
f1 working
f2 working
f3 working
f4 working …Run Code Online (Sandbox Code Playgroud) java evaluation expression-evaluation operator-precedence jls
为什么ArrayList add()和add(int index,E)复杂度是分摊的常量时间?
为什么O(1)用于单个add()操作,O(n)用于单个add(int index,E)操作,O(n)用于添加n个元素(n add操作)使用任何(任何)add方法?假设我们使用add(int index,E)很少添加到数组端?
数组(和ArrayList)的一个操作复杂性不是已经有n个元素:
如果我们进行一百万次插入,1和2的平均值不能为O(1),对吗?
为什么甲骨文说
添加操作以分摊的常量时间运行,即添加n个元素需要O(n)时间.
我认为add()的复杂度为O(1),add(int index,E)的复杂度为O(n).
这是否意味着"n个操作的整体复杂性"(复杂度O(1)的每个操作)可以说是n*O(1)= O(n).我错过了什么?
也许对于Oracle"添加操作"总是意味着只有add()?而add(int,E)是"插入操作"?然后完全清楚!
我有一个猜测,它与渐近分析和摊销分析之间的差异有关,但我无法把握它到最后.
为什么数组插入的时间复杂度是O(n)而不是O(n + 1)?
JUnit 5 是模块化的。
我了解一切都基于平台模块( junit-platform-engine-1.3.2.jar):
Jupiter 模块(API + 引擎部件:junit-jupiter-engine-5.3.2.jar+ junit-jupiter-api-5.3.2.jar)和
Vitage 模块(API + 引擎部分:junit-vintage-engine-5.3.2.jar+junit-4.12.jar和hamcrest-core-1.3.jar)都使用平台模块作为基本模块。
但是什么是平台启动器,什么时候需要它?
我何时以及为什么需要它以及如何将其添加到pom.xml?
(图片来自此链接)
将 Jupiter(仅用于 JUnit 5 测试)和 Vintage(用于 Junit4/Junit3 兼容性 - 从 JUnit5 运行遗留 JUnit4 测试)到 pom.xml 是这样的(仅供将来参考):
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter-engine</artifactId>
<version>5.3.2</version>
<scope>test</scope>
</dependency>
<!-- Vintage Module to run JUnit4 from JUnit 5 -->
<dependency>
<groupId>org.junit.vintage</groupId>
<artifactId>junit-vintage-engine</artifactId>
<version>5.3.2</version>
<scope>test</scope>
</dependency>
Run Code Online (Sandbox Code Playgroud) class Test{
int p = (p=1) + p; // ERR "Cannot reference a field before it is defined"
int q = (q=1) + this.q; //fine!
void f() {
int t = (t=1) + t; // fine!
}
}
Run Code Online (Sandbox Code Playgroud)
在第一种情况下,我了解:执行赋值(或后续加法?)时,p被视为未声明。
但是,为什么一个方法内有不同呢?OK t不会被视为未初始化,因为(t = 1)在加法之前执行。好的,t不是一个字段,但是目前还没有声明!
我能以某种方式理解吗?还是我会记住这种差异?
也许这也与以下内容有关:
static int x = Test.x + (x=1) + Test.x; // produces 2
void f() {
int y = y + (y=1) + y; // ERR local variable y may not have been initialized
}
Run Code Online (Sandbox Code Playgroud)
为什么是2?首先以某种方式评估(x …
你能举几个模糊的例子(代码片段)吗?
我读过JLS,但我不明白这个概念.JLS没有提供代码示例.
隐藏在Base和Derived类的字段之间.
阴影位于字段和局部变量之间.
模糊 - 在什么(?)和什么(?)之间
SIDELINE:有趣的是,JLS表示如果隐藏来自父类的相应字段,则不会继承:
阴影与隐藏不同(§8.3,§8.4.8.2,§8.5,§9.3,§9.5),它仅适用于否则将被继承但不是因为子类中的声明的成员.阴影也不同于模糊(第6.4.2节).
我也知道类名,方法名和字段名都在不同的名称空间中:
// no problem/conflict with all three x's
class x {
void x() { System.out.println("all fine"); }
int x = 7;
}
Run Code Online (Sandbox Code Playgroud)
例子:
最后找到了一个例子,有些解释什么声称是模糊(它会导致编译错误):
class C {
void m() {
String System = "";
// Line below won't compile: java.lang.System is obscured
// by the local variable String System = ""
System.out.println("Hello World"); // error: out can't be resolved …Run Code Online (Sandbox Code Playgroud) public class Base {
<T> List<? extends Number> f1() {return null;}
List<? extends Number> f2() {return null;}
<T extends Number> List<T> f3() {return null; }
}
class Derived extends Base {
List<String> f1() {return null;} // compiles fine !!!
List<String> f3() {return null; } // compiles fine !!!
// compile ERR: return type is incompatible with Base.f2()
List<String> f2() {return null;}
}
Run Code Online (Sandbox Code Playgroud)
为什么在Derived类中定义重写方法f1()和f3()不会产生编译错误,比如Derived类中的重写f2()方法的定义(它给出编译错误"返回类型与Base.f2()不兼容")?
JLS中的子签名覆盖规则允许覆盖方法(在Derived类中)是非泛型的,而重写方法(在Base类中)是通用的.
未经检查的覆盖规则允许在子类List<String>而不是List<T>在Base类中生成返回类型.
但我无法解释下面的行为差异,我不明白为什么fin()和f3()覆盖Derived类中的定义成功编译(在Eclipse,SE8上),忽略了f3()的有界类型参数所施加的限制f1()的有界通配符!
PS我的猜测 - 在衍生编译器中的f1()和f3()中将两个方法视为仅返回"原始"列表 - 编译器首先进行擦除(此时仅在Derived!中),然后在Derived中比较这些已擦除的方法Base中未删除(迄今为止)的方法.现在未经检查的覆盖规则是正常的(并且不需要检查边界 - …
为什么静态和默认接口方法不能同步?
人们说synchronized是一个实现细节.那么,strictfp也是一个实现细节,但这并不妨碍在静态和默认接口方法上允许strictfp.
如果实现接口的类没有覆盖默认方法,则继承默认方法并使其已经同步可能非常方便.
我猜测synchronized(以及strictfp)不是继承的(我在这里吗?),但这并不能解释为什么strictfp也允许静态和默认接口方法.
static <T> void f1(Base arg1, T arg2) {
T loc = (T) arg1; // why Derived is "kind of cast" to String?
System.out.println(loc.getClass().getName()); // would print: Derived
}
f1(new Derived(), "sdf"); // T is String - inferred from arg2
class Base { }
class Derived extends Base { }
Run Code Online (Sandbox Code Playgroud)
我的想法是正确的:写作演员(T)意味着"编译器不能也不会检查这个演员".在编译时编译器不知道arg2会是什么(并且它可能是任何东西),因此编译器不能排除强制转换可以工作并且必须信任程序员.因此,在编译时永远不会检查此强制转换.在运行时,局部var声明看起来像Object loc = arg1;(在类型擦除之后).所以一切正常,因为编译器从不关心这个(T)演员?
PS:我的研究:这个,这个.这也很有意思("将原语转换为通用":( T)true)我的问题更明确地指出问题,问题还在于编译器是否检查了演员(T)并且没有分心有问题的代码示例.
为什么在接口中,从默认接口方法调用静态接口方法我不能使用this.staticInterfaceMethod(),而在常规类中,从实例方法调用静态类方法是完全有效的 this.staticClassMethod()(虽然它是不好的风格)?
同时,this在接口的默认方法中使用是完全有效的 - 我可以合法地执行以下操作:
interface I {
int MY_CONST = 7;
static void st_f() {}
default void f1() {}
default void f_demo() {
this.f1(); // fine!
int locvar = this.MY_CONST; // also fine!
this.st_f(); // c.ERR: static method of interface I can only be accessed as I.st_f
}
}
Run Code Online (Sandbox Code Playgroud)