容器
1136(一个图一个类三个知识点六个接口)
Set:没有顺序,不能重复
List:有顺序,可以重复
重复的意思是指,两个对象互相equals,就算重复了
Map:定义了存储“键”(key),值(value)映射对的方法
一、Collection接口
示例1:
import java.util.*;
public class BasicContainer {
public static void main(String[] args) {
// TODO 自动生成的方法存根
Collection c=new ArrayList();
//父类引用指向子类对象,可以改掉new后面的,提高对象灵活性(比如改为LinkedList)
c.add("hello");
c.add(new Name("f1","l1"));
//add里装的必须是对象object(对象),对象是定义在堆上的,栈里的是值,值随时会被清空
c.add(new Integer(100));
System.out.println(c.size());//装了几个对象
System.out.println(c);//相当于调用了c.toString
}
class Name {
private String firstName,lastName;
public Name(String firstName,String lastName) {//构造方法
// TODO 自动生成的构造函数存根
this.firstName=firstName;
this.lastName=lastName;
}
public String getFirstName() {
return firstName;
}
public String getLastName() {
return lastName;
}
public String toString() {
return firstName+" "+lastName;
}
输出结果:3
[hello,f1 11,100]
示例2:
// TODO 自动生成的方法存根
Collection c=new HashSet();//父类引用指向子类对象,可以改掉new后面的代码,提高灵活性
c.add("hello");
c.add(new Name("f1","11"));//add里装的必须是对象object(对象),对象是定义在堆上的,栈里的是值,值随时会被清空
c.add(new Integer(100));
c.remove("hello");//可以remove掉
c.remove(new Integer(100));//可以remove掉,因为Integer也重写了equals方法,而且他们俩只要值一样就算equals
System.out.println(c.remove(new Name("f1","l1")));//返回true/false //没有重写的equals方法Hash就不能去除
System.out.println(c);//相当于调用了c.toString
输出:false
[f1,l1]
Collection方法举例:
重写一个对象的equals()方法必须要重写它的hashCode()方法
两个对象互相的equals,两个对象具备相同的hashCode
什么时候有用?当这个对象当做索引(键)的时候
示例3:
---在Name类中重写equals和hashCode---
class Name {
private String firstName,lastName;
public Name(String firstName,String lastName) {//构造方法
// TODO 自动生成的构造函数存根
this.firstName=firstName;
this.lastName=lastName;
}
public String getFirstName() {
return firstName;
}
public String getLastName() {
return lastName;
}
public String toString() {
return firstName+""+lastName;
}
public boolean equals(Object obj) {
if(obj instanceof Name) {
Name name=(Name)obj;//强制转换为Name对象
return (firstName.equals(name.firstName))&&
(lastName.equals(name.lastName));
}
return super.equals(obj);//如果传入的不是 Name对象,就交给Name父类Object类处理传入的对象
}
public int hashCode(){//重写equals()方法必须重写hashCode()方法。当这个对象当做索引当做键的时候
return firstName.hashCode();
}
输出:true
[]
二、Iterator接口
Iterator像是用来做遍历的
ArrayList底层是数组,要找一个数组,从头到尾找就可以了(找快)
LinkedList是连接的,是以链表为底层元素的(找慢)
示例1:
一个典型的遍历
import java.util.*;
public class Test {
public static void main(String[] args) {
// TODO 自动生成的方法存根
Collection c=new HashSet();//没顺序
c.add(new Name("f1","11"));
c.add(new Name("f2","12"));
c.add(new Name("f3","13"));
Iterator i =c.iterator();//拿到HashSet本身遍历自身的对象,那个对象是什么没关系不用去管//拿到对象了
while(i.hasNext()) {
//next()的返回值为object类型,需要转换为相应类型
Name n=(Name) i.next();//强制转换为Name类型
System.out.print(n.getFirstName()+" ");
}
}
}
输出:f1 f2 f3
示例2:
Iterator对象的remove()方法是迭代过程中删除元素的唯一的安全方法
import java.util.*;
public class Test2 {
public static void main(String[] args) {
// TODO 自动生成的方法存根
Collection c=new HashSet();
c.add(new Name("fff1","1111"));
c.add(new Name("f2","12"));
c.add(new Name("fff3","1113"));
for (Iterator i =c.iterator();i.hasNext();) {//for的第一个语句只执行一次,i被初始化。没有第三个语句
Name name=(Name)i.next();
if(name.getFirstName().length()<3) {//getFirstName返回的String类型
i.remove();
//如果换成c.remove(name);会产生例外
//不能使用容器自身的remove()方法,要用Iterator的,因为在执行过程中,Iterator执行了锁定(线程)
}
}
System.out.println(c);
}
}
输出:[fff3 1113, fff1 1111]
三、EnhancedFor
import java.util.*;
public class EnhancedFor {
public static void main(String[] args) {
// TODO 自动生成的方法存根
int []arr= {1,2,3,4,5};
for (int i : arr) {//把arr数组的元素存到i中
System.out.println(i);
}
Collection c=new ArrayList();
c.add(new String ("aaa"));
c.add(new String ("bbb"));
c.add(new String ("ccc"));
for (Object o : c) {//把c中的元素放到对象o中
System.out.println(o);//把o打印出来,相当于调用o.toString
}
}
}
输出:1
2
3
4
5
aaa
bbb
ccc
四、Set接口
示例1:
import java.util.*;
public class TestSet2 {
public static void main(String[] args) {
// TODO 自动生成的方法存根
Set s1=new HashSet();
Set s2=new HashSet();
s1.add("a");s1.add("b");s1.add("c");
s2.add("d");s2.add("a");s2.add("b");
//Set和List容器类都具有Constructor(Collection c)
//构造方法用以初始化容器类
Set sn=new HashSet(s1);//s1中所有内容给sn
sn.retainAll(s2);//求s1,s2的交集
Set su=new HashSet(s1);
su.addAll(s2);//s1全部元素添加到s2里,重复元素不添加
System.out.println(sn);
System.out.println(su);
}
}
输出
:
[a, b][a, b, c, d]
示例2:
import java.util.*;;
public class TestSet {
public static void main(String[] args) {
// TODO 自动生成的方法存根
Set s=new HashSet();//父类引用指向子类对象
s.add("hello");
s.add("world");
s.add(new Name("f1","f2"));
s.add(new Integer(100));
s.add(new Name("f1","f2"));//相同元素不会往里添加
s.add("hello");//相同元素不会往里添加
System.out.println(s);
}
}
输出:[world, 100, hello, f1 f2]
五、List接口
List非常像数组
set():返回的是一个对象,因为是替换掉一个对象,不是覆盖
add():添加一个元素,在原来元素上往后挤一格
indexOf():求一个字符或者字符串在另一个字符串中出现的位置。用到了equals()方法
返回该列表中指定元素的第一次出现的索引,或者如果该列表不包含元素,则返回-1。
示例:
import java.util.*;
public class TestList {
public static void main(String[] args) {
// TODO 自动生成的方法存根
List l1=new LinkedList();
for (int i = 0; i <=5; i++) {
l1.add("a"+i);
}
System.out.println(l1);
l1.add(3,"a100");//add是往后挤一个
System.out.println(l1);
l1.set(6, "a200");//替换
System.out.println(l1);
System.out.print((String)l1.get(2)+" ");//返回第2个位置的元素,转回字符串类型
System.out.println(l1.indexOf("a3"));//找到a3的位置
l1.remove(1);//移除第一个位置的元素,即a1
System.out.println(l1);
}
}
输出:
[a0, a1, a2, a3, a4, a5]
[a0, a1, a2, a100, a3, a4, a5][a0, a1, a2, a100, a3, a4, a200]
a2 4
[a0, a2, a100, a3, a4, a200]
六、Collections类
1136(一个图一个类三个知识点六个接口)
binarySearch():用二分法查找
示例:
import java.util.*;
public class TestList2 {
public static void main(String[] args) {
// TODO 自动生成的方法存根
List l1=new LinkedList();
List l2=new LinkedList();
for (int i = 0; i <=9; i++) {
l1.add("a"+i);
}
System.out.println(l1);
Collections.shuffle(l1);//随机排序
System.out.println(l1);
Collections.reverse(l1);//逆序
System.out.println(l1);
Collections.sort(l1);//排序
System.out.println(l1);
System.out.println(Collections.binarySearch(l1, "a5"));//折半查找
}
}
输出:
[a0, a1, a2, a3, a4, a5, a6, a7, a8, a9]
[a3, a0, a6, a9, a1, a5, a4, a8, a2, a7]
[a7, a2, a8, a4, a5, a1, a9, a6, a0, a3]
[a0, a1, a2, a3, a4, a5, a6, a7, a8, a9]
5
LinkedList逆序起来比ArrayList容易
如果要排从低到高,则先排好序(循环实现)再逆序
七、Comparable接口
comparaTo里传的可以是任何对象
示例:给字母顺序给名字排序
import java.util.*;
public class BC2 {
public static void main(String[] args) {
// TODO 自动生成的方法存根
List l1=new LinkedList();
l1.add(new Name("Karl","M"));
l1.add(new Name("Steven","Lee"));
l1.add(new Name("John","O"));
l1.add(new Name("Tom","M"));
System.out.println(l1);
Collections.sort(l1);
System.out.println(l1);
}
}
class Name implements Comparable{
private String firstName,lastName;
public Name(String firstName,String lastName) {//构造方法
// TODO 自动生成的构造函数存根
this.firstName=firstName;
this.lastName=lastName;
}
public String getFirstName() {
return firstName;
}
public String getLastName() {
return lastName;
}
public String toString() {
return firstName+" "+lastName;
}
public boolean equals(Object obj) {
if(obj instanceof Name) {
Name name=(Name)obj;//强制转换为Name对象
return (firstName.equals(name.firstName))&&
(lastName.equals(name.lastName));
}
return super.equals(obj);
//如果传入的不是 Name对象,就交给Name父类Object类处理传入的对象
}
public int hashCode(){
//重写equals()方法必须重写hashCode()方法。当这个对象当做索引当做键的时候
return firstName.hashCode();
}
public int compareTo(Object o) {
Name n=(Name)o;//强制转换类型,如果传入其他对象,立马出现问题
int lastCmp=lastName.compareTo(n.lastName);
//String类实现了Comparabel接口,所以可以调用compareTo方法,比较姓氏首字母
return (lastCmp!=0?lastCmp:firstName.compareTo(n.firstName));
//如果lastCmp!=0,就返回姓氏,如果姓氏相同,比较名字首字母
}
}
输出:
[Karl M, Steven Lee, John O, Tom M]
[Steven Lee, Karl M, Tom M, John O]
八、如何选择数据结构
九、Map接口
HashMap是用哈希表实现的
TreeMap是用二叉树实现的
**这里的重复指的还是equals,但是比较equals来查键不能重复,效率太低,直接比较hashCode,所以重写了equals的类必须重写hashCode,两个对象互相equals,它们的hashCode必须相等就在于这个地方,因为Map规定了键值不能重复,比较equals太慢,所以比较hashCode**
put():返回的是object,因为是替换掉原来的value,替换掉的就被返回了
get():通过key找到相对应的对象object
putAll():把另外一个Map的东西都加进来
clear():清除
示例:
import java.util.*;
public class MapTest {
public static void main(String[] args) {
// TODO 自动生成的方法存根
Map m1=new HashMap();
Map m2=new TreeMap();
m1.put("one",new Integer(1));
//key是string类型,value是Integer对象类型
m1.put("two",new Integer(2));
m1.put("three",new Integer(3));
//key:one two three,对应的对象1 2 3,只不过不是基本数据类型,是基本数据类型包装的对象
m2.put("A",new Integer(1));
m2.put("B",new Integer(2));
System.out.println(m1.size());
System.out.println(m1.containsKey("one"));//判断是否包含key
System.out.println
(m2.containsValue(new Integer(1)));//判断是否包含value
if (m1.containsKey("two")) {
int i=((Integer)m1.get("two")).intValue();
//get找到键(key),根据索引找到相对应的对象value
//拿到的是object,所以要强制转换为Integer,
//因为要复制到int的基础类型,求它作为int类型的值再穿进去(.intValue())
System.out.println(i);
}
Map m3=new HashMap(m1);//m1的数据放到m3里
m3.putAll(m2);//m2的数据全放到m2里
System.out.println(m3);
}
}
输出:
3
true
true
2
{A=1, B=2, two=2, three=3, one=1}
十、自动打包解包
修改代码:利用自动打包解包
修改TestMap:
import java.util.*;
public class MapTest2 {
public static void main(String[] args) {
// TODO 自动生成的方法存根
Map m1=new HashMap();
Map m2=new TreeMap();
m1.put("one",1); //把1自动打包为对象
m1.put("two",2);
m1.put("three",3);
m2.put("A",1);
m2.put("B",2);
System.out.println(m1.size());
System.out.println(m1.containsKey("one"));//判断是否包含key
System.out.println
(m2.containsValue(1));//自动把1打包成Integer对象
if (m1.containsKey("two")) {
int i=(Integer)m1.get("two");
//***一定加上(Integer)才可以自动拆包
//因为拿到的时候是个对象,不知道能不能转换为int
//所以强制转换后,会自动拆包成相对应的值
System.out.println(i);
}
Map m3=new HashMap(m1);//m1的数据放到m3里
m3.putAll(m2);//m2的数据放到m2里
System.out.println(m3);
}
}
输出:
3
true
true
2
{A=1, B=2, two=2, three=3, one=1}
示例:判断字符串出现次数
import java.util.*;
//判断字符串出现次数
public class TestArgsWords {
private static final Integer ONE=new Integer(1);//ONE里存的是1
public static void main(String[] args) {
// TODO 自动生成的方法存根
Map m=new HashMap();
for (int i = 0; i < args.length; i++) {
Integer freq=(Integer)m.get(args[i]);//以key(键)来查找value(值)
m.put(args[i], (freq==null?ONE:new Integer(freq.intValue()+1)));
}
System.out.println(m.size()+" distinct words detected:");
System.out.println(m);
}
}
//输入aaa bbb aaa
//aaa是key,一开始对应的value是null,运行11行,freq==null,第12行,设置aaa的value为1
//bbb同上
//再次输入aaa,已经可以索引到value,所以12行中,取出value,然后+1,再转为Integer对象输出,即value变为2
//输出结果:
//3 distinct words detected:
//{aaa:2,bbb:1}
修改代码:改为自动打包解包
import java.util.*;
//判断字符串出现次数
public class TestArgsWords2 {
private static final int ONE=1;
public static void main(String[] args) {
// TODO 自动生成的方法存根
Map m=new HashMap();
for (int i = 0; i < args.length; i++) {
int freq=(Integer)m.get(args[i])==null?0:(Integer)m.get(args[i]);
//把对象转换为Integer对象,因为传入的是对象,要判断是不是为空,为空就赋值0,不为空就是自身
m.put(args[i], (freq==0?ONE:freq+1));
}
System.out.println(m.size()+" distinct words detected:");
System.out.println(m);
}
}
十一、泛型
容易出错在于:比如扔进去一只狗,强制转化成一只猫
示例:泛型
import java.util.*;
//泛型
public class BasicGeneric {
public static void main(String[] args) {
// TODO 自动生成的方法存根
List<String> c=new ArrayList<String>();//表示只能装String
c.add("aaa");
c.add("bbb");
c.add("ccc");
for (int i = 0; i < c.size(); i++) {
String s=c.get(i);//原来需要强制转换,现在不需要了,因为扔进的是String,拿出来也是String
System.out.println(s);
}
Collection<String>c2=new HashSet<String>();
c2.add("aaa");
c2.add("bbb");
c2.add("ccc");
for (Iterator <String> it = c2.iterator(); it.hasNext();) {
String s=it.next();
System.out.println(s);
}
}
}
class MyName implements Comparable<MyName>{
//只跟MyName作比较,和其他类作比较没意义,其他类一传进来就出错
int age;
public int compareTo(MyName mn) {
//原本compareTo方法里面的参数是object类型,利用泛型之后,指定为MyName类型
//由编译器判断传入的是不是MyName类型,不再需要强制转换
if (this.age>mn.age)
return 1;
else if(this.age<mn.age)
return -1;
else return 0;
}
}
输出:
aaa
bbb
ccc
aaa
ccc
bbb
修改代码:利用泛型和自动打包解包
修改MapTest:
import java.util.*;
//利用泛型和自动打包解包修改代码
public class MapTest3 {
public static void main(String[] args) {
// TODO 自动生成的方法存根
Map<String,Integer> m1=new HashMap<String,Integer>();
Map<String,Integer> m2=new TreeMap<String,Integer>();
m1.put("one",1); //把1自动打包为对象
m1.put("two",2);
m1.put("three",3);
m2.put("A",1);
m2.put("B",2);
System.out.println(m1.size());
System.out.println(m1.containsKey("one"));//判断是否包含key
System.out.println
(m2.containsValue(1));//自动把1打包成Integer对象
if (m1.containsKey("two")) {
int i=m1.get("two");//拿出来是Integer对象类型
System.out.println(i);
}
Map m3=new HashMap(m1);//m1的数据放到m3里
m3.putAll(m2);//m2的数据放到m2里
System.out.println(m3);
}
}
输出:
3
true
true
2
{A=1, B=2, two=2, three=3, one=1}
修改TestArgsWords:
import java.util.*;;
//判断字符串出现次数
public class TestArgsWords3 {
private static final int ONE=1;
public static void main(String[] args) {
// TODO 自动生成的方法存根
Map<String,Integer>m=new HashMap<String,Integer>();
for (int i = 0; i < args.length; i++) {
if (!m.containsKey(args[i])) {//判断是=是否含有key
m.put(args[i],ONE);
//如果没有,就把ONE的值给它,这里用到了自动打包解包,因为put传入的是object类型
}else {
int freq=m.get(args[i]);//拿到key对应的value值并转换为int类型
m.put(args[i],freq+1);//value+1
}
}
System.out.println(m.size()+" distinct words detected:");
System.out.println(m);
}
}
以后用到集合的时候,尽量使用泛型
十二、总结
(Generic:泛型)
六个接口:
1、Collection接口--->2、Set接口
--->3、List接口
4、Map接口
5、Iterator接口:标准的、统一的来遍历一个Collection方式
6、Comparable接口:可以运用泛型,来定义这个类之间两个对象谁大谁小