java中的集合
Java 集合可分为 Collection 和 Map 两种体系
Collection接口:
Set:元素无序、不可重复的集合
List:元素有序,可重复的集合
arraylist
linkedlist
vector
Map接口具有映射关系“key-value对”的集合
Collection 接口是 List、Set 和 Queue 接口的父接口,该接口里定义的方法既可用于操作 Set 集合,也可用于操作 List 和 Queue 集合。
JDK不提供此接口的任何直接实现,而是提供更具体的子接口(如:Set和List)实现。
在 Java5 之前,Java 集合会丢失容器中所有对象的数据类型,把所有对象都当成 Object 类型处理;从 JDK 5.0 增加了泛型以后,Java 集合可以记住容器中对象的数据类型。
ArrayList
public class Test {
public static void main(String[] args) {
//集合中添加的数据,都不是基本类型,都是包装类
List list=new ArrayList();
//添加元素 任意类型
list.add(10);
list.add("lxy");
list.add(new Dog());
System.out.println(list);
System.out.println(list.size());
//获取每一个元素
System.out.println(list.get(2));
//往集合的某处插入元素
list.add(2,"zll");
System.out.println(list.get(2));
for (Object o : list) {
System.out.println(o);
}
List list1=new ArrayList();
//添加所有
list1.add(100);
list1.add(200);
list.addAll(list1);
System.out.println(list);
//移除
list.remove(2);
list.remove("zll");
list.removeAll(list1);
System.out.println(list);
//清除
//list.clear();
//System.out.println(list);
//判断 该元素是否在该集合中
System.out.println(list.contains(2222)); //false
//修改值
list.set(2,"lxy");
System.out.println(list.get(2));
}
}
迭代器
Iterator对象称为迭代器(设计模式的一种),主要用于遍历 Collection 集合中的元素。
所有实现了Collection接口的集合类都有一个iterator()方法,用以返回一个实现了Iterator接口的对象。
Iterator 仅用于遍历集合,Iterator 本身并不提供承装对象的能力。如果需要创建 Iterator 对象,则必须有一个被迭代的集合。
jdk1.5之后遍历集合可以使用增强for循环,iter
在java中,迭代器共用一个对象 在循环遍历的时候,迭代器自己生成一个迭代器对象
返回值为iterator时,只能用while(iterator.hasNext())
迭代器里面不要进行增,删等操作,因为迭代器共用一个对象
首次出现,indexOf() list中有相同的数据时,使用indexOf()返回第一次出现的下标
public class Iters {
public static void main(String[] args) {
ArrayList<Integer> list = new ArrayList<>();
list.add(10);
list.add(20);
list.add(15);
//集合使用迭代器遍历
Iterator<Integer> iterator = list.iterator();
while(iterator.hasNext())
{
Integer next = iterator.next();
//不能用list删 迭代器有锁
//list.remove(3);
if(next.equals(15))
{
//迭代器只能自己删自己 迭代器的内部不能修改外部的地址值
iterator.remove();
}
}
for (Integer integer : list) {
//list对象只能修改 迭代器只能自己删除,增加
//迭代器的内部不能修改外部的地址值
System.out.println(integer);
}
System.out.println(list);
//jdk1.5之后遍历集合可以使用增强for循环,iter
//返回值为iterator时,只能用while(iterator.hasNext())
//在java中,迭代器共用一个对象 在循环遍历的时候,迭代器自己生成一个迭代器对象
//迭代器里面不要进行增,删等操作
//首次出现,indexOf()
}
}
如果要让它输出,可以采用这样的方式 arrayList.add(6);
public class IteratorTest {
public static void main(String[] args) {
ArrayList list = new ArrayList();
list.add(new Person("asde",17,29,"asx",98));
list.add(new Person("qwe",12,22,"qwz",67));
list.add(new Person("aqqde",13,29,"asx",78));
list.add(new Person("qwe",12,22,"qwz",67));
//增强for循环 一个副本 所以迭代器的内部不能修改外部对象的地址值
for (Object o : list) {
//list对象不能在迭代器中增加,删除,只有迭代器对象自己才可以增加,删除
//list.remove(1); //不能删除
//list.add(new Person("qwe",12,22,"qwz",67));//不能添加
list.set(2,new Person("qwe",12,22,"qwz",67));//可以修改
//迭代器内部不能修改外部的地址值
o=new Person("qwe",12,22,"qwz",67);//赋值不起作用,list中不会发生改变
//System.out.println(o);//输出四个o 迭代器的内部不能修改外部对象的地址值
}
System.out.println(list);
}
}
list接口
ArrayList 是线程不安全的,效率高,而 Vector 是线程安全的,效率低,异步时使用,即使为保证 List 集合线程安全(同步时使用),也不推荐使用Vector,底层都是可变的数组结构
ArrayList查询快,LinkedList增删改快(底层是链表),是线程不安全的,效率高。
Arrays.asList(…) 方法返回的 List 集合既不是 ArrayList 实例,也不是 Vector 实例。 Arrays.asList(…) 返回值是一个固定长度的 List 集合
//集合的排序
Collections.sort(list);
//反转
Collections.reverse(list);
对象的排序
对于存放在Set容器中的对象,对应的类一定要重写equals()和hashCode(Object obj)方法,以实现对象相等规则。
重写 hashCode() 方法的基本原则
在程序运行时,同一个对象多次调用 hashCode() 方法应该返回相同的值
当两个对象的 equals() 方法比较返回 true 时,这两个对象的 hashCode() 方法的返回值也应相等
对象中用作 equals() 方法比较的 Field,都应该用来计算 hashCode 值
内部比较器
public class Person implements Comparable<Person> {
private String name;
private int id;
private int age;
private String address;
private int score;
public Person() {
}
public Person(String name, int id, int age, String address, int score) {
this.name = name;
this.id = id;
this.age = age;
this.address = address;
this.score = score;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public String getAddress() {
return address;
}
public void setAddress(String address) {
this.address = address;
}
public int getScore() {
return score;
}
public void setScore(int score) {
this.score = score;
}
@Override
public String toString() {
return "Person{" +
"name='" + name + '\'' +
", id='" + id + '\'' +
", age=" + age +
", address='" + address + '\'' +
", score=" + score +
'}';
}
@Override
//内部比较器使用 this that
public int compareTo(Person that) {
if(this.getScore()==that.getScore())
{//this在前,为升序(this-that)
return this.getAge()-that.getAge();
}
else
{
//降序
return that.getScore()-this.getScore();
}
}
}
//内部比较器
public class Test {
public static void main(String[] args) {
ArrayList<Person> people = new ArrayList<>();
people.add(new Person("张三1",1,18,"山西",86));
people.add(new Person("张三2",2,20,"山西",90));
people.add(new Person("张三3",3,22,"山西",86));
people.add(new Person("张三4",4,19,"山西",95));
people.add(new Person("张三5",5,24,"山西",76));
people.add(new Person("张三6",6,30,"山西",59));
Collections.sort(people);
for (Person person : people) {
System.out.println(person);
}
}
}
外部比较器
javabean和上面的一样
public class Test2 {
public static void main(String[] args) {
ArrayList<Person> people = new ArrayList<>();
people.add(new Person("张三1",1,18,"山西",86));
people.add(new Person("张三2",2,20,"山西",90));
people.add(new Person("张三3",3,22,"山西",86));
people.add(new Person("张三4",4,19,"山西",95));
people.add(new Person("张三5",5,24,"山西",76));
people.add(new Person("张三6",6,30,"山西",59));
//想比较对象 我们就必须引入比较器 Comparator (外部比较器) Comparable(内部比较器)
//外部比较器 严于 内部比较器
//内部类的概念 匿名内部类(是一个类,但没有名字)
//当你去new 一个接口的时候 ,必须要实现接口内部方法具体的实现
Collections.sort(people,new Comparator<Person>() {
@Override
public int compare(Person o1, Person o2) {
if(o1.getScore()==o2.getScore())
{
//o1-o2 升序
return o1.getAge()-o2.getAge();
}
else
{
return o2.getScore()-o1.getScore();
}
}
});
for (Person person : people) {
System.out.println(person);
}
}
}
当两个String进行比较的时候,使用compareTo()
LinkedList
public class Test {
static LinkedList list = new LinkedList();
public static void add()
{
list.addFirst(12);//链表结构有的,获取第一个
list.add(18);
list.add("asd");
list.add(29.8);
list.addLast("asdqwe");
//list.add(5,5); 下标越界
System.out.println(list.getLast());
System.out.println(list.removeFirst());
System.out.println(list.size());
System.out.println(list.get(2));//得到下标为2的数
//迭代器
Iterator iterator=list.iterator();
while (iterator.hasNext())
{
Object next=iterator.next();
System.out.println(next);
}
}
public static void add1()
{
list.add(new Person("asde",17,29,"asx",98));
list.add(new Person("qwe",12,22,"qwz",67));
show();
}
public static void show()
{
for (Object o : list) {
System.out.println(o);
}
}
public static void main(String[] args) {
add();
add1();
}
}
Set
无序,不可重复,线程不安全,查询快,增删也快
底层原理
set的底层是数组+链表,数组是主干
HashSet
public class Person implements Comparable<Person> {
private String name;
private int id;
private int age;
private String address;
private int score;
public Person() {
}
public Person(String name, int id, int age, String address, int score) {
this.name = name;
this.id = id;
this.age = age;
this.address = address;
this.score = score;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public String getAddress() {
return address;
}
public void setAddress(String address) {
this.address = address;
}
public int getScore() {
return score;
}
public void setScore(int score) {
this.score = score;
}
@Override
public String toString() {
return "Person{" +
"name='" + name + '\'' +
", id='" + id + '\'' +
", age=" + age +
", address='" + address + '\'' +
", score=" + score +
'}';
}
@Override
public int compareTo(Person that) {
if(this.getScore()==that.getScore())
{//this在前,为升序
return this.getAge()-that.getAge();
}
else
{
return that.getScore()-this.getScore();
}
}
@Override
public int hashCode() {
return name.hashCode()+id+age+address.hashCode()+score;
}
@Override
public boolean equals(Object obj) {
if(this==obj)
return true;
if(!(obj instanceof Person))
{
return false;
}
//强制转换 上面已经排除了其他的方法
Person person=(Person)obj;
if(this.getName().equals(person.getName())&&this.getId()==((Person) obj).getId()&&this.getAge()==((Person) obj).getAge()&&this.getAddress().equals(((Person) obj).getAddress())&&this.getScore()==((Person) obj).getScore())
return true;
else
return false;
}
}
public class HashSetTest {
static HashSet hashSet = new HashSet();
public static void main(String[] args) {
//无序,不可重复
hashSet.add(10);
hashSet.add(20.0);
hashSet.add("qwe");
hashSet.add(10);
//new出来的相同的东西不止一份,需要重写,要不然无法去重
//在Person中重写hashCode方法和equals方法,可以将new出来的相同的数据只保留一份 先走hashCode,hashCode相同时再走equals
hashSet.add(new Person("asde",17,29,"asx",98));
hashSet.add(new Person("asd",19,29,"asx",98));
hashSet.add(new Person("asde",17,30,"asx",68));
hashSet.add(new Person("asde",17,29,"asx",98));
hashSet.add(new Person("asde",17,29,"asx",98));
for (Object o : hashSet) {
System.out.println(o);
}
}
}
TreeSet
有序,查询快
底层结构
二叉树里的红黑树
红黑树:jdk引入,当两边数据不均衡时,会在内部自动调用自己的算法把内部打乱,重新找到一个合适的基点,可以保证两边的平衡
public class TreeSetTest {
public static void main(String[] args) {
//外部比较器
TreeSet<Person> treeSet=new TreeSet<Person>(new Comparator<Person>() {
@Override
public int compare(Person o1, Person o2) {
if(o1.equals(o2))//判断两个对象是否相同
//if(o1.getName().equals(o2.getName())&&o1.getId()==o2.getId()&&o1.getAge()==o2.getAge()&&o1.getAddress().equals(o2.getAddress())&&o2.getScore()==o1.getScore())
//o1-o2,升序
return 0;//如果所有的都相同,返回0
else if(o1.getName().equals(o2.getName()))
return o1.getId()-o2.getId();
else if(o1.getId()==o2.getId())
return o1.getAge()-o2.getAge();
else if(o1.getAge()==o2.getAge())
return o2.getScore()-o1.getScore();
else
return o2.getScore()-o1.getScore();
}
});//底层结构为二叉树的红黑树
//默认情况下添加的为同一类型 因为他要比较大小,不同类型之间无法比较大小
treeSet.add(new Person("asde",17,29,"asx",98));
treeSet.add(new Person("sde",19,29,"asx9",94));
treeSet.add(new Person("dea",19,20,"asx8",68));
treeSet.add(new Person("asde",19,18,"asx1",91));
treeSet.add(new Person("ade",25,29,"asx8",94));
treeSet.add(new Person("asde",17,29,"asx",98));
for (Object o : treeSet) {
System.out.println(o);
}
}
}
Map
hashmap的底层原理
Map 中的 key 和 value 都可以是任何引用类型的数据
Map 中的 key 用Set来存放,不允许重复,即同一个 Map 对象所对应的类,须重写hashCode()和equals()方法
1.子类:hashMap 无序的
底层结构:数组(key,value)+链表结构
线程安全:不安全,他是异步的
效率: 高
存储:key跟value都可以为null
优点: 查找速度快
缺点: 增删慢
2.子类:hashtable 无序
底层结构:数组(key,value)+链表结构
线程安全:安全,他是同步的
存储:key跟value都不可以为null
3.子类:treeMap 有序的
底层:二叉树(红黑树)
线程安全:不安全,他是异步的
效率: 高
public class HashMap1 {
public static void main(String[] args) {
HashMap map = new HashMap();
map.put(10,20);
map.put("asd",12);
map.put(null,10);
map.put(50,null);
map.put(null,null);
System.out.println(map.get(null));//输出null,根据key值,获取value值,后面的覆盖了前面的
//如果key存在,返回value,如果key不存在,设置value值
System.out.println(map.getOrDefault(38, "我来了"));
Collection value=map.values();
System.out.println("所有的value值为:"+value);//输出所有的值
//不会重复,变成了Set集合
Set set = map.keySet();
System.out.println("所有的key值为:"+set);//输出所有的键
System.out.println(map.remove(null, null));//会有一个boolean类型的返回值
System.out.println(map);
//循环遍历map的方法一
Set set1 = map.keySet();
for (Object o : set1) {
System.out.println(o+"-->"+map.get(o));
}
//循环遍历map的方法二,尽量用这种
Set set2 = map.entrySet();//将map变成Set
for (Object o : set2) {
System.out.println(o);
}
}
}
案例
//使用HashMap添加几个员工对象,要求键:员工
//值:员工工资
//并遍历显示工资>18000的员工
//员工类:姓名、工资、编号
//要求:姓名和编号一样的员工为同一个员工!!
public class Staff {
private String name;
private double salary;
private String id;
public Staff() {
}
public Staff(String name, double salary, String id) {
this.name = name;
this.salary = salary;
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public double getSalary() {
return salary;
}
public void setSalary(double salary) {
this.salary = salary;
}
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
@Override
public boolean equals(Object o) {
if(this==o)
return true;
if(!(o instanceof Staff))
return false;
Staff staff=(Staff) o;
if(this.getName().equals(staff.getName())&&this.getId().equals(((Staff) o).getId()))
return true;
else
return false;
}
@Override
public int hashCode() {
return getName().hashCode()+getId().hashCode();
}
@Override
public String toString() {
return "Staff{" +
"name='" + name + '\'' +
", salary=" + salary +
", id='" + id + '\'' +
'}';
}
}
public class Test {
public static void main(String[] args) {
HashMap<Staff,Integer> map = new HashMap();
map.put(new Staff("张三1",19000,"10"),19000);
map.put(new Staff("张三2",30000,"10"),30000);
map.put(new Staff("张三3",17000,"10"),17000);
map.put(new Staff("张三4",20000,"10"),20000);
map.put(new Staff("张三5",12000,"10"),12000);
map.put(new Staff("张三1",19000,"10"),19000);
Set<Map.Entry<Staff, Integer>> entries = map.entrySet();
ArrayList<Map.Entry<Staff, Integer>> list = new ArrayList<>(entries);
list.sort(new Comparator<Map.Entry<Staff, Integer>>() {
@Override
public int compare(Map.Entry<Staff, Integer> o1, Map.Entry<Staff, Integer> o2) {
return o2.getValue()-o1.getValue();
}
});
for (Map.Entry<Staff, Integer> staffIntegerEntry : list) {
if (staffIntegerEntry.getValue()>18000) System.out.println(staffIntegerEntry.getKey());
}
}
}
排序
public class HashMapSort {
public static void main(String[] args) {
HashMap<String,Integer> map = new HashMap();
map.put("手机",2000);
map.put("电脑",1200);
map.put("笔",100000);
map.put("饮料",5000);
map.put("水果",880);
System.out.println(map);
System.out.println("------------------------");
//根据value排序,把map转换为list
Set<Map.Entry<String, Integer>> entries = map.entrySet();
ArrayList<Map.Entry<String, Integer>> list = new ArrayList<>(entries);
//重写排序的方法
list.sort(new Comparator<Map.Entry<String, Integer>>() {
@Override
public int compare(Map.Entry<String, Integer> o1, Map.Entry<String, Integer> o2) {
return o2.getValue()-o1.getValue();
}
});
for (Map.Entry<String, Integer> stringIntegerEntry : list) {
System.out.println(stringIntegerEntry.getKey()+"---->"+stringIntegerEntry.getValue());
}
}
}
Collections
排序:不能排自己定义的类
public class Test {
public static void main(String[] args) {
ArrayList list = new ArrayList();
list.add(10);
list.add(50);
list.add(30);
list.add(40);
list.add(40);
Collections.sort(list);
System.out.println(list);
//反转
Collections.reverse(list);
System.out.println("----------------------");
System.out.println(list);
System.out.println("-----------------");
Collections.swap(list,1,2);//交换
System.out.println(list);
//Collections.addAll(list,20,40,60);//添加多个元素
//System.out.println("------------------------------");
//System.out.println(list);
//二分查找
System.out.println(Collections.binarySearch(list, 10));
System.out.println("------------------------");
System.out.println(Collections.max(list));
System.out.println("------------------------");
System.out.println(Collections.min(list));
System.out.println("---------------------------");
System.out.println(Collections.frequency(list, 40));//40在list中出现的次数
Collections.fill(list,88);//填充
System.out.println(list);
}
}
泛型
为什么要有泛型?
-
解决元素存储的安全性问题
-
解决获取数据元素时,需要类型强转的问题
泛型,JDK1.5新加入的,解决数据类型的安全性问题,其主要原理是在类声明时通过一个标识表示类中某个属性的类型或者是某个方法的返回值及参数类型。这样在类声明或实例化时只要指定好需要的具体的类型即可
使用泛型的主要优点是能够在编译时而不是在运行时检测错误。
静态方法中不能使用类的泛型
异常类不能是泛型的
泛型不同的引用不能相互赋值
泛型的指定中不能使用基本数据类型,可以使用包装类替换。
如果B是A的一个子类型(子类或者子接口),而G是具有泛型声明的类或接口,G(B)并不是G(A)的子类型!
比如:String是Object的子类,但是List并不是List的子类。
使用类型通配符:?
List<?>是List、List等各种泛型List的父类
读取List<?>的对象list中的元素时,永远是安全的,因为不管list的真实类型是什么,它包含的都是Object。
写入list中的元素时,不行。因为我们不知道c的元素类型,我们不能向其中添加对象。
<? extends Number> (无穷小 , Number] 只允许泛型为Number及Number子类的引用调用 <? super Number> [Number , **无穷大**) 只允许泛型为Number及Number父类的引用调用 <? extends Comparable> 只允许泛型为实现Comparable接口的实现类的引用调用 .frequency(list, 40));//40在list中出现的次数 Collections.fill(list,88);//填充 System.out.println(list); } }