一、异或
可以用异或来实现交换两个变量的值:
原理是:(x^y^y)==x;
如果一个变量异或另一个变量两次,将会得到异或以前的值;
因此可以使用该性质来实现对两个变量值的交换。
x=x^y;//将异或的中间结果存储在x中
y=x^y;//利用上面的原理,将x异或y两次,得到以前的x值,赋值给y
x=x^y;//异或x两次,得到以前y的值,赋值给x
二、循环语句的调整
1.嵌套循环的调整
//第一种循环:外层循环次数大于内层循环
int v1=100;
int v2=100;
int v3=10;
for(int i=0;i<v1;i++){
for(int j=0;j<v2;j++){
for(int k=0;k<v3;k++){
dosomething();
}
}
}
//第二种循环:外层循环次数小于内层循环
int v1=100;
int v2=100;
int v3=10;
for(int i=0;i<v3;i++){
for(int j=0;j<v2;j++){
for(int k=0;k<v1;k++){
dosomething();
}
}
}
由于CPU在内外之间的切换会有一定的开销,因此如果可能的话,应该尽可能较少内外层循环切换的次数。只需使最外层循环的次数最少,内层循环次数多即可。
2.重复使用的调整
//第一种:每次循环都要重新计算upperLimit(),造成浪费
for(int i=0;i<upperLimit();i++){
dosomething();
}
//第二种:先在循环外将定值upperLimit()赋值给upper,不需每次循环都重新计算,但因为upper是在循环外,如果误用upper可能会造成错误
int upper=upperLimit();
for(int i=0;i<upper;i++){
dosomething();
}
//第三种:在for循环初始条件中先计算好upperLimit()使得upper只能再循环中起作用
for(int i=0,upper=upperLimit();i<upper;i++){
dosomething();
}
3.在循环中使用StringBuilder拼接对象
//使用“+”对String对象进行连接,如下所示。不过由于String对象时不可改变的,
//每次对String对象的拼接都会重新创建一个对象,以前的对象被丢弃,造成时间和空
//间的浪费
public String getString(String[] arr){
String result="";
for(int i=0;i<arr.length;i++){
result+=arr[i];
}
return result;
}
//相对于String的不可变性,Java中提供了相应的可变类——StringBuilder,因为
//StringBuilder是可以改变的,在拼接的过程中直接改变原来对象,而不是创建新的
//对象,这样可以提高效率,程序修改如下(需要使用到StringBuilder中的成员方法
//append()和toString()):
public String getString(String[] arr){
StringBuilder result=new StringBuilder("");
for(int i=0;i<arr.length;i++){
result.append(arr[i]);
}
return result.toString();
}
4.跳转控制——循环标签
Java中不能使用C/C++中的goto语句,但是可以使用循环标签来实现循环的跳转。当程序存在多重循环嵌套语句时,如果需要直接跳出最外层的循环(使用break),或是中止内层的循环,而从外层的循环继续进行(使用continue),都可以用循环标签实现
C/C++中goto语句可以随意跳转;但Java中循环标签只能跳出循环
- 循环标签也可以放在与循环不相关的位置,只是这样做这个循环标签就没有什么意义了,而且循环体内就不能使用该标签(原因请看下一个要求);
- 如果循环体中使用了某个标签,那么该标签与循环之间不能有任何语句(注释除外)。例如:
public void labelTest(){
label1:
dosomething();
label2:
//循环标签和循环体之间不能有任何语句(注释除外)
while(true){
for(int i=0;i<100;i++){
for(int j=0;j<100;j++){
if(i==10||j==10){
break label2;//直接跳出最外层的循环(即跳出while循环)
}
}
}
}
}
5.for/in循环
即for(item:collecion)循环依次对collection中的每个元素进行相关的操作,使得循环方便很多。例如:
public static void main(String[] args){
for(String s:args){
dosomething();
//相当于是将args数组中的元素依次赋给s,因此如果s是基本数据类型(即int,long,
//float等),在循环体中修改s的值并不会改变args,但是如果s是引用数据类型
//(即String等),则修改s也就会修改args.
}
}
for/in循环的局限:
只能对集合或者数组的全部元素进行顺序操作,而在某些情况下,我们可能只需
- 对其中部分元素进行操作,
- 或者非顺序操作,
这时就不能用for/in循环。
三、数组
1.数组的声明
- Java中声明数组的时候不能指定数组的大小,如下声明是错误的:
int[5] array;
int array[5];
- 这两种声明也是有些细小区别的,如下:
int[] array1,array2;//int[]后面的array1和array2都是数组
int array3[],array4;//带[]的array3是数组,而后面的array4不是数组
2.数组的初始化
(1)一维数组的初始化有两种方式:
int[] a={1,2,3,4,5};//声明并直接初始化和赋值
int[] a=new int[5];//声明并指定数组的大小,但并未赋值
第二种方式,如果要赋值的话,可以这样:
int[] a=new int[]{1,2,3,4,5};//如果直接赋值的话就不能指定数组的大小。
//即以下做法是错误的:
int[] a=new int[5]{1,2,3,4,5};//错误做法
(2)多维数组的初始化
在Java中多维数组可以是不规则的(每维的元素个数可以不同),在为多维数组分配空间时一定要从高维到低维分配:
int[][] a=new int[3][];
a[0]=new int[2];
a[1]=new int[3];
a[2]=new int[4];
对于矩阵数组(即每维元素个数相等),则可以采用比较简单的分配方式:
int[][][] a=new int[2][3][4];//一共有三维,2*3*4
(3)arraycopy的使用
arraycopy可以实现对数组的复制。
arraycopy的申明原型:
public static native void arraycopy(Object src,int srcPos,Object dest,int destPos,int length);
arraycopy对基本数据类型和对象型数据类型的作用效果是不同的;
- 如果数组元素类型为基本数据类型,那么数组复制后就类似于基本数据类型数据之间的赋值。
- 如果数组元素类型为引用类型,那么数组复制之后就类似于引用类型变量的赋值,赋值后两个引用指向同一内存单元,其中一个引用对对象所做的任何改变将直接影响到另一个引用。
(四)参数传递
Java中的参数传递都是按值传递,没有像C++中的按引用传递(使用&)
1.基本数据类型的参数传递:
public static void pass(int ax,int bx){
//在调用方法时(如pass(a,b)),相当于进行了如下的隐含操作:
//ax=a;
//bx=b;
ax=5;
bx=29;
}
2.参数传递的是对象的引用
需留意修改的是引用本身,还是对象。
3.数组参数传递
4.String参数传递
(五)访问修饰符
访问修饰符 | 可见范围 |
public | 所有 |
protect | 本类中,本包中,包外子类 |
默认 | 本类中,本包中 |
private | 本类中 |