数据结构及算法Thinking in java

java 运算符及初始化

2017-11-01  本文已影响0人  谁吃了我的薯条

1、自动递增和递减

 {
        int i=1;
        int j=1;
        System.out.println("i++="+(i++));
        System.out.println("++j="+(++j));
        System.out.println("i="+i);
        System.out.println("j="+j);
        System.out.println("i--="+(i--));
        System.out.println("--j="+(--j));
    }

观察一下,这些计算的答案为多少:

 i++=1
 ++j=2
 i=2
 j=2
 i--=2
 --j=1

前缀表达式,先执行计算再返回值,即返回的值为已经计算过的值;
而后缀表达式先返回值,在进行计算,返回的是计算前的值;

2、字符串操作符+和+=

    {
       String s="hello";
       System.out.println(s+" "+1+2+3);
       System.out.println(s+" "+(1+2+3));
       s+=1+2+3;
       System.out.println(s);
       s+=123;
       System.out.println(s);
    }

字符串后跟+或者+=默认执行字符串转换的方式(隐式地调用了toString()方法)

3、逻辑运算符短路

先看一个例子:

static boolean test1(int val){
        System.out.println("test1("+val+")");
        System.out.println("result:"+(val<1));
        return val<1;
    }
    static boolean test2(int val){
        System.out.println("test2("+val+")");
        System.out.println("result:"+(val<2));
        return val<2;
    }
    static boolean test3(int val){
        System.out.println("test3("+val+")");
        System.out.println("result:"+(val<2));
        return val<2;
    }

 public static  void main(String args[])
    {
        boolean b=test1(0)&&test2(2)&&test3(3);
        System.out.println(b);
    }

以上运算的输出为多少?

test1(0)
result:true
test2(2)
result:false
false

从结果可看到,test3()没有执行,这是因为&&与操作符,一旦有一个为false值,其后面的操作不会再进行执行;
而如果将表达式改为:
boolean b=test1(0)&test2(2)&test3(3);
输出结果会变成:

  test1(0)
  result:true
  test2(2)
  result:false
  test3(3)
  result:false
  false

4、What goto?

java中保留着goto,但是在语言中并没有使用它;java,可以通过breakcontinue关键字实现一些类似与跳转的功能;
比如:

public class tesk {

    static boolean test1(int val){
        System.out.println("test1("+val+")");
        System.out.println("result:"+(val<1));
        return val<1;
    }
    static boolean test2(int val){
        System.out.println("test2("+val+")");
        System.out.println("result:"+(val<2));
        return val<2;
    }
    static boolean test3(int val){
        System.out.println("test3("+val+")");
        System.out.println("result:"+(val<2));
        return val<2;
    }
    public static  void main(String args[])
    {
      int i=0;
      outer:
        while (true){
          System.out.println("outer while loop");
          while (true){
              i++;
              System.out.println("i="+i);
              if(i==1){
                  System.out.println("continue");
                  continue ;
              }
              if(i==3){
                  System.out.println("continue outer");
                  continue outer;
              }
              if(i==5){
                  System.out.println("break");
                  break ;
              }
              if(i==7){
                  System.out.println("break outer");
                  break outer; 
              }
          }
        }

    }
}
----
outer while loop
i=1
continue
i=2
i=3
continue outer
outer while loop
i=4
i=5
break
outer while loop
i=6
i=7
break outer

从结果可看出:
continue回会退到最内层循环的开头;
continue带标签,回会退到标签所在的位置,并重新进入循环;
break会中断并跳出当前循环
break带标签,会中断,并跳到标签所指的循环;
标签慎用,因为会造成程序难以分析,不好进行调试;

5、初始化

初始化和清理是涉及到安全的两个重要因素;
java引入了构造器的概念进行类成员变量的初始化;
其主要解决了两个问题:
1、保证每个成员变量都被初始化;
2、解决了命名问题,它与它的类名相同;
不接受任何参数的构造器被称为默认构造器,又被称为无参构造器;
当类中未定义任何构造器时,它默认的调用了无参构造器,并采用默认赋值为每个成员变量赋值;同时,一旦存在有参构造器,则此默认无参构造器不起作用;

方法的重载:
类的方法允许进行重载,即永远相同的方法名称,但是默认参数不同;
例如:

public class couse {
    private int id;
    public couse(){} //无参构造方法
    public couse(int id){ //有参构造方法,构造方法的重载
        this.id=id;
    }

    public int getId() {  //成员方法
        return id;
    }
    public int getId(int index){ //成员方法的重载
        return id+index;
    }
}

区分重载的方法:采用参数类型进行区分
为什么不采用返回值作为区分呢?
看下面一个例子:

   public int getId() {  //成员方法
        return id;
    }
    public void getId(){
        return id;
    }

如果我们调用方法:
getId()怎末判定调用的是哪一个,因为有时候,返回值是不需要用到的,不知道返回值的类型,所以会造成jvm的无法解析;
关于无参构造方法的默认值,参照http://www.jianshu.com/p/20a644b8e8c8

this关键字
this在构造器中的使用,如果在构造器中调用构造器,例如:

public class couse {
    private int id;
    private int nums;
    public couse(){
        this(0,0); 
       // this.id=12; //调用两次回报出错误
    } //无参构造方法
    public couse(int id){ //有参构造方法,构造方法的重载
       this(id,0);
    }

    public couse(int id, int nums) {
        this.id = id; //this 指明id为哪个id
        this.nums = nums;
    }
}

6、清理:终结处理和垃圾回收

java的垃圾回收器,负责回收无用对象占据的内存资源,但是,如果有一块特殊的内存(非new创建分配的),垃圾回收期无法处理它;
因此,java中定义了一个finalize()方法,
内存被清理的条件:

public class Book {
    boolean checkout=false;
    Book(boolean checkout){
        this.checkout=checkout;
    }
    public void checkin(){
        checkout=false;
    }

    @Override
    protected void finalize() throws Throwable {
        if(checkout){
            System.out.println("error,has book not be checked");
        }
        //super.finalize();
    }
    public static void main(String args[]){
        Book book=new Book(true);
        book.checkin();;
        new Book(true);
        System.gc();//强制终结状态
    }
}

---
error,has book not be checked

7、垃圾回收器

常见的垃圾回收机制:

引用计数法
顾名思义,将每个对象添加一个引用计数器,当对象的增加一个引用时,其计数器加1,当其引用离开作用域或者变为null时,其计数器减少1,当计数器为0时,该对象被清除;
此种方法简单但是效率低下,而且当存在循环引用时,起计数器不会清零,但是此类对象需要被回收;
自适应的垃圾回收机制
主要机理为:对任何存活的对象,一定可以追溯到其静态存储区或者堆栈;因此从静态存储区或者堆栈开始进行遍历,找到所有存活的对象,将其复制到另一个堆上,没有被复制的全部都是垃圾,这些对象可以被自动回收了;
但是,这种方法效率会降低,因为要保有两个堆,这样内存多出一倍,而且若垃圾较少的时候进行复制的话,造成巨大浪费,因此此种停止-复制的方法,在垃圾较少的时候切换到了另一种工作方式;
标记-清扫,标记清扫的方式速度很慢,但是当垃圾很少的时候,起执行速度就会很快;
标记-清扫采用类似的方法,从静态存储区和堆栈出发,遇到存活的对象,就会给对象一个标记,这个过程不会进行垃圾回收动作;当全部对象标记完毕后,开始进行清理,但是清理过后,其堆空间不是连续的;

8、成员初始化

public class couse {
    private int id;
    public couse(){
        System.out.println(id);
        id=7;
        System.out.println(id);
    }

    public static void main(String args[]){
        couse c=new couse();
    }

}

0
7

看上述代码,其输出结果为:
说明编译器会给每个成员变量一个初始值,即使它已经被显示初始化了;
静态数据的初始化
无论创建多少对象,静态数据始终都只占据一份存储区域,

上一篇下一篇

猜你喜欢

热点阅读