Java集合详

Java集合详,第1张

引入:

【1】数组,集合都是对多个数据进行存储 *** 作的,简称为容器。
PS:这里的存储指的是内存层面的存储,而不是持久化存储(.txt,.avi,.jpg,数据库)。

特点:
(1)数组一旦指定了长度,那么长度就被确定了,不可以更改。
int[] arr = new int[6];
(2)数组一旦声明了类型以后,数组中只能存放这个类型的数据。数组中只能存放同一种类型的数据。
int[] arr,String[] s,double[] d.....

缺点:
(1)数组一旦指定了长度,那么长度就被确定了,不可以更改。
(2)删除,增加元素  效率低。
(3)数组中实际元素的数量是没有办法获取的,没有提供对应的方法或者属性来获取
(4)数组存储:有序,可重复 ,对于无序的,不可重复的数组不能满足要求。

【2】正因为上面的缺点,引入了一个新的存储数据的结构---》集合
 

简要集合结构图:

一、Collection接口 1、常用方法:

 增加:add(E e) addAll(Collection c)
 删除:clear() remove(Object o)
 修改:
 查看:iterator() size()
 判断:contains(Object o)  equals(Object o) isEmpty()

public static void main(String[] args) {
    Collection col = new ArrayList();
    //添加
    //1、add(E e)
    col.add(18);
    System.out.println(col/*.toString()*/);
    //2、addAll(Collection c)
    List list = Arrays.asList(new Integer[]{11, 15, 3, 7, 1});
    col.addAll(list);

    //删除、
    //1、clear() 
    //col.clear();清空集合
    System.out.println(col);
    System.out.println("集合中元素的数量为:"+col.size());
    System.out.println("集合是否为空:"+col.isEmpty());
    //2、remove(Object o)
    boolean isRemove = col.remove(15);
    System.out.println(col);
    System.out.println("集合中数据是否被删除:"+isRemove);

    //判断
    Collection col2 = new ArrayList();
    col2.add(18);
    col2.add(12);
    col2.add(11);
    col2.add(17);
    Collection col3 = new ArrayList();
    col3.add(18);
    col3.add(12);
    col3.add(11);
    col3.add(17);
    System.out.println(col2.equals(col3));
    System.out.println(col2==col3);//地址一定不相等  false
    System.out.println("是否包含元素:"+col3.contains(117));

}
2、注意:

 接口不能创建对象,利用实现类创建对象

Collection col = new ArrayList();

只能存放引用数据类型的数据,不能是基本数据类型

基本数据类型自动装箱,对应包装类。int--->Integer

Collection集合遍历方式:

方式一:

public static void main(String[] args) {
        Collection col = new ArrayList();
        col.add(18);
        col.add(12);
        col.add(11);
        col.add(17);
        col.add("abc");
        col.add(9.8);
        //方式1:增强for循环
        for(Object o:col){
            System.out.println(o);
        }
    }

 方式二:

public static void main(String[] args) {
        Collection col = new ArrayList();
        col.add(18);
        col.add(12);
        col.add(11);
        col.add(17);
        col.add("abc");
        col.add(9.8);   
        //方式2:iterator()迭代器
        Iterator it = col.iterator();
        while(it.hasNext()){
            System.out.println(it.next());
        }
    }

注意:不能用普通for循环遍历,因为没有可以调用的方法
/*for(int i= 0;i
(一)List系列集合 1、常用方法

增加:add(int index, E element)
删除:remove(int index)  remove(Object o)
修改:set(int index, E element)
查看:get(int index)

 添加:

List list = new ArrayList();
list.add(13);
list.add(17);
list.add(6);
list.add(-1);
list.add(2);
list.add("abc");
System.out.println(list);
//在某个索引处添加
list.add(3,66);
System.out.println(list);
list.set(3,77);
System.out.println(list);

删除:

list.remove(2);
//在集合中存入的是Integer类型数据的时候,调用remove方法调用的是:remove(int index)
//根据索引来删除
System.out.println(list);
list.remove("abc");
System.out.println(list);

 修改:

list.set(4,55);
System.out.println(list);
list.set(4,99);
System.out.println(list);

 查看:

 Object o = list.get(0);
 System.out.println(o);
2、List遍历集合方式

方式一:

//方式1:普通for循环:
        System.out.println("---------------------");
        for(int i = 0;i

方式二:

//方式2:增强for循环:
        System.out.println("---------------------");
        for(Object obj:list){
            System.out.println(obj);
        }

方式三:

//方式3:迭代器:
        System.out.println("---------------------");
        Iterator it = list.iterator();
        while(it.hasNext()){
            System.out.println(it.next());
        }
 ArrayList:

包含一定泛型类容,以及对集合的一些补充

CSDNhttps://mp.csdn.net/mp_blog/creation/editor/124676600

泛型:

方便以后API的阅读

1、概述:

泛型就相当于标签
形式:<>  
集合容器类在设计阶段/声明阶段不能确定这个容器到底实际存的是什么类型的对象,所以在JDK1.5之前只能把元素类型设计为Object,
JDK1.5之 后使用泛型来解决。因为这个时候除了元素的类型不确定,其他的部分是确定的,例如关于这个元素如何保存,如何管理等是确定的,因此此时把元素的类型设计成一个参数,这个类型参数叫做泛型。

2、自定义泛型

泛型类的定义和实例化:

//GenericTes就是一个普通的类
//GenericTest 就是一个泛型类
//<>里面就是一个参数类型,这个类型现在是不确定的,相当于一个占位
public class GenericTest {
    int age;
    String name;
    E sex;
    public void a(E n){
    }
    public void b(E[] m){
    }
}
class Test{
    //这是main方法,程序的入口
    public static void main(String[] args) {
        //GenericTest进行实例化:
        //(1)实例化的时候不指定泛型:如果实例化的时候不明确的指定类的泛型,那么认为此泛型为Object类型
        GenericTest gt1 = new GenericTest();
        gt1.a("abc");
        gt1.a(17);
        gt1.a(9.8);
        gt1.b(new String[]{"a","b","c"});
        //(2)实例化的时候指定泛型:---》推荐方式
        GenericTest gt2 = new GenericTest<>();
        gt2.sex = "男";
        gt2.a("abc");
        gt2.b(new String[]{"a","b","c"});
        
    }
}

继承情况:

 (1)父类指定泛型

class SubGenericTest extends GenericTest{
}
class Demo{
    //这是main方法,程序的入口
    public static void main(String[] args) {
        //指定父类泛型,那么子类就不需要再指定泛型了,可以直接使用
        SubGenericTest sgt = new SubGenericTest();
        sgt.a(19);
    }
}

(2)父类不指定泛型

 如果父类不指定泛型,那么子类也会变成一个泛型类,那这个E的类型可以在创建子类对象的时候确定

class SubGenericTest2 extends GenericTest{
}
class Demo2{
    //这是main方法,程序的入口
    public static void main(String[] args) {
        SubGenericTest2 s = new  SubGenericTest2<>();
        s.a("abc");
        s.sex = "女";
    }
}

细节:

(1)泛型类可以使用多个参数类型:

public class TestGeneric{
    A age;
    B name;
    C sex;
    public void a(A m,B n,C x){

    }
}

(2) 泛型类的构造器的写法:

public TestGeneric(){
}

 (3)不同泛型的引用类型不可以相互赋值

public void(){
    ArrayList list1 = null;
    ArrayList list2 = null;
    //list1 = list2;报错
}

 (4)当泛型参数存在继承情况时

Object obj = new Object();
String s = new String();
obj = s;//多态的一种形式

Object[] objArray = new Object[10];
String[] strArray = new Stirng[10];
objArray = strArray;//多态的一种形式

List list1 = new ArrayList<>();
List list2 = new ArrayList<>();
lis1 = list2;//报错
 

 总结:当A和B是子类父类的关系的时候,G和G不存在继承的关系,它们是并列的关系

(5)泛型如果不指定,对应类型就会变为Object类型,即可以添加任何引用类型的数据 

(6)泛型类中的静态方法不能调用类的泛型:

public class TestGeneric{
    A age;
    B name;
    C sex;
    public static int c(A a){
    //报错
        return 10;
    }
}

原因:static方法在对象之前创建,而泛型类型还未确定

 (7)不可以直接使用E[]的创建

public void a(A a,B b,C c){
    //不可以:A[] i = new A[10];
    A[] i = (A[])new Object[]10;
}

 泛型方法:

泛型方法对应的那个泛型参数类型,和当前所在的这个类,是否是泛型类,泛型是什么无关

public class TestGeneric {
    //不是泛型方法 (不能是静态方法)
    public static void a(E e){
    }
    //是泛型方法
    public static   void b(T t){
    }
}
class Demo{
    //这是main方法,程序的入口
    public static void main(String[] args) {
        TestGeneric tg = new TestGeneric<>();
        tg.a("abc");
        tg.b("abc");
        tg.b(19);
        tg.b(true);
    }

注:

①泛型方法定义的时候,前面要加上,如果不加的话,会把T当做一种数据类型,然而代码中没有T类型那么就会报错 

②泛型方法可以是静态方法

③      泛型方法的泛型在调用方法时传入

通配符:

 (1)概述:A 和 B是子类父类的关系,G和G不存在子类父类关系,是并列的
加入通配符后,G就变成了 G和G的父类

List list1 = new ArrayList<>();
        List list2 = new ArrayList<>();
        List list3 = new ArrayList<>();
        List list = null;
        list = list1;//不报错
        list = list2;
        list = list3; 

(2)通配符使用细节:

public void a(List list){
        //1.遍历:
        for(Object a:list){
            System.out.println(a);
        }
        //2.数据的写入 *** 作 :
        //list.add("abc");-->出错,不能随意的添加数据,因为泛型类型不确定
        list.add(null);
        //3.数据的读取 *** 作:
        Object s = list.get(0);
    }

泛型受限:

定义一个Student类和Person类,Student类继承Person类

定义三个并列关系的集合

List a = new ArrayList<>();
List b = new ArrayList<>();
List c = new ArrayList<>(); 

(1)使用泛型受限:泛型的上限

List list1 = null;
        //list1 = a;报错
        list1 = b;
        list1 = c;

解释:List就相当于List是List的父类,是List的父类

(2)使用泛型受限:泛型的下限

List list2 = null;
        list2 = a;
        list2 = b;
        //list3 = c;报错

解释:  List就相当于List是List的父类,是List的父类

LinkedList: 1、常用方法

增加 addFirst(E e) addLast(E e)
             offer(E e) offerFirst(E e) offerLast(E e)
删除 poll()
         pollFirst() pollLast()  ---》JDK1.6以后新出的方法,提高了代码的健壮性
         removeFirst() removeLast()
查看 element()

        getFirst()  getLast()
        indexOf(Object o)   lastIndexOf(Object o)
        peek()
        peekFirst() peekLast()

 LinkedList list = new LinkedList<>();
 list.add("aaaaa");
 list.add("bbbbb");
 list.add("ccccc");
 list.add("ddddd");
 list.add("eeeee");
 list.add("bbbbb");
 list.add("fffff");
 list.addFirst("jj");//添加元素在头
 list.addLast("hh");//添加元素在尾端
 list.offer("kk");//添加元素在尾端
 list.offerFirst("pp");//添加元素在头
 list.offerLast("rr");//添加元素在尾端
 System.out.println(list);//LinkedList可以添加重复数据
 System.out.println(list.poll());//删除头上的元素并且将元素输出
 System.out.println(list.pollFirst());
 System.out.println(list.pollLast());
 System.out.println(list.removeFirst());
 System.out.println(list.removeLast());
 System.out.println(list);//LinkedList可以添加重复数据
 /*list.clear();//清空集合
 System.out.println(list);*/
 /*System.out.println(list.pollFirst());*/
 /*System.out.println(list.removeFirst());报错:Exception in thread "main" java.util.NoSuchElementException*/
 2、LinkedList遍历集合方式

(1)普通for循环

for(int i = 0;i

(2)增强for循环

for(String s:list){
    System.out.println(s);
}

(3)迭代器

/*Iterator it = list.iterator();
    while(it.hasNext()){
        System.out.println(it.next());
    }*/
//下面这种方式好,节省内存
for(Iterator it = list.iterator();it.hasNext();){
    System.out.println(it.next());
}
 3、LinkedList简要底层原理图

(二)Set系列集合

Set集合的功能基本上与Collection的一致

特点:

①无序:存取顺序不一致

②不重复:可以去除重复

③无索引:没有带索引的方法,所以不能使用for循环遍历,也不能通过索引来获取元素

HashSet: 特点:

无序、不重复、无索引

Set sets = new HashSet<>();
sets.add("Java");
sets.add("Java");
sets.add("MySQL");
sets.add("MySQL");
sets.add("HTML");
sets.add("HTML");
sets.add("SpringBoot");
sets.add("SpringBoot");
System.out.println(sets);
[MySQL, Java, HTML, SpringBoot]
//无序
 底层原理:

①JDLK8之前的,底层使用数组+链表组

●创建一个默认长度16的数组,数组名table

●根据元素的哈希值跟数组长度求余计算出应存入的位置(哈希算法)

●判断当前位置是否为null,如果是null直接存入

●如果位置不为空,则调用equals方法比较

●如果一样,则不存,如果不一样,则存入数组

新元素占老元素位置,指向老元素

②JDK8开始后,底层采用数组+链表+红黑树组成

新元素挂在老元素下面

 当挂在元素下面的数据过多时,查询性能降低,于是,当链表长度超过8的时候,自动转换成红黑树

哈希值:是JDK根据对象的地址,按照某种规则算出来的int类型的数值

Object类的API:public int hashCode():返回对象的哈希值

对象哈希值的特点:

①同一个对象多次调用hashCode()方法返回的哈希值是相同的

②默认情况下,不同对象的哈希值是不同的

String name = "aaaa";
System.out.println(name.hashCode());
System.out.println(name.hashCode());

String name1 = "bbbb";
System.out.println(name1.hashCode());
System.out.println(name1.hashCode());
2986048
2986048
3016832
3016832
 注意:

如果往HashSet中放入数据,需要重写hashCode和equals

 学生类:

public class Student {
    private String name;
    private int age;
    private char sex;

    public Student() {
    }

    public Student(String name, int age, char sex) {
        this.name = name;
        this.age = age;
        this.sex = sex;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }

    public char getSex() {
        return sex;
    }

    public void setSex(char sex) {
        this.sex = sex;
    }

    @Override
    public String toString() {
        return "Student{" +
                "name='" + name + '\'' +
                ", age=" + age +
                ", sex=" + sex +
                '}';
    }
}

不重写的话:

public static void main(String[] args) {
        Set sets = new HashSet<>();
        Student s1 = new Student("无恙",20,'男');
        Student s2 = new Student("无恙",20,'男');
        Student s3 = new Student("周维",21,'男');
        sets.add(s1);
        sets.add(s2);
        sets.add(s3);
        System.out.println(sets);
    }
[Student{name='周维', age=21, sex=男}, Student{name='无恙', age=20, sex=男}, Student{name='无恙', age=20, sex=男}]
//添加了两个信息一样的学生

重写:在学生类里右键,生成

 一路next,即可生成

@Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;
        Student student = (Student) o;
        return age == student.age && sex == student.sex && Objects.equals(name, student.name);
    }

    @Override
    public int hashCode() {
        return Objects.hash(name, age, sex);
    }

重写后:

[Student{name='无恙', age=20, sex=男}, Student{name='周维', age=21, sex=男}]

 结论:

哈希表是一种对于增删改查数据性能都较好的结构

LinkedHashSet:

特点:有序、不重复、无索引

Set sets = new LinkedHashSet<>();
sets.add("Java");
sets.add("Java");
sets.add("MySQL");
sets.add("MySQL");
sets.add("HTML");
sets.add("HTML");
sets.add("SpringBoot");
sets.add("SpringBoot");
System.out.println(sets);
[Java, MySQL, HTML, SpringBoot]
//有序

原理:底层数据结构依然哈希表,只是每个元素又额外的多了一个双链表的机制记录存储的顺序 

TreeSet: 特点:

①可排序、不重复、无索引(按元素大小默认升序)

②TreeSet集合是基于红黑树的数据结构排序的,增删改查性能都较好

③TreeSet集合是一定要排序的,可将元素按照指定的规则进行排序

默认排序规则:

●对于数值型,Integer,Double,官方默认按照大小进行升序排序

●对于字符串类型,默认按照首字符的编号升序排序

●对于自定义的Student对象,TreeSet无法直接排序(需制定排序规则)

数值型:

public static void main(String[] args) {
        Set sets = new TreeSet<>();
        sets.add(23);
        sets.add(12);
        sets.add(13);
        sets.add(32);
        sets.add(21);
        sets.add(14);
        System.out.println(sets);
    }
[12, 13, 14, 21, 23, 32]

字符型:

Set sets1 = new TreeSet<>();
        sets1.add("Java");
        sets1.add("Java");
        sets1.add("About");
        sets1.add("Python");
        sets1.add("UI");
        sets1.add("UI");
        System.out.println(sets1);
[About, Java, Python, UI]

自定义:

定义一个苹果类:

public class Apple {
    private String name;
    private String color;
    private double price;
    private int weight;

    public Apple() {
    }

    public Apple(String name, String color, double price, int weight) {
        this.name = name;
        this.color = color;
        this.price = price;
        this.weight = weight;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public String getColor() {
        return color;
    }

    public void setColor(String color) {
        this.color = color;
    }

    public double getPrice() {
        return price;
    }

    public void setPrice(double price) {
        this.price = price;
    }

    public int getWeight() {
        return weight;
    }

    public void setWeight(int weight) {
        this.weight = weight;
    }

    @Override
    public String toString() {
        return "Apple{" +
                "name='" + name + '\'' +
                ", color='" + color + '\'' +
                ", price=" + price +
                ", weight=" + weight +
                '}';
    }
}
 Set apples = new TreeSet<>();
        apples.add(new Apple("红富士","红色",9.9,500));
        apples.add(new Apple("青苹果","绿色",15.9,300));
        apples.add(new Apple("绿苹果","青色",29.9,400));
        apples.add(new Apple("黄苹果","黄色",9.8,500));
        System.out.println(apples);

因为无法对Apple排序,所以 

 所以,自定义排序规则

方法一:让自定义的类实现Comparable接口重写的comparaTo方法来制定比较规则

方式二:TreeSet集合有参数构造器,可以设置Comparator接口对应的比较对象,来制定比较规则

后续继续补充

欢迎分享,转载请注明来源:内存溢出

原文地址: https://outofmemory.cn/web/1294802.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2022-06-10
下一篇 2022-06-10

发表评论

登录后才能评论

评论列表(0条)