3.1 :顺序容器
容器是现代程序设计非常基础而重要的手段。
所谓容器,就是“放东西的东西”。数组可以看作是一种容器,但是数组的元素个数一旦确定就无法改变,这在实际使用中是很大的不足。一般意义上的容器,是指具有自动增长容量能力的存放数据的一种数据结构。在面向对象语言中,这种数据结构本身表达为一个对象。所以才有“放东西的东西”的说法。 Java具有丰富的容器,Java的容器具有丰富的功能和良好的性能。熟悉并能充分有效地利用好容器,是现代程序设计的基本能力。
顺序容器
- 放进容器中的对象是按照指定的顺序(放的顺序)排列起来的,而且允许具有相同值的多个对象存在。
Notebook
我们设计一个记事本,首先明确需求
- 能存储记录不限制能存储的记录的数量
- 能知道已经存储的记录的数量
- 能查看存进去的每一条记录
- 能删除一条记录
- 能列出所有的记录
设计记事本这个类,我们应该完成一些什么接口? 成熟的类一定是人机交互与业务逻辑分离,所以我们需要完成接口设计
- add(String note); 实现添加功能
- getSize(); 获取记事本的记录数量
- getNote(int index); 通过序号获取记事本记录
- removeNote(int index); 删除记录
- list(); 获取所有记录
定义接口
public void add(String s) {
// 添加note
}
public int getSize() {
// 返回note数量
return 0;
}
public String getNote(int index){
// 通过序号返回某个note
return "";
}
public boolean removeNote(int index) {
// 可能会通过返回布尔值,表示是否删除
return true;
}
public String[] list() {
// 返回数组,仅关注数据本身与业务逻辑,后续显示交给界面显示
return new String[1];
}
定义数据容器
- 容器类:用来存放任意数量的对象
容器类有两个类型:容器类型,元素类型
//定义一个私有数组
//容器类型<元素类型>
private ArrayList<String> notes = new ArrayList<String>();
//ArrayList范型类容器
//notes :本身为一个对象管理者
编写方法
public void add(String s) {
// 添加note
notes.add(s);
}
public void add(String s,int location) {
// 添加note到某个现有位置的前面
notes.add(location, s);
}
public int getSize() {
// 返回note数量
return notes.size();
}
public String getNote(int index){
// 通过序号返回某个note
return notes.get(index);
}
public void removeNote(int index) {
// 不用返回布尔值,直接删除
notes.remove(index);
}
public String[] list() {
// 返回数组,仅关注数据本身与业务逻辑,后续显示交给界面显示
String[] a = new String[notes.size()];
// for(int i=0;i<notes.size();i++)
// {
// a[i] = notes.get(i);
// }
notes.toArray(a);
// 调用ArrayList自带方法
return a;
}
编写测试main函数
public static void main(String[] args) {
Notebook nb = new Notebook();
nb.add("first");
nb.add("second");
nb.add("third",1); //定位添加
System.out.println(nb.getSize());
System.out.println(nb.getNote(1));
nb.removeNote(1);
String[] b = nb.list();
for(String s:b) {
System.out.println(s);
}
//使用for-each循环输出
}
思考:究竟把什么放进容器里去了?
当我们用add函数把对象放进容器中去的时候,究竟是把什么放进了容器?放进去的是对象本身吗?放进去以后,那个对象还在外面吗?如果修改了放进去的那个对象,容器中的对象会变化吗?
- 验证代码
```java
ArrayList
s = new ArrayList (); //定义s 类型为ArrayList ,新建一个ArrayList 交给s管理 String a =”12345”; //创建一个string类:对象a,其数据为“12345” s.add(a); System.out.println(s.get(0)); //第一次输出 System.out.println(a); //第二次输出 a = “11111”; //改变a的值 System.out.println(s.get(0)); //第三次输出 System.out.println(a); //第四次输出
- 结果:可见修改a的值后,s[0]并没有随之修改
```java
12345
12345
12345
11111
- 结论:仅仅是将对象的数据放入容器,对象作为数据的管理者,对象依然在外部。
3.2 :对象数组
当数组的元素的类型是类的时候,数组的每一个元素其实只是对象的管理者而不是对象本身。因此,仅仅创建数组并没有创建其中的每一个对象!
对象数组与普通数组
- 定义一个int数组与String字符串数组: ```java int[] ia = new int[10]; String[] a = new String[10]; System.out.println(ia[0]); System.out.println(a[0]); System.out.println(a[0].length());
结果: 0 null “nullpointException空指针异常”
- 给String数组的每个元素赋值
```java
int[] ia = new int[10];
String[] a = new String[10];
for (int i=0;i<a.length;i++) {
a[i]=""+i;
}
System.out.println(ia[0]+2);
System.out.println(a[0]);
System.out.println(a[0].length());
结果:
2
0
1
- 通过上面代码,我们知道对象数组中,每个元素都是对象的管理者而非对象本身
- int数组的元素就是数据本身
- String数组的元素是某一字符串对象的管理者
对象数组使用for-each循环操作
class Value{
private int i;
public void set(int i) {this.i = i;}
public int get() {return i;}
public String toString() {return ""+i;}
//在Value类中添加public String toString()后
}
定义一个Value类
public static void main(String[] args) {
Value[] a = new Value[10];
for(int i=0;i<a.length;i++){
a[i]=new Value();
a[i].set(i);
} //给数组中的每个Value对象赋值
for(Value v:a){
System.out.println(v.get());
v.set(0);
}
//通过for-each循环遍历并执行get方法
}
- 假如
for-each
循环执行到a
数组的第1
个元素,循环变量V
这时候也指向a[0]
所指的对象
也就可以通过.
运算符执行Value
对象的成员函数set
,从而改变当前对象的值
3.3 :集合容器(set)
集合就是数学中的集合的概念:所有的元素都具有唯一的值,元素在其中没有顺序。
集合容器
ArrayList<String> s = new ArrayList<String>();
s.add("first");
s.add("second");
s.add("first");
System.out.println(s);
System.out.println("-----------------");
HashSet<String> a = new HashSet<String>();
a.add("second");
a.add("first");
a.add("first");
a.add("second");
System.out.println(a);
结果:
[first, second, first]
-----------------
[first, second]
- 可知
SET容器
与数学中的SET
具有相同特性:无序,唯一
public String toString()
- Java内置对象基本自带此方法:将输出转化为字符串输出 ```java 使用此前定义的 Value 类 public static void main(String[] args) { Value a1 = new Value(); a1.set(10); System.out.println(a1); }
输出: Value@15db9742
- 因为自定义的`Value`类没有`toString()`方法,所以输出了对象管理者`a1`的地址
```java
class Value{
private int i;
public void set(int i) {this.i = i;}
public int get() {return i;}
public String toString() {return ""+i;}
//现在我们添加上这个方法
}
public static void main(String[] args) {
Value a1 = new Value();
a1.set(10);
System.out.println(a1);
}
输出:
10
- 可见对象已自动调用
toString()
方法
思考:集合能用get()函数来获得某个位置上的元素吗?
因为set是一个无序的集合容器,所以不可以用
get()
函数来调用set容器
中的某一具体位置的值
3.4 :散列表(Hash)
传统意义上的Hash表,是能以int做值,将数据存放起来的数据结构。 Java的Hash表可以以任何实现了hash()函数的类的对象做值来存放对象。 Hash表是非常有用的数据结构,熟悉它,充分使用它,往往能起到事半功倍的效果。
Hash表的应用
我们想要做一个查找硬币的程序,每个数字对应着相应的叫法,我们希望程序和具体的数据是无关的,我们需要设计一个普遍适用的程序该如何实现?
- 抽象思维:这个程序只不过是需要接收,存储与查找数据,我们仅需要一个合理的数据存储结构与数据接口,就可以实现,这种一一对应且无序的存储结构,就可以使用散列表Hashmap。 | 1 | penny | | —- | —- | | 5 | nickel | | 10 | dime | | 25 | quanter | | 50 | half-doller |
Hashmap:以一对数据为单位进行存储,<键key:值Value>
一个包裹类型的变量,可以直接接收它所对应的基础类型的变量:Integer类型可直接接收整数
- 先定义私有变量coinnames与Coin类构造函数,进行coinnames数据初始化
定义数据接口:getName获取对应值,add添加新数据
public class Coins{
private HashMap<Integer,String> coinnames = new HashMap<Integer,String>();
public Coins(){
coinnames.put(1,"penny");
coinnames.put(10,"dime");
coinnames.put(25,"quarter");
coinnames.put(50,"half-dollar");
coinnames.put(50,"五毛");
// 具有覆盖特性,对于相同的键,值总是取最后录入的那一个
}
public void add(int amount,String name){
Integer i = amount;
coinnames.put(i,name);
}
//add输入函数
public String getName(int amount){
if(coinnames.containsKey(amount))
return coinnames.get(amount);
else return "莫得!";
}
//getName取值函数,通过键获取到对应值
进行主函数数据测试
public static void main(String[] args) {
Scanner in = new Scanner(System.in);
int amount = in.nextInt(); //输入查询数值
Coins coin = new Coins(); //新建Coin对象
String name = coin.getName(amount); //定义String对象接收返回的数据
System.out.println(name);
System.out.println(coin.coinnames);
}
可以利用
for-each
循环进行遍历,也可以直接输出Hashmap(自带to String函数)for (Integer k: coinnames.keySet()) {
String s = coinnames.get(k);
System.out.println(s);
}
//通过for-each遍历哈希表中的元素,通过keySet取到每个对应的键与值