java 运算符及初始化
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,可以通过break
和continue
关键字实现一些类似与跳转的功能;
比如:
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
看上述代码,其输出结果为:
说明编译器会给每个成员变量一个初始值,即使它已经被显示初始化了;
静态数据的初始化
无论创建多少对象,静态数据始终都只占据一份存储区域,