TIJ学习笔记(三)——零散笔记(1)

这是Thinging in Java学习笔记的第三篇,主要是一些零散的笔记。
不足之处,欢迎斧正。

索引

Java 操作符优先级问题

int a = 1;
int b = 2;
System.out.println(a + b +"结束");
int + int = int
int +String = String
// 3结束

System.out.println("开始" + a + b +"结束");
String + int = String
String + int = String
String + String = String
// 开始12结束

System.out.println("开始" + a + b);
String + int = String
String + int = String
// 开始12

System.out.println(a + b + "中间" + a + b);
int + int = int
int + String = String
String + String = String
String + int = String
String + int = String
// 3中间12

System.out.println(a + b + "中间" + (a + b));
String + int = String
String + int = String
String + String = String
int + int = int
String + int = String
// 3中间3

       由上面的代码可以看出:

              1. System.out.print(println)中的 + 与正常的操作符操作是一样的。

              2. + 号计算遵循计算优先级法则。

              3. 一个字符串加上一个数字是把数字转换成字符串(toString)后再连接的,与数学计算无关。

别名现象

Tank t1 = new Tank();
Tank t2 = new Tank();
t1.level = 9;
t2.level = 47;
System.out.println("1: t1.level: " + t1.level +", t2.level: " + t2.level);
t1 = t2;
System.out.println("2: t1.level: " + t1.level +", t2.level: " + t2.level);
t1.level = 27;
System.out.println("3: t1.level: " + t1.level +", t2.level: " + t2.level);
/* Output:
 *1: t1.level: 9, t2.level: 47
 *2: t1.level: 47, t2.level: 47
 *3: t1.level: 27, t2.level: 27
 */

       在 1 的时候t1和t2还是相互独立的,但由于赋值操作的是一个对象的引用,所以修改t1的同时也修改了t2!

       为了防止出现“别名现象”(Aliasing),可以这样写

t1.level = t2.level;

方法调用中的别名问题

class Letter {
  char c;
}

public class PassObject {
  static void f(Letter y) {
    y.c = 'z';
  }
  public static void main(String[] args) {
    Letter x = new Letter();
    x.c = 'a';
    System.out.println("1: x.c: " + x.c);
    f(x);
    System.out.println("2: x.c: " + x.c);
  }
} 
/* Output:
 *1: x.c: a
 *2: x.c: z
 */

       在Java中方法调用传递的是一个引用

操作符提前停止(短路)

&& 运算符

public static void main(String[] args) {
    boolean b = test1()&&test2()&&test3();
    System.out.println(b);
}
public static boolean test1(){
    System.out.println("test1");
    return true;
}
public static boolean test2(){
    System.out.println("test2");
    return false;
}
public static boolean test3(){
    System.out.println("test3");
    return true;
}
/* Output:
 * test1
 * test2
 * false
*/

       当&&运算符发现有错误(false)时,立即返回错误(false),而不进行后面的运算了。

|| 运算符

public static void main(String[] args) {
    boolean b = test1()||test2()||test3();
    System.out.println(b);
}
public static boolean test1(){
    System.out.println("test1");
    return false;
}
public static boolean test2(){
    System.out.println("test2");
    return true;
}
public static boolean test3(){
    System.out.println("test3");
    return true;
}
/* Output:
 * test1
 * test2
 * true
*/

       当&&运算符发现有正确(true)时,立即返回正确(true),而不进行后面的运算了。

       利用这一特性,我们可以将易于判断(运算量小)的操作放在前面,以优化代码运行时间。

字符串连接耗时

public static void main(String[] args) {
        test1();
        test2();
    }
    public static void test1(){
        long startTime=System.nanoTime();
        String a = "String a",b = "String b",c = "String c";
        String d = "";
        for(int i=1;i<10000;i++){
           d = d + a + b + c;
        }
        long endTime=System.nanoTime();
        System.out.println("程序运行1时间: "+(endTime-startTime)+"ns");
    }
    public static void test2(){
        long startTime=System.nanoTime();
        String a = "String a",b = "String b",c = "String c";
        StringBuilder stringBuilder = new StringBuilder();
        for(int i=1;i<10000;i++){
            stringBuilder.append(a);
            stringBuilder.append(b);
            stringBuilder.append(c);
        }
        long endTime=System.nanoTime();
        System.out.println("程序运行2时间: "+(endTime-startTime)+"ns");
    }
/* (JDK11)
 * 程序运行1时间: 232712818ns
 * 程序运行2时间: 1746122ns
 */
/* (JDK10)
 * 程序运行1时间: 239926036ns
 * 程序运行2时间: 1238935ns
 */
/* (JDK8)
 * 程序运行1时间: 1314058092ns
 * 程序运行2时间: 494996ns
 */

       可以看出,直接用 + 号连接无论在哪个JDK版本都会比 StringBuilder 慢。

       在JDK8以后(准确是JDK9),String的 + 连接进行了优化,但StringBuilder的速度却下降了(?)。

       不过即使在这种情况下,StringBuilder也比直接+快200倍以上,如果是JDK8这个倍数可以达到2600倍!

goto语句 Java中的跳转

int x=10;
test1:
for(int i=0;i<3;i++) {
    switch (x) {
        case 10:
            System.out.println("case 10");
            break test1;
        default:
            System.out.println("default");
            break;
    }
}
System.out.println("End");
/* Output:
 * case 10
 * End
 */
int x=10;
test2:
for(int i=0;i<3;i++) {
    switch (x) {
        case 10:
            System.out.println("case 10");
            continue test2;
        default:
            System.out.println("default");
            break;
    }
}
System.out.println("End");
/* Output:
 * case 10
 * case 10
 * case 10
 * End
 */

       Java中没有goto语句,但可以使用 continue label; 或 break label; 来进行跳转。

       在Java中,标签起作用的唯一的地方刚好是在迭代语句之前。

       continue lable; 同时中断内部迭代以及外部迭代,直接转到 label 处,随后继续进入迭代。它实际上是继续迭代过程,但却从外部迭代开始。

       break label; 也会中断所有迭代,并回到 label 处,但并不重新进入迭代。也就是说,它实际是完全终止了两个迭代。

参考资料

《Thinking in Java》 Fourth Edition ——Bruce Eckel

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值