Java基础--集合

集合

当需要将相同结构的个体整合到一起的时候,需要集合。

Collection接口

注意!!!集合存入的都是引用数据类型,不能存基本数据类型

常用方法:

add(e) addAll(collection c)
删 clear() remove(Object o )
查 size() ietrator()
判断:contains(Object o)  equals(Object o)  isEmpty()
//接口不能创建对象,用它的实现类创建对象
Collection c1 = new ArrayList();
//集合只能存放引用数据类型的数据,不能存基本数据类型
//基本数据类型自动装箱,转换成对应的包装类  int--->Integer
c1.add(18);  //添加元素
c1.add(12);
c1.add(17);
System.out.println(c1.toString());    //输出[18, 12, 17]

 //addAll(Collection c) 传入一个集合名字,将集合c添加到本集合中
        List list = Arrays.asList(new Integer[]{23,25,29,36});
        c1.addAll(list);
        System.out.println(c1.toString());  //输出[18, 12, 17, 23, 25, 29, 36]

//equals比较的是两个集合中的值是否对应相等,==比较的是两个集合的地址
//contains判断集合是否包含某元素
System.out.println("是否包含9:"+c1.contains(9));

遍历方式:

方法一:增强for

for (Object o:c1)   //(用什么接收:要遍历哪个)
      { System.out.println(o);
}

方法二:迭代器iterator

Iterator it = c1.iterator();  //把迭代器看作一个“指针”
while(it.hasNext()){     //通过hashNex()判断是否有下一个元素,返回true
    System.out.println(it.next());  //next()将元素获取到,“指针”下移
}

List接口:不唯一,有序

常用方法:扩展的方法都和索引相关

//list接口常用方法-是collection接口的子接口,继承了collection,还有一些通过索引来操作的
//增 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(1);
list.add(3);
list.add(130);
list.add("zxy");
System.out.println(list);
list.add(3,33);    //下标从0开始,在下标为3的位置添加33
list.set(3,77);   //把下标为3的数改成77
list.remove(4);     //把下标为4的删除
System.out.println(list); //若在集合中存的是Integer类型数据,调用哪个remove都可以
list.remove("zxy");    //若是其他类型,必须调用remove(Object o)才能删除
//通过索引获取元素
  Object o = list.get(5);  //集合里有多种类型,要用Object类型接收
  System.out.println(o);

遍历方法:

//方式一:普通for循环
System.out.println("===========================");
for (int i = 0; i <list.size() ; i++) {
    System.out.println(list.get(i));   //可以用下标获取元素
}
//方式二:增强for循环
System.out.println("===========================");
for (Object value : list) {
    System.out.println(value);
}
//方式三:迭代器
Iterator it = list.iterator();
while(it.hasNext()){
    System.out.println(it.next());
}
ArrayList实现类

ArrayList的源码与StringBuider极为相似,都有两个重要的属性:ArrayList是Object[]型数组,int size指代数组中的有效长度

而StringBuider中是char[] value--底层的存储数组, int count--数组中的有效长度

JDK1.8源码:底层是数组,在调用构造器时,底层数组为{},在调用了add()方法后,底层数组才重新赋值为新数组,长度为10-->节省了内存

数据结构:

  • 物理结构:紧密结构(顺序结构)
  • 逻辑结构:线性表(数组)
vector实现类(已淘汰)

JDK1.8源码:底层Object类型数组,int类型属性表示有效长度

vector与ArrayList的联系与区别:

联系:底层都是数组的扩容

区别:1)ArrayList底层扩容长度为原数组的1.5倍,线程不安全,效率高

​ 2)vector底层扩容长度为原数组的2倍,线程安全,效率低 (已淘汰 )

  • 什么是泛型:相当于标签--实际就是一个<>引起来的参数类型,在使用时才会确定具体类型

  • 没有泛型时:集合中任何的引用类型都能存,有多种类型的,不太方便。

  • 加入泛型:在编译时期会对类型进行检查,不是对应的类型就不会加入这个集合。此时集合中是同一类型

  • 使用了泛型,后序遍历操作简单;泛型一般都是用来修饰集合,所以泛型的类型都是引用数据类型,不能是基本数据类型

  • ArrayList<Integer> a = new ArrayList<>();
    

---泛型类

//test04就是一个普通类,而test04<E>就是个泛型类
//<>里面是一个参数类型,但这个类型现在不确定,相当于一个占位符,
// 唯一确定的是他一定是一个引用数据类型
    public class test04 <E>{
    int age;
    String name;
    E sex;
    public void a(E n){ }
    public void b(E[] m){ }}
public static void main(String[] args) {
   //实例化泛型类
    //实例化时不指定泛型,默认此泛型为Object类型
     test04 t = new test04();
     t.a("zxy");
     t.a(2);
     t.b(new String[]{"a","b"});
     //实例化时指定泛型!!!
    test04<String> t1 = new test04<>();  //确定了泛型为String类型,故上面的E对应String
    t1.sex = "男";
    t1.a("abc");

继承情况:

1)父类指定泛型,子类就不必指定

class subtest04 extends test04<Integer>{
}

2)父类不指定泛型,子类也会变成一个泛型类,E的类型可以在创建子类对象时确定

class subtest004<E> extends test04<E>{
}

细节:

1)泛型类可以定义多个参数

2)泛型类对应的构造器--不可以加泛型<>

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

public void c(){
    ArrayList<String> list1 = null;
    ArrayList<Integer> list1 = null;
    list1 = list2;    //错误代码,不可以相互赋值
}

4)泛型如果不指定,用的时候就会默认为Object类型

5)泛型类中的静态方法不能使用类的泛型

public static void b(E[] m){ }  //报错,静态方法在最开始就会被加载,而泛型在实例化后才能确定

6)不能直接使用E[]创建:e[] i = new e[10]; //不可以

---泛型接口:类似于泛型类

---泛型方法:这个方法的泛型参数类型 与 当前所在类 是否是泛型类,泛型是啥 无关!

​ 定义时要加上,不加的话会把T看作一种数据类型,会报错

​ T 的类型是在调用的时候才确定的(根据传入的参数类型),所以泛型方法可以是静态方法

public class test05 <E> {
    public void a(E e){ }      //不是泛型方法
    public <T> void b(T t){ }  //是泛型方法
    public static <T> void b(T t){ }  //是泛型方法
}

---泛型参数存在继承关系

Object obj = new Object();
String s = new String();
obj = s;   //多态的一种形式---父类的引用指向子类

Object[] objArr = new Object[];
String[] strArr = new String[];
objArr = strArr;  //多态的一种形式

List<Object> list1 = new ArrayList<>();
List<String> list2 = new ArrayList<>();
list1 = list2;   //报错--ArrayList底层都是Object数组,利用泛型给他加限制,只是在编译时限制,
                 // 所以list1和list2是并列关系

总结:A和B是子类父类关系,但G和G不存在继承关系,是并列的

---通配符 <?>

        //数据的写入操作
        //list.add("abc"); 不能随意添加数据,只能填null
        list.add(null);
        //数据的读取操作--用Object类型接收
        Object s = list.get(0);

泛型受限:List<? extends Person>

       //使用泛型受限--上限,也就是说Person是天花板
        List<? extends Person> list1 = null;
// 报错       list1 = a;
        list1 = b;   //只能是Person类或者他的子类
        list1 = c;

        //使用泛型受限--下限,也就是说Person是地板
        List<? super Person> list2 = null;
        list2 = a;
        list2 = b;   //只能是Person类或者他的父类
// 报错       list1 = c;
LinkList实现类

常用方法:

LinkList常用方法:
增 addFirst(E e) addLast(E e)
offer(E e) offerFirst(E e) offerLast(E e)
删  poll() pollFirst() pollLast() //poll是JDK1.6之后的,代码健壮性好
removeFirst()  removeLast()
查 element() getFirst() getLast()
 indexOf(Object o) lastIndexOf(Object o)
 peek() peekFirst() peekLast()
 //创建一个对象
        LinkedList<String> list = new LinkedList<>();
        list.add("zzzzzz");
        list.add("xxxxxxx");
        list.add("yyyyyyy");
        list.add("zzzzzz");  //可以添加重复数据

        list.addFirst("hh"); //向头、尾添加
        list.addLast("gg");
        list.offer("aa");   //添加到尾部
        list.offerFirst("bb"); //头部
        list.offerLast("cc");  //尾部

        list.poll();  //删除头部元素 pollFirst()
        list.pollLast(); //删除尾部元素
        list.clear();  //清空
        System.out.println(list);

        System.out.println(list.pollFirst());   //集合为空,返回null
        System.out.println(list.removeFirst());  //若集合为空,报错了

遍历方法

实现List接口,和他一样有三种遍历方式。。。

迭代器遍历有另一种写法:更节省内存

Iterator it = list.iterator();
while(it.hasNext()){
System.out.println(it.next());}
for(Iterator<String> it = list.iterator(); it.hasNext();){
    System.out.println(it.next());
}

底层原理:

数据结构:

  • 物理结构:跳转结构(链式结构)
  • 逻辑结构:线性表(链表)
  • LinkedList底层是是双向链表 --一个节点包含三部分:前一个元素地址+当前存入的元素+后一个元素地址

Set接口:唯一,无序(无序不是随机)

遍历:迭代器,增强for循环

Set接口:唯一,无序(无序不是随机)

方法:add(),clear(),remove()...

HashSet<Integer> hs = new HashSet<>();
System.out.println(hs.add(10));  //true
hs.add(0);
hs.add(15);
System.out.println(hs.add(10));  //false,这个10没有返回到集合中
hs.add(12);
System.out.println(hs.size()); //唯一,不存在重复元素
System.out.println(hs);
HashSet<test10.Student> ts = new HashSet<>();   //自定义数据类型--不满足唯一
ts.add(new test10.Student("lili",20,"男"));
ts.add(new test10.Student("ll",15,"女"));
ts.add(new test10.Student("lili",20,"男"));
ts.add(new test10.Student("li",200,"女"));
System.out.println(ts.size());  //4
//在自定义的类型中,重写hashCode方法和equals方法就可以达到唯一

底层原理

哈希表=数组+链表

注意:如果放入HashSet中的数据,一定要重写两个方法:hashCode,equals

LinkedHashSet实现类

特点:唯一,有序--按照输入顺序进行输出

底层:在HashSet的基础上多了一个总链表,把元素按照顺序链接起来,方便有序遍历

插入知识点:比较器

  1. 比较Int类型数据:将比较的数据作差,然后返回一个int类型的数据,将这个int类型的数值 按照 =0 >0 <0

  2. 比较String类型数据:String类实现了Comparable接口,这个接口中有一个抽象方法compareTo,String类中重写这个方法即可。

    public static void main(String[] args) {
        String a = "A";
        String b = "B";
        System.out.println(a.compareTo(b));   //-1
        //String实现了Comparable接口,Comparable里有抽象方法compareTo,在String中重写了这个方法
    }
    
  3. 比较double类型数据:将数据包装成Double类,调用compareTo方法

    double c = 9.987;
    double d = 8.876;
    System.out.println(((Double)c).compareTo((Double)d));
    
  4. 比较自定义的数据类型:

    1)内部比较器(实现Comparable接口)--每次只能比较一个(在类里面写)

      @Override
        //实现Comparable接口必须重写compareTo方法
        public int compareTo(Student o) {
            //比较年龄
    //        return this.getAge() - o.getAge();
            //比较身高
    //        return ((Double)(this.getHeight())).compareTo((Double)(o.getHeight()));
            //比较名字
            return this.getName().compareTo(o.getName());
        }
    
    public static void main(String[] args) {
        Student s1  = new Student(16,165.2,"nana");
        Student s2 = new Student(18,160.6,"lala");
        System.out.println(s1.compareTo(s2));
    }
    

    2)外部比较器--更好,多态,扩展性好

    在类之外写外部比较器(实现 Comparator接口 )--可以同时比较多个

    public class Student1 {
     ... 
    }
    class biJiao1 implements Comparator<Student> {
        @Override
        //重写了Comparator接口中的compare方法
        public int compare(Student o1, Student o2) {
            //比较年龄
            return o1.getAge() - o2.getAge();
        }
    }
    class biJiao2 implements Comparator<Student> {
        @Override
        public int compare(Student o1, Student o2) {
            //比较身高
            return ((Double) (o1.getHeight())).compareTo((Double) (o2.getHeight()));
        }
    }
    
        //获取外部比较器--多态
            Comparator bj1 = new biJiao1();
            System.out.println(bj1.compare(s1,s2));
    
            Comparator bj2 = new biJiao2();
            System.out.println(bj2.compare(s1,s2));
    
TreeSet实现类
  1. 存入Integer类型数据:底层是内部比较器,唯一,有序(按升序进行遍历),无序(不是按照输入顺序)

  2. 存入String类型数据--底层实现类内部比较器

  3. 放入自定义的Student类型数据--可以利用内部比较器--也可以利用外部比较器

  4. 原理:底层-二叉树(逻辑结构)-物理结构:跳转结构(链式结构)

    在数中放入数据时,最重要的是比较的实现-->内部比较器或者外部比较器

    底层的二叉树遍历是中序遍历得到的,即按照升序结果出现

Map接口

HashMap实现类

底层原理:数组+链表+红黑树(java8新增红黑树)

TreeMap实现类

posted @   二白--  阅读(35)  评论(0编辑  收藏  举报
努力加载评论中...
点击右上角即可分享
微信分享提示