函数就是定义在类中的具有特定功能的一段独立小程序,函数也称为方法
函数
四个方面:
函数的定义
函数的特点
函数的应用
函数的重载
一、函数的定义及特点
1) 什么是函数?
函数就是定义在类中的具有特定功能的一段独立小程序,函数也称为方法
2)Java中函数的格式:
修饰符 返回值类型函数名(参数类型 形式参数1,参数类型 形式参数2,。。)
{ 执行语句;
return 返回值;
}
返回值类型:函数运行后的结果的数据类型
参数类型:是形式参数的数据类型
形式参数:是一个变量,用于存储调用函数时传递给函数的实际参数
实际参数:传递给形式参数的具体数值
return:用于结束函数
返回值:该值会返回给调用者
3) 函数的特点
a) 定义函数可以将功能代码进行封装
b) 便于对该功能进行复用
c) 函数只有被调用才会被执行
d) 函数的出现提高了代码的复用性
e) 对于函数没有具体返回值的情况,返回值类型用关键字void表示,那么该函数中的return语句如果在最后一行可以省略不写,系统会帮你自动加上。
注:
a) 函数中只能调用函数,不可以在函数内部定义函数。
b) 定义函数时,函数的结果应该返回给调用者,交由调用者处理。
c) 当函数运算后,没有具体的返回值时,这是返回值类型用一个特殊的关键字来标识该关键字就是void,void:代表的是函数没有具体返回值的情况。
d) 当函数的返回值类型是void时,函数中的return语句可以省略不写。
4) 如何定义一个函数?
函数其实就是一个功能,定义函数就是实现功能,通过两个明确来完成:
1)、明确该功能的运算完的结果,其实是在明确这个函数的返回值类型。
2)、在实现该功能的过程中是否有未知内容参与了运算,其实就是在明确这个函数的参数列表(参数类型&参数个数)。
5) 函数的作用:
1)、用于定义功能。
2)、用于封装代码提高代码的复用性。
注意:函数中只能调用函数,不能定义函数。
6) 主函数:
1)、保证该类的独立运行。
2)、因为它是程序的入口。
3)、因为它在被jvm调用。
7) 函数定义名称是为什么呢?
答:1)、为了对该功能进行标示,方便于调用。
2)、为了通过名称就可以明确函数的功能,为了增加代码的阅读性。
二、函数的应用
1) 两个明确
a) 明确要定义的功能最后的结果是什么?
b) 明确在定义该功能的过程中,是否需要未知内容参与运算
2) 示例:
举例1:
class FunctionDemo
{
public static void main(String[] args)
{
int x = 4;
System.out.println(x*3+5);
x = 6;
System.out.println(x*3+5);
int y = 4*3+5;
int z = 6*3+5;
System.out.println(y);
System.out.println(z);
}
}
发现以上的运算,因为获取不同数据的运算结果,代码出现了重复。
为了提高代码的复用性。对代码进行抽取。将这个部分定义成一个独立的功能。方便与日后使用。
java中对功能的定义是通过函数的形式来体现的。
明确功能:需要定义功能,完成一个整数的*3+5的运算,
1,先明确函数定义的格式。
/*
修饰符返回值类型函数名(参数类型形式参数1,参数类型形式参数2,)
{
执行语句;
return 返回值;
}
class FunctionDemo
{
public static void getResult(int num)
{
System.out.println(num * 3 + 5);
return;//可以省略
}
public static void main(String[] args)
{
getResult(5);
}
}
对上述关于return是否省略这一小小知识点的总结:
当函数运算后,没有具体的返回值时,这是返回值类型用一个特殊的关键字来标识。
该关键字就是void。void:代表的是函数没有具体返回值的情况。
当函数的返回值类型是void时,函数中的return语句可以省略不写。
举例2:
class FunctionDemo2
{
public static void main(String[] args)
{
int sum = getSum(4,6);
System.out.println("sum="+sum);
sum = getSum(2,7);
System.out.println("sum="+sum);
}
/*下面的这个功能定义思想有问题,为什么呢?因为只为完成加法运算,至于是否要对和进行打印操作,
那是调用者的事,不要在该功能中完成。*/
public static void get(int a,int b)
{
System.out.println(a+b);
return ;
}
}
如何定义一个函数呢?
1,既然函数是一个独立的功能,那么该功能的运算结果是什么先明确
因为这是在明确函数的返回值类型。
2,在明确在定义该功能的过程中是否需要未知的内容参与运算。
因为是在明确函数的参数列表(参数的类型和参数的个数)。
class FunctionDemo2
{
public static void main(String[] args)
{
/*
int sum = getSum(4,6);
System.out.println("sum="+sum);
sum = getSum(2,7);
System.out.println("sum="+sum);
*/
//get(4,5);
int x = getSum(4,4);
int y = getSum(7,9);
int num = getMax(x,y);
}
//需求:定义一个功能。完成3+4的运算。并将结果返回给调用者。
/*
1,明确功能的结果:是一个整数的和。
2,在实现该功能的过程中是否有未知内容参与运算,没有。
其实这两个功能就是在明确函数的定义。
1,是在明确函数的返回值类型。
2,明确函数的参数列表( 参数的类型和参数的个数)。
*/
public static int getSum()
{
return 3+4;
}
/*
以上这个函数的功能,结果是固定的,毫无扩展性而言。
为了方便用户需求。由用户来指定加数和被加数。这样,功能才有意义。
思路:
1,功能结果是一个和。返回值类型是int。
2,有未知内容参与运算。有两个。这个两个未知内容的类型都是int。
*/
public static int getSum(int x,int y)
{
return x+y;
}
/*
需求:判断两个数是否相同。
思路:
1,明确功能的结果:结果是:boolean 。
2,功能是否有未知内容参与运算。有,两个整数。
*/
public static boolean compare(int a,int b)
{
/*
if(a==b)
return true;
//else
return false;
*/
//return (a==b)?true:false;
return a==b;
}
/*
需求:定义功能,对两个数进行比较。获取较大的数。
*/
public static int getMax(int a,int b)
{
/*
if(a>b)
return a;
else
return b;
//或者用下面的三元运算符
*/
return (a>b)?a:b;
}
}
3) 练习:
1,定义一个功能,用于打印矩形。
2,定义一个打印99乘法表功能的函数。
class FunctionTest
{
public static void main(String[] args)
{
draw(5,6);
printHr();
draw(7,9);
printHr();
print99();
}
/*
定义一个功能,用于打印矩形。
思路:
1,确定结果:没有,因为直接打印。所以返回值类型是void
2,有未知内容吗?有,两个,因为矩形的行和列不确定。
*/
public static void draw(int row,int col)
{
for(int x=0; x<row; x++)
{
for(int y=0; y<col; y++)
{
System.out.print("*");
}
System.out.println();
}
}
public static void printHr()
{
System.out.println("------------------------------");
}
/*
定义一个打印99乘法表功能的函数。
*/
public static void print99()
{
for(int x=1; x<=9; x++)
{
for(int y=1; y<=x; y++)
{
System.out.print(y+"*"+x+"="+y*x+"\t");
}
System.out.println();
}
}
}
三、函数的重载(overload)
重载的概念:
在同一个类中,允许存在一个以上的同名函数,只要它们的参数个数或者参数类型不同即可。
重载的特点:
与返回值类型无关,只看参数列表。
重载的好处:
方便于阅读,优化了程序设计。
重载示例:
返回两个整数的和
int add(int x,int y){return x+y;}
返回三个整数的和
int add(int x,int y, int z){return x+y+z;}
返回两个小数的和
double add(double x,double y){return x+y;}
什么时候用重载?
当定义的功能相同,但参与运算的未知内容不同。
那么,这时就定义一个函数名称以表示起功能,方便阅读,而通过参数列表的不同来区分多个同名函数。
重载范例:
class FunctionOverload
{
public static void main(String[] args)
{
add(4,5);
add(4,5,6);
print99();
}
public static void print99(int num)
{
for(int x=1; x<=num; x++)
{
for(int y=1; y<=x; y++)
{
System.out.print(y+"*"+x+"="+y*x+"\t");
}
System.out.println();
}
}
//打印99乘法表
public static void print99()
{
print99(9);
}
//定义一个加法运算,获取两个整数的和。
public static int add(int x,int y)
{
return x+y;
}
//定义一个加法,获取三个整数的和。
public static int add(int x,int y,int z)
{
return add(x,y)+z;
}
}
练习:区分是否是重载
void show(int a,char b,double c){}
下面的a,b,c,d,e,f与上述一句的区别:
a.
void show(int x,char y,double z){}//没有,因为和原函数一样。
b.
int show(int a,double c,char b){}//重载,因为参数类型不同。注意:重载和返回值类型没关系。
c.
void show(int a,double c,char b){}//重载,因为参数类型不同。注意:重载和返回值类型没关系。
d.
boolean show(int c,char b){}//重载了,因为参数个数不同。
e.
void show(double c){}//重载了,因为参数个数不同。
f.
double show(int x,char y,double z){}//没有,这个函数不可以和给定函数同时存在与一个类中。
如何区分重载:当函数同名时,只看参数列表。和返回值类型没关系。
一、函数
函数的定义
什么是函数?
函数就是定义在类中的具有特定功能的一段独立小程序,也可以称之为方法
函数的格式
/*
修饰符 返回值类型 函数名(参数类型 形式参数1,参数类型 形式参数2,........){
执行语句;
return 返回值;
}
返回值类型:函数运行后的结果的数据类型。
参数类型:是形式参数的数据类型。
形式参数:是一个变量,用于存储调用函数时传递给函数的实际参数。
实际参数:传递给形式参数的具体数值。
return:用于结束函数。
返回值:该值会返回给调用者。
*/
函数的特点
定义函数可以将功能代码进行封装
便于对该功能进行复用
函数只有被调用才会被执行
函数的出现提高了代码的复用性
对于函数没有具体返回值的情况,返回值类型用关键 字 void表示,那么该函数中的return语句如果在最后一 行可以省略不写。
注意: 函数中只能调用函数,不可以在函数内部定义函数。 定义函数时,函数的结果应该返回给调用者,交由调用者处 理。
函数的应用
两个明确
明确要定义的功能最后的结果是什么?
明确在定义该功能的过程中,是否需要未知内容参与运
函数的小应用
class FunctionDemo1
{
public static void main(String[] args)
{
System.out.println(getAdd(5,8));
}
/*
函数小练习
需求:定义一个功能,实现两个整数的加法运算
思路:1、因为需求是定义一个功能,所以应使用函数来实现
2、通过 需求发现需要把结果返回给调用者,所以该函数有返回值,
因为是两个整数进行运算,所以返回值是int类型
3、通过需求发现是两个未知整数进行未知运算,所以该函数有参数列表,
而且参数为三个,类型应为 两个int类型和一个char类型
*/
//第一种实现方法 将运算后的值返回给调用者
public static int getAdd(int a, int b){
return a+b;
}
//第二种实现方法 将运算后的值在该函数内部打印
public static void getAdd1(int a,int b){
System.out.println(a+b);
}
/*
问题:
getAdd和getAdd1这两个函数有什么一样么?
最大的区别就是getAdd1这个函数已经违背了我们定义函数的初衷,为什么呢?
因为我们定义这个函数的初衷只是为了对两个数进行求和运算,而getAdd1这个函数在
完成求和运算的基础上又做了打印操作。如果我们仅仅是为了打印两个数的和,
那么getAdd1这个函数这样定义倒是不为过,但是当需要拿两个数的和进行其他运算时,
getAdd1这个函数就偏离了我们要实现的功能,所以,再定义函数时,尽可能的巴函数的
结果返回给调用者,让调用者去决定该结果的去向。
*/
}
函数的重载
重载的概念
在同一个类中,允许存在一个以上的同名函数,只要它们的参数个数或者参数类型不 同即可。
重载的特点
与返回值类型无关,只看参数列表
重载的好处
方便阅读优化了程序设计
什么时候使用重载?
当功能相同,但功能主体不同时,可以使用重载
重载的应用
class FunctionDemo
{
public static void main(String[] args)
{
System.out.println("Hello World!");
}
/*函数重载小练习
需求:利用函数重载分别实现打印99乘法表和根据用户输入打印乘法表
思路:1、通过需求发现两个函数都是打印乘法表,只不过一个是固定打印,
一个是根据用户输入数据打印,所以为方便阅读,
可以定义函数名相同的函数来实现
2、通过99乘法表发现,需要用到循环嵌套,而且是尖朝上,
所以利用尖朝上,可以通过控制内循环条件,
让条件随着外循环的变化而变化这一规律来完成程序设计
*/
//打印固定99乘法表
public static void print99(){
/*
for(int i=1;i<=9;i++){ //用来控制*号右边的数字
for(int j=1;j<=i;j++){ //用来控制*号左边的数字
//输出乘法表口诀
System.out.print(j+"*"+i+"="+(j*i)+"\t");
}
System.out.println(); //输出换行
}
*/
/*发现使用重载后出现了重复代码,
经过观察发现该函数内部可以通过调用另一个函数来实现自己原有的功能,
而且代码相对简单 代码如下:
*/
print99(9);
}
//通过重载的形式实现打印
public static void print99(int num){
for(int i=1;i<=num;i++){ //用来控制*号右边的数字
for(int j=1;j<=i;j++){ //用来控制*号左边的数字
//输出乘法表口诀
System.out.print(j+"*"+i+"="+(j*i)+"\t");
}
System.out.println(); //输出换行
}
}
}
函数重载判断
//函数重载判断
/*
判断下面所列举的函数是否与 public static void print(int n,char c,double num){}重载
1、public static void print(int x,char ch,double do){} //没有重载,因为参数类型一样
2、public static void print(double d,char c,int n){} //重载了,因为参数类型不一样
3、public static int print(char c,int a){} //重载了,因为参数类型不一样
4、public static int print(int a,char c,double d){} //没有重载,因为重载和返回值类型没有关系
5、public static void print(int a,char c){} //重载了,因为参数类型不一样
*/
二、数组
数组的定义
概念:同一种数据类型的集合,相当于一个容器
数组的好处
可以给放入的元素进行编号,编号是从0开始的
几种常见的数组创建方式:
1、元素类型 [] 数组名 = new 元素类型[数组的长度] 如: int [] array = new int[5];
2、元素类型 数组名[] = new 元素类型[数组长度] 如: int array[] = new int [6];
3、元素类型 [] 数组名 = new 元素类型[]{元素,元素,元素.....} 如: int [] array = new int [] {1,2,3,4,5,6,7};
4、元素类型 [] 数组名 = {}; 如: int [] array = {1,2,3,4,5,6,7}
数组的内存分配及特点
内存结构
Java程序在运行时,需要在内存中的分配空间。为了提高运算效率,有对空 间进行了不同区域的划分,因为每一片区域都有特定的处理数据方式和内存管理方式。
栈内存
用于存储局部变量,当数据使用完,所占空间会自动释放。
堆内存
数组和对象,通过new建立的实例都存放在堆内存中。
每一个实体都有内存地址值
实体中的变量都有默认初始化值
int——>0
double——>0.0
boolean——>false
char——>'\u0000' 空字符ASCII表
实体不在被使用,会在不确定的时间内被垃圾回收器回收
方法区
本地方法区:调用的是Windows系统底层资源
寄存器:和CPU有关
数组操作常见问题
1、数组脚标越界异常(ArrayIndexOutOfBoundsException)
class ArrayException
{
public static void main(String[] args)
{
int [] array = new int[3];
System.out.println(array[3]);
/*由于访问了不存在的角标,
所以会出现数组脚标越界异常(ArrayIndexOutOfBoundsException)
*/
}
}
2、空指针异常(NullPointerException)
class ArrayException
{
public static void main(String[] args)
{
int [] array =null;
System.out.println(array[0]);
/*由于array=null,所以array并没有指向实体,而却在操作实体中的元素
所以会出现空指针异常(NullPointerException)*/
}
}
数组常见操作
打印数组内存地址值
public static void main(String[] args)
{
int [] arr = new int[]{10,22,35,47,56,64,78,82,96};
System.out.println(arr);
}
其中“[”代表的是这是一个数组
“I”代表的是这个数组的类型是int类型
“15db9742”代表的是这个数组在内存中的位置,是一个十六进制的表现形式
数组遍历
class ArrayException
{
//实现数组遍历
public static void main(String[] args)
{
int [] array = {1,4,6,4,8,9,11,56};
for(int i=0;i<array.length;i++){
System.out.println(array[i]);
}
}
}
数组获取最值
class ArrayException
{
//获取数组中的最大值
public static void main(String[] args)
{
int [] array = {1,4,6,4,8,9,11,56};
/*第一种方式:定义第三方变量,初始化为array[0],
让这个变量与数组中的元素进行比较,并记录较大的值
*/
int temp = array[0];
for(int i=1;i<array.length;i++){ //对数组进行遍历,并从下标1开始
//取出较大的值
if(array[i]>temp)
temp = array[i];
}
System.out.println("数组array中的最大值是:"+temp);
//第二种方式:定义第三方变量,初始化值为0,作为数组的下标使用
int index = 0;
for(int i=1;i<array.length;i++){
if(array[i]>array[index])
index = i;
}
System.out.println("数组array中的最大值是:"+array[index]);
}
}
数组排序
选择排序
选择排序原理图
代码实现
class ArraySort1
{
//选择排序
public static void main(String[] args)
{
int [] arr = {2,5,3,4,7,6,1};
System.out.sort("排序前");
getPrint(arr);
System.out.println("排序后");
getSort(arr);
}
/*
选择排序:
思路:因为选择排序是拿一个元素与数组中的其他元素进行比较,
所以应该是嵌套循环,外层循环控制一个数个内层循环的所有数字
一一进行比较而比较的第一个数是这个数+1,而外层循环的最后一个
数,肯定是数组中最大(或最小)的数,所以是不用再次参与比较
的,所以外层循环循环次数应-1
*/
//选择排序
public static void getSort(int [] arr){
for(int i = 0; i<arr.length-1;i++){
for(int j=i+1;j<arr.length;j++){
if(arr[i]>arr[j]){
int temp = arr[i];
arr[i] = arr[j];
arr[j] = temp;
}
}
}
}
}
但是通过观察发现这样写的代码只要条件成立每次都要进行换位操作,而计算机底层是二进制运算,相对比较麻烦,所以能不能每比较一轮换一下位置呢??所以代码可以修改为:
class ArraySort1
{
//选择排序
public static void main(String[] args)
{
int [] arr = {2,5,3,4,7,6,1};
System.out.println("排序前");
getPrint(arr);
System.out.println("排序后");
getSort(arr);
}
public static void getSort(int [] arr){
//用于记录最值下标
int index = 0;
for(int i = 0; i<arr.length-1;i++){
index = i;
for(int j=i+1;j<arr.length;j++){
if(arr[index]>arr[j]){
//记录最值下标
index = j;
}
}
//进行换位操作
int temp = arr[i];
arr[i] = arr[index];
arr[index] = arr[i];
}
}
冒泡排序
冒泡排序示例图:
代码实现:
class ArraySort1
{
//数组中常用的两种排序方式
public static void main(String[] args)
{
int [] arr = {2,5,3,4,7,6,1};
System.out.println("排序前");
getPrint(arr);
System.out.println("排序后");
getSortM(arr);
getPrint(arr);
}
/*冒泡排序:
思路:外循环:因为冒泡排序是相邻两个数进行的比较,比较一轮后找出最值,
所以外循环比较次数也应该-1,
内循环:因为冒泡排序每循环一轮都会找出一个最值,所以内循环比较
次数也应该在-1的基础上还应该减去外循环的初始化值
*/
//冒泡排序
public static void getSortM(int [] arr){
for(int i = 0; i<arr.length-1;i++){
for(int j=0;j<arr.length-1-i;j++){
if(arr[j]>arr[j+1]){
int temp = arr[j];
arr[j] = arr[j+1];
arr[j+1] = temp;
}
}
}
}
基本查找
class ArrayFind1
{
/*数组查找,
需求:给定一个数查找概该数是否存在,并返回改数在数组中的位置
*/
public static void main(String[] args)
{
int [] arr = new int[]{10,22,35,47,56,64,78,82,96};
System.out.println("原数组");
print(arr);
//要使用折半查找,数组中的元素必须是有序的(如:从小到大)
System.out.println("使用一般查找方法");
System.out.println("要查找的数字的在数组中的下标为"+find(arr,64));
System.out.println("使用折半查找方法");
System.out.println("要查找的数字的在数组中的下标为:"+find1(arr,64));
}
//遍历数组,用于显示数组元素
public static void print(int [] arr){
System.out.print("[");
for(int i=0;i<arr.length;i++){
if(i==arr.length-1){
System.out.print(arr[i]+"]");
}
else
System.out.print(arr[i]+",");
}
System.out.println();
}
/*
一般查找方法
思路:可以通过遍历数组的方式让数组中的每个元素与要查找的
数字进行比较,如果相等,这返回该元素所在的下标即可
如果该数不存在返回-1 */
public static int find(int [] arr, int num){
for(int i=0;i<arr.length;i++){
if(num==arr[i])
return i;
}
return -1;
}
/*
折半查找:对于有序数组,可以使用折半查找提高效率
思路:1、因为是折半查找,所以应该定义三个变量(min(最小下标),mid(中间下标),max(最大下标))
2、因为需要进行循环,而循环次数不固定,所以应使用while循环,
而循环条件应为(min<=max)(因为min是最小下标,如果min>max还没
找到,那就说明该数组中并没有要查找的元素)
3、当要查找的数大于mid所在的元素时,应从min的位置应该发生改变,应为mid+1
然后在找出中间值继续循环,如果要查找的数小于此时的mid所在的
元素时,则max的位置应该发生改变,应为mid-1,然后再取中间值,
直到(min<=max)不成立,不成立返回-1
*/
public static int find1(int [] arr,int num){
int min = 0;
int max = arr.length-1;
int mid = (min+max)/2;
while(min<=max){
if(num==arr[mid])
return mid;
else if(num>arr[mid])
min = mid+1;
else if(num<arr[mid])
max = mid-1;
mid = (min+max)/2;
}
return -1;
}
}
数组中的数组(二维数组)
二维数组的定义
1、元素类型 [][] 数组名 = new 元素类型[数组长度][数组中的数组的长度];
如 int [] [] array = new int [3] [4];
定义了名称为array的二维数组
二维数组中有3个一维数组
每一个一维数组中有4个元素
一维数组的名称分别为arr[0], arr[1], arr[2]
给第一个一维数组1脚标位赋值为78写法是:arr[0][1] = 78;
2、元素类型 [][] 数组名 = new 元素类型[4][];
如: int [] [] array = new int [3] [];
二维数组中有3个一维数组
每个一维数组都是默认初始化值null
可以对这个三个一维数组的长度分别进行初始化
arr[0] = new int[3];
arr[1] = new int[1];
arr[2] = new int[2]
Java 数组
数组对于每一门编程语言来说都是重要的数据结构之一,当然不同语言对数组的实现及处理也不尽相同。
Java语言中提供的数组是用来存储固定大小的同类型元素。
你可以声明一个数组变量,如numbers[100]来代替直接声明100个独立变量number0,number1,....,number99。
本教程将为大家介绍Java数组的声明、创建和初始化,并给出其对应的代码。
声明数组变量
首先必须声明数组变量,才能在程序中使用数组。下面是声明数组变量的语法:
dataType[] arrayRefVar; // 首选的方法
或
dataType arrayRefVar[]; // 效果相同,但不是首选方法
注意: 建议使用dataType[] arrayRefVar 的声明风格声明数组变量。 dataType arrayRefVar[] 风格是来自 C/C++ 语言 ,在Java中采用是为了让 C/C++ 程序员能够快速理解java语言。
实例
下面是这两种语法的代码示例:
double[] myList; // 首选的方法
或
double myList[]; // 效果相同,但不是首选方法
创建数组
Java语言使用new操作符来创建数组,语法如下:
arrayRefVar = new dataType[arraySize];
上面的语法语句做了两件事:
一、使用dataType[arraySize]创建了一个数组。
二、把新创建的数组的引用赋值给变量 arrayRefVar。
数组变量的声明,和创建数组可以用一条语句完成,如下所示:
dataType[] arrayRefVar = new dataType[arraySize];
另外,你还可以使用如下的方式创建数组。
dataType[] arrayRefVar = {value0, value1, ..., valuek};
数组的元素是通过索引访问的。数组索引从0开始,所以索引值从0到arrayRefVar.length-1。
实例
下面的语句首先声明了一个数组变量myList,接着创建了一个包含10个double类型元素的数组,并且把它的引用赋值给myList变量。
public class TestArray {
public static void main(String[] args) {
// 数组大小
int size = 10;
// 定义数组
double[] myList = new double[size];
myList[0] = 5.6;
myList[1] = 4.5;
myList[2] = 3.3;
myList[4] = 4.0;
myList[5] = 34.33;
myList[6] = 34.0;
myList[7] = 45.45;
myList[8] = 99.993;
myList[9] = 11123;
// 计算所有元素的总和
double total = 0;
for (int i = 0; i < size; i++) {
total += myList[i];
}
System.out.println("总和为: " + total);
}
}
以上实例输出结果为:
总和为: 11354.173
下面的图片描绘了数组myList。这里myList数组里有10个double元素,它的下标从0到9。
处理数组
数组的元素类型和数组的大小都是确定的,所以当处理数组元素时候,我们通常使用基本循环或者foreach循环。
示例
该实例完整地展示了如何创建、初始化和操纵数组:
public class TestArray {
public static void main(String[] args) {
double[] myList = {1.9, 2.9, 3.4, 3.5};
// 打印所有数组元素
for (int i = 0; i < myList.length; i++) {
System.out.println(myList[i] + " ");
}
// 计算所有元素的总和
double total = 0;
for (int i = 0; i < myList.length; i++) {
total += myList[i];
}
System.out.println("Total is " + total);
// 查找最大元素
double max = myList[0];
for (int i = 1; i < myList.length; i++) {
if (myList[i] > max) max = myList[i];
}
System.out.println("Max is " + max);
}
}
以上实例编译运行结果如下:
1.9
2.9
3.4
3.5
Total is 11.7
Max is 3.5
foreach循环
JDK 1.5 引进了一种新的循环类型,被称为foreach循环或者加强型循环,它能在不使用下标的情况下遍历数组。
示例
该实例用来显示数组myList中的所有元素:
public class TestArray {
public static void main(String[] args) {
double[] myList = {1.9, 2.9, 3.4, 3.5};
// 打印所有数组元素
for (double element: myList) {
System.out.println(element);
}
}
}
以上实例编译运行结果如下:
1.9
2.9
3.4
3.5
数组作为函数的参数
数组可以作为参数传递给方法。例如,下面的例子就是一个打印int数组中元素的方法。
public static void printArray(int[] array) {
for (int i = 0; i < array.length; i++) {
System.out.print(array[i] + " ");
}
}
下面例子调用printArray方法打印出 3,1,2,6,4和2:
printArray(new int[]{3, 1, 2, 6, 4, 2});
数组作为函数的返回值
public static int[] reverse(int[] list) {
int[] result = new int[list.length];
for (int i = 0, j = result.length - 1; i < list.length; i++, j--) {
result[j] = list[i];
}
return result;
}
以上实例中result数组作为函数的返回值。
Arrays 类
java.util.Arrays类能方便地操作数组,它提供的所有方法都是静态的。具有以下功能:
给数组赋值:通过fill方法。
对数组排序:通过sort方法,按升序。
比较数组:通过equals方法比较数组中元素值是否相等。
查找数组元素:通过binarySearch方法能对排序好的数组进行二分查找法操作。
具体说明请查看下表:
序号 方法和说明
1 public static int binarySearch(Object[] a, Object key)
用二分查找算法在给定数组中搜索给定值的对象(Byte,Int,double等)。数组在调用前必须排序好的。如果查找值包含在数组中,则返回搜索键的索引;否则返回 (-(插入点) - 1)。
2 public static boolean equals(long[] a, long[] a2)
如果两个指定的 long 型数组彼此相等,则返回 true。如果两个数组包含相同数量的元素,并且两个数组中的所有相应元素对都是相等的,则认为这两个数组是相等的。换句话说,如果两个数组以相同顺序包含相同的元素,则两个数组是相等的。同样的方法适用于所有的其他基本数据类型(Byte,short,Int等)。
3 public static void fill(int[] a, int val)
将指定的 int 值分配给指定 int 型数组指定范围中的每个元素。同样的方法适用于所有的其他基本数据类型(Byte,short,Int等)。
4 public static void sort(Object[] a)
对指定对象数组根据其元素的自然顺序进行升序排列。同样的方法适用于所有的其他基本数据类型(Byte,short,Int等)。
数组:是一组相关变量的集合
数组是一组相关数据的集合,一个数组实际上就是一连串的变量,数组按照使用可以分为一维数组、二维数组、多维数组
数据的有点
不使用数组定义100个整形变量:int i1;int i2;int i3
使用数组定义 int i[100];
数组定义:int i[100];只是一个伪代码,只是表示含义的
一维数组
一维数组可以存放上千万个数据,并且这些数据的类型是完全相同的,
使用java数组,必须经过两个步骤,声明数组和分配内存给该数组,
声明形式一
声明一维数组:数据类型 数组名[]=null;
非配内存给数组:数组名=new 数据类型[长度];
声明形式二
声明一维数组:数据类型 [] 数组名=null;
java数据类型分为两大类
基本数据类型
int、long操作的时候本身就是具体的内容
引用数据类型:数组、类、接口
引用传递的就是一个内存的使用权,一块内存空间,可能有多个人同时使用
事例声明数组
package com.qn.array;
public class Test {
public static void main(String[] args) {
int score[]=null;//声明数组
score=new int[3];//开辟空间,大小为3
}
}
数组的声明格式里,数据类型是数组元素的数据类型,常见的有整形、浮点型、与字符型等
数组名是用来统一这组相同数据类型元素的名称,其命名规则和变量的相同
数组声明后实际上是在栈内存中保存了此数组的名称,结下了是要在堆内存中配置数组所需要的内存,齐产固定是告诉编译器,所声明的数组要存放多少个元素,而new 则是命令编译器根据括号里的长度
基本数据类型偶读有其默认值:int 0;只要是引用数据类型默认值就是null
事例
package com.qn.array;
public class Test {
public static void main(String[] args) {
int score[]=null;//声明数组
score=new int[3];//开辟空间,大小为3
System.out.print('score[0]='+score[0]);
System.out.print('\tscore[1]='+score[1]);
System.out.print('\tscore[2]='+score[2]);
}
}
堆栈内存的解释
数组操作中,在栈内存中保存的永远是数组的名称,只开辟了栈内的空间,数组是永远无法使用的,必须有指向的对内存才可以使用,要想开辟新对内存空间必须使用new关键字,之后就是将对内存的使用权交给对应的栈内存,而且一个堆内存空间可以同时被多个栈内存空间指向,比如一个人可以有多个名字,人就相当于对内存,名字就相当于栈内存
声明数组的同时分配内存空间
声明数组的同时非配内存
数据类型 数组名[]=new 数据类型[个数]
int score[]=new int[10];
声明一个元素个数为10的整形数组score,同时开辟依靠内存空间工期使用
java中,由于整形数据类型占用的空间为4个byte,而整个数组score可保存的元素有10个。所以上例中占用的内存共有4*10=40个字节
数组的访问
数组中元素的表示方法
想要访问数组里的元素可以利用索引来完成,java的数组索引标号由10开始,以一个score[10]的整形数组为例,score[0]代表第一个元素
一直向下,最后一个为score[9]
取得数组的长度
在java中取得数组的长度(也就是数组元素的长度)可以利用数组名称.length完成,
数组名称.length--返回一个int类型的数据
package com.qn.array;
public class Test {
public static void main(String[] args) {
int score[]=null;//声明数组
score=new int[3];//开辟空间,大小为3
System.out.println(score.length);
}
}
结果
数组的静态初始化
之前的数组,所采用的都是动态初始化,所有的内容在数组声明的时候并不具体的指定,而是以默认值的形式出现
静态初始化是指在数组声明后直接为数组指定具体的内容
如果想要直接在声明的时候给数组赋初始值,可以采用大括号完成,只要在数组的生命格式后面加上初值的赋值即可,
数据类型 数组名 []={初始值0,初始值1,初始值3,....初始值n};
package com.qn.array;
public class Test {
public static void main(String[] args) {
int score[]={1,2,3,4,5,6};//使用静态初始化声明数组
System.out.println(score.length);
}
}
结果
6
范例求出数组中的最大值和最小值
package com.qn.array;
public class Test {
public static void main(String[] args) {
int score[]={45,12,8,23,89,56};//使用静态初始化声明数组
int max=0;
int min=0;
max=min=score[0];
for (int i = 0; i < score.length; i++) {
if(score[i]>max){
max=score[i];
}
if(score[i]
min=score[i];
}
}
System.out.println('最大值:'+max);
System.out.println('最小值:'+min);
}
}
结果
范例排序,在操作中排序是比较常用的
从大到小
package com.qn.array;
public class Test {
public static void main(String[] args) {
int score[]={45,12,8,23,89,56};//使用静态初始化声明数组
int temp=0;
for (int i = 0; i < score.length; i++) {
for (int j = 0; j < score.length-1; j++) {
if(score[i]>score[j]){
temp=score[i];
score[i]=score[j];
score[j]=temp;
}
}
}
for (int i = 0; i < score.length; i++) {
System.out.print(score[i]+'\t');
}
}
}
结果
这个时候不要被i值所迷惑 if(score[i]>score[j]){
这一步主要知识为了比较,实际上完成之后输出的时候是根据j的值排序的
二维数组
如果可以把一维数组当做几何中的一条线图形,那么二维数组就相当于一个表格
A B
1 姓名 年龄
2 齐宁 21
3 齐燕 23
4 齐威 26
二维数组声明的方式和以为数组的类似,内存分配也一样是用new这个关键字
其实声明与分配内存的格式如下
动态初始化
数据类型 数组名[][];
数组名=new 数据类型[行的个数][列的个数];
声明并初始化数组
数据类型 数组名[][]=new 数据类型[行的个数][列的个数];
静态初始化
二维数组的存储
声明二维数组score 同时开辟一段内存空间
int score[][]=new int[4][3];
整体数据score可保存的元素是4*3=12个,在java中,int数据类型所占用的空间为4个字节,因此该整形数组占用的内存共为4*12=48个字节
事例
package com.qn.array;
public class test1 {
public static void main(String[] args) {
int score[][] = new int[4][3];
score[0][1] = 30;
score[1][0] = 31;
score[2][1] = 32;
score[2][2] = 33;
score[3][1] = 34;
score[1][1] = 35;
for (int i = 0; i < score.length; i++) {
for (int j = 0; j < score[i].length; j++) {
System.out.print(score[i][j]+'\t');
}
System.out.println('');
}
}
}
结果
二维数组静态初始化
用到的时候才会开辟空间,不用的(红色部分)则不开辟空间
多维数组
一般只是用到二维数组
三维数组简单了解
package com.qn.array;
public class test1 {
public static void main(String[] args) {
int score[][][]={
{
{5,1},{6,7}
},
{
{9,4},{8,3}
}
};
System.out.print(score[0][0][0]+'\t');
System.out.print(score[0][0][1]+'\t');
System.out.print(score[0][0][0]+'\t');
System.out.print(score[0][0][1]+'\t');
System.out.print(score[1][0][0]+'\t');
System.out.print(score[1][0][1]+'\t');
System.out.print(score[1][1][0]+'\t');
System.out.print(score[1][1][1]+'\t');
}
}
数组:是一组相关变量的集合
数组是一组相关数据的集合,一个数组实际上就是一连串的变量,数组按照使用可以分为一维数组、二维数组、多维数组
数据的有点
不使用数组定义100个整形变量:int i1;int i2;int i3
使用数组定义 int i[100];
数组定义:int i[100];只是一个伪代码,只是表示含义的
一维数组
一维数组可以存放上千万个数据,并且这些数据的类型是完全相同的,
使用java数组,必须经过两个步骤,声明数组和分配内存给该数组,
声明形式一
声明一维数组:数据类型 数组名[]=null;
非配内存给数组:数组名=new 数据类型[长度];
声明形式二
声明一维数组:数据类型 [] 数组名=null;
java数据类型分为两大类
基本数据类型
int、long操作的时候本身就是具体的内容
引用数据类型:数组、类、接口
引用传递的就是一个内存的使用权,一块内存空间,可能有多个人同时使用
事例声明数组
package com.qn.array;
public class Test {
public static void main(String[] args) {
int score[]=null;//声明数组
score=new int[3];//开辟空间,大小为3
}
}
数组的声明格式里,数据类型是数组元素的数据类型,常见的有整形、浮点型、与字符型等
数组名是用来统一这组相同数据类型元素的名称,其命名规则和变量的相同
数组声明后实际上是在栈内存中保存了此数组的名称,结下了是要在堆内存中配置数组所需要的内存,齐产固定是告诉编译器,所声明的数组要存放多少个元素,而new 则是命令编译器根据括号里的长度
基本数据类型偶读有其默认值:int 0;只要是引用数据类型默认值就是null
事例
package com.qn.array;
public class Test {
public static void main(String[] args) {
int score[]=null;//声明数组
score=new int[3];//开辟空间,大小为3
System.out.print('score[0]='+score[0]);
System.out.print('\tscore[1]='+score[1]);
System.out.print('\tscore[2]='+score[2]);
}
}
堆栈内存的解释
数组操作中,在栈内存中保存的永远是数组的名称,只开辟了栈内的空间,数组是永远无法使用的,必须有指向的对内存才可以使用,要想开辟新对内存空间必须使用new关键字,之后就是将对内存的使用权交给对应的栈内存,而且一个堆内存空间可以同时被多个栈内存空间指向,比如一个人可以有多个名字,人就相当于对内存,名字就相当于栈内存
声明数组的同时分配内存空间
声明数组的同时非配内存
数据类型 数组名[]=new 数据类型[个数]
int score[]=new int[10];
声明一个元素个数为10的整形数组score,同时开辟依靠内存空间工期使用
java中,由于整形数据类型占用的空间为4个byte,而整个数组score可保存的元素有10个。所以上例中占用的内存共有4*10=40个字节
数组的访问
数组中元素的表示方法
想要访问数组里的元素可以利用索引来完成,java的数组索引标号由10开始,以一个score[10]的整形数组为例,score[0]代表第一个元素
一直向下,最后一个为score[9]
取得数组的长度
在java中取得数组的长度(也就是数组元素的长度)可以利用数组名称.length完成,
数组名称.length--返回一个int类型的数据
package com.qn.array;
public class Test {
public static void main(String[] args) {
int score[]=null;//声明数组
score=new int[3];//开辟空间,大小为3
System.out.println(score.length);
}
}
结果
数组的静态初始化
之前的数组,所采用的都是动态初始化,所有的内容在数组声明的时候并不具体的指定,而是以默认值的形式出现
静态初始化是指在数组声明后直接为数组指定具体的内容
如果想要直接在声明的时候给数组赋初始值,可以采用大括号完成,只要在数组的生命格式后面加上初值的赋值即可,
数据类型 数组名 []={初始值0,初始值1,初始值3,....初始值n};
package com.qn.array;
public class Test {
public static void main(String[] args) {
int score[]={1,2,3,4,5,6};//使用静态初始化声明数组
System.out.println(score.length);
}
}
结果
6
范例求出数组中的最大值和最小值
package com.qn.array;
public class Test {
public static void main(String[] args) {
int score[]={45,12,8,23,89,56};//使用静态初始化声明数组
int max=0;
int min=0;
max=min=score[0];
for (int i = 0; i < score.length; i++) {
if(score[i]>max){
max=score[i];
}
if(score[i]
min=score[i];
}
}
System.out.println('最大值:'+max);
System.out.println('最小值:'+min);
}
}
结果
范例排序,在操作中排序是比较常用的
从大到小
package com.qn.array;
public class Test {
public static void main(String[] args) {
int score[]={45,12,8,23,89,56};//使用静态初始化声明数组
int temp=0;
for (int i = 0; i < score.length; i++) {
for (int j = 0; j < score.length-1; j++) {
if(score[i]>score[j]){
temp=score[i];
score[i]=score[j];
score[j]=temp;
}
}
}
for (int i = 0; i < score.length; i++) {
System.out.print(score[i]+'\t');
}
}
}
结果
这个时候不要被i值所迷惑 if(score[i]>score[j]){
这一步主要知识为了比较,实际上完成之后输出的时候是根据j的值排序的
二维数组
如果可以把一维数组当做几何中的一条线图形,那么二维数组就相当于一个表格
A B
1 姓名 年龄
2 齐宁 21
3 齐燕 23
4 齐威 26
二维数组声明的方式和以为数组的类似,内存分配也一样是用new这个关键字
其实声明与分配内存的格式如下
动态初始化
数据类型 数组名[][];
数组名=new 数据类型[行的个数][列的个数];
声明并初始化数组
数据类型 数组名[][]=new 数据类型[行的个数][列的个数];
静态初始化
二维数组的存储
声明二维数组score 同时开辟一段内存空间
int score[][]=new int[4][3];
整体数据score可保存的元素是4*3=12个,在java中,int数据类型所占用的空间为4个字节,因此该整形数组占用的内存共为4*12=48个字节
事例
package com.qn.array;
public class test1 {
public static void main(String[] args) {
int score[][] = new int[4][3];
score[0][1] = 30;
score[1][0] = 31;
score[2][1] = 32;
score[2][2] = 33;
score[3][1] = 34;
score[1][1] = 35;
for (int i = 0; i < score.length; i++) {
for (int j = 0; j < score[i].length; j++) {
System.out.print(score[i][j]+'\t');
}
System.out.println('');
}
}
}
结果
二维数组静态初始化
用到的时候才会开辟空间,不用的(红色部分)则不开辟空间
多维数组
一般只是用到二维数组
三维数组简单了解
package com.qn.array;
public class test1 {
public static void main(String[] args) {
int score[][][]={
{
{5,1},{6,7}
},
{
{9,4},{8,3}
}
};
System.out.print(score[0][0][0]+'\t');
System.out.print(score[0][0][1]+'\t');
System.out.print(score[0][0][0]+'\t');
System.out.print(score[0][0][1]+'\t');
System.out.print(score[1][0][0]+'\t');
System.out.print(score[1][0][1]+'\t');
System.out.print(score[1][1][0]+'\t');
System.out.print(score[1][1][1]+'\t');
}
}
、定义一个Java数组
String[] aArray = new String[5];
String[] bArray = {"a","b","c", "d", "e"};
String[] cArray = new String[]{"a","b","c","d","e"};
第一种是定义了一个数组,并且指定了数组的长度,我们这里称它为动态定义。
第二种和第三种在分配内存空间的同时还初始化了值。
1、打印Java数组中的元素
int[] intArray = { 1, 2, 3, 4, 5 };
String intArrayString = Arrays.toString(intArray);
// print directly will print reference value
System.out.println(intArray);
// [I@7150bd4d
System.out.println(intArrayString);
// [1, 2, 3, 4, 5]
这里的重点是说明了Java中数组的引用和值得区别,第三行直接打印intArray,输出的是乱码,因为intArray仅仅是一个地址引用。第4行输出的则是真正的数组值,因为它经过了Arrays.toString()的转化。对Java初学者来说,引用和值仍需重视。
2、从Array中创建ArrayList
String[] stringArray = { "a", "b", "c", "d", "e" };
ArrayList<String> arrayList = new ArrayList<String>(Arrays.asList(stringArray));
System.out.println(arrayList);
// [a, b, c, d, e]
为什么要将Array转换成ArrayList呢?可能是因为ArrayList是动态链表,我们可以更方便地对ArrayList进行增删改,我们并不需要循环Array将每一个元素加入到ArrayList中,用以上的代码即可简单实现转换。
3、检查数组中是否包含某一个值
String[] stringArray = { "a", "b", "c", "d", "e" };
boolean b = Arrays.asList(stringArray).contains("a");
System.out.println(b);
// true
先使用Arrays.asList()将Array转换成List<String>,这样就可以用动态链表的contains函数来判断元素是否包含在链表中。
4、连接两个数组
int[] intArray = { 1, 2, 3, 4, 5 };
int[] intArray2 = { 6, 7, 8, 9, 10 };
// Apache Commons Lang library
int[] combinedIntArray = ArrayUtils.addAll(intArray, intArray2);
ArrayUtils是Apache提供的数组处理类库,其addAll方法可以很方便地将两个数组连接成一个数组。
5、声明一个数组内链
method(new String[]{"a", "b", "c", "d", "e"});
6、将数组中的元素以字符串的形式输出
// containing the provided list of elements
// Apache common lang
String j = StringUtils.join(new String[] { "a", "b", "c" }, ", ");
System.out.println(j);
// a, b, c
同样利用StringUtils中的join方法,可以将数组中的元素以一个字符串的形式输出。
7、将Array转化成Set集合
Set<String> set = new HashSet<String>(Arrays.asList(stringArray));
System.out.println(set);
//[d, e, b, c, a]
在Java中使用Set,可以方便地将需要的类型以集合类型保存在一个变量中,主要应用在显示列表。同样可以先将Array转换成List,然后再将List转换成Set。
8、数组翻转
int[] intArray = { 1, 2, 3, 4, 5 };
ArrayUtils.reverse(intArray);
System.out.println(Arrays.toString(intArray));
//[5, 4, 3, 2, 1]
依然用到了万能的ArrayUtils。
9、从数组中移除一个元素
int[] intArray = { 1, 2, 3, 4, 5 };
int[] removed = ArrayUtils.removeElement(intArray, 3);//create a new array
System.out.println(Arrays.toString(removed));
再补充一个:将一个int值转化成byte数组
byte[] bytes = ByteBuffer.allocate(4).putInt(8).array();
for (byte t : bytes) {
System.out.format("0x%x ", t);
}
在JAVA里面,可以用复制语句”A=B”给基本类型的数据传递值,但是如果A,B是两个同类型的数组,复制就相当于将一个数组变量的引用传递给另一个数组;如果一个数组发生改变,那么引用同一数组的变量也要发生改变.
以下是归纳的JAVA中复制数组的方法:
1.使用FOR循环,将数组的每个元素复制或者复制指定元素,不过效率差一点
2.使用clone方法,得到数组的值,而不是引用,不能复制指定元素,灵活性差一点
3.使用System.arraycopy(src, srcPos, dest, destPos, length)方法,推荐使用
举例:
1.使用FOR循环
int[] src={1,3,5,6,7,8};
int[] dest = new int[6];
for(int i=0;i<6;i++) dest[i] = src[i];
2.使用clone
int[] src={1,3,5,6,7,8};
int[] dest;
dest=(int[]) src.clone();//使用clone创建
副本,注意clone要使用强制转换
3.使用System.arraycopy
int[] src={1,3,5,6,7,8};
int[] dest = new int[6];
System.arraycopy(src, 0, dest, 0, 6);
——————————————————————-
System提供了一个静态方法arraycopy(),我们可以使用它来实现数组之间的复制.
其函数原型是:
public static void arraycopy(Object src, int srcPos, Object dest, int destPos, int length)
src:源数组; srcPos:源数组要复制的起始位置;
dest:目的数组; destPos:目的数组放置的起始位置;
length:复制的长度.
注意:src and dest都必须是同类型或者可以进行转换类型的数组.
有趣的是这个函数可以实现自己到自己复制,
比如:int[] fun ={0,1,2,3,4,5,6};
System.arraycopy(fun,0,fun,3,3);
则结果为:{0,1,2,0,1,2,6};
数组比较】
Arrays提供了重载后的equals()方法,针对所有类型和Object类型都做了重载,用来比较整个数组。数组相等的条件是元素个数必须相等,并且对应位置的元素也相等。而多维数组的比较用deepEquals()方法。Array.equals()方法比较的两个数组必须是同类型的数组。
import java.util.Arrays;
public class javaArrayEquals{
public static void main(String args[]){
int[] arrayA = {1,2,3};
int[] arrayB = {1,2,3,};
int[] arrayC = new int[4]; //if int[] arrayC = new int[3],return true
arrayC[0] = 1;
arrayC[1] = 2;
arrayC[2] = 3;
System.out.println(Arrays.equals(arrayA, arrayB));
System.out.println(Arrays.equals(arrayA, arrayC));
String[][] arrayD = {{"a","b"},{"c","d"}};
String[][] arrayE = {{"a","b"},{"c","d"}};
System.out.println(Arrays.deepEquals(arrayD, arrayE));
}
}
【数组排序与查找】
数组提供了内置的排序方法sort(),可以对任意基本类型数组或者对象数组进行排序(该对象必须实现Comparable接口或者具有相关联的Comparator)。JAVA对不同的类型提供了不同的排序方法----针对基本类型设计的快速排序,以及针对对象设计的“稳定归并排序”,所以无需担心数组排序的效率问题。
binarySearch()用于在以排好序的数组中快速查找元素,如果对未排序的数组使用binarySearch(),那么将产生难以预料的结果。
【返回数组】
C和C++不能返回一个数组,只能返回指向数组的指针,因为返回数组使得控制数组的生命周期变得困难,并且容易造成内存泄漏。java允许直接返回一个数组,并且可以由垃圾回收机制回收。
【数组与容器转换】【无法转换基本类型数组】
数组转为List:
import java.util.*;
public class arrayToList{
public static void main(String args[]){
String[] arrayA = {"a","b","c"};
List listA = java.util.Arrays.asList(arrayA);
System.out.println("listA: " + listA);
int[] arrayB = {1,2,3};
List listB = java.util.Arrays.asList(arrayB);
System.out.println("listB: " + listB);
Integer[] arrayC = {1,2,3};
List listC = java.util.Arrays.asList(arrayC);
System.out.println("listC: " + listC);
}
}
输出:
listA: [a, b, c]
listB: [[I@de6ced]
listC: [1, 2, 3]
为什么int和Integer输出会不同呢?
List转为数组
import java.util.*;
public class listToArray{
public static void main(String args[]){
List<String> list = new ArrayList<String>();
String[] array;
list.add("testA");
list.add("testB");
list.add("testC");
System.out.println("list: " + list);
String[] strings = new String[list.size()];
array = list.toArray(strings);
for(int i = 0, j = array.length; i < j; i++){
System.out.print(array[i] + ",");
}
}
}
输出为:
list: [testA, testB, testC]
testA,testB,testC
【去除重复数据】
利用数组和容器转换可以方便地去除数组重复数据,不过如果数组过大,效率是一个问题。
import java.util.*;
public class javaArrayUnique{
public static void main(String args[]){
String[] array = {"a","b","a","a","c","b"};
arrayUnique(array);
//test
for(int i = 0, j = arrayUnique(array).length; i < j; i++){
System.out.print(arrayUnique(array)[i] + ",");
}
}
public static String[] arrayUnique(String[] array){
List<String> list = new ArrayList<String>();
for(int i = 0, j = array.length; i < j; i++){
if(!list.contains(array[i])){
list.add(array[i]);
}
}
String[] strings = new String[list.size()];
String[] arrayUnique = list.toArray(strings);
return arrayUnique;
}
}
关于效率问题,我做了一个对比,在我电脑上运行十万数据的数组大概是577ms,而运行一百万数据的数据大约要5663ms。这还跟计算机的运行能力有关,但是明显是随着数组大小递增的。
import java.util.*;
public class javaArrayUnique{
public static void main(String args[]){
Double[] array = new Double[100000];
for(int i = 0, j = array.length; i < j; i++){
array[i] = Math.ceil(Math.random()*1000);
}
Double[] arrayB = new Double[1000000];
for(int i = 0, j = arrayB.length; i < j; i++){
arrayB[i] = Math.ceil(Math.random()*1000);
}
System.out.println("start");
long startTime = System.currentTimeMillis();
arrayUnique(array);
long endTime = System.currentTimeMillis();
System.out.println("array unique run time: " +(endTime - startTime) +"ms");
long startTimeB = System.currentTimeMillis();
arrayUnique(arrayB);
long endTimeB = System.currentTimeMillis();
System.out.println("arrayB unique run time: " +(endTimeB - startTimeB) +"ms");
}
public static Double[] arrayUnique(Double[] array){
List<Double> list = new ArrayList<Double>();
for(int i = 0, j = array.length; i < j; i++){
if(!list.contains(array[i])){
list.add(array[i]);
}
}
Double[] doubles = new Double[list.size()];
Double[] arrayUnique = list.toArray(doubles);
return arrayUnique;
}
}
输出:
start
array unique run time: 577ms
arrayB unique run time: 5663ms
函数
四个方面:
函数的定义
函数的特点
函数的应用
函数的重载
一、函数的定义及特点
1) 什么是函数?
函数就是定义在类中的具有特定功能的一段独立小程序,函数也称为方法
2)Java中函数的格式:
修饰符 返回值类型函数名(参数类型 形式参数1,参数类型 形式参数2,。。)
{ 执行语句;
return 返回值;
}
返回值类型:函数运行后的结果的数据类型
参数类型:是形式参数的数据类型
形式参数:是一个变量,用于存储调用函数时传递给函数的实际参数
实际参数:传递给形式参数的具体数值
return:用于结束函数
返回值:该值会返回给调用者
3) 函数的特点
a) 定义函数可以将功能代码进行封装
b) 便于对该功能进行复用
c) 函数只有被调用才会被执行
d) 函数的出现提高了代码的复用性
e) 对于函数没有具体返回值的情况,返回值类型用关键字void表示,那么该函数中的return语句如果在最后一行可以省略不写,系统会帮你自动加上。
注:
a) 函数中只能调用函数,不可以在函数内部定义函数。
b) 定义函数时,函数的结果应该返回给调用者,交由调用者处理。
c) 当函数运算后,没有具体的返回值时,这是返回值类型用一个特殊的关键字来标识该关键字就是void,void:代表的是函数没有具体返回值的情况。
d) 当函数的返回值类型是void时,函数中的return语句可以省略不写。
4) 如何定义一个函数?
函数其实就是一个功能,定义函数就是实现功能,通过两个明确来完成:
1)、明确该功能的运算完的结果,其实是在明确这个函数的返回值类型。
2)、在实现该功能的过程中是否有未知内容参与了运算,其实就是在明确这个函数的参数列表(参数类型&参数个数)。
5) 函数的作用:
1)、用于定义功能。
2)、用于封装代码提高代码的复用性。
注意:函数中只能调用函数,不能定义函数。
6) 主函数:
1)、保证该类的独立运行。
2)、因为它是程序的入口。
3)、因为它在被jvm调用。
7) 函数定义名称是为什么呢?
答:1)、为了对该功能进行标示,方便于调用。
2)、为了通过名称就可以明确函数的功能,为了增加代码的阅读性。
二、函数的应用
1) 两个明确
a) 明确要定义的功能最后的结果是什么?
b) 明确在定义该功能的过程中,是否需要未知内容参与运算
2) 示例:
举例1:
class FunctionDemo
{
public static void main(String[] args)
{
int x = 4;
System.out.println(x*3+5);
x = 6;
System.out.println(x*3+5);
int y = 4*3+5;
int z = 6*3+5;
System.out.println(y);
System.out.println(z);
}
}
发现以上的运算,因为获取不同数据的运算结果,代码出现了重复。
为了提高代码的复用性。对代码进行抽取。将这个部分定义成一个独立的功能。方便与日后使用。
java中对功能的定义是通过函数的形式来体现的。
明确功能:需要定义功能,完成一个整数的*3+5的运算,
1,先明确函数定义的格式。
/*
修饰符返回值类型函数名(参数类型形式参数1,参数类型形式参数2,)
{
执行语句;
return 返回值;
}
class FunctionDemo
{
public static void getResult(int num)
{
System.out.println(num * 3 + 5);
return;//可以省略
}
public static void main(String[] args)
{
getResult(5);
}
}
对上述关于return是否省略这一小小知识点的总结:
当函数运算后,没有具体的返回值时,这是返回值类型用一个特殊的关键字来标识。
该关键字就是void。void:代表的是函数没有具体返回值的情况。
当函数的返回值类型是void时,函数中的return语句可以省略不写。
举例2:
class FunctionDemo2
{
public static void main(String[] args)
{
int sum = getSum(4,6);
System.out.println("sum="+sum);
sum = getSum(2,7);
System.out.println("sum="+sum);
}
/*下面的这个功能定义思想有问题,为什么呢?因为只为完成加法运算,至于是否要对和进行打印操作,
那是调用者的事,不要在该功能中完成。*/
public static void get(int a,int b)
{
System.out.println(a+b);
return ;
}
}
如何定义一个函数呢?
1,既然函数是一个独立的功能,那么该功能的运算结果是什么先明确
因为这是在明确函数的返回值类型。
2,在明确在定义该功能的过程中是否需要未知的内容参与运算。
因为是在明确函数的参数列表(参数的类型和参数的个数)。
class FunctionDemo2
{
public static void main(String[] args)
{
/*
int sum = getSum(4,6);
System.out.println("sum="+sum);
sum = getSum(2,7);
System.out.println("sum="+sum);
*/
//get(4,5);
int x = getSum(4,4);
int y = getSum(7,9);
int num = getMax(x,y);
}
//需求:定义一个功能。完成3+4的运算。并将结果返回给调用者。
/*
1,明确功能的结果:是一个整数的和。
2,在实现该功能的过程中是否有未知内容参与运算,没有。
其实这两个功能就是在明确函数的定义。
1,是在明确函数的返回值类型。
2,明确函数的参数列表( 参数的类型和参数的个数)。
*/
public static int getSum()
{
return 3+4;
}
/*
以上这个函数的功能,结果是固定的,毫无扩展性而言。
为了方便用户需求。由用户来指定加数和被加数。这样,功能才有意义。
思路:
1,功能结果是一个和。返回值类型是int。
2,有未知内容参与运算。有两个。这个两个未知内容的类型都是int。
*/
public static int getSum(int x,int y)
{
return x+y;
}
/*
需求:判断两个数是否相同。
思路:
1,明确功能的结果:结果是:boolean 。
2,功能是否有未知内容参与运算。有,两个整数。
*/
public static boolean compare(int a,int b)
{
/*
if(a==b)
return true;
//else
return false;
*/
//return (a==b)?true:false;
return a==b;
}
/*
需求:定义功能,对两个数进行比较。获取较大的数。
*/
public static int getMax(int a,int b)
{
/*
if(a>b)
return a;
else
return b;
//或者用下面的三元运算符
*/
return (a>b)?a:b;
}
}
3) 练习:
1,定义一个功能,用于打印矩形。
2,定义一个打印99乘法表功能的函数。
class FunctionTest
{
public static void main(String[] args)
{
draw(5,6);
printHr();
draw(7,9);
printHr();
print99();
}
/*
定义一个功能,用于打印矩形。
思路:
1,确定结果:没有,因为直接打印。所以返回值类型是void
2,有未知内容吗?有,两个,因为矩形的行和列不确定。
*/
public static void draw(int row,int col)
{
for(int x=0; x<row; x++)
{
for(int y=0; y<col; y++)
{
System.out.print("*");
}
System.out.println();
}
}
public static void printHr()
{
System.out.println("------------------------------");
}
/*
定义一个打印99乘法表功能的函数。
*/
public static void print99()
{
for(int x=1; x<=9; x++)
{
for(int y=1; y<=x; y++)
{
System.out.print(y+"*"+x+"="+y*x+"\t");
}
System.out.println();
}
}
}
三、函数的重载(overload)
重载的概念:
在同一个类中,允许存在一个以上的同名函数,只要它们的参数个数或者参数类型不同即可。
重载的特点:
与返回值类型无关,只看参数列表。
重载的好处:
方便于阅读,优化了程序设计。
重载示例:
返回两个整数的和
int add(int x,int y){return x+y;}
返回三个整数的和
int add(int x,int y, int z){return x+y+z;}
返回两个小数的和
double add(double x,double y){return x+y;}
什么时候用重载?
当定义的功能相同,但参与运算的未知内容不同。
那么,这时就定义一个函数名称以表示起功能,方便阅读,而通过参数列表的不同来区分多个同名函数。
重载范例:
class FunctionOverload
{
public static void main(String[] args)
{
add(4,5);
add(4,5,6);
print99();
}
public static void print99(int num)
{
for(int x=1; x<=num; x++)
{
for(int y=1; y<=x; y++)
{
System.out.print(y+"*"+x+"="+y*x+"\t");
}
System.out.println();
}
}
//打印99乘法表
public static void print99()
{
print99(9);
}
//定义一个加法运算,获取两个整数的和。
public static int add(int x,int y)
{
return x+y;
}
//定义一个加法,获取三个整数的和。
public static int add(int x,int y,int z)
{
return add(x,y)+z;
}
}
练习:区分是否是重载
void show(int a,char b,double c){}
下面的a,b,c,d,e,f与上述一句的区别:
a.
void show(int x,char y,double z){}//没有,因为和原函数一样。
b.
int show(int a,double c,char b){}//重载,因为参数类型不同。注意:重载和返回值类型没关系。
c.
void show(int a,double c,char b){}//重载,因为参数类型不同。注意:重载和返回值类型没关系。
d.
boolean show(int c,char b){}//重载了,因为参数个数不同。
e.
void show(double c){}//重载了,因为参数个数不同。
f.
double show(int x,char y,double z){}//没有,这个函数不可以和给定函数同时存在与一个类中。
如何区分重载:当函数同名时,只看参数列表。和返回值类型没关系。
一、函数
函数的定义
什么是函数?
函数就是定义在类中的具有特定功能的一段独立小程序,也可以称之为方法
函数的格式
/*
修饰符 返回值类型 函数名(参数类型 形式参数1,参数类型 形式参数2,........){
执行语句;
return 返回值;
}
返回值类型:函数运行后的结果的数据类型。
参数类型:是形式参数的数据类型。
形式参数:是一个变量,用于存储调用函数时传递给函数的实际参数。
实际参数:传递给形式参数的具体数值。
return:用于结束函数。
返回值:该值会返回给调用者。
*/
函数的特点
定义函数可以将功能代码进行封装
便于对该功能进行复用
函数只有被调用才会被执行
函数的出现提高了代码的复用性
对于函数没有具体返回值的情况,返回值类型用关键 字 void表示,那么该函数中的return语句如果在最后一 行可以省略不写。
注意: 函数中只能调用函数,不可以在函数内部定义函数。 定义函数时,函数的结果应该返回给调用者,交由调用者处 理。
函数的应用
两个明确
明确要定义的功能最后的结果是什么?
明确在定义该功能的过程中,是否需要未知内容参与运
函数的小应用
class FunctionDemo1
{
public static void main(String[] args)
{
System.out.println(getAdd(5,8));
}
/*
函数小练习
需求:定义一个功能,实现两个整数的加法运算
思路:1、因为需求是定义一个功能,所以应使用函数来实现
2、通过 需求发现需要把结果返回给调用者,所以该函数有返回值,
因为是两个整数进行运算,所以返回值是int类型
3、通过需求发现是两个未知整数进行未知运算,所以该函数有参数列表,
而且参数为三个,类型应为 两个int类型和一个char类型
*/
//第一种实现方法 将运算后的值返回给调用者
public static int getAdd(int a, int b){
return a+b;
}
//第二种实现方法 将运算后的值在该函数内部打印
public static void getAdd1(int a,int b){
System.out.println(a+b);
}
/*
问题:
getAdd和getAdd1这两个函数有什么一样么?
最大的区别就是getAdd1这个函数已经违背了我们定义函数的初衷,为什么呢?
因为我们定义这个函数的初衷只是为了对两个数进行求和运算,而getAdd1这个函数在
完成求和运算的基础上又做了打印操作。如果我们仅仅是为了打印两个数的和,
那么getAdd1这个函数这样定义倒是不为过,但是当需要拿两个数的和进行其他运算时,
getAdd1这个函数就偏离了我们要实现的功能,所以,再定义函数时,尽可能的巴函数的
结果返回给调用者,让调用者去决定该结果的去向。
*/
}
函数的重载
重载的概念
在同一个类中,允许存在一个以上的同名函数,只要它们的参数个数或者参数类型不 同即可。
重载的特点
与返回值类型无关,只看参数列表
重载的好处
方便阅读优化了程序设计
什么时候使用重载?
当功能相同,但功能主体不同时,可以使用重载
重载的应用
class FunctionDemo
{
public static void main(String[] args)
{
System.out.println("Hello World!");
}
/*函数重载小练习
需求:利用函数重载分别实现打印99乘法表和根据用户输入打印乘法表
思路:1、通过需求发现两个函数都是打印乘法表,只不过一个是固定打印,
一个是根据用户输入数据打印,所以为方便阅读,
可以定义函数名相同的函数来实现
2、通过99乘法表发现,需要用到循环嵌套,而且是尖朝上,
所以利用尖朝上,可以通过控制内循环条件,
让条件随着外循环的变化而变化这一规律来完成程序设计
*/
//打印固定99乘法表
public static void print99(){
/*
for(int i=1;i<=9;i++){ //用来控制*号右边的数字
for(int j=1;j<=i;j++){ //用来控制*号左边的数字
//输出乘法表口诀
System.out.print(j+"*"+i+"="+(j*i)+"\t");
}
System.out.println(); //输出换行
}
*/
/*发现使用重载后出现了重复代码,
经过观察发现该函数内部可以通过调用另一个函数来实现自己原有的功能,
而且代码相对简单 代码如下:
*/
print99(9);
}
//通过重载的形式实现打印
public static void print99(int num){
for(int i=1;i<=num;i++){ //用来控制*号右边的数字
for(int j=1;j<=i;j++){ //用来控制*号左边的数字
//输出乘法表口诀
System.out.print(j+"*"+i+"="+(j*i)+"\t");
}
System.out.println(); //输出换行
}
}
}
函数重载判断
//函数重载判断
/*
判断下面所列举的函数是否与 public static void print(int n,char c,double num){}重载
1、public static void print(int x,char ch,double do){} //没有重载,因为参数类型一样
2、public static void print(double d,char c,int n){} //重载了,因为参数类型不一样
3、public static int print(char c,int a){} //重载了,因为参数类型不一样
4、public static int print(int a,char c,double d){} //没有重载,因为重载和返回值类型没有关系
5、public static void print(int a,char c){} //重载了,因为参数类型不一样
*/
二、数组
数组的定义
概念:同一种数据类型的集合,相当于一个容器
数组的好处
可以给放入的元素进行编号,编号是从0开始的
几种常见的数组创建方式:
1、元素类型 [] 数组名 = new 元素类型[数组的长度] 如: int [] array = new int[5];
2、元素类型 数组名[] = new 元素类型[数组长度] 如: int array[] = new int [6];
3、元素类型 [] 数组名 = new 元素类型[]{元素,元素,元素.....} 如: int [] array = new int [] {1,2,3,4,5,6,7};
4、元素类型 [] 数组名 = {}; 如: int [] array = {1,2,3,4,5,6,7}
数组的内存分配及特点
内存结构
Java程序在运行时,需要在内存中的分配空间。为了提高运算效率,有对空 间进行了不同区域的划分,因为每一片区域都有特定的处理数据方式和内存管理方式。
栈内存
用于存储局部变量,当数据使用完,所占空间会自动释放。
堆内存
数组和对象,通过new建立的实例都存放在堆内存中。
每一个实体都有内存地址值
实体中的变量都有默认初始化值
int——>0
double——>0.0
boolean——>false
char——>'\u0000' 空字符ASCII表
实体不在被使用,会在不确定的时间内被垃圾回收器回收
方法区
本地方法区:调用的是Windows系统底层资源
寄存器:和CPU有关
数组操作常见问题
1、数组脚标越界异常(ArrayIndexOutOfBoundsException)
class ArrayException
{
public static void main(String[] args)
{
int [] array = new int[3];
System.out.println(array[3]);
/*由于访问了不存在的角标,
所以会出现数组脚标越界异常(ArrayIndexOutOfBoundsException)
*/
}
}
2、空指针异常(NullPointerException)
class ArrayException
{
public static void main(String[] args)
{
int [] array =null;
System.out.println(array[0]);
/*由于array=null,所以array并没有指向实体,而却在操作实体中的元素
所以会出现空指针异常(NullPointerException)*/
}
}
数组常见操作
打印数组内存地址值
public static void main(String[] args)
{
int [] arr = new int[]{10,22,35,47,56,64,78,82,96};
System.out.println(arr);
}
其中“[”代表的是这是一个数组
“I”代表的是这个数组的类型是int类型
“15db9742”代表的是这个数组在内存中的位置,是一个十六进制的表现形式
数组遍历
class ArrayException
{
//实现数组遍历
public static void main(String[] args)
{
int [] array = {1,4,6,4,8,9,11,56};
for(int i=0;i<array.length;i++){
System.out.println(array[i]);
}
}
}
数组获取最值
class ArrayException
{
//获取数组中的最大值
public static void main(String[] args)
{
int [] array = {1,4,6,4,8,9,11,56};
/*第一种方式:定义第三方变量,初始化为array[0],
让这个变量与数组中的元素进行比较,并记录较大的值
*/
int temp = array[0];
for(int i=1;i<array.length;i++){ //对数组进行遍历,并从下标1开始
//取出较大的值
if(array[i]>temp)
temp = array[i];
}
System.out.println("数组array中的最大值是:"+temp);
//第二种方式:定义第三方变量,初始化值为0,作为数组的下标使用
int index = 0;
for(int i=1;i<array.length;i++){
if(array[i]>array[index])
index = i;
}
System.out.println("数组array中的最大值是:"+array[index]);
}
}
数组排序
选择排序
选择排序原理图
代码实现
class ArraySort1
{
//选择排序
public static void main(String[] args)
{
int [] arr = {2,5,3,4,7,6,1};
System.out.sort("排序前");
getPrint(arr);
System.out.println("排序后");
getSort(arr);
}
/*
选择排序:
思路:因为选择排序是拿一个元素与数组中的其他元素进行比较,
所以应该是嵌套循环,外层循环控制一个数个内层循环的所有数字
一一进行比较而比较的第一个数是这个数+1,而外层循环的最后一个
数,肯定是数组中最大(或最小)的数,所以是不用再次参与比较
的,所以外层循环循环次数应-1
*/
//选择排序
public static void getSort(int [] arr){
for(int i = 0; i<arr.length-1;i++){
for(int j=i+1;j<arr.length;j++){
if(arr[i]>arr[j]){
int temp = arr[i];
arr[i] = arr[j];
arr[j] = temp;
}
}
}
}
}
但是通过观察发现这样写的代码只要条件成立每次都要进行换位操作,而计算机底层是二进制运算,相对比较麻烦,所以能不能每比较一轮换一下位置呢??所以代码可以修改为:
class ArraySort1
{
//选择排序
public static void main(String[] args)
{
int [] arr = {2,5,3,4,7,6,1};
System.out.println("排序前");
getPrint(arr);
System.out.println("排序后");
getSort(arr);
}
public static void getSort(int [] arr){
//用于记录最值下标
int index = 0;
for(int i = 0; i<arr.length-1;i++){
index = i;
for(int j=i+1;j<arr.length;j++){
if(arr[index]>arr[j]){
//记录最值下标
index = j;
}
}
//进行换位操作
int temp = arr[i];
arr[i] = arr[index];
arr[index] = arr[i];
}
}
冒泡排序
冒泡排序示例图:
代码实现:
class ArraySort1
{
//数组中常用的两种排序方式
public static void main(String[] args)
{
int [] arr = {2,5,3,4,7,6,1};
System.out.println("排序前");
getPrint(arr);
System.out.println("排序后");
getSortM(arr);
getPrint(arr);
}
/*冒泡排序:
思路:外循环:因为冒泡排序是相邻两个数进行的比较,比较一轮后找出最值,
所以外循环比较次数也应该-1,
内循环:因为冒泡排序每循环一轮都会找出一个最值,所以内循环比较
次数也应该在-1的基础上还应该减去外循环的初始化值
*/
//冒泡排序
public static void getSortM(int [] arr){
for(int i = 0; i<arr.length-1;i++){
for(int j=0;j<arr.length-1-i;j++){
if(arr[j]>arr[j+1]){
int temp = arr[j];
arr[j] = arr[j+1];
arr[j+1] = temp;
}
}
}
}
基本查找
class ArrayFind1
{
/*数组查找,
需求:给定一个数查找概该数是否存在,并返回改数在数组中的位置
*/
public static void main(String[] args)
{
int [] arr = new int[]{10,22,35,47,56,64,78,82,96};
System.out.println("原数组");
print(arr);
//要使用折半查找,数组中的元素必须是有序的(如:从小到大)
System.out.println("使用一般查找方法");
System.out.println("要查找的数字的在数组中的下标为"+find(arr,64));
System.out.println("使用折半查找方法");
System.out.println("要查找的数字的在数组中的下标为:"+find1(arr,64));
}
//遍历数组,用于显示数组元素
public static void print(int [] arr){
System.out.print("[");
for(int i=0;i<arr.length;i++){
if(i==arr.length-1){
System.out.print(arr[i]+"]");
}
else
System.out.print(arr[i]+",");
}
System.out.println();
}
/*
一般查找方法
思路:可以通过遍历数组的方式让数组中的每个元素与要查找的
数字进行比较,如果相等,这返回该元素所在的下标即可
如果该数不存在返回-1 */
public static int find(int [] arr, int num){
for(int i=0;i<arr.length;i++){
if(num==arr[i])
return i;
}
return -1;
}
/*
折半查找:对于有序数组,可以使用折半查找提高效率
思路:1、因为是折半查找,所以应该定义三个变量(min(最小下标),mid(中间下标),max(最大下标))
2、因为需要进行循环,而循环次数不固定,所以应使用while循环,
而循环条件应为(min<=max)(因为min是最小下标,如果min>max还没
找到,那就说明该数组中并没有要查找的元素)
3、当要查找的数大于mid所在的元素时,应从min的位置应该发生改变,应为mid+1
然后在找出中间值继续循环,如果要查找的数小于此时的mid所在的
元素时,则max的位置应该发生改变,应为mid-1,然后再取中间值,
直到(min<=max)不成立,不成立返回-1
*/
public static int find1(int [] arr,int num){
int min = 0;
int max = arr.length-1;
int mid = (min+max)/2;
while(min<=max){
if(num==arr[mid])
return mid;
else if(num>arr[mid])
min = mid+1;
else if(num<arr[mid])
max = mid-1;
mid = (min+max)/2;
}
return -1;
}
}
数组中的数组(二维数组)
二维数组的定义
1、元素类型 [][] 数组名 = new 元素类型[数组长度][数组中的数组的长度];
如 int [] [] array = new int [3] [4];
定义了名称为array的二维数组
二维数组中有3个一维数组
每一个一维数组中有4个元素
一维数组的名称分别为arr[0], arr[1], arr[2]
给第一个一维数组1脚标位赋值为78写法是:arr[0][1] = 78;
2、元素类型 [][] 数组名 = new 元素类型[4][];
如: int [] [] array = new int [3] [];
二维数组中有3个一维数组
每个一维数组都是默认初始化值null
可以对这个三个一维数组的长度分别进行初始化
arr[0] = new int[3];
arr[1] = new int[1];
arr[2] = new int[2]
Java 数组
数组对于每一门编程语言来说都是重要的数据结构之一,当然不同语言对数组的实现及处理也不尽相同。
Java语言中提供的数组是用来存储固定大小的同类型元素。
你可以声明一个数组变量,如numbers[100]来代替直接声明100个独立变量number0,number1,....,number99。
本教程将为大家介绍Java数组的声明、创建和初始化,并给出其对应的代码。
声明数组变量
首先必须声明数组变量,才能在程序中使用数组。下面是声明数组变量的语法:
dataType[] arrayRefVar; // 首选的方法
或
dataType arrayRefVar[]; // 效果相同,但不是首选方法
注意: 建议使用dataType[] arrayRefVar 的声明风格声明数组变量。 dataType arrayRefVar[] 风格是来自 C/C++ 语言 ,在Java中采用是为了让 C/C++ 程序员能够快速理解java语言。
实例
下面是这两种语法的代码示例:
double[] myList; // 首选的方法
或
double myList[]; // 效果相同,但不是首选方法
创建数组
Java语言使用new操作符来创建数组,语法如下:
arrayRefVar = new dataType[arraySize];
上面的语法语句做了两件事:
一、使用dataType[arraySize]创建了一个数组。
二、把新创建的数组的引用赋值给变量 arrayRefVar。
数组变量的声明,和创建数组可以用一条语句完成,如下所示:
dataType[] arrayRefVar = new dataType[arraySize];
另外,你还可以使用如下的方式创建数组。
dataType[] arrayRefVar = {value0, value1, ..., valuek};
数组的元素是通过索引访问的。数组索引从0开始,所以索引值从0到arrayRefVar.length-1。
实例
下面的语句首先声明了一个数组变量myList,接着创建了一个包含10个double类型元素的数组,并且把它的引用赋值给myList变量。
public class TestArray {
public static void main(String[] args) {
// 数组大小
int size = 10;
// 定义数组
double[] myList = new double[size];
myList[0] = 5.6;
myList[1] = 4.5;
myList[2] = 3.3;
myList[4] = 4.0;
myList[5] = 34.33;
myList[6] = 34.0;
myList[7] = 45.45;
myList[8] = 99.993;
myList[9] = 11123;
// 计算所有元素的总和
double total = 0;
for (int i = 0; i < size; i++) {
total += myList[i];
}
System.out.println("总和为: " + total);
}
}
以上实例输出结果为:
总和为: 11354.173
下面的图片描绘了数组myList。这里myList数组里有10个double元素,它的下标从0到9。
处理数组
数组的元素类型和数组的大小都是确定的,所以当处理数组元素时候,我们通常使用基本循环或者foreach循环。
示例
该实例完整地展示了如何创建、初始化和操纵数组:
public class TestArray {
public static void main(String[] args) {
double[] myList = {1.9, 2.9, 3.4, 3.5};
// 打印所有数组元素
for (int i = 0; i < myList.length; i++) {
System.out.println(myList[i] + " ");
}
// 计算所有元素的总和
double total = 0;
for (int i = 0; i < myList.length; i++) {
total += myList[i];
}
System.out.println("Total is " + total);
// 查找最大元素
double max = myList[0];
for (int i = 1; i < myList.length; i++) {
if (myList[i] > max) max = myList[i];
}
System.out.println("Max is " + max);
}
}
以上实例编译运行结果如下:
1.9
2.9
3.4
3.5
Total is 11.7
Max is 3.5
foreach循环
JDK 1.5 引进了一种新的循环类型,被称为foreach循环或者加强型循环,它能在不使用下标的情况下遍历数组。
示例
该实例用来显示数组myList中的所有元素:
public class TestArray {
public static void main(String[] args) {
double[] myList = {1.9, 2.9, 3.4, 3.5};
// 打印所有数组元素
for (double element: myList) {
System.out.println(element);
}
}
}
以上实例编译运行结果如下:
1.9
2.9
3.4
3.5
数组作为函数的参数
数组可以作为参数传递给方法。例如,下面的例子就是一个打印int数组中元素的方法。
public static void printArray(int[] array) {
for (int i = 0; i < array.length; i++) {
System.out.print(array[i] + " ");
}
}
下面例子调用printArray方法打印出 3,1,2,6,4和2:
printArray(new int[]{3, 1, 2, 6, 4, 2});
数组作为函数的返回值
public static int[] reverse(int[] list) {
int[] result = new int[list.length];
for (int i = 0, j = result.length - 1; i < list.length; i++, j--) {
result[j] = list[i];
}
return result;
}
以上实例中result数组作为函数的返回值。
Arrays 类
java.util.Arrays类能方便地操作数组,它提供的所有方法都是静态的。具有以下功能:
给数组赋值:通过fill方法。
对数组排序:通过sort方法,按升序。
比较数组:通过equals方法比较数组中元素值是否相等。
查找数组元素:通过binarySearch方法能对排序好的数组进行二分查找法操作。
具体说明请查看下表:
序号 方法和说明
1 public static int binarySearch(Object[] a, Object key)
用二分查找算法在给定数组中搜索给定值的对象(Byte,Int,double等)。数组在调用前必须排序好的。如果查找值包含在数组中,则返回搜索键的索引;否则返回 (-(插入点) - 1)。
2 public static boolean equals(long[] a, long[] a2)
如果两个指定的 long 型数组彼此相等,则返回 true。如果两个数组包含相同数量的元素,并且两个数组中的所有相应元素对都是相等的,则认为这两个数组是相等的。换句话说,如果两个数组以相同顺序包含相同的元素,则两个数组是相等的。同样的方法适用于所有的其他基本数据类型(Byte,short,Int等)。
3 public static void fill(int[] a, int val)
将指定的 int 值分配给指定 int 型数组指定范围中的每个元素。同样的方法适用于所有的其他基本数据类型(Byte,short,Int等)。
4 public static void sort(Object[] a)
对指定对象数组根据其元素的自然顺序进行升序排列。同样的方法适用于所有的其他基本数据类型(Byte,short,Int等)。
数组:是一组相关变量的集合
数组是一组相关数据的集合,一个数组实际上就是一连串的变量,数组按照使用可以分为一维数组、二维数组、多维数组
数据的有点
不使用数组定义100个整形变量:int i1;int i2;int i3
使用数组定义 int i[100];
数组定义:int i[100];只是一个伪代码,只是表示含义的
一维数组
一维数组可以存放上千万个数据,并且这些数据的类型是完全相同的,
使用java数组,必须经过两个步骤,声明数组和分配内存给该数组,
声明形式一
声明一维数组:数据类型 数组名[]=null;
非配内存给数组:数组名=new 数据类型[长度];
声明形式二
声明一维数组:数据类型 [] 数组名=null;
java数据类型分为两大类
基本数据类型
int、long操作的时候本身就是具体的内容
引用数据类型:数组、类、接口
引用传递的就是一个内存的使用权,一块内存空间,可能有多个人同时使用
事例声明数组
package com.qn.array;
public class Test {
public static void main(String[] args) {
int score[]=null;//声明数组
score=new int[3];//开辟空间,大小为3
}
}
数组的声明格式里,数据类型是数组元素的数据类型,常见的有整形、浮点型、与字符型等
数组名是用来统一这组相同数据类型元素的名称,其命名规则和变量的相同
数组声明后实际上是在栈内存中保存了此数组的名称,结下了是要在堆内存中配置数组所需要的内存,齐产固定是告诉编译器,所声明的数组要存放多少个元素,而new 则是命令编译器根据括号里的长度
基本数据类型偶读有其默认值:int 0;只要是引用数据类型默认值就是null
事例
package com.qn.array;
public class Test {
public static void main(String[] args) {
int score[]=null;//声明数组
score=new int[3];//开辟空间,大小为3
System.out.print('score[0]='+score[0]);
System.out.print('\tscore[1]='+score[1]);
System.out.print('\tscore[2]='+score[2]);
}
}
堆栈内存的解释
数组操作中,在栈内存中保存的永远是数组的名称,只开辟了栈内的空间,数组是永远无法使用的,必须有指向的对内存才可以使用,要想开辟新对内存空间必须使用new关键字,之后就是将对内存的使用权交给对应的栈内存,而且一个堆内存空间可以同时被多个栈内存空间指向,比如一个人可以有多个名字,人就相当于对内存,名字就相当于栈内存
声明数组的同时分配内存空间
声明数组的同时非配内存
数据类型 数组名[]=new 数据类型[个数]
int score[]=new int[10];
声明一个元素个数为10的整形数组score,同时开辟依靠内存空间工期使用
java中,由于整形数据类型占用的空间为4个byte,而整个数组score可保存的元素有10个。所以上例中占用的内存共有4*10=40个字节
数组的访问
数组中元素的表示方法
想要访问数组里的元素可以利用索引来完成,java的数组索引标号由10开始,以一个score[10]的整形数组为例,score[0]代表第一个元素
一直向下,最后一个为score[9]
取得数组的长度
在java中取得数组的长度(也就是数组元素的长度)可以利用数组名称.length完成,
数组名称.length--返回一个int类型的数据
package com.qn.array;
public class Test {
public static void main(String[] args) {
int score[]=null;//声明数组
score=new int[3];//开辟空间,大小为3
System.out.println(score.length);
}
}
结果
数组的静态初始化
之前的数组,所采用的都是动态初始化,所有的内容在数组声明的时候并不具体的指定,而是以默认值的形式出现
静态初始化是指在数组声明后直接为数组指定具体的内容
如果想要直接在声明的时候给数组赋初始值,可以采用大括号完成,只要在数组的生命格式后面加上初值的赋值即可,
数据类型 数组名 []={初始值0,初始值1,初始值3,....初始值n};
package com.qn.array;
public class Test {
public static void main(String[] args) {
int score[]={1,2,3,4,5,6};//使用静态初始化声明数组
System.out.println(score.length);
}
}
结果
6
范例求出数组中的最大值和最小值
package com.qn.array;
public class Test {
public static void main(String[] args) {
int score[]={45,12,8,23,89,56};//使用静态初始化声明数组
int max=0;
int min=0;
max=min=score[0];
for (int i = 0; i < score.length; i++) {
if(score[i]>max){
max=score[i];
}
if(score[i]
min=score[i];
}
}
System.out.println('最大值:'+max);
System.out.println('最小值:'+min);
}
}
结果
范例排序,在操作中排序是比较常用的
从大到小
package com.qn.array;
public class Test {
public static void main(String[] args) {
int score[]={45,12,8,23,89,56};//使用静态初始化声明数组
int temp=0;
for (int i = 0; i < score.length; i++) {
for (int j = 0; j < score.length-1; j++) {
if(score[i]>score[j]){
temp=score[i];
score[i]=score[j];
score[j]=temp;
}
}
}
for (int i = 0; i < score.length; i++) {
System.out.print(score[i]+'\t');
}
}
}
结果
这个时候不要被i值所迷惑 if(score[i]>score[j]){
这一步主要知识为了比较,实际上完成之后输出的时候是根据j的值排序的
二维数组
如果可以把一维数组当做几何中的一条线图形,那么二维数组就相当于一个表格
A B
1 姓名 年龄
2 齐宁 21
3 齐燕 23
4 齐威 26
二维数组声明的方式和以为数组的类似,内存分配也一样是用new这个关键字
其实声明与分配内存的格式如下
动态初始化
数据类型 数组名[][];
数组名=new 数据类型[行的个数][列的个数];
声明并初始化数组
数据类型 数组名[][]=new 数据类型[行的个数][列的个数];
静态初始化
二维数组的存储
声明二维数组score 同时开辟一段内存空间
int score[][]=new int[4][3];
整体数据score可保存的元素是4*3=12个,在java中,int数据类型所占用的空间为4个字节,因此该整形数组占用的内存共为4*12=48个字节
事例
package com.qn.array;
public class test1 {
public static void main(String[] args) {
int score[][] = new int[4][3];
score[0][1] = 30;
score[1][0] = 31;
score[2][1] = 32;
score[2][2] = 33;
score[3][1] = 34;
score[1][1] = 35;
for (int i = 0; i < score.length; i++) {
for (int j = 0; j < score[i].length; j++) {
System.out.print(score[i][j]+'\t');
}
System.out.println('');
}
}
}
结果
二维数组静态初始化
用到的时候才会开辟空间,不用的(红色部分)则不开辟空间
多维数组
一般只是用到二维数组
三维数组简单了解
package com.qn.array;
public class test1 {
public static void main(String[] args) {
int score[][][]={
{
{5,1},{6,7}
},
{
{9,4},{8,3}
}
};
System.out.print(score[0][0][0]+'\t');
System.out.print(score[0][0][1]+'\t');
System.out.print(score[0][0][0]+'\t');
System.out.print(score[0][0][1]+'\t');
System.out.print(score[1][0][0]+'\t');
System.out.print(score[1][0][1]+'\t');
System.out.print(score[1][1][0]+'\t');
System.out.print(score[1][1][1]+'\t');
}
}
数组:是一组相关变量的集合
数组是一组相关数据的集合,一个数组实际上就是一连串的变量,数组按照使用可以分为一维数组、二维数组、多维数组
数据的有点
不使用数组定义100个整形变量:int i1;int i2;int i3
使用数组定义 int i[100];
数组定义:int i[100];只是一个伪代码,只是表示含义的
一维数组
一维数组可以存放上千万个数据,并且这些数据的类型是完全相同的,
使用java数组,必须经过两个步骤,声明数组和分配内存给该数组,
声明形式一
声明一维数组:数据类型 数组名[]=null;
非配内存给数组:数组名=new 数据类型[长度];
声明形式二
声明一维数组:数据类型 [] 数组名=null;
java数据类型分为两大类
基本数据类型
int、long操作的时候本身就是具体的内容
引用数据类型:数组、类、接口
引用传递的就是一个内存的使用权,一块内存空间,可能有多个人同时使用
事例声明数组
package com.qn.array;
public class Test {
public static void main(String[] args) {
int score[]=null;//声明数组
score=new int[3];//开辟空间,大小为3
}
}
数组的声明格式里,数据类型是数组元素的数据类型,常见的有整形、浮点型、与字符型等
数组名是用来统一这组相同数据类型元素的名称,其命名规则和变量的相同
数组声明后实际上是在栈内存中保存了此数组的名称,结下了是要在堆内存中配置数组所需要的内存,齐产固定是告诉编译器,所声明的数组要存放多少个元素,而new 则是命令编译器根据括号里的长度
基本数据类型偶读有其默认值:int 0;只要是引用数据类型默认值就是null
事例
package com.qn.array;
public class Test {
public static void main(String[] args) {
int score[]=null;//声明数组
score=new int[3];//开辟空间,大小为3
System.out.print('score[0]='+score[0]);
System.out.print('\tscore[1]='+score[1]);
System.out.print('\tscore[2]='+score[2]);
}
}
堆栈内存的解释
数组操作中,在栈内存中保存的永远是数组的名称,只开辟了栈内的空间,数组是永远无法使用的,必须有指向的对内存才可以使用,要想开辟新对内存空间必须使用new关键字,之后就是将对内存的使用权交给对应的栈内存,而且一个堆内存空间可以同时被多个栈内存空间指向,比如一个人可以有多个名字,人就相当于对内存,名字就相当于栈内存
声明数组的同时分配内存空间
声明数组的同时非配内存
数据类型 数组名[]=new 数据类型[个数]
int score[]=new int[10];
声明一个元素个数为10的整形数组score,同时开辟依靠内存空间工期使用
java中,由于整形数据类型占用的空间为4个byte,而整个数组score可保存的元素有10个。所以上例中占用的内存共有4*10=40个字节
数组的访问
数组中元素的表示方法
想要访问数组里的元素可以利用索引来完成,java的数组索引标号由10开始,以一个score[10]的整形数组为例,score[0]代表第一个元素
一直向下,最后一个为score[9]
取得数组的长度
在java中取得数组的长度(也就是数组元素的长度)可以利用数组名称.length完成,
数组名称.length--返回一个int类型的数据
package com.qn.array;
public class Test {
public static void main(String[] args) {
int score[]=null;//声明数组
score=new int[3];//开辟空间,大小为3
System.out.println(score.length);
}
}
结果
数组的静态初始化
之前的数组,所采用的都是动态初始化,所有的内容在数组声明的时候并不具体的指定,而是以默认值的形式出现
静态初始化是指在数组声明后直接为数组指定具体的内容
如果想要直接在声明的时候给数组赋初始值,可以采用大括号完成,只要在数组的生命格式后面加上初值的赋值即可,
数据类型 数组名 []={初始值0,初始值1,初始值3,....初始值n};
package com.qn.array;
public class Test {
public static void main(String[] args) {
int score[]={1,2,3,4,5,6};//使用静态初始化声明数组
System.out.println(score.length);
}
}
结果
6
范例求出数组中的最大值和最小值
package com.qn.array;
public class Test {
public static void main(String[] args) {
int score[]={45,12,8,23,89,56};//使用静态初始化声明数组
int max=0;
int min=0;
max=min=score[0];
for (int i = 0; i < score.length; i++) {
if(score[i]>max){
max=score[i];
}
if(score[i]
min=score[i];
}
}
System.out.println('最大值:'+max);
System.out.println('最小值:'+min);
}
}
结果
范例排序,在操作中排序是比较常用的
从大到小
package com.qn.array;
public class Test {
public static void main(String[] args) {
int score[]={45,12,8,23,89,56};//使用静态初始化声明数组
int temp=0;
for (int i = 0; i < score.length; i++) {
for (int j = 0; j < score.length-1; j++) {
if(score[i]>score[j]){
temp=score[i];
score[i]=score[j];
score[j]=temp;
}
}
}
for (int i = 0; i < score.length; i++) {
System.out.print(score[i]+'\t');
}
}
}
结果
这个时候不要被i值所迷惑 if(score[i]>score[j]){
这一步主要知识为了比较,实际上完成之后输出的时候是根据j的值排序的
二维数组
如果可以把一维数组当做几何中的一条线图形,那么二维数组就相当于一个表格
A B
1 姓名 年龄
2 齐宁 21
3 齐燕 23
4 齐威 26
二维数组声明的方式和以为数组的类似,内存分配也一样是用new这个关键字
其实声明与分配内存的格式如下
动态初始化
数据类型 数组名[][];
数组名=new 数据类型[行的个数][列的个数];
声明并初始化数组
数据类型 数组名[][]=new 数据类型[行的个数][列的个数];
静态初始化
二维数组的存储
声明二维数组score 同时开辟一段内存空间
int score[][]=new int[4][3];
整体数据score可保存的元素是4*3=12个,在java中,int数据类型所占用的空间为4个字节,因此该整形数组占用的内存共为4*12=48个字节
事例
package com.qn.array;
public class test1 {
public static void main(String[] args) {
int score[][] = new int[4][3];
score[0][1] = 30;
score[1][0] = 31;
score[2][1] = 32;
score[2][2] = 33;
score[3][1] = 34;
score[1][1] = 35;
for (int i = 0; i < score.length; i++) {
for (int j = 0; j < score[i].length; j++) {
System.out.print(score[i][j]+'\t');
}
System.out.println('');
}
}
}
结果
二维数组静态初始化
用到的时候才会开辟空间,不用的(红色部分)则不开辟空间
多维数组
一般只是用到二维数组
三维数组简单了解
package com.qn.array;
public class test1 {
public static void main(String[] args) {
int score[][][]={
{
{5,1},{6,7}
},
{
{9,4},{8,3}
}
};
System.out.print(score[0][0][0]+'\t');
System.out.print(score[0][0][1]+'\t');
System.out.print(score[0][0][0]+'\t');
System.out.print(score[0][0][1]+'\t');
System.out.print(score[1][0][0]+'\t');
System.out.print(score[1][0][1]+'\t');
System.out.print(score[1][1][0]+'\t');
System.out.print(score[1][1][1]+'\t');
}
}
、定义一个Java数组
String[] aArray = new String[5];
String[] bArray = {"a","b","c", "d", "e"};
String[] cArray = new String[]{"a","b","c","d","e"};
第一种是定义了一个数组,并且指定了数组的长度,我们这里称它为动态定义。
第二种和第三种在分配内存空间的同时还初始化了值。
1、打印Java数组中的元素
int[] intArray = { 1, 2, 3, 4, 5 };
String intArrayString = Arrays.toString(intArray);
// print directly will print reference value
System.out.println(intArray);
// [I@7150bd4d
System.out.println(intArrayString);
// [1, 2, 3, 4, 5]
这里的重点是说明了Java中数组的引用和值得区别,第三行直接打印intArray,输出的是乱码,因为intArray仅仅是一个地址引用。第4行输出的则是真正的数组值,因为它经过了Arrays.toString()的转化。对Java初学者来说,引用和值仍需重视。
2、从Array中创建ArrayList
String[] stringArray = { "a", "b", "c", "d", "e" };
ArrayList<String> arrayList = new ArrayList<String>(Arrays.asList(stringArray));
System.out.println(arrayList);
// [a, b, c, d, e]
为什么要将Array转换成ArrayList呢?可能是因为ArrayList是动态链表,我们可以更方便地对ArrayList进行增删改,我们并不需要循环Array将每一个元素加入到ArrayList中,用以上的代码即可简单实现转换。
3、检查数组中是否包含某一个值
String[] stringArray = { "a", "b", "c", "d", "e" };
boolean b = Arrays.asList(stringArray).contains("a");
System.out.println(b);
// true
先使用Arrays.asList()将Array转换成List<String>,这样就可以用动态链表的contains函数来判断元素是否包含在链表中。
4、连接两个数组
int[] intArray = { 1, 2, 3, 4, 5 };
int[] intArray2 = { 6, 7, 8, 9, 10 };
// Apache Commons Lang library
int[] combinedIntArray = ArrayUtils.addAll(intArray, intArray2);
ArrayUtils是Apache提供的数组处理类库,其addAll方法可以很方便地将两个数组连接成一个数组。
5、声明一个数组内链
method(new String[]{"a", "b", "c", "d", "e"});
6、将数组中的元素以字符串的形式输出
// containing the provided list of elements
// Apache common lang
String j = StringUtils.join(new String[] { "a", "b", "c" }, ", ");
System.out.println(j);
// a, b, c
同样利用StringUtils中的join方法,可以将数组中的元素以一个字符串的形式输出。
7、将Array转化成Set集合
Set<String> set = new HashSet<String>(Arrays.asList(stringArray));
System.out.println(set);
//[d, e, b, c, a]
在Java中使用Set,可以方便地将需要的类型以集合类型保存在一个变量中,主要应用在显示列表。同样可以先将Array转换成List,然后再将List转换成Set。
8、数组翻转
int[] intArray = { 1, 2, 3, 4, 5 };
ArrayUtils.reverse(intArray);
System.out.println(Arrays.toString(intArray));
//[5, 4, 3, 2, 1]
依然用到了万能的ArrayUtils。
9、从数组中移除一个元素
int[] intArray = { 1, 2, 3, 4, 5 };
int[] removed = ArrayUtils.removeElement(intArray, 3);//create a new array
System.out.println(Arrays.toString(removed));
再补充一个:将一个int值转化成byte数组
byte[] bytes = ByteBuffer.allocate(4).putInt(8).array();
for (byte t : bytes) {
System.out.format("0x%x ", t);
}
在JAVA里面,可以用复制语句”A=B”给基本类型的数据传递值,但是如果A,B是两个同类型的数组,复制就相当于将一个数组变量的引用传递给另一个数组;如果一个数组发生改变,那么引用同一数组的变量也要发生改变.
以下是归纳的JAVA中复制数组的方法:
1.使用FOR循环,将数组的每个元素复制或者复制指定元素,不过效率差一点
2.使用clone方法,得到数组的值,而不是引用,不能复制指定元素,灵活性差一点
3.使用System.arraycopy(src, srcPos, dest, destPos, length)方法,推荐使用
举例:
1.使用FOR循环
int[] src={1,3,5,6,7,8};
int[] dest = new int[6];
for(int i=0;i<6;i++) dest[i] = src[i];
2.使用clone
int[] src={1,3,5,6,7,8};
int[] dest;
dest=(int[]) src.clone();//使用clone创建
副本,注意clone要使用强制转换
3.使用System.arraycopy
int[] src={1,3,5,6,7,8};
int[] dest = new int[6];
System.arraycopy(src, 0, dest, 0, 6);
——————————————————————-
System提供了一个静态方法arraycopy(),我们可以使用它来实现数组之间的复制.
其函数原型是:
public static void arraycopy(Object src, int srcPos, Object dest, int destPos, int length)
src:源数组; srcPos:源数组要复制的起始位置;
dest:目的数组; destPos:目的数组放置的起始位置;
length:复制的长度.
注意:src and dest都必须是同类型或者可以进行转换类型的数组.
有趣的是这个函数可以实现自己到自己复制,
比如:int[] fun ={0,1,2,3,4,5,6};
System.arraycopy(fun,0,fun,3,3);
则结果为:{0,1,2,0,1,2,6};
数组比较】
Arrays提供了重载后的equals()方法,针对所有类型和Object类型都做了重载,用来比较整个数组。数组相等的条件是元素个数必须相等,并且对应位置的元素也相等。而多维数组的比较用deepEquals()方法。Array.equals()方法比较的两个数组必须是同类型的数组。
import java.util.Arrays;
public class javaArrayEquals{
public static void main(String args[]){
int[] arrayA = {1,2,3};
int[] arrayB = {1,2,3,};
int[] arrayC = new int[4]; //if int[] arrayC = new int[3],return true
arrayC[0] = 1;
arrayC[1] = 2;
arrayC[2] = 3;
System.out.println(Arrays.equals(arrayA, arrayB));
System.out.println(Arrays.equals(arrayA, arrayC));
String[][] arrayD = {{"a","b"},{"c","d"}};
String[][] arrayE = {{"a","b"},{"c","d"}};
System.out.println(Arrays.deepEquals(arrayD, arrayE));
}
}
【数组排序与查找】
数组提供了内置的排序方法sort(),可以对任意基本类型数组或者对象数组进行排序(该对象必须实现Comparable接口或者具有相关联的Comparator)。JAVA对不同的类型提供了不同的排序方法----针对基本类型设计的快速排序,以及针对对象设计的“稳定归并排序”,所以无需担心数组排序的效率问题。
binarySearch()用于在以排好序的数组中快速查找元素,如果对未排序的数组使用binarySearch(),那么将产生难以预料的结果。
【返回数组】
C和C++不能返回一个数组,只能返回指向数组的指针,因为返回数组使得控制数组的生命周期变得困难,并且容易造成内存泄漏。java允许直接返回一个数组,并且可以由垃圾回收机制回收。
【数组与容器转换】【无法转换基本类型数组】
数组转为List:
import java.util.*;
public class arrayToList{
public static void main(String args[]){
String[] arrayA = {"a","b","c"};
List listA = java.util.Arrays.asList(arrayA);
System.out.println("listA: " + listA);
int[] arrayB = {1,2,3};
List listB = java.util.Arrays.asList(arrayB);
System.out.println("listB: " + listB);
Integer[] arrayC = {1,2,3};
List listC = java.util.Arrays.asList(arrayC);
System.out.println("listC: " + listC);
}
}
输出:
listA: [a, b, c]
listB: [[I@de6ced]
listC: [1, 2, 3]
为什么int和Integer输出会不同呢?
List转为数组
import java.util.*;
public class listToArray{
public static void main(String args[]){
List<String> list = new ArrayList<String>();
String[] array;
list.add("testA");
list.add("testB");
list.add("testC");
System.out.println("list: " + list);
String[] strings = new String[list.size()];
array = list.toArray(strings);
for(int i = 0, j = array.length; i < j; i++){
System.out.print(array[i] + ",");
}
}
}
输出为:
list: [testA, testB, testC]
testA,testB,testC
【去除重复数据】
利用数组和容器转换可以方便地去除数组重复数据,不过如果数组过大,效率是一个问题。
import java.util.*;
public class javaArrayUnique{
public static void main(String args[]){
String[] array = {"a","b","a","a","c","b"};
arrayUnique(array);
//test
for(int i = 0, j = arrayUnique(array).length; i < j; i++){
System.out.print(arrayUnique(array)[i] + ",");
}
}
public static String[] arrayUnique(String[] array){
List<String> list = new ArrayList<String>();
for(int i = 0, j = array.length; i < j; i++){
if(!list.contains(array[i])){
list.add(array[i]);
}
}
String[] strings = new String[list.size()];
String[] arrayUnique = list.toArray(strings);
return arrayUnique;
}
}
关于效率问题,我做了一个对比,在我电脑上运行十万数据的数组大概是577ms,而运行一百万数据的数据大约要5663ms。这还跟计算机的运行能力有关,但是明显是随着数组大小递增的。
import java.util.*;
public class javaArrayUnique{
public static void main(String args[]){
Double[] array = new Double[100000];
for(int i = 0, j = array.length; i < j; i++){
array[i] = Math.ceil(Math.random()*1000);
}
Double[] arrayB = new Double[1000000];
for(int i = 0, j = arrayB.length; i < j; i++){
arrayB[i] = Math.ceil(Math.random()*1000);
}
System.out.println("start");
long startTime = System.currentTimeMillis();
arrayUnique(array);
long endTime = System.currentTimeMillis();
System.out.println("array unique run time: " +(endTime - startTime) +"ms");
long startTimeB = System.currentTimeMillis();
arrayUnique(arrayB);
long endTimeB = System.currentTimeMillis();
System.out.println("arrayB unique run time: " +(endTimeB - startTimeB) +"ms");
}
public static Double[] arrayUnique(Double[] array){
List<Double> list = new ArrayList<Double>();
for(int i = 0, j = array.length; i < j; i++){
if(!list.contains(array[i])){
list.add(array[i]);
}
}
Double[] doubles = new Double[list.size()];
Double[] arrayUnique = list.toArray(doubles);
return arrayUnique;
}
}
输出:
start
array unique run time: 577ms
arrayB unique run time: 5663ms