1、数组的定义
数组定义:
格式1
元素类型[] 数组名 = new 元素类型[]{元素}//动态初始化
元素类型[] 数组名 = new 元素类型[元素个数或者数组程度长度]
或元素类型[] 数组名 = {元素}//这两种定义方法是静态初始化,是一样的
注意:
数组是一种单独的数据类型(引用数据类型)
2、数组的内存结构
Java程序在运行时,需要在内存中的分配空间。为了提高运算效率,有对空间进行了不同区域的划分,因为每一片区域都有特定的处理数据方式和内存管理方式。java在运行的时候将内存划分为5片区域,方法区、堆内存(线程共享)、本地方法区、寄存器(程序计数器)、虚拟机栈(线程隔离)
具体内存的分配可以参考下面这篇文章:
java内存区域划分
关于内存还可以参考(就业班-day05-pdf相关解析以及就业班-day05-07、08(重要)、09、10视频解析 )
栈内存:用于存储局部变量,当数据使用完,所占空间会自动释放。
(局部变量:定义在方法中的变量;而定义在类里面的变量则是全局变量)
堆内存:数组和对象,通过new建立的实例都存放在堆内存中。每一个实体都有内存地址值,实体中的变量都有默认初始化值。实体不再使用,会在不确定的时间内被垃圾回收器回收。
首先,我们int[] arr,那么在栈内存中就会开辟一个空间存放数组变量arr。而new出来的实体,会存放在堆里面,实体包括数组和对象。也就是说,当我们new int[4]的时候,系统会在堆内存里面开辟4块空间来存放实体,且每一个空间都有一个编号与值(有指定就取指定值,如果没有指定就会默认初始化值int0,double0.0,boolean false)。
堆与栈的联系:首先,系统在堆中开辟一个内存空间存放实体,假设该内存空间的起始地址为0x0012,我们将这个地址值赋予栈内存中的x,用该地址来标识数组位置,这样x就指向数组,或者说x引用了数组。栈中x没有存放堆中数组的实体,而只是存放地址。
我们定义int[] x = new int[3],如果设置x=null(空),这时x不指向数组堆中的内存空间,堆内存的空间没有任何引用来使用它。java会在不定时的时间内启动垃圾清除机制,将垃圾清除。
c++中的垃圾需要程序员手动清除,java堆中则有垃圾自动回收机制,栈中的垃圾在不使用的时候会自动释放。
要注意int[] arr与 new int[3]两部分的不同内存操作的涵义。
3、数组操作常见问题
4、数组常见操作
A、遍历数组
首先举一个使用for循环遍历二元数组的例子
public static void main(String[] args) {
int[][] array = new int[][] {{1,2,3,4},{2,6,8},{8,0,1,5,6}};
for(int x=0; x<array.length ;x++) {//注意这里取数组长度的格式
for(int y=0; y<array[x].length ;y++) {//注意这里取内层数组长度的格式
System.out.print(array[x][y]+" ");
}
System.out.println();
}
接下来我们试着用foreach的形式遍历
public static void main(String[] args) {
int[][] array = new int[][] {{1,2,3,4},{2,6,8},{8,0,1,5,6}};
int i = 0;//设置i为外层循环的遍历计数器
for(int innerArray[]: array) {//由于数组为二元数组,外部循环变量应设置为一维数组,使用一维数组来遍历,这样内部循环才可以继续遍历
i++;//外层遍历一次,i自加1
int j = 0;//设置i为内层循环的遍历计数器
for(int x:innerArray) {//用x遍历内部数组
/*
* 每遍历一个内层数组j自动加一,注意j必须在第一个for循环内设置,
* 外循环每循环一次就会自动把j置零,这样才可以达到找到最后一个元素的效果,否则j会一直增加*/
j++;
if(i==array.length && j==innerArray.length) {
System.out.print(x);
}else {
System.out.print(x+"、");
}
}
}
}
需要注意,上面的i,j只是用来控制输出,如果“、”用“ ”(空格)代替,不需要设置x,y。
1、2、3、4、2、6、8、8、0、1、5、6
试着打印一元数组
public static void main(String[] args) {
int[] array = new int[] {2,4,56,78,12};
for(int x=0; x<array.length ;x++) {
if(x==array.length) {//这里一元的只需要用x即可,而上面二元是foreach则需要用i,j
System.out.print(array[x]);
}else {
System.out.print(array[x]+",");
}
}
}
如果我们直接打印数组,
int[] array = new int[] {2,4,56,78,12};
System.out.println(array);
结果是,我们打印的是数组实体的引用
[I@7852e922 //[代表数组,I指数组中的元素类型,7852e922是数组的内存存放地址(十六进制表示),是由哈希算法计算得出的哈希值
B、获取数组最值
package lkj;
/*
给定一个数组,获取其最值
*/
public class Main {
public static void main(String[] args) {
int[] array = new int[] {2,4,5,18,12,1,5,-1,56,-4};
System.out.println("数组元素最大值为:"+getMax(array));
System.out.println("数组元素最小值为:"+getMin(array));
}
public static int getMax(int[] array) {
int max = array[0];//设定一个参数来存放最大值
for(int x=1; x<array.length ;x++){
if(array[x] > max) {
max = array[x];
}
}
return max;
}
public static int getMin(int[] array) {
int min = array[0];//设定一个参数来存放最小值
for(int x=1; x<array.length ;x++) {
if(array[x] < min) {
min = array[x];
}
}
return min;
}
}
C、数组排序
常见的排序算法有冒泡排序、直接选择排序和反转排序。
(1)冒泡排序
思想:就是按一定的规律把相邻2个数对比,并把当次最大的数排到最后(内循环从头到尾两两排序)或者把当次最小的数排到最前面(内循环从尾到头两两排序)。外循环用于控制排序轮数,一般等于数组的长度减一;内循环用于对比数组中临近元素的,对比轮数随排序轮数的增加而减少。
内循环从头到尾两两排序
public class SortTest {
public static void main(String[] args) {
int [] array = new int[] {9,1,2,3,8,7,4,6,10};
SortTest obj = new SortTest();//创建本类的对象
obj.bubbleSortPositive(array);
}
public static void bubbleSortPositive(int[] array) {//正冒泡排序,既内循环从头到尾
int num = 0;//定义num来计算比较次数
for(int i=1; i<array.length ;i++) {
//内循环的次数与外循环的轮数相关,因此要将他们联系起来,这里j必须从0开始,否则可能会数组越界
//每一轮的内循环都到array.length-i,每一轮都将此轮最大的数排到最后,因此从下标是array.length-i到array.length的数不需要再排
for(int j=0; j<array.length-i ;j++) {
num++;//num计算的是比较的次数,不是换数的次数,因此我们将其设置在外面
if(array[j]>array[j+1]) {
//或者利用下面的方法交换两个数也是一样的
array[j] = array[j]^array[j+1];
array[j+1] = array[j]^array[j+1];
array[j] = array[j]^array[j+1];
}
}
}
System.out.println("比较的次数为:"+num);
showArray(array);
}
public static void showArray(int[] array) {
for(int i=0; i<array.length ;i++) {
if(i == array.length-1) {
System.out.print(array[i]);
}else {
System.out.print(array[i]+">");
}
}
}
}
结果:
比较的次数为:36
1>2>3>4>6>7>8>9>10
//一共比较(8+1)*8/2=36次,符合计算规则
冒泡排序优化
public static void bubbleSortPositive(int[] array) {//正冒泡排序,既内循环从头到尾
int num = 0;//定义num来计算比较次数
boolean flag = true;//定义一个布尔型参数来判断是否需要继续执行排序
for(int i=1; i<array.length && flag==true;i++) {//当flag=true的时候才继续执行下一轮的排序
flag = false;
//内循环的次数与外循环的轮数相关,因此要将他们联系起来,这里j必须从0开始,否则可能会数组越界
//每一轮的内循环都到array.length-i,每一轮都将此轮最大的数排到最后,因此从下标是array.length-i到array.length的数不需要再排
for(int j=0; j<array.length-i ;j++) {
num++;//num计算的是比较的次数,不是换数的次数,因此我们将其设置在外面
if(array[j]>array[j+1]) {
//或者利用下面的方法交换两个数也是一样的
array[j] = array[j]^array[j+1];
array[j+1] = array[j]^array[j+1];
array[j] = array[j]^array[j+1];
/*
* 对于某一轮的对比,如果存在换数行为,说明还可能存在不按顺序排列的数,我们会将flag置true,并继续执行下一轮,
* 如果不存在换数行为,说明换数已经结束,不需要执行下一轮的排序,此时flag为假,那么说明数组已经顺序排列,不需要再对比
* 这一方法主要判断的是不存在换数行为排序已经完成
*/
flag = true;
}
}
}
System.out.println("比较的次数为:"+num);
showArray(array);
}
结果为:
比较的次数为:26
1>2>3>4>6>7>8>9>10
内循环从尾到头两两排序
public class SortTest {
public static void main(String[] args) {
int [] array = new int[] {1,2,5,3,6,7,8,9,10};
SortTest obj = new SortTest();//创建本类的对象
obj.bubbleSortNegative(array);
}
public static void bubbleSortNegative(int[] array) {//正冒泡排序,既内循环从头到尾
int num = 0;//定义num来计算比较次数
boolean flag = true;//定义一个布尔型参数来判断是否需要继续执行排序
for(int i=1; i<array.length && flag==true;i++) {//当flag=true的时候才继续执行下一轮的排序
flag = false;
//内循环的次数与外循环的轮数相关,因此要将他们联系起来,这里j必须从0开始,否则可能会数组越界
//每一轮的内循环都从array.length-i开始,每一轮都将此轮最小的数排到最前面,因此从下标是0到i-1的数不需要再排
for(int j=array.length-1; j>=i ;j--) {
num++;//num计算的是比较的次数,不是换数的次数,因此我们将其设置在外面
if(array[j]<array[j-1]) {//这里要特别注意正负号!
//或者利用下面的方法交换两个数也是一样的
array[j] = array[j]^array[j-1];
array[j-1] = array[j]^array[j-1];
array[j] = array[j]^array[j-1];
/*
* 对于某一轮的对比,如果存在换数行为,说明还可能存在不按顺序排列的数,我们会将flag置true,并继续执行下一轮,
* 如果不存在换数行为,说明换数已经结束,不需要执行下一轮的排序,此时flag为假,那么说明数组已经顺序排列,不需要再对比
* 这一方法主要判断的是不存在换数行为排序已经完成
*/
flag = true;
}
}
}
System.out.println("比较的次数为:"+num);
showArray(array);
}
public static void showArray(int[] array) {
for(int i=0; i<array.length ;i++) {
if(i == array.length-1) {
System.out.print(array[i]);
}else {
System.out.print(array[i]+"<");
}
}
}
}
结果是:
比较的次数为:15
1<2<3<5<6<7<8<9<10
//9个数正常情况下需要36次排序,这里用15次排序就解决,说明算法有所优化
(2)直接选择排序
直接选择排序是选择排序的一种,它的排序速度比冒泡排序要快一点。
主要思想:从一列数中选出符合指标的某个数,并把它的位置与指定排序位置交换。比如从一列数中选择出最大的数并把它与最后的数的位置交换。(由于直接选择排序是通过比较后交换下标,找出符合条件数的下标(如最大数),等比较结束后再进行交换,所以交换次数较少,比冒泡排序要快)
public class SortTest {
public static void main(String[] args) {
int [] array = new int[] {12,2,25,3,36,7,48,9,123};
SortTest obj = new SortTest();//创建本类的对象
obj.selectSort(array);
}
public static void selectSort(int[] array) {
//外循环用于控制内循环找到最大数的下标之后,进行交换的次数,等于数组长度减一
for(int i=1; i<=array.length-1; i++) {
//index必须设置在外循环中内循环外,因为每一个外循环开始都必须从0角标开始比较
int index = 0;//首先创建一个变量用来保存比较过程中数的下标
//内循环每一轮需要比较到最远的位置是array[array.length-i],因为每一轮循环之后都会将当前最大的数排序到最后
//且j从1开始,因为0的位置已经被index所占
for(int j=1; j<=array.length-i ;j++) {
if(array[j]>array[index]) {//相当于找出最大数的下标
index = j;//如果j位置比index位置的数要大,j与index交换
}
}
//找到当前轮最大数的下标之后,将其移动到本轮的最末端位置array.lengeh-i,既交换array[index]与array[array.lengeh-i]位置的数
// array[index] = array[index]^array[array.length-i];
// array[array.length-i] = array[index]^array[array.length-i];
// array[index] = array[index]^array[array.length-i];
int temp = array[array.length-i];
array[array.length-i] = array[index];
array[index] = temp;
}
showArray(array);
}
public static void showArray(int[] array) {
for(int i=0; i<array.length ;i++) {
if(i == array.length-1) {
System.out.print(array[i]);
}else {
System.out.print(array[i]+"<");
}
}
}
}
结果:
2<3<7<9<12<25<36<48<123
异或方法
2<3<0<9<12<25<36<48<0
//异或交换数的方法格式并没有写错,为什么会出现错误?出现0的位置都正确,说明我们内部排序没有出错,而是在交换的时候出错导致其置零。有大神看出为什么麻烦在评论下或者私信我告知,谢谢!!!
普通选择排序
public class SortTest {
public static void main(String[] args) {
int [] array = new int[] {45,12,16,58,23,56,78,4,6};
SortTest obj = new SortTest();//创建本类的对象
obj.selectSort(array);
}
//普通选择排序
//其实普通选择排序类似于直接选择排序,只不过直接选择排序是通过对比,找出角标最大(小)的数,然后再进行交换
//而普通选择排序则是一一比较后直接对换,这样便使得程序的执行时间较长
public static void selectSort(int[] array) {
for(int i=1; i<array.length ;i++) {//对比array.length-1轮
for(int j=i; j<array.length ;j++) {
if(array[i-1]>array[j]) {
int temp = array[i-1];
array[i-1] = array[j];
array[j] = temp;
}
}
}
showArray(array);
}
public static void showArray(int[] array) {
for(int i=0; i<array.length ;i++) {
if(i == array.length-1) {
System.out.print(array[i]);
}else {
System.out.print(array[i]+",");
}
}
}
}
直接选择排序毕普通选择排序的性能高,是因为它只在栈内存中进行角标的交互,等找到当前的最值之后,再在堆内存中进行实际值的交换,这样便节省了在堆内存中所占的空间。要注意,堆内存操作是比较占内存空间的!
(3)反转排序
以相反的顺序把原有数组的内容重新排序。只需要循环数组长度的半数次,如数组的长度为7,则只需要循环3次。
public class SortTest {
public static void main(String[] args) {
int [] array = new int[] {1,2,3,4,5,6,7};
SortTest obj = new SortTest();//创建本类的对象
obj.reverseSort(array);
}
public static void reverseSort(int[] array) {
System.out.print("原数组为:");
showArray(array);
int length = array.length;//获取数组长度
//如果length为偶数,那么交换的次数为length/2,若其为奇数,则交换次数为(length-1)/2
//注意此处i<(length-1)/2,其实可以写作i<(length)/2,但是如果这样,当数组长度为奇数的时候,会多出一次无谓的交换,既中间的数与自己交换
for(int i=0; i<(length-1)/2 ;i++) {
int temp = array[i];
array[i] = array[length-1-i];
array[length-1-i] = temp;
}
System.out.println();
System.out.print("反转排序后的数组为:");
showArray(array);
}
public static void showArray(int[] array) {
for(int i=0; i<array.length ;i++) {
if(i == array.length-1) {
System.out.print(array[i]);
}else {
System.out.print(array[i]+",");
}
}
}
}
数组排序——位置置换功能的抽取
//对于这一部分,我们可以用一个交换函数替换
int temp = array[i];
array[i] = array[length-1-i];
array[length-1-i] = temp;
swap(array,i,length-1-i);
//如果不把数组也添加到形参中,swap()内数会在内存中开辟另一块区域并执行换数
//swap()中的换数与数组相关,如果不把数组传递进来,数组的数并不会随着swap()函数的交换而交换,而仅仅是交换了i与length-1-i的值
public static void swap(int[] array,int a,int b){
int temp = array[a];
array[a] = array[b];
array[b] = temp;
}
//当然,上面其实有点复杂化了,也可以不考虑数组,直接交换数组内的2个数,这样就不用把数组也加入形参
swap(array[i-1],array[j]);
public static void swap(int a,int b){
int temp = a;
a = b;
b = temp;
}
D、数组查询
普通查找方法
//比如我们想要查找数组内的某一个数,我们一般会遍历整个数组
public class SortTest {
public static void main(String[] args) {
int [] array = new int[] {45,12,16,58,12,23,56,78,12,4,6};
SortTest obj = new SortTest();//创建本类的对象
int index = getIndex(array,12);
System.out.println("index="+index);
}
public static int getIndex(int[] array,int key) {
for(int x=0; x<array.length ;x++) {
if(array[x] == key) {
return x;
}
}
return -1;
}
}
折半查找,效率较高,但是必须对数组提前进行排序
//考虑我们所查找的数在数组中可能不存在,利于折半的中间值array[mid]!=key
import java.util.*;
public class SortTest {
public static void main(String[] args) {
int [] array = new int[] {45,16,58,23,56,78,12,4,6};
int index = 0;
//首先,如果要使用折半排序,必须先对数组进行排序
Arrays.sort(array);
System.out.print("排序后的数组为:");
showArray(array);
System.out.println();
index = halfSearch(array,100);
System.out.println("index="+index);
}
public static int halfSearch(int[] array,int key) {
int min = 0;//定义min来保存折半查找的下限
int max = array.length-1;//定义max来保存折半查找的上限
int mid = (min+max)/2;//定义mid来保存折半查找的中间值
while(array[mid] != key) {//如果中间值的数不等于查找的数
/*
通过下面这个循环就可以找到满足条件的mid,如果不理解,自己画个图就清楚
*/
if(key>array[mid]) {
min = mid+1;//key大于中间值下标的数值,min等于mid+1
}else if(key<array[mid]){
max = mid-1;//key大于中间值下标的数值,max等于mid-1
}
//通过画图我们知道,如果所查找的数不存在于数组中,会出现min=max,下一次就是min>max
//在min=max的时候,如果array[mid]任然不等于key,说明数组中没有我们想要查询的数,返回-1(注意min=max的时候也必须求,只有max<min的时候才可以停止比较)
if(max == min && array[mid] != key) {
return -1;
}
//当然,也可以不判断min=max,直接判断min>max,这个时候铁定array[mid]任然不等于key,那么说明数组中没有我们想要查询的数,返回-1
//这两种方法的区别在于下面这种方法多做了一次循环
if(max<min){
return -1;
}
mid = (min+max)/2;
}
return mid;//当中间值等于我们所查找数的下标的时候,返回中间值
}
public static void showArray(int[] array) {
for(int x=0; x<array.length ;x++) {
if(x == array.length-1) {
System.out.print(array[x]);
}else {
System.out.print(array[x]+",");
}
}
}
}
//折半的另一个思路,我们前面说到,当min>max的时候,说明不存在我们要查找的数
//那么,我们将循环条件设置为min<=max,这样子一直查找,找到就返回mid,
//找不到就说明不存在我们要查找的数,跳出循环返回-1
import java.util.*;
public class SortTest {
public static void main(String[] args) {
int [] array = new int[] {45,16,58,23,56,78,12,4,6};
int index = 0;
//首先,如果要使用折半排序,必须先对数组进行排序
Arrays.sort(array);
System.out.print("排序后的数组为:");
showArray(array);
System.out.println();
index = halfSearch(array,56);
System.out.println("index="+index);
}
public static int halfSearch(int[] array,int key) {
int min = 0;//定义min来保存折半查找的下限
int max = array.length-1;//定义max来保存折半查找的上限
int mid = (min+max)/2;//定义mid来保存折半查找的中间值
while(min<=max) {//如果min<=max,继续查找
if(key>array[mid]) {
min = mid+1;
}else if(key<array[mid]){
max = mid-1;
}else {//当array[mid]=key,找到我们要查询的数
return mid;
}
mid = (min+max)/2;
}
return -1;//当max>min,说明所查找的数不存在,返回-1
}
public static void showArray(int[] array) {
for(int x=0; x<array.length ;x++) {
if(x == array.length-1) {
System.out.print(array[x]);
}else {
System.out.print(array[x]+",");
}
}
}
}
总结:
我们列一组数据如1,3,5,7,9,11,13,假设我们要查找10并插入,那么有:
min = 0、max = 7-1 = 6、mid = 3
发现array[mid] = array[3] = 7<10,那么:
min = min+1 = 4、max = 6、mid = 5
发现array[mid] = array[5] = 11>10,那么:
min = 4 、max = mid-1 = 4、mid = 4
发现array[mid] = array[4] =9<10,那么:
min = mid+1 = 5,max = 4、mid = 4.5
说明10应该插入下标为5的位置!
至此,我们发现一种折半下去,会出现min = max以及min>max的情况,如果要插入数,当min>max的时候:
(1)若不存在与要插入数相同的数,则min的位置就是我们要插入的位置;
(2)若存在于原数相同的数,mid的位置就是我们要插入的位置。
练习:
//练习:有一个有序的数组,想要将一个元素插入到该数组中,还要保证该数组是有序的。
import java.util.*;
public class SortTest {
public static void main(String[] args) {
int [] array = new int[] {45,16,58,23,23,78,12,4,6};
int index = 0;
//首先,如果要使用折半排序,必须先对数组进行排序
Arrays.sort(array);
System.out.print("插入前的数组为:");
showArray(array);
System.out.println();
int insertLocation = halfSearch(array,23);//定义一个数来获取我们要插入的位置
int[] newArray = insertArray(array,insertLocation,23);//获取插入的数组
System.out.print("插入后的数组为:");
showArray(newArray);
}
//该方法用于获取插入位置
public static int getInsertLocation(int[] array,int insert) {
int min = 0;//定义min来保存折半查找的下限
int max = array.length-1;//定义max来保存折半查找的上限
int mid = (min+max)/2;//定义mid来保存折半查找的中间值
/*
*前面说我们要插入数,如果查找到,说明mid就是我们要插入的位置,且这个位置原来的数与我们要插入的数相同
*如果没有查找到,我们返回min,min就是我们要插入的位置
*/
while(min <= max) {
if(insert>array[mid]) {
min = mid+1;
}else if(insert<array[mid]){
max = mid-1;
}else {//当array[mid]=key
return mid;
}
mid = (min+max)/2;
}
//当min>max的时候,表示满意找到,跳出循环
return min;
}
//该方法的第一个参数是我们要排序的数组,第二个参数是要插入的位置,第三个参数是我们要插入的数,用于获取插入后的数组
//对于insertLocation=min,我们直接把这个位置原来的数的下标都加一位,把我们要插入的数插入这个位置即可
//对于insertLocation=mid,由于insertNum等于数组原来这个位置的数,同样把这个位置原来的数的下标都加一位,效果是一样的
public static int[] insertArray(int[] array,int insertLocation,int insertNum) {
int[] newArray = new int[array.length+1] ;//定义一个比原数组厂一个数的数组
for(int x=0;x<insertLocation;x++) {//对于insertLocation之前的数,直接将Array的值赋予即可
newArray[x] = array[x];
}
newArray[insertLocation] = insertNum;//将我们要插入的数插入相应的位置
//对于insertLocation+1位置开始的数,将array数组从下标为insertLocation开始的数赋予即可
for(int y=insertLocation+1; y<newArray.length ;y++) {
newArray[y] = array[y-1];
}
return newArray;//结果返回一个插入的数组
}
public static void showArray(int[] array) {
for(int x=0; x<array.length ;x++) {
if(x == array.length-1) {
System.out.print(array[x]);
}else {
System.out.print(array[x]+",");
}
}
}
}
//结果是无论数组中有没有我们要插入的数,或者有几个我们要插入的数,排序都成功!
E、数据进制转换
(1)十进制转二进制与十进制转十六进制
import java.util.*;
public class SortTest {
public static void main(String[] args) {
toBin(60);
System.out.println();
toBin_2(-6);
System.out.println();
toHex(60);
System.out.println();
toHex_2(60);
}
/*
* 十进制转二进制
*/
public static void toBin(int num) {
System.out.print(num+"的二进制形式为");
StringBuffer sb = new StringBuffer();//用StringBuffer类创建一个保存字符串的容器sb
while(num != 0) {
sb.append(num%2);//用append方法将获取的数保存到容器内
num=num/2;
}
System.out.print(sb.reverse());
}
/*
* 查表法十进制转二进制
*/
public static void toBin_2(int num) {
//定义二进制的表
char[] chs = {'0','1'};
//定义一个数组用来保存num的各个二进制位,int数最多有32位,因此数组长度应该为32
char[] arr = new char[32];
//定义一个指针用来遍历num的各位
int pos = 0;
while(num != 0) {
int temp = num&1;//定义temp临时保存二进制位
arr[pos++] = chs[temp];
num = num>>>1;//查完一个二进制位后,num右移一位
}
System.out.print(num+"的二进制形式为:");
for(int x=pos-1; x>=0 ;x--) {//从最后有数保存的位置pos-1开始反向遍历
System.out.print(arr[x]);
}
}
/*
* 十进制转十六进制
*/
public static void toHex(int num) {
StringBuffer sb = new StringBuffer();//用StringBuffer类创建一个保存字符串的容器sb
while(num != 0) {//n1=0的时候说明不需要
int temp = num & 15;
if(temp>9)
sb.append((char)(temp-10+'A'));
else
sb.append(temp);
num = num>>>4;
}
System.out.print("十六进制形式为:0x"+sb.reverse());
}
/*
* 查表法十进制转十六进制
* 查装法:将所有的元素临时存储起来。建立对应关系。
* 每一次&15后的值作为索引去查建立好的表。就可以找对应的元素。
* 通过数组的形式定义要查询的表格
*/
public static void toHex_2(int num) {
//字符数组在内存中的默认初始化值是Unicode码'\u0000',代表空格的涵义
char[] arr = new char[8];//建立数组用于存储转换后的十六进制数的各位
//建立用于查询的表
char[] chs = {'0','1','2','3',
'4','5','6','7',
'8','9','A','B',
'C','D','E','F'};
int pos = 0;
while(num!=0) {
int temp = num&15;//用temp来临时保存我们所获取的4位
arr[pos++] = chs[temp];//注意此处这种pos++的用法
num = num>>>4;
}
// showArray(arr);
//当然,我们也可以不使用showArray方法,直接for循环,从pos的位置开始反向打印,这是课程内老师所给的方法
System.out.print("十六进制形式为:0x");
for(int x=pos-1; x>=0 ;x--) {//注意最后pos在判断num之前还会再自加一次,因此pos自减一
System.out.print(arr[x]);
}
}
public static void showArray(char[] arr) {
System.out.print("十六进制形式为:0x");
for(int x=arr.length-1; x>=0 ;x--) {
if(arr[x] != '\u0000') {//当数组内的值不为'\u0000',说明有保存值,将其打印
System.out.print(arr[x]);
}
}
}
}
结果如下:
60的二进制形式为111100
-6的二进制形式为:11111111111111111111111111111010
十六进制形式为:0x3C
十六进制形式为:0x3C
//两个取十六进制的方法对负数依然适用,第一个方法中,十进制转二进制的负数,必须先求负数的绝对值的二进制,再将其转换为补码,第二个查表的方法就可以直接将负数的十进制转二进制
查表法十进制转二进制,八进制,十六进制的优化——将2个表的共性抽取出来
import java.util.*;
public class SortTest {
public static void main(String[] args) {
toBin(60);
System.out.println();
toOct(60);
System.out.println();
toHex(60);
}
/*
* 十进制转二进制
*/
public static void toBin(int num) {
//直接调用trans方法,赋值即可
trans(num,1,1);
}
/*
* 十进制转八进制
*/
public static void toOct(int num) {
//直接调用trans方法,赋值即可
trans(num,7,3);//三个二进制位等于一个八进制位
}
/*
* 十进制转二进制
*/
public static void toHex(int num) {
//直接调用trans方法,赋值即可
trans(num,15,4);
}
/*
* 查表法十进制转二进制,八进制,十六进制的优化——将2个表的共性抽取出来
* 先创建一个总体的转化方法,给其他进制转换方法调用
* 不直接在main函数中调用,这样代码显得更加合理有序
*/
public static void trans(int num,int base,int offset) {//base代表&的数不一样,offset代表偏移的位数不一样
if(num == 0)
System.out.println(0);
char[] arr = new char[32];
char[] chs = {'0','1','2','3',
'4','5','6','7',
'8','9','A','B',
'C','D','E','F'};
int pos = 0;
while(num!=0) {
int temp = num&base;//用temp来临时保存我们所获取的4位
arr[pos++] = chs[temp];//注意此处这种pos++的用法
num = num>>>offset;
}
for(int x=pos-1; x>=0 ;x--) {//注意最后pos在判断num之前还会再自加一次,因此pos自减一
System.out.print(arr[x]);
}
}
}
5、二维数组
public static void main(String[] args) {
int[][] arr = new int[3][4];
System.out.println(arr);
System.out.println(arr[0]);
}
结果是
[[I@7852e922
[I@4e25154f
//“[[”表示二维数组,“I”表示int类型,@后面是二维数组在内存中的地址
//下面的是二维数组内一维数组的地址
public static void main(String[] args) {
int[][] arr = new int[3][];
System.out.println(arr);
System.out.println(arr[0]);
arr[0] = new int[3];
arr[1] = new int[1];
arr[2] = new int[2];
System.out.println(arr.length);//打印是二维数组的长度=3
System.out.println(arr[0].length);//打印二维数组中第一个一维数组长度
}
结果是
[[I@7852e922
null
3
3
//“[[”表示二维数组,“I”表示int类型,@后面是二维数组在内存中的地址
//下面的二维数组内一维数组没有初始化,故系统默认初始化为空null,不会给它分配具体的地址
public static void main(String[] args) {
int[][] arr = {{1,4,7,4},{1,2,3,2},{1,1,4,4}};
//求二维数组所有元素的和
int sum = 0;
for(int x=0; x<arr.length ;x++) {
for(int y=0; y<arr[x].length ;y++) {
sum += arr[x][y];
}
}
System.out.println("二维数组所有元素的和为"+sum);
}
结果是
二维数组所有元素的和为34
6、数组补充
知识点1
//1. 静态初始化标准格式可以拆分成为两个步骤。
//2. 动态初始化也可以拆分成为两个步骤。
//3. 静态初始化一旦使用省略格式,就不能拆分成为两个步骤了。
// 静态初始化的标准格式,可以拆分成为两个步骤
int[] arrayB;
arrayB = new int[] { 11, 21, 31 };
// 动态初始化也可以拆分成为两个步骤
int[] arrayC;
arrayC = new int[5];
// 静态初始化的省略格式,不能拆分成为两个步骤。
// int[] arrayD;
// arrayD = { 10, 20, 30 };
知识点2
/*
使用动态初始化数组的时候,其中的元素将会自动拥有一个默认值。规则如下:
如果是整数类型,那么默认为0;
如果是浮点类型,那么默认为0.0;
如果是字符类型,那么默认为'\u0000';unicode中字符类型的默认值,打印不可见
如果是布尔类型,那么默认为false;
如果是引用类型,那么默认为null。
注意事项:
静态初始化其实也有默认值的过程,只不过系统自动马上将默认值替换成为了大括号当中的具体数值。
*/