Java基础学习笔记之数组详解
本文实例讲述了java基础学习笔记之数组。分享给大家供大家参考,具体如下:
数组的定义于使用
1:数组的基本概念
一组相关变量的集合;在java里面将数组定义为引用数据类型,所以数组的使用一定要牵扯到内存分配;想到了用new 关键字来处理。
2:数组的定义格式
区别:
动态初始化后数组中的每一个元素的内容都是其对应数据类型的默认值,随后可以通过下标进行数组内容的修改;
如果希望数组定义的时候就可以提供内容,则采用静态初始化的方式;
a:数组的动态初始化(声明并初始化数组):
数据类型 数组名称 【】 = new 数据类型 【长度】;
数据类型 【】 数组名称 = new 数据类型 【长度】
b:数组的静态初始化(在数组定义的时候就为其设置好了里面的内容)
简化格式:数据类型 数组 数组名称 【】 = {数据1,数据2,数据3,。。。};
完整格式:数据类型 数组名称【】 = new 数据类型【】{ 数据1,数据2,数据3,。。。};
3:数组的特点
通过脚标访问:0~n-1;
进行数组操作的时候往往会利用for循环来完成;
数组的长度:“数组名称.length”;
4:数组的引用传递
数组定义时用到了new,所以这里存在有内存关系匹配。
public class arraydemo { public static void main(string args[]) { // 使用数组的静态初始化 int data [] = new int [3] ; data [0] = 10 ; // 为数组设置内容 data [1] = 20 ; // 为数组设置内容 data [2] = 30 ; // 为数组设置内容 for (int x = 0 ; x < data.length ; x ++) { system.out.println(data[x]) ; } } }
一个堆内存可以被多个栈内存所指向
public class arraydemo { public static void main(string args[]) { int data [] = new int [] {10,20,30} ; // 静态初始化 int temp [] = data ; // 引用传递 temp [0] = 99 ; for (int x = 0 ; x < data.length ; x ++) { system.out.println(data[x]) ; } } }
由于数组是引用数据类型,所以一定要为其开辟堆内存空间(也就是实例化对象)才可以使用,如果使用了未开辟堆内存空间的数组则一定会出现“nullpointerexception”异常
5foreach迭代输出
jdk1.5之后为了减轻下标对程序的影响(以为下标处理不当则会出现数组越界异常),参考了.net的设计,引入了增强型for循环:foreach
for(数据类型 变量 :数组名) { }
特点:可以自动将数组中的每一个元素的内容取出保存到变量里,这样就可以直接通过变量获取数组的内容,避免了数组越界。
public class arraydemo { public static void main(string args[]) { int data [] = new int [] {1,2,3,4,5} ; for (int temp : data) { // 自动循环,将data数组每一个内容交给temp system.out.println(temp) ; } } }
6:二维数组
定义格式:
a:动态初始化:数据类型 数组名称【】【】 = new 数据类型【行个数】【列个数】;
b:静态初始化:数据类型 【】【】 new 数据类型 【】【】 { { 数据,数据 …},{ 数据,数据…},… }
public class arraydemo { public static void main(string args[]) { int data [][] = new int [][] { {1,2,3,4,5} , {1,2,3} , {5,6,7,8}} ; for (int x = 0 ; x < data.length ; x ++) { for (int y = 0 ; y < data[x].length ; y ++) { system.out.println("data["+x+"]["+y+"] = " + data[x][y]) ; } system.out.println() ; // 换行 } } } //输出结果: data[0][0] = 1 data[0][1] = 2 data[0][2] = 3 data[0][3] = 4 data[0][4] = 5 data[1][0] = 1 data[1][1] = 2 data[1][2] = 3 data[2][0] = 5 data[2][1] = 6 data[2][2] = 7 data[2][3] = 8
同一个二维数组通过foreach输出
public class arraydemo { public static void main(string args[]) { int data [][] = new int [][] { {1,2,3,4,5} , {1,2,3} , {5,6,7,8}} ; for (int temp [] : data) { for (int num : temp) { system.out.print(num + "、") ; } system.out.println() ; } } } //输出结果 1、2、3、4、5、 1、2、3、 5、6、7、8
7数组与方法
对于引用数据类型,主要的特点是可以于方法进行引用传递,数组本身也是引用数据类型,所以自然也可以通过方法实现引用传递的操作。
public class arraydemo { public static void main(string args[]) { int data [] = new int [] {1,2,3,4,5} ; printarray(data) ; // 传递数组 } // 要求接收一个int型的数组 public static void printarray(int temp []) { for (int x = 0 ; x < temp.length ; x ++) { system.out.println(temp[x]) ; } } } //通过方法来接收一个数组
public class arraydemo { public static void main(string args[]) { int data [] = initarray() ; // 通过方法可以获得数组内容 printarray(data) ; // 传递数组 } public static int [] initarray() { int arr [] = new int [] {1,2,3,4,5} ; return arr ; // 返回一个数组 } // 要求接收一个int型的数组 public static void printarray(int temp []) { for (int x = 0 ; x < temp.length ; x ++) { system.out.println(temp[x]) ; } } } //通过方法返回一个数组对象
public class arraydemo { public static void main(string args[]) { int data [] = new int [] {1,2,3,4,5} ; changearray(data) ; // 修改数组内容 printarray(data) ; // 传递数组 } public static void changearray(int arr[]) { for (int x = 0 ; x < arr.length ; x ++) { arr[x] *= 2 ; // 每个元素的内容乘2保存 } } // 要求接收一个int型的数组 public static void printarray(int temp []) { for (int x = 0 ; x < temp.length ; x ++) { system.out.println(temp[x]) ; } } } //通过方法修改数组内容。
下面写一个案例,总结上面内容
案例;定义一个int数组,要求计算出这个数组元素的总和,最大值,最小值,平均值。
//此程序的基本实现 public class arraydemo { public static void main(string args[]) { int data [] = new int [] {1,2,3,4,5} ; int sum = 0 ; ; double avg = 0.0 ; int max = data[0] ; // 假设第一个是最大值 int min = data[0] ; // 假设第一个是最小值 for (int x = 0 ; x < data.length ; x ++) { if (data[x] > max) { // max地位改变了 max = data[x] ; } if (data[x] < min) { min = data[x] ; } sum += data[x] ; } avg = sum / data.length ; system.out.println("数组内容总和:" + sum) ; system.out.println("数组内容平均值:" + avg) ; system.out.println("数组内容最大值:" + max) ; system.out.println("数组内容最小值:" + min) ; } public static void printarray(int temp []) { for (int x = 0 ; x < temp.length ; x ++) { system.out.println(temp[x]) ; } } }
问题:主函数所在的类往往被称为主类,那么既然是主类中不希望涉及过多复杂的功能;在开发的过程中,主方法本身就相当于是一个客户端,而对于客户端的代码尽量简单一些,所以这个时候是将一系列的计算过程交给单独的程序类去完成。
//改善操作设计 class arrayutil { // 是一个操作工具的类 private int sum ; // 保存总和 private double avg ; // 保存平均值 private int max ; // 保存最大值 private int min ; // 保存最小值 public arrayutil(int data[]) { // 进行数组计算 this.max = data[0] ; // 假设第一个是最大值 this.min = data[0] ; // 假设第一个是最小值 for (int x = 0 ; x < data.length ; x ++) { if (data[x] > max) { // max地位改变了 this.max = data[x] ; } if (data[x] < min) { this.min = data[x] ; } this.sum += data[x] ; } this.avg = this.sum / data.length ; } public int getsum() { return this.sum ; } public double getavg() { return this.avg ; } public int getmax() { return this.max ; } public int getmin() { return this.min ; } } public class arraydemo { public static void main(string args[]) { int data [] = new int [] {1,2,3,4,5} ; arrayutil util = new arrayutil(data) ; // 数据计算 system.out.println("数组内容总和:" + util.getsum()) ; system.out.println("数组内容平均值:" + util.getavg()) ; system.out.println("数组内容最大值:" + util.getmax()) ; system.out.println("数组内容最小值:" + util.getmin()) ; } }
8:数组操作案例:数组反转
做法一:定义一个新的数组而后按照逆序的方式保存(会产生无用的垃圾空间)
class arrayutil { public static void printarray(int temp []) { for (int x = 0 ; x < temp.length ; x ++) { system.out.print(temp[x] + "、") ; } system.out.println() ; } } public class arraydemo { public static void main(string args[]) { int data [] = new int [] {1,2,3,4,5,6,7,8,9} ; int temp [] = new int [data.length] ; // 第二个数组 int foot = temp.length - 1; // 第二个数组的脚标 for (int x = 0 ; x < data.length ; x ++) { temp[foot --] = data[x] ; } data = temp ; arrayutil.printarray(data) ; } }
做法二:在一个数组上进行转置
class arrayutil { public static void printarray(int temp []) { for (int x = 0 ; x < temp.length ; x ++) { system.out.print(temp[x] + "、") ; } system.out.println() ; } } public class arraydemo { public static void main(string args[]) { int data [] = new int [] {1,2,3,4,5,6,7,8,9} ; int center = data.length / 2 ; // 确定转换的次数 int head = 0 ; // 操作脚标 int tail = data.length - 1 ; // 操作脚标 for (int x = 0 ; x < center ; x ++) { int temp = data [head] ; data [head] = data [tail] ; data [tail] = temp ; head ++ ; tail -- ; } arrayutil.printarray(data) ; } }
比较两种方式:第一种循环次数较多,会产生垃圾;第二种实现循环次数较低,但是存在if判断增加了
时间复杂度,可是减少了无用对象的产生,提升了性能。
//将转换功能变为类定义 class arrayutil { public static void reverse(int data[]) { int center = data.length / 2 ; // 确定转换的次数 int head = 0 ; // 操作脚标 int tail = data.length - 1 ; // 操作脚标 for (int x = 0 ; x < center ; x ++) { int temp = data [head] ; data [head] = data [tail] ; data [tail] = temp ; head ++ ; tail -- ; } } public static void printarray(int temp []) { for (int x = 0 ; x < temp.length ; x ++) { system.out.print(temp[x] + "、") ; } system.out.println() ; } } public class arraydemo { public static void main(string args[]) { int data [] = new int [] {1,2,3,4,5,6,7,8,9} ; arrayutil.reverse(data) ; // 转置处理 arrayutil.printarray(data) ; } }
9数组相关类操作方法
java语言本身提供有数组的相关支持处理。
a:数组排序:java.util.arrays.sort(数组名称)
class arrayutil { public static void printarray(int temp []) { for (int x = 0 ; x < temp.length ; x ++) { system.out.print(temp[x] + "、") ; } system.out.println() ; } } public class arraydemo { public static void main(string args[]) { int data [] = new int [] {23,12,1,234,2,6,12,34,56} ; java.util.arrays.sort(data) ; // 排序 arrayutil.printarray(data) ; } }
b:数组拷贝:system.arraycopy(源数组,源数组开始点,目标数组,目标数组开始点,拷贝长度)
class arrayutil { public static void printarray(int temp []) { for (int x = 0 ; x < temp.length ; x ++) { system.out.print(temp[x] + "、") ; } system.out.println() ; } } public class arraydemo { public static void main(string args[]) { int dataa [] = new int [] {1,2,3,4,5,6,7,8,9} ; int datab [] = new int [] {11,22,33,44,55,66,77,88,99} ; system.arraycopy(dataa,5,datab,3,3) ; arrayutil.printarray(datab) ; } } //结果: 11、22、33、6、7、8、77、88、99、
10方法可变参数
需求:定义一个方法,可以实现任意多个整型数据的相加处理。
传统实现。
class arrayutil { public static int sum(int [] data) { int sum = 0 ; for (int temp : data) { sum += temp ; } return sum ; } } public class arraydemo { public static void main(string args[]) { system.out.println(arrayutil.sum(new int [] {1,2,3})) ; } }
上述代码可以实现任意多个数字的参数内容传递,但是与实际的要求并不符合,实际要求的是可以传递任意多个参数,而不是一个数组。
从jdk1.5开始为了方便开发组进行可变参数的定义。
class arrayutil { public static int sum(int ... data) { // 变种数组 int sum = 0 ; for (int temp : data) { sum += temp ; } return sum ; } } public class arraydemo { public static void main(string args[]) { system.out.println(arrayutil.sum(1,2,3,4)) ; system.out.println(arrayutil.sum(new int [] {1,2,3})) ; } } //输出 10 6
总结:可变参数的最大作用:在以后进行一些程序类设计或者开发者调用的时候,利用次种形式可以避免数组的传递操作;可变参数的本质:依然属于数组。
11对象数组(重点)
之前接触到的都是基本数据类型定义的数组;java程序中各种数据类型都可以成为数组类型,所以类也可以成为数组类型:对象数组。
动态初始化: 类 对象数组名称 【】 = new 类 【长度】;
静态初始化: 类 对象数组名称 【】 = new 类 【】{实例化对象,实例化对象,… };
动态初始化每个元素为null;
//动态初始化 class person { private string name ; private int age ; public person(string name,int age) { this.name = name ; this.age = age ; } public string getinfo() { return "姓名:" + this.name + "、年龄:" + this.age ; } // setter、getter略 } public class arraydemo { public static void main(string args[]) { person per [] = new person[3] ; // 对象数组 per[0] = new person("张三",20) ; per[1] = new person("李四",20) ; per[2] = new person("王五",20) ; for (int x = 0 ; x < per.length ; x ++) { system.out.println(per[x].getinfo()) ; } } }
//静态初始化 class person { private string name ; private int age ; public person(string name,int age) { this.name = name ; this.age = age ; } public string getinfo() { return "姓名:" + this.name + "、年龄:" + this.age ; } // setter、getter略 } public class arraydemo { public static void main(string args[]) { person per [] = new person[] { new person("张三",20) , new person("李四",20) , new person("王五",20)} ; // 对象数组 for (int x = 0 ; x < per.length ; x ++) { system.out.println(per[x].getinfo()) ; } } }
对于对象数组而言,上述代码只是更换了一种所谓的数组定义的类型,但是内存图变得复杂:
总结
数组最大缺陷:
长度是固定的;
优势:线性保存,根据索引访问,速度较块。(时间复杂度为“1”)。
面试题:定义类的时候什么情况下会考虑使用static方法?
在类中不提供任何成员属性的情况下,如果定义的是普通方法,那么就必须通过实例化对象来进行调用,这样就会产生许多无用的实例化对象。那么在这样的情况下会考虑直接定义static方法,这样可以由类名称直接调用。