数组
数组
批量类似数据的处理问题
- 100个类似的变量
- 100次类似的处理
数组的定义
数组可以用来存储元素个数固定和性质相似的数据集
声明、创建、默认值
声明
-
elementType[ ] arrayRefVar;(元素类型[ ] 数组引用变量;)
-
double [] myList;
创建
-
arrayRefVar = new elementType(arrayType[arraySize]);
(元素类型[ ] 数组引用变量 = new 元素类型[数组大小]😉
-
double [] myList = new double[10];
默认值
-
创建数组后,每个元素的值是这个类型的默认值
-
数值型0/0.0,布尔型默认为false,引用型默认为null
数据类型 默认值 int 0 long 0 float 0.0 double 0.0 boolean false char 空白 short 0 byte 0 Object null
内存模型和引用数据类型
myList这个引用里面所存储的东西就是第一个元素的地址,也就是首地址
常用操作(封装在Util类中)
产生一个随机数组
public static int[] getRandomArr(int length,int min,int max) {
int [] arr = new int [length];
for (int i = 0; i < arr.length; i++) {
arr[i] = (int)(Math.random()*(max+1-min)+min);
}
return arr;
}
注意:要产生一个[min,max]的整数是(int)(Math.random()*(max+1-min)+min);
打印输出数组元素
出现的问题:输出一串整数
调试发现:因为字符'\t'参与运算,它会把它变为一个整数,'\t'的ASCII码值为9,输出的其实是arr[i]与9的和。
制表符为'\t',相当于4个或8个空格符,其ASCII码为9。
解决:
以下两种方式都可以🔽
System.out.print(arr[i]+"\t");
System.out.print("" + arr[i]+'\t');
拓展:
换行符为'\n',作用是将光标移至下一行,其ASCII码为10
空白符的含义模糊,通常是指空格' ',其ASCII码为32。
还要特别注意一下要输出\t
需要一个转义字符\,即要写成\\t
求和求平均
求和
public static double getArrAvg(int []arr) {
int total = 0;
int len = arr.length;
for (int i = 0; i < len; i++) {
total+=arr[i];
}
return (double)total/len;//想要得到比较精确的平均值
// return total/len;
}
求平均
public static double avg(int []arr) {
// return getArrSum(arr)/(double)arr.length;
return (double)getArrSum(arr)/arr.length;
}
4和10都是整数int类型的,所以4/10结果也是int的,就是0,把结果赋值给double类型,才会转换成double,就是0.0d;若果想得到完整的结果0.4,那就需要在除法前先将4或者10转换成double类型
比如(double)4/10;
java中数字的运算是按照double float long int char byte 的顺序向上靠拢的,比如flout和int运算结果就是float , 而int和int运算结果就是int,所以java中涉及数字运算的时候要注意根据你想要的结果类型对数字进行转换
求最大值
public static void max(int []arr) {
int max = arr[0];
int maxIndex = 0;
for (int i = 1; i < arr.length; i++) {
if(arr[i]>max) {
max = arr[i];
maxIndex = i;
}
}
System.out.println("最大值是:" + max +" 下标为:" + maxIndex);
}
求最小值
public static void min(int []arr) {
int min = arr[0];
int minIndex = 0;
for (int i = 1; i < arr.length; i++) {
if(arr[i]<min) {
min = arr[i];
minIndex = i;
}
}
System.out.println("最小值是:" + min +" 下标为:" + minIndex);
}
随机打乱
//随机打乱
public static int[] swapRandom(int [] arr) {
for (int i = 0; i < arr.length; i++) {
int j = (int)Math.random()*(i+1);//0<=j<=i
int temp = arr[i];
arr[i] = arr[j];
arr[j] = temp;
}
return arr;
}
//向前依次移动
public static int[] moveForward(int [] arr) {
int first = arr[0];
for (int i = 0; i < arr.length-1; i++) {
arr[i] = arr[i+1];
}
arr[arr.length-1] = first;
return arr;
}
//向后依次移动
public static int[] moveBackward(int [] arr) {
int last = arr[arr.length-1];
System.out.println(last);
for (int i = arr.length-1; i >=1; i--) {
arr[i] = arr[i-1];
}
arr[0] = last;
return arr;
}
交换两个位置的元素
//交换两个位置的元素
public static void swap(int [] arr,int i,int j) {
int temp = arr[i];
arr[i] = arr[j];
arr[j] = temp;
}
foreach
对myList中的每个元素e进行以下操作
当需要以其他顺序遍历数组或者改变数组中的元素时,还是必须使用下标变量
一定是正序的!
//foreach改写
public static void printArr2(int []arr) {
for (int e:arr) {
// System.out.print(arr[i]+"\t");
System.out.print("" + e+'\t');
}
System.out.println();
}
命令行参数
无论你在这个地方输入的参数是什么类型,java统一把它解读为字符串
但是如果你希望你本身第一个参数就是123 abc那么你就需要用双引号把它引起来,通常情况无需加双引号,但是如果你想组合的时候包括空格就需要引起来。
引用的拷贝
基本数据类型
int i = 10;
int j = i;
i = 20;
System.out.println(j);//10
分析:j = i;意思是把i的内容拷贝一份赋给j
基本数据类型都是存在于栈空间当中。j和i是相互不会影响的
引用数据类型:
double [] list1 = {1,2,3,4,5};
double [] list2 = new double[5];
list2 = list1;
list1[0] = 0;
System.out.println(list2[0]);//0.0
分析:对象是存放在栈里的。
list2 = list1;
这句话的意思是让list2和list1指向同一个空间。
java里面 = 就是赋值,但是list1的内容是一个地址,而不是具体的数据
在java里面。可以使用赋值语句复制基本数据类型的变量,但是不能复制数组,讲一个数组变量赋值给另一个数组变量实际上是将一个数组的引用复制给另一个变量,使得两个变量都指向相同的内存地址。
基本数据类型存放在哪?
在Java里面new出来的对象都是在堆上分配空间存储的,但是针对基本类型却有所区别,基本类型可以分配在栈上,也可以分配在堆上,这是为什么?
在这之前,我们先看下Java的基本类型8种分别是:
byte =>8bit
short => 16bit
int => 32bit
long =>64bit
folat => 单精度32位
double => 双精度64位
boolean => 注意oracle官网文档介绍,boolean代表1bit的信息,但它本身的size却不是精确的,依赖于jvm和os的实现,比较常见的说法是,boolean单独使用的时候,在编译时是使用int代替的,如果是boobean数组,则是使用1byte代替
char => 16bit
基本类型在成员变量和局部(local)变量的时候其内存分配机制是不一样的。
基本类型的变量存在栈里或者堆里不是由"大小可知,生存期可知"就能确定了。关键是上下文。
如果是成员变量,那么不分基本类型和引用类型都是在java的堆内存里面分配空间,而局部变量的基本类型是在栈上分配的。栈属于线程私有的空间,局部变量的生命周期和作用域一般都很短,为了提高gc效率,所以没必要放在堆里面。
比如
void func(){
int a = 3;
}
这自然是存在栈里的。局部方法嘛。
而
class Test{
int a = 3;
}
这就肯定是随对象放到堆里的。
public class DemoTest {
int y;// 分布在堆上
public static void main(String[] args) {
int x=1; //分配在栈上
String name=new String("cat");//数据在堆上,name变量的指针在栈上
String address="北京";//数据在常量池,属于堆空间,指针在栈
Integer price=4;//包装类型同样是引用类型,编译时会自动装拆相,所以数据在堆上,指针在栈
}
}
在java里面通过new出来的对象都在堆上分配,这里有两种特殊情况,
(1)字符串的字面量
字符串的字面量,没有new关键字,但却是在堆上分配内存的,严格的说是在堆里面的字符串常量池里面。
(2)基本类型的包装类
同样的道理,针对各个基本类型的包装类型,如:Integer,Double,Long等,这些属于引用类型,我们直接在局部方法里面使用包装类型赋值,那么数据真正的内存分配还是在堆内存里面,这里有个隐式的拆装箱来自动完成转换,数据的指针是在栈上,包装类型的出现主要是为了基本类型能够用在泛型的设计上和使用null值,而基本类型则拥有更好的计算性能,这一点我们也需要注意。
注:参考https://zhuanlan.zhihu.com/p/74377344
https://blog.csdn.net/cuser_online/article/details/6051645?utm_source=blogxgwz7
复制数组内容
-
使用循环语句逐个复制
-
使用System类中的静态方法arraycopy
arraycopy(sourceArray,srcPos(原数组的位置),targetArray,tarPos(目标位置),length(拷贝多长));
arraycopy不会给目标数组分配内存空间,复制之前必须创建目标数组以及给它分配内存空间。复制完成之后,sourceArray和targetArray具有相同的内容,但占有独立的内存空间
方法传参:按值传递的含义
public class TestPassArgs {
public static void main(String[] args) {
// TODO Auto-generated method stub
int x = 1;
int [] y = new int [10];
m(x,y);
System.out.println("x是"+x);
System.out.println("y[0]是"+y[0]);
}
public static void m(int number,int[] numbers) {
number = 10;
numbers[0] = 5555;
}
}
输出:
x是1
y[0]是5555
引用数据类型进行传值的时候相当于你复制了一把钥匙给别人,别人拿到钥匙就可以操作这个空间。
方法和堆栈模型
一个线程是从main方法开始的,然后不停的调方法,然后返回。
main方法在栈底
调方法的时候,x一直是在栈中,所以它不会到堆内存中进行一次拷贝,所以x就把1赋给了number。
y传给numbers,此时发生了一个引用的拷贝,这个拷贝指向了堆空间的这个数组。
因为numbers和y指向同一个空间,你通过numbers对这个空间不断的进行更改,由于时间的原因这个m方法是先改了这个内容,再返回main方法的时候你再去输出这个y来进行引用打印输出一定是一个最新的状态在上面numbers也可以对数组进行更改,在下面y也可以对数组进行更改。
numbers = new 一个对象会怎么样?
案例
统计字符数组中每个字母出现的次数(假设不区分大小写)
利用下标的紧密性来表示每个字母的出现的次数
public class Case01_CountOfLetter {
public static void main(String[] args) {
// TODO Auto-generated method stub
String randomString = RandomString.getSmallCharaStr(30);
System.out.println(randomString);
char[] arr = randomString.toCharArray();
int[] res = new int[26];
for (char c : arr) {
res[c - 'a']++;
}
for (int i = 0; i < res.length; i++) {
if (res[i]!=0) {
char resi = (char) (i + 'a');
System.out.println(resi + ":" + res[i]);
}
}
}
}