java08 数组与集合
1 数组的定义与规范
一个变量只能存放一个数据,一个数组是一个容器,可以存放多个数据
数组的特点
1 数组是一种引用数据类型
2 数组中的多个数据,类型必须统一
3 数组的长度在程序运行期间,不可改变
数组的初始化
1 动态初始化 指定长度: 数据类型[] 数组名称 = new 数据类型 [ 数组长度]
左侧的数据类型 表示数组中保存的数据类型
左侧的中括号 代表我是一个数组
左侧的组名称 给数组取一个名字
右侧的new 代表创建数组的动作
右侧的数据类型 必须和左边的数据类型保存一直
右侧的括号长度 标书数组中,存放多少个数据,是一个int数字
public class HelloWorld2 { public static void main(String[] args) { int[] a = new int[1]; float[] b = new float[2]; double[] c = new double[3]; } }
2 静态初始化 指定内容: 数据类型[] 数组名称 = new 数据类型 [ ]{元素1,元素2,,,,}
public class HelloWorld2 { public static void main(String[] args) { int[] a = new int[]{1,2,3,4,5,6,7,0}; } }
虽然静态初始化没有给定长度,但可以根据大括号的元素格式,推算出数组长度
3 省略静态初始化 数据类型[] 数组名称 = {1,2,3,4,5,6,7,9}
说明:
静态初始化,没有直接指定长度,仍然可以推算出长度
静态初始化标准格式可以拆分为两个步骤,但省略的静态初始化不可以
动态标准化也可以拆分2个步骤
public class HelloWorld2 { public static void main(String[] args) { int [] a; a = new int[5] } }
使用区别 已知内容使用静态,指定长度使用动态
2 数组的各种方法
2.1 指定打印数组名称 输出的是数组的内存地址
public class HelloWorld2 { public static void main(String[] args) { int [] a; a = new int[5]; System.out.println(a); } } 结果 [I@1b6d3586
2.2.指定数组,访问数组的具体元素-数组索引自 0 到 n -1
public class HelloWorld2 { public static void main(String[] args) { int [] a = new int[]{10,20,30}; System.out.println(a[0]); } } 结果 10
2.3 访问指定数组元素,并赋值。
使用动态初始化数组的时候,其中的元素将会自动拥有一个默认值
1)如果是整数类型,那么默认0
2)如果是浮点类型,那么默认0.0
3)如果是字符类型,那么默认为\u0000
4)如果是布尔类型,那么默认为false
5)如果是引用类型,那么默认为null
使用静态初始化数组的时候,也有默认值,只不过迅速变成了指定值
public class HelloWorld2 { public static void main(String[] args) { int [] a = new int[]{10,20,30}; System.out.println(a); System.out.println(a[0]); System.out.println(a[1]); System.out.println(a[2]); int [] b = new int[3]; System.out.println(b); System.out.println(b[0]); System.out.println(b[1]); System.out.println(b[2]); } }
结果
[I@1b6d3586
10
20
30
[I@4554617c
0
0
0
2.3 访问指定数组元素,并赋值。
public class HelloWorld2 { public static void main(String[] args) { int [] a = new int[]{10,20,30}; System.out.println(a); System.out.println(a[0]); System.out.println(a[1]); System.out.println(a[2]); System.out.println("------------"); a[1] = 123; System.out.println(a[1]); } } 结果 [I@1b6d3586 10 20 30 ------------ 123
2.5 java内存分布
java内存分为5个部分
1)栈内存 stack 存放的是方法中的局部变量;
局部变量:方法中的参数,或者是方法{}内部变量;
作用域 :一旦超出作用域,立刻从栈中消失
2)堆内存 heap 凡是new出来东西,都在堆中;
堆内存里面的东西,都有一个地址,16进制;
堆内存里面的数据,都有默认值,如下:
如果是整数,默认为0
如果是浮点数 默认为0.0
如果是字符,默认为 \u0000
如果是布尔 默认为false
如果是引用类型 默认为null
3)方法区 method area 存储class相关信息,包含方法的信息
4)本地方法栈(native method stack) 与操作系统相关
5)寄存器(PC register) 与CPU相关
6)两个数组指向同一个地址时,其中一个数组修改,另一个数组值也将修改
数组常见错误
1)数组长度的越界;
2)数组必须new初始化,才能使用其中元素,或者对于引用类型变量,赋值为null,否则会引起空指针异常。
2.6 数组的方法
1)数组的长度: 数组名称.length;即可
2) 数组的遍历
指定一个数组
使用另外一种方式,数组长度。length,可以使用for循环
public class HelloWorld2 { public static void main(String[] args) { int [] b = {1,2,3,4,5,6,7,88,8}; int len = b.length; for (int i = 0; i <len ; i++) { System.out.println(b[i]); } } }
3)数组的最大值
使用变量获取最大值,循环比较
4)数组的反转
数组的元素反转,要么定义新数组,要么数组的自我反转(对称位置的反转)
5)数组作为方法参数
有时候,我们需要对数组进行无数次遍历
我们可以定义一个方法,来实现这个动作
运行结果如下:
任何数据类型,都可以作为方法的返回值
一个方法可以有多个参数,但是只能有0,1,不能有多个返回值;
如果希望一个方法当中产生了多个结果数据进行返回,怎么办
解决方案 使用一个数组作为返回值类型即可
数组作为方法的返回值,返回的是地址值
3 集合
集合和数组都是容器,主要区别在
1)数组长度是固定的,集合长度是可变;
2)数组可以存在数据和对象,而集合存储的都是对象(可不同类型)
3.1 集合框架
集合按照存储结构,分为两大类,单列集合(java.util.Collection)和双列集合(java.util.Map),现在独立学单列集合java.util.Collection.
单列集合java.util.Collection 用于存储一系列符合某种规则的元素,它有两个重要的子接口分别是 java.out.List和java.util.Set,
其中List是元素有序,元素可重复,主要实现的类有java.util.ArrayList和java.util.LinkedList.
其中Set是元素无序,而且不可重复。主要实现的类有java.util,HashSet 和java.util.TreeSet.
3.2Collection集合功能
Collection是所以单列集合的父几口,因此在Collection中定义了单列集合通用的一些方法,可以用在操作所有
4 迭代器
每种集合存储信息不同,对于Collection集合元素的通用存取方法,在取元素之前先要判断集合中有没有元素,如果有,就把这个元素取出来,继续再【判断。如果还有就再取出来,一直把集合中的所有元素全部取出,这种取出方式的专业术语叫迭代。
4.1 Iterator接口
java.util.Interator接口:迭代器
boolean hasNext()如果还有元素可以迭代,就返回true
判断集合中还有没有下一个元素,有就true 没有就false
E next()返回迭代的下一个元素,取出集合中的下一个元素。
迭代器的使用步骤
1 使用集合中的方法iterator获取迭代器的实现类对象,使用Iterator接口接受(多态)
2使用Iterator接口中的方法hasNext()判断还有没有下一个元素
3使用Iterator接口中的法法Next()取出集合中下一个元素
import java.util.ArrayList; import java.util.Collection; import java.util.Iterator; //定义一个方法,求出1-100之间的和 public class HelloWorld2 { public static void main(String[] args) { //创建一个集合对象 Collection<String> coll = new ArrayList<>(); //往集合对象中添加元素 coll.add("哈哈1"); coll.add("哈哈2"); coll.add("哈哈3"); coll.add("哈哈4"); //多态 接口 实现类对象 Iterator<String> it = coll.iterator(); // 发现使用迭代器取出集合中元素的代码,是一个重复的过程 //所以我们使用循环化 //不知道集合中有多少对象,使用while循环 // 循环结束,hasNext方法返回false while(it.hasNext()){ String e = it.next(); System.out.println(e); } } }
增强for循环
5 泛型
前面学习集合时,我们都知道集合中是可以存放任意对象的,只要把对象存储集合后,那么这时他们都会被提升成Object类型,当我们在取出每一个对象时,并且进行相应的操作,这时必须采用类型转换、。
泛型是一个未知的数据类型,当我们不知道使用什么数据类型的时候,可以用泛型, 泛型也可以看出是一个变量,用来接收数据类型。
E e Elemant元素
T t Type类型
以集合ArrayList为例,ArrayList集合定义时候,不知道会存储什么类型的数据,所以类型使用泛型,E 未知的数据类型。
那么类型什么时候能够确定,创建集合对象的时候,就会确定=泛型的数据类型
会把数据类型作为参数传递,把String赋值给泛型E。
使用案例表达下使用泛型与不使用泛型的区别
1 集合不使用泛型,默认类型是Object类型,可以存储任意类型数据,迭代器的泛型是跟着集合走,集合没有泛型,那么迭代器也就没有泛型。
弊端 不安全,会引发异常
import java.util.ArrayList; import java.util.Iterator; /* 创建对象,不使用泛型 好处: 集合不使用泛型,默认类型就是Object类型,可以存储任意类型的数据 弊端 不安全,容易引发异常 */ class hellword2{ public static void main(String[] args) { show1(); } private static void show1(){ ArrayList list = new ArrayList(); list.add("abc"); list.add("1"); // 使用迭代器遍历list集合 //获取迭代器 Iterator it = list.iterator(); //使用迭代器中的方法hasNext 和 next遍历集合 while(it.hasNext()){ //取出元素也是Object类型 Object obj = it.next(); System.out.println(obj); //使用string类特有的方法,length获取字符串的长度, //多态的弊端,不能使用子类的方法。 //需要向下转型。 String s = (String)obj; System.out.println(s.length()); } } } 结果 abc 3 1 1
2 集合使用泛型,避免了类型转换的麻烦,存储是什么类型,取出就是什么类型,同时运行异常,提升到了编译期间(代码编写时候,提醒错误)
弊端,泛型是什么类型, 只能存储什么类型。
import java.util.ArrayList; import java.util.Iterator; /* 创建对象,不使用泛型 好处: 集合不使用泛型,默认类型就是Object类型,可以存储任意类型的数据 弊端 不安全,容易引发异常 */ class hellword2{ public static void main(String[] args) { show1(); show2(); } public static void show2(){ ArrayList<String> list = new ArrayList<>(); list.add("123"); list.add("456"); //使用迭代器遍历list集合 Iterator<String> it = list.iterator(); while (it.hasNext()){ String s = it.next(); System.out.println(s); } } private static void show1(){ ArrayList list = new ArrayList(); list.add("abc"); list.add("1"); // 使用迭代器遍历list集合 //获取迭代器 Iterator it = list.iterator(); //使用迭代器中的方法hasNext 和 next遍历集合 while(it.hasNext()){ //取出元素也是Object类型 Object obj = it.next(); System.out.println(obj); //使用string类特有的方法,length获取字符串的长度, //多态的弊端,不能使用子类的方法。 //需要向下转型。 String s = (String)obj; System.out.println(s.length()); } } }
5.泛型的定义和使用
我们在集合中会大量使用到泛型,泛型用来灵活的将数据类型应用到不同的类,方法和接口当中,将数据类型作为参数进行传递。
1定义和使用含有泛型的类
定义格式
修饰符 class 类名<代表泛型的变量>{}
例如:API 中的ArrayList集合:
class ArrayList<E>{ public boolean add(E e){} public E get(int index){} }
public class nohello { public static void main(String[] args){ //创建helloworld2的对象 helloworld2 gc = new helloworld2(); gc.setName("只能是字符串"); String name = gc.getName(); System.out.println(name); } }