文章目录
关于一维数组
Array
1、Java语言中的数据是一种引用数据类型,不属于基本数据类型。数组的父类是Object
2、数据实际上是一个容器,可以同时容纳多个元素(元素是一个数据的集合。)
数组:字面意思是:一组数据
3、数据当中可以存储“几本书类型的数据”,也可以存储“引用数据类型”的数据
4、数组因为是引用数据类型,所以数组对象是堆内存中的(数组是存储在堆当中的)
5、数组当中如果存储的是java对象的话,实际上存储的是对象“引用(内存地址)”,数组当中不能直接存储java对象
6、数组一旦创建,在java中规定,长度不可变。(数组长度不可变)
7、数组的分类:一位数组,二维数组,三维数组,多维数组…(一维数组常用,二维数组偶尔使用)
8、所有数组对象都有length属性(java自带的),用来获取数组中元素的个数
9、java中的数组要求属猪中元素的类型要统一。比如int类型数组只能存储int类型,Person类型智能存储Person类型
10、数组中在内存方面存储的时候,数组当中的元素内存地址连续。内存地址连续,这是数据存储元素的特点,
11、所有的数组都是拿“第一个小方框的内存地址”作为整个数组对象的内存地址(数组中首元素的内存地址作为整个数组对象的)
12、数组中每一个元素都是由下表的,下标从0开始,以1递增,最后一个元素的下标是:length-1
下标非常重要,因为我们对象中元素进行“存取”时,都得通过下表
13、数组这种数据结构的优缺点是什么?
优点:查询/查找/检索某个下标上的元素试效率很高,可以说是查询效率最高的一个数据结构
为什么检索效率高?
第一:每一个元素在内存地址在空间上是联系的
第二:每一个元素类型相同,所以占用空间大小一样
第三:知道第一个元素的内存地址,知道每一个元素占用空间的大小,又知道下表,所以
通过一个数学表达式就可以计算出下表上的内存地址,直接通过内存地址定位元素,所以
数据的检索效率是非常高的
数组中存储100个元素,或者存储10000个元素,在元素查询/检索方面,效率是相同的
因为数组中元素查找的时候不会一个一个找,是通过数学表达式计算出来的。(算出一个内
存地址,直接定位)
缺点:
第一:由于为了保证每个元素的内存地址连续,所以在数据上随机删除或者增加元素的时候,
效率较低,因为随机增删元素会涉及到后面元素统一向前或者向后位置的操作
第二:数组不能存储大数据量,为什么?
因为很难再没存空间上找到一块特别大的连续的内存空间,
注意:对数组最后一个元素的增删是没有影响的
14、怎么声明/定义一个一位数组?
语法格式:
int[] array1;
double[] array2;
boolean[] array3;
String[] array4;
Object[] array5;
15、怎么初始化一个以为数组呢?
包括两种方式:静态初始化一位数组,动态初始化一位数组。
静态初始化语法格式:
int[] array = {100,2100,300,55};
动态初始化语法格式:
int[] array = new int[5]; //这里的5表示数组的元素个数
//初始化一个5个长度的int类型数组,每个元素默认值0
String[] names = new String[6]; //初始化6个长度的String类型数组,每个元素默认值null
1.一维数组的取、存和遍历
1.1代码展示
package com.power.Javase.array;
public class ArrayTest01 {
public static void main(String[] args) {
//声明一个int类型的数据,使用静态初始化的方式
int[] a = {1,2,6,85,20,12};
//所有的数组对象都有length属性
System.out.println("数组中元素的个数" + a.length);
//数组中每一个元素都有下标
//通过下表对数组中的元素进行存和取
//取
System.out.println("第一个元素 =" + a[0]);
System.out.println("最后一个元素 =" + a[5]);
System.out.println("最后一个元素 =" + a[a.length - 1]);
//存(改)
a[0] = 111;
a[a.length - 1] = 0;
System.out.println("第一个元素 =" + a[0]);
System.out.println("最后一个元素 =" + a[5]);
//一维数组怎么遍历呢?
for(int i=0;i<a.length;i++){
System.out.println(a[i]);
}
//下标为6表示第7个元素,第7个元素没有,下标越界了,会出现什么异常呢?
//ArrayIndexOutOfBoundsException(比较著名的异常)
//从最后一个元素遍历到第一个元素
for(int i = a.length - 1;i>=0; i++){
System.out.println(a[i]);
}
}
}
1.2执行结果
1.3内存结构图展示
示例二:
什么时候采用静态初始化方法,什么时候采用动态初始化方法?
当你创建数组的时候,确定数组中存储的哪些具体的元素时,采用静态初始化方式
当你创建数组的时候,不确定将来数组中存储那些数据,你可以采用动态初始化的方式,预先分配内存空间
2.初始化一位数组
2.1 2.初始化一位数组
public class ArrayTest02 {
public static void main(String[] args) {
//声明/定义一个数组,采用动态初始化方式创建
int[] a = new int[4]; //创建长度为4的int数组,数组中每个元素默认值是0
//遍历数组
for(int i = 0;i<a.length;i++){
System.out.println("数组中下标为:" + i+ "的元素是:" + a[i]);
}
//后期赋值
a[0] = 8;
a[1] = 25;
a[2] = 34;
a[3] = 41;
//初始化一个Object类型的数组,采用动态初始化方式
Object[] objs = new Object[3]; //3个长度,动态初始化,所以每个元素默认值是null
for(int i = 0; i < objs.length;i++){
System.out.println(objs[i]);
}
System.out.println("====================================");
String[] str = new String[3];
for(int i = 0; i<str.length;i++){
System.out.println(str[i]);
}
//采用静态初始化的方式
String[] str2 ={"abc","def","xyz"};
for(int i=0; i<str2.length;i++){
System.out.println(str2[i]);
}
//存储Object,采用静态初始化呢?
Object o1 = new Object();
Object o2 = new Object();
Object o3 = new Object();
Object[] objects = {o1,o2,o3};
for(int i =0;i<objects.length;i++){
System.out.println(objects[i]);
}
}
}
2.2执行结果:
2.3内存结构图展示
3方法的参数是数组(1)
3.1代码展示:
数组类型作为这个方法体的参数
(1)
public static void printArray(int[] array) {
for (int i=0;i<array.length;i++){
System.out.println(array[i]);
}
}
(2)
public static void printArray(String[] array) {
for (int i = 0; i < array.length; i++) {
System.out.println(array[i]);
}
}
完整代码如下:
package com.power.Javase.array;
public class ArrayTest03 {
public static void main(String[] args) {
System.out.println("hello world!");
int[] a1 = {12,45,63};
for (int i = 0; i<a1.length;i++){
System.out.println(a1[i]);
}
System.out.println("===================================");
//创建int数组
int[] x = {1,2,3,4};
printArray(x);
//创建String数组
String[] str = {"abc","def","haha","lala"};
printArray(str);
String[] str2 = new String[10];
printArray(str2);
}
public static void printArray(int[] array) {
for (int i=0;i<array.length;i++){
System.out.println(array[i]);
}
}
public static void printArray(String[] array) {
for (int i = 0; i < array.length; i++) {
System.out.println(array[i]);
}
}
}
3.2执行结果
4方法的参数是数组(2)
4.1代码展示
(1)
int[] a2 = new int[4];
printArray(a2);
(2)
printArray(new int[3]);
对于动态初始化数组来说,我们可以看出(1)和(2)本质上其实是一样的都是创建了一个数组类型的对象。
(3)
没有这种语法
没有这种语法
printArray({1,2,3});
(4)
如果直接传递一个静态数组的话,语法必须这样写:
如果直接传递一个静态数组的话,语法必须这样写:
printArray(new int[]{1,2,3});
package com.power.Javase.array;
//当一个方法的参数是一个数据的时候,我们还可以采用这种方式传
import com.sun.scenario.effect.impl.sw.sse.SSEBlend_SRC_OUTPeer;
import java.util.jar.JarOutputStream;
public class ArrayTest04 {
public static void main(String[] args) {
//静态初始化一位数组
int[] a = {1,2,3,4};
printArray(a);
System.out.println("=====================================");
//没有这总这种语法
//printArray({1,2,3});
//如果直接传递一个静态数组的话,语法必须这样写:
printArray(new int[]{1,2,3});
//动态初始化一位数组
int[] a2 = new int[4];
printArray(a2);
System.out.println("=========================================");
printArray(new int[3]);
}
public static void printArray(int[] array) {
for(int i=0;i<array.length;i++){
System.out.println(array[i]);
}
}
}
4.2执行结果
5.main方法的String[ ]数组
你有没有疑问过为什么主函数最后部分要写上String[] args,原来它本质上也是一个数组,在DOS窗口手动传入参数之后就会自动到这个数组中,可以用数组自带的长度函数来进行验证
//这个数组什么时候里面会有值呢?
//其实这个数字是留给用户的,用户可以在控制台上输入参数,这个参数自动回复被转换为“String[] args”
//例如这样与奴性程序:java ArrayTest05 abc def xyz
//那么这个时候JVM会自动将“abc def xyz”通过空格的方式进行分离,分立完成之后,自动放到“String[] args”数组
//所以main方法上面的String[] args数组主要是用来接受用户输入参数二代
//把abc def xyz 转换成字符串数组;{“abc”,“def”,“xyz”}
//遍历数组
核心代码
public static void main(String[] args) {
//JVM默认传递过来的这个数组对象的长度?默认0
//通过测试得出:args不是null
System.out.println("JVM给传递过来的String数组参数,它这个数组长度是?" + args.length);
5.1代码展示
/*
1、main方法上面的“String[] args”有什么用?
分析如下:谁负责调用main方法(JVM)
JVM调用main方法的时候,会自动传一个String数组过来
*/
public class ArrayTest05 {
//这个方法程序员负责写出来,JVM负责调用。JVM负责调用一定会传一个String数组过来
public static void main(String[] args) {
//JVM默认传递过来的这个数组对象的长度?默认0
//通过测试得出:args不是null
System.out.println("JVM给传递过来的String数组参数,它这个数组长度是?" + args.length);
//以下这一行代码表示的含义:数据对象创建了,但是数组中,诶有任何数据
//String[] strs = new String[0];
//String[] strs = {}; //静态初始化数组,里面没东西
//printLength(strs);
//这个数组什么时候里面会有值呢?
//其实这个数字是留给用户的,用户可以在控制台上输入参数,这个参数自动回复被转换为“String[] args”
//例如这样与奴性程序:java ArrayTest05 abc def xyz
//那么这个时候JVM会自动将“abc def xyz”通过空格的方式进行分离,分立完成之后,自动放到“String[] args”数组
//所以main方法上面的String[] args数组主要是用来接受用户输入参数二代
//把abc def xyz 转换成字符串数组;{“abc”,“def”,"xyz"}
//遍历数组
for(int i = 0;i < args.length; i++){
System.out.println(args[i]);
}
}
public static void printLength(String[] args) {
System.out.println(args.length);
}
}
5.2执行结果
在DOS窗口手动传值,传入的值都将保留到main方法的String[ ]数组中
6.main方法的String[ ]数组
注意代码:
username.equals("admain")&& password.equals("123")
使用以下这种编码风格,即使username和password都是null,也不会出现空指针异常
因为调用的是”admin“的equals方法
if("admain".equals(username)&& "123".equals(password)){
6.1代码展示
/*
* 模拟一个系统,假设而这个系统要使用,必须输入用户名和密码
*/
public class ArrayTest06 {
//用户名和密码输入到String[] args数组当中
public static void main(String[] args) {
if(args.length !=2){
System.out.println("使用该系统时输入程序参数,参数中包括用户名和密码信息,例如:zhangsan 123");
return;
}
//程序执行到此处说明用户确实提供了用户名和密码
//接下来你应该判断用户名和密码是否正确
//取出用户名
String username = args[0];
//取出密码
String password = args[1];
//假设用户名数admain,密码是123的时候表示登陆成功。其它一律失败
//判断两个字符是否相等,需要使用equals方法
if(username.equals("admain")&& password.equals("123")){
System.out.println("登陆成功,欢迎" + username + "回来");
System.out.println("您可以继续使用该系统");
}else{
System.out.println("验证失败,用户名不存在或者密码错误");
}
}
}
6.2执行结果
7.main方法的String[ ]数组
核心代码:
1.可以看(1)和(2)是一样的,(2)是在(1)的基础之上将代码合并
(1)
Animal a = animals[i];
a.move();
(2)
//代码合并
animals[i].move(); //这个move()方法不是数组的,是数组当中Animal对象的move()方法
2.同理,可以看出(3)和(4)是一样的,(4)是将(3)代码合并
(3) //创建一个Animal类型的数组,数组当中存储Cat和Bird
//创建一个Animal类型的数组,数组当中存储Cat和Bird
Cat c = new Cat();
Bird b = new Bird();
Animal[] anis ={c,b};
(4)
Animal[] anis = {new Cat[];new Bird[]}; //该数组存储量两个对象的内存地址
3.具有继承关系的数据类型引用时需要注意的问题?
(5)这个取出来的可能是Cat,也可能是Bird,不过肯定是一个Animal,如果调用的方法是父类中
存在的方法不需要向下转型,直接使用父类型引用调用即可
//这个取出来的可能是Cat,也可能是Bird,不过肯定是一个Animal
//如果调用的方法是父类中存在的方法不需要向下转型,直接使用父类型引用调用即可
Animal an = anis[i];
an.move();
(6)调用子类特有对象时,需要向下转型
if(anis[i] instanceof Cat){
Cat cat =(Cat)anis[i];
cat.catMouse();
}else if(anis[i] instanceof Bird){
Bird bird = (Bird)anis[i];
bird.sing();
}
7.1代码展示
package com.power.Javase.array;
/**
* 一维数组的深入,数组中存储的类型为:引用数据类型
* 对于数组来说,实际上只能存储java 对象的内存地址,数组中存储的每个元素的引用
*/
public class ArrayTest07 {
public static void main(String[] args) {
int[] array = {1,2,3};
for(int i=0;i<array.length;i++){
/*int temp = array[i];
System.out.println(temp);*/ //简单理解为拿过来赋给变量
//代码合并
System.out.println(array[i]);
}
//创建一个Aminal类型的数组
Animal a1 = new Animal();
Animal a2 = new Animal();
Animal[] animals = {a1,a2};
//对Animal数组进行遍历
for(int i =0; i <animals.length;i++){
/*Animal a = animals[i];
a.move();*/
//代码合并
animals[i].move(); //这个move()方法不是数组的,是数组当中Animal对象的move()方法
}
//动态初始化一个长度为2的animal数组
Animal[] ans = new Animal[2];
//创建一个Animal对象,放到数组的第一个盒子中
ans[0] = new Animal();
//Animal数组中只能存放Animal类型,不能存放Product类型
//ans[1] = new Product();
//Animal数组中可以存放Cat类型的数据,
//Cat是Animal的子类,因为Cat是一个Animal。
ans[1] = new Cat();
//创建一个Animal类型的数组,数组当中存储Cat和Bird
Cat c = new Cat();
Bird b = new Bird();
Animal[] anis ={c,b};
//Animal[] anis = {new Cat[];new Bird[]}; //该数组存储量两个对象的内存地址
for(int i = 0; i < anis.length; i++){
//这个取出来的可能是Cat,也可能是Bird,不过肯定是一个Animal
//如果调用的方法是父类中存在的方法不需要向下转型,直接使用父类型引用调用即可
//Animal an = anis[i];
//an.move();
//调用子类特有对象时,需要向下转型
if(anis[i] instanceof Cat){
Cat cat =(Cat)anis[i];
cat.catMouse();
}else if(anis[i] instanceof Bird){
Bird bird = (Bird)anis[i];
bird.sing();
}
}
}
}
class Animal{
public void move(){
System.out.println("Animal move...");
}
}
//s商品类
class Product{
}
//Cat是子类
class Cat extends Animal{
public void move(){
System.out.println("猫在走猫步");
}
//特有方法
public void catMouse(){
System.out.println("猫抓老鼠");
}
}
//Bird子类
class Bird extends Animal{
public void move(){
System.out.println("Bird fly");
}
public void sing(){
System.out.println("鸟儿在唱歌");
}
}
7.2执行结果
8.数组的扩容
关于一位数组的扩容
在java开发中,数组长度一旦确定不可变,那么数组满了怎么办?
数组满了,需要扩容
java中对数组的扩容是:
先新建一个大容量的数组,然后将小容量数组中的数据一个一个拷贝到大数组中
结论:数组库哦哦让效率比较低。因为涉及到拷贝的问题。所以在以后的开发中请注意,尽可能少的进行数组的拷贝
可以在创建数组对象的时候预估计以下多长合适,最好与古尊却,这样可以减少数组的扩容次数,提高效率
8.1代码展示
package com.power.Javase.array;
/*
关于一位数组的扩容
在java开发中,数组长度一旦确定不可变,那么数组满了怎么办?
数组满了,需要扩容
java中对数组的扩容是:
先新建一个大容量的数组,然后将小容量数组中的数据一个一个拷贝到大数组中
结论:数组库哦哦让效率比较低。因为涉及到拷贝的问题。所以在以后的开发中请注意,尽可能少的进行数组的拷贝
可以在创建数组对象的时候预估计以下多长合适,最好与古尊却,这样可以减少数组的扩容次数,提高效率
*/
public class ArrayTest08 {
public static void main(String[] args) {
//java中的数据怎么进行拷贝呢?
//System.arraycopy();
//拷贝源(从这个数组中进行拷贝)
int[] src = {1, 11, 22, 3, 4};
//拷贝目标(拷贝到这个目标数组上)
int[] dest = new int[20];
/* //调用JDK System类中的arraycopy犯法,来完成数组的拷贝
System.arraycopy(src,1,dest,3,2);
//遍历目标数组
for(int i = 0;i < dest.length;i++){
System.out.println(dest[i]); //0 0 0 11 22 ... 0
}
*/
System.arraycopy(src, 0, dest, 0, src.length);
for (int i = 0; i < dest.length; i++) {
System.out.println(dest[i]); //
}
/*
//数组中如果有存储的元素是引用,可以存储吗?当然可以
String[] strs = {"hello", "world", "study", "java", "oracle", "aysql", "javase"};
String[] newStrs = new String[20];
System.arraycopy(strs, 0, newStrs, 0, strs.length);
for (int i = 0; i < newStrs.length; i++) {
System.out.println(newStrs[i]);
}*/
System.out.println("================================");
Object[] objs ={new Object(), new Object(), new Object()};
Object[] newObjs = new Object[5];
//思考一下,这里的拷贝的时候是拷贝到是对象还是拷贝的地址(答案:地址)
System.arraycopy(objs,0,newObjs,0,objs.length);
for(int i=0;i<newObjs.length;i++){
System.out.println(newObjs[i]);
}
}
}
8.2执行结果
8.2内存展示
(1)
(2)
(3)