天天看点

黑马程序员--Java基础之语法和数组总结

------- android培训、 java培训、期待与您交流! ----------       标识符的命名:由26个英文字母的大小写、0-9数字、_和$字符组成,数字不可以作为开头,不能使用关键字,为了提高阅读性,尽量使用有意义的单词。java中的命名规范,包名:多单子组成时所有字母都小写xxyyyzzz,类名接口名:多单词组成时,所有的单词首字母大写XxxYyyZzz,变量名函数名:多单词组成时第一个单子小写,第二个单词开始首字母大写xxxYyyZzz,常量名:多有字母大写,单词之间用下划线_连接XXX_YYY_ZZZ。       整数的进制形式:任何数据在计算机中都是以二进制形式存在的,即0或者1组成的数值。为了方便表示数据,人们将二进制缩短表示,从而有了十进制、八进制、十六进制三种形式。十进制是0-9,满10进1,八进制是0-7,满8进1,开头用0表示,十进制是0-9,A-F,满16进1,开头用0x表示。举例说明,十进制数60,二进制是111100,八进制是074,十六进制是0x3c。负数的二进制表现形式其实就是负数的取反再加1。       转义字符:通过\来转变后面字母或者符号的含义

\n:表示换行
\b:退格,相当于Backspace
\r:按下回车键,windows系统下回车符是俩个字符\r\n
\t:制表符,相当于tab键
           

      类型的转换问题:运算中会遇到类型的转换问题,这涉及到类型的自动转换。

int a=1;
a=a+3;
a+=3;
//以上运行没有问题
short s=1;
s=s+3;//运行会出错,报类型错误
s+=3;//运行没有问题
/*
s=s+1做了俩次操作,一次是加法运算,一次是赋值运算,加法运算时s是short类型,加上一个整型3后,低类型的short自动转换成整型,所以结
果是将整型赋值给short类型的s,那么此时必然会出现类型错误。同样的道理,a本来是整型,它的运算是没有错误的。
s+=3只做了一次赋值运算,它就像short s=1时的赋值,会产生一个自动装换类型的动作,将整型1转换成了short类型,这样的运行结果没有问题。
*/
s=(short)(s+3);//这样做过强制类型转换后才是正确的
           

       &和&&,|和||的特点:&无论左边是true或者false,右边都运算,&&当左边为false时,右边不运算。|两边都参与运算,||当左边为true时,右边不参加运算。       位运算的使用方法:计算机运算时,最快的运算方法是位运算,其中包括左移(<<)、右移(>>)、与(&)、或(|)、异或(^)、反码(~)。       3<<2;//结果为12,即3*2的2次幂,乘以2的移动的位数次幂

      12>>2;//结果为3,即12/2的2次幂,除以2的移动的位数次幂

      3<<2示例:

      3的二进制:        0000-0000 0000-0000 0000-0000 0000-0011

      左移2位后:        0000-0000 0000-0000 0000-0000 0000-1100(末尾用0补)

      12>>2示例:

      12的二进制:      0000-0000 0000-0000 0000-0000 0000-1100

      右移 2 位 后:     0000-0000 0000-0000 0000-0000 0000-0011(前面用最高位0补)

      >> 最高位补什么由原有数据的最高位值而定

      如果最高位0,右移后,用0补空位

      如果最高位1,右移后,用1补空位

      >>>无论最高位是什么,右移后都用0补

      &,|,^,~即将数字转换成二进制形式,再对其进行相应的运算。注意:一个数异或一个数俩次还是它本身。

      示例:6&3=2;       6|5=7;      6^5=3;      ~6=-7;

                  110            110          110          ~ 0000...0110

                &011           |101         ^101            1111...1001//最高位是1则为负数,正数取反再加1即为负数,相反操作后(减1再取反)得到为7,即值为7的负数

                 -------          -------        -------

                   010 =2      111 =7     011 =3       效率最高的运算方法:正常运算时我们计算2乘以8即2*8,但是计算机最终运算还是转换成位运算,所以运算时直接写成位运算是效率最高的方法,即写成2>>3。       俩个整数值进行互换的三种方法:分别是需要第三方变量和不需要第三方变量,其中不需要第三方变量时包含俩种方法。

int m = 5, n = 8;
		// 需要第三方变量的方法,该方法简单易懂,实际开发中基本都使用该方法
		int tmp = m;
		m = n;
		n = tmp;
		System.out.println("m=" + m + ",n=" + n);
		//使用累计俩数之和再分别求差值
		m=m+n;
		n=m-n;
		m=m-n;
		System.out.println("m=" + m + ",n=" + n);
		//使用 一个数异或另一个数俩次还是该数本身的原理
		m=m^n;
		n=m^n;
		m=m^n;
		System.out.println("m=" + m + ",n=" + n);
           

      switch语句结束的注意点:在使用switch语句时,每当匹配到相应的值则执行相应的case语句块,若不存在匹配的语句块则执行default,当default执行完毕后,按照从上往下的顺序继续执行到switch语句块的末尾}处。若满足一个条件,default在上方或者中间时,而又匹配到default去执行它的语句,那么当default执行完毕后,程序switch语句不是执行结束,而是接着往下执行。

int a = 7;
		switch (a) {
		default:
			System.out.println(a);//a是7,当程序判断完既不是1也不是2后执行到此处的default
		case 1:
			System.out.println(a);//程序执行完default后不是结束程序,而是再继续向下执行
			break;
		case 2:
			System.out.println(a);
			break;
		}//最终结果输出了2个7
           

      while和do-while的区别:while(循环条件) {循环体}是先判断循环条件,再执行循环体,do{循环体}while(循环条件)是先执行循环体,再执行循环条件,当满足循环条件处于临界值时,俩者可能会出现结果的不同。

int sum=5;
		while(sum<5){
			sum++;
		}
		System.out.println(sum);//循环结束后输出结果是5,先判断5是否小于5,不满足条件不执行循环,sum仍然是5
		sum=5;
		do{
			sum++;
		}while(sum<5);
		System.out.println(sum);//循环结束后输出结果是6,先执行循环sum加1后是6,然后判断sum是否小于5,不满足条件不执行下次循环,sum是6
           

      栈和堆的一些特点:栈存放的是局部变量内容,例如方法中定义的变量,方法参数定义的变量,for()循环中定义的变量,另外main方法,调用的show方法都是在栈中开辟的,在栈中开辟的内存空间一使用完则立即释放。int[] x=new int[3],其中x是临时变量存放在栈中,而所有new出来的实体都是存在堆中,该数组在堆中开辟了一个存放数组值的空间,该空间的首地址值(起始位置)保存在变量x中,即首地址指向了x,访问数组x时则通过其首地址来访问。堆有三个特点,第一是堆内存的实体都有空间地址值,所有在堆中开辟空间的实体都有一个地址值,通过该地址访问存放在堆中的数据;第二是堆内存的实体的都有默认初始化值,例如int数组的初始化值都为0,float数组初始化值都为0.0f,double数组初始化值都为0.0,boolean数组初始化值都为false,string数组初始化值都为""空;第三是堆内存垃圾回收机制,当堆空间中的实体不再被使用时(没有任何引用使用它,例如x=null后,x原有的引用空间变成废空间,或者x被重新赋值新的引用),jvm虚拟机会不定时清理释放内存。java成长于c++,内存空间的优化比c++好,c++是程序员手动释放垃圾内存,若忘记释放则可能导致程序越用越卡,甚至导致死机,而java是jvm虚拟机不定时调用垃圾回收机制来释放内存。       选择和冒泡排序方法:排序有许多种方法,比较容易理解和常用的方法是一下的选择和冒泡排序,另外还有快速排序、哈希排序等,效率最高的是哈希排序。Java中封装了一种优化好的排序方法,即Arrays.sort(arr)这种方法,它是开发中比较常用的方法。排序的本质都需要进行元素位置的互换,下面排序中的互换都是在堆内存中进行频繁的互换,相对而言比较耗内存,可以使用临时变量存储下标,最后比较完毕时再将相应的元素进行互换,这样减少了数组元素互换的次数,使用临时变量代替,原理是减少了堆内存的交换次数而用栈内存的交换代替,优化了性能。       1、选择排序原理:从第一个元素开始和后面每一个元素比较,将最小元素放到第一个元素处,然后从第二个元素开始向后比较,将第二小的元素放在第二个位置,依次进行长度-1次的比较。

for(int i=0;i<a.length-1;i++)
		{//外层循环条件是长度-1次,因为最后一次不需要比较,只剩下一个最大值在末尾
			for(int j=i+1;j<a.length;j++)
			{//内层循环每次都是拿当前i元素的后一个开始比较,按次向后直到最后一个,将每一个元素和起始的元素比较
				if(a[i]>a[j])
				{//每当起始元素比和它比较的元素大时,将它们互换,保证每层内循环结束都是最小元素在i的起始位置
					int tmp=a[i];
					a[i]=a[j];
					a[j]=tmp;
				}
			}
		}
           

       2、冒泡排序原理:将相邻的俩个元素进行比较,一直比较到最后一个元素,最大的元素将被换到最后一个位置,然后继续从第一个元素开始俩俩相邻比较,一直比较到倒数第二个,下一轮则比较到倒数第三个,每轮比较将小的元素往前浮,类似冒泡。

for (int i = 0; i < a.length-1; i++) {//外层循环执行长度-1次,俩俩相邻比较,最后一次是一个最值不需要
			for (int j = 0; j < a.length - i - 1; j++) {//由于每轮比较的最值在最后,每轮比较次数都减少,-i让每次比较的元素减少
				if (a[j] > a[j + 1]) {//-1是为了让元素角标不越界,若j能取到length-1,则a[j+1]即a[length]是取不到的
					int temp = a[j];
					a[j] = a[j + 1];
					a[j + 1] = temp;
				}
			}
		}
           

      3、排序的位置置换功能抽取:排序的核心是元素的位置置换,不管什么排序都需要,我们可以将其功能抽取封装成一个方法。

//参数列表的数组是用来获取数组地址从而使元素交换,整型a和b是用来存储交换的俩个元素下标
	public static void swap(int[] arr, int a, int b) {
		int temp = arr[a];
		arr[a] = arr[b];
		arr[b] = temp;
	}
           

      数组的折半查找:折半查找一般只用于一组已经排好序的数组,当要确定一个元素在该有序数组中的位置时,使用折半查找效率比较高,它的原理是从数组中间位置开始比较,若大于中间元素则以中间元素后的元素到最后一个元素为范围,然后继续取中间元素比较,若小于中间元素则以第一个元素到中间元素为范围,然后取中间元素比较。同时一道面试题也有它的应用,求如何将一个数插入到一组有序数组中?这里也是先用折半查找法找出该元素在该有序数组中的适当位置,再将其插入并将其它元素移动。折半查找法结束都是以min值都是比max值大的条件而结束循环,举例说,若以数组5,8,10中查找7来计算,最后三次值得情况是:min是5的位置0,max是8的位置1;min是8的位置1,max是8的位置1;min是8的位置1,max是7的位置0。

// 折半查找的第一种方法
	public static int halfSearch1(int[] arr, int key) {
		int min = 0;
		int max = arr.length - 1;
		int mid = (min + max) / 2;
		while (key != arr[mid]) {//当值不等于中间元素时一直循环
			if (key > arr[mid])
				min = mid + 1;//当值大于中间元素时,最小范围变成中间位置向右进一位
			else if (key < arr[mid])
				max = mid - 1;//当值小于中间元素时,最大范围变成中间位置向左减一位
			if(min>max)//当最小范围大于最大范围时代表已经全部比较过不存在查询的值
				return -1;
			mid=(min+max)/2;
		}
		return mid;
	}

	// 折半查找的第二种方法
	public static int halfSearch2(int[] arr, int key) {
		int min = 0;
		int max = arr.length - 1;
		int mid = (min + max) / 2;
		while (min <= max) {//当最小范围小于最大范围时进行查找的循环
			if (key > arr[mid])
				min = mid + 1;
			else if (key < arr[mid])
				max = mid - 1;
			else
				return mid;
			mid=(min+max)/2;
		}
		return -1;//return min;若是面试题,当查找不到值时返回min最小范围就是插入的位置,恰好是比它小的元素的后一个位置
		//比如说数组4,6,9中插入7,那么最后7是大于6小于9的,最后返回的结果是2,恰好是9这个位置。
	}
           

      十进制转换二进制和十六进制:十进制数转换成二进制,将数先取模2,得到的数是1或0,它是二进制数的最后一位,然后将该数除2运算,得到的数继续刚才的运算,直到数本身是1为止。十进制数转换成十六进制数,每次应该取它二进制的最后四位,将其转换成十六进制数的表现形式,同时每次最后四位运算完后将其本身向右移4位,这里将它与15取模,得到的就是它的最后四位二进制数,根据大于9则是字母,小于等于9则是本身的原理进行转换,然后将其向右移4位后继续运算。

// 十进制转换二进制
	public static void toBin(int num) {
		StringBuffer sb = new StringBuffer();
		while (num > 0) {
			sb.append(num % 2);// 将数取模2得到十进制的最后一位
			num = num >>> 1;// 位移1位后继续运算
		}
		System.out.println(sb.reverse());// 由于字符串是十进制的倒序,需要将字符串反向
	}

	// 十进制转换十六进制
	public static void toHex(int num) {
		StringBuffer sb = new StringBuffer();
		for (int i = 0; i < 8; i++)// 整型是4个字节,每个字节8位,所以每个整型至多位移操作8次
		{
			int tmp = num & 15;// 每次对15进行&与运算时都会得到最后4位的二进制数
			if (tmp > 9) {// 当该数大于9时则要转换成十六进制的字母,因为十六进制是由0-9,A到F组成的
				sb.append((char) (tmp - 10 + 'A'));
			} else {
				sb.append(tmp);
			}
			num = num >>> 4;// 将数向右移4位,继续运算它最后的4位二进制数
		}
		System.out.println(sb.reverse());
	}
           

      查表法和进制转换优化:查表法就是将需要表达的字符放在数组里,使用它的变量作为该数组的下标值,例如char[] chs=new{'0','1','A'},此时引用变量就是用0和1,chs[0]即是字符0,chs[2]即是字符A。将几个转换方法写完后发现有很多代码都是公用的,将其抽取出来封装成一个方法,再对代码优化,具体方法如下:

public static void main(String[] args) {
		System.out.println(toBin(6));
		System.out.println(toHex(60));
		System.out.println(toOct(60));
	}
	/*
	 * 十进制转换二进制
	 */
	public static String toBin(int num) {
		return trans(num, 1, 1);
	}
	/*
	 * 十进制转换八进制
	 */
	public static String toOct(int num) {
		return trans(num, 7, 3);
	}
	/*
	 * 十进制转换十六进制
	 */
	public static String toHex(int num) {
		return trans(num, 15, 4);
	}
	/*
	 * 进制转换公用方法
	 */
	public static String trans(int num, int base, int offset) {
		StringBuffer sb = new StringBuffer();
		if (num == 0) {//当传递的数是0时直接结束函数,返回0
			sb.append("0");
			return sb.toString();
		}
		//用于查找的字符表
		char[] chs = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A',
				'B', 'C', 'D', 'E', 'F' };
		char[] arr = new char[32];//一个十进制整型是4个字节,一共32位有效位
		int pos = arr.length;//定义存储到字符数组的指针从最后一位开始,即倒序存储转换后的结果
		while (num != 0) {//当位移后的数字为0时结束循环
			int temp = num & base;//存储转换后的数值
			arr[--pos] = chs[temp];//将查表后的结果倒序存储到数组arr中,pos为每次存储的指针
			num = num >>> offset;//将转换后的数字位移相应的位数
		}
		for (int i = pos; i < arr.length; i++) {
			sb.append(arr[i]);//从最后存储的位置开始,读取到最后一位
		}
		return sb.toString();
	}