栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > Java

Java学习(第五周)

Java 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

Java学习(第五周)

本次我们来学习容器这一章,前面我们学过数组,如果要存放多个对象,可以使用数组,但是数组有局限性,比如声明长度是10的数组,不用的数组就浪费了,超过10的个数,又放不下 。

java容器类的好处就在于可以自动地调整自己的尺寸大小。在实际的编程中可以往容器中放置任何数量的对象,而不用担心容器应该设置成多大。

目录

容器

泛型

Collection

                 List 

                         Vector

                 Set

Map

ArrayList

     常用方法:

通配符

泛型转换


容器

容器可以管理对象的生命周期、对象与对象之间的依赖关系,可以使用一个配置文件,在上面定义好对象的名称、如何产生、哪个对象产生之后必须设定成为某个对象的属性等,在启动容器之后,所有的对象都可以直接取用,不用编写任何一行程序代码来产生对象,或是建立对象与对象之间的依赖关系。

容器的接口层次结构图

基于数组并不能满足我们对于“管理和组织数据的需求”,所以我们需要一种更强大、更灵活、容量随时可扩的容器来装载我们的对象。 这就是我们今天要学习的容器。

为了能够更好的学习容器,我们首先要先来学习一个概念:泛型

泛型

泛型的本质就是"数据类型的参数化"。我们可以把"泛型"理解为数据类型的一个占位符(形式参数),即告诉编译器,在调用泛型时必须传入实际类型。
泛型的用法是在容器后面添加
Type可以是类,抽象类,接口
泛型表示这种容器,只能存放Type和它的子类,其他的就放不进去了

泛型类的声明

class MyCollection {// E:表示泛型;
    Object[] objs = new Object[5];
    public E get(int index) {// E:表示泛型;
        return (E) objs[index];
    }
    public void set(E e, int index) {// E:表示泛型;
        objs[index] = e;
    }
}


泛型类的应用

public class TestGenerics {
    public static void main(String[] args) {
        // 这里的”String”就是实际传入的数据类型;
        MyCollection mc = new MyCollection();
        mc.set("aaa", 0);
        mc.set("bbb", 1);
        String str = mc.get(1); //加了泛型,直接返回String类型,不用强制转换;
        System.out.println(str);
    }
}


泛型类的在集合中的使用

public class Test {
    public static void main(String[] args) {
        // 以下代码中List、Set、Map、Iterator都是与容器相关的接口;
        List list = new ArrayList();
        Set mans = new HashSet();
        Map maps = new HashMap();
        Iterator iterator = mans.iterator();
    }
}

Collection

Collection 表示一组对象,它是集中、收集的意思。

Collection接口的两个子接口是List、Set接口。

Collection接口中定义的方法

List 

List是有序、可重复的容器。

      有序:List中每个元素都有索引标记。可以根据元素的索引标记(在List中的位置)访问元素,从而精确控制这些元素。

      可重复:List允许加入重复的元素。更确切地讲,List通常允许满足 e1.equals(e2) 的元素重复加入容器。

List接口中定义的方法


List接口常用的实现类有3个:ArrayList、LinkedList和Vector。

List的常用方法

public class TestList {
     public static void test() {
        List list = new ArrayList();
        System.out.println(list.isEmpty()); // true,容器里面没有元素
        list.add("111");
        System.out.println(list.isEmpty()); // false,容器里面有元素
        list.add("222");
        list.add("333");
        System.out.println(list);
        System.out.println("list的大小:" + list.size());
        System.out.println("是否包含指定元素:" + list.contains("333"));
        list.remove("111");    //使用remove()后把容器内的地址删掉了,并不是删对象
        System.out.println(list);
        Object[] objs = list.toArray();
        System.out.println("转化成Object数组:" + Arrays.toString(objs));
        list.clear();
        System.out.println("清空所有元素:" + list);
    }
    public static void main(String[] args) {
        test();
    }
}


两个List之间的元素处理

    public static void test() {
        List list = new ArrayList();
        list.add("111");
        list.add("222");
        list.add("333");
        List list2 = new ArrayList();
        list2.add("111");
        list2.add("444");
        list2.add("555");
        System.out.println(list.containsAll(list2)); //false list是否包含list2中所有元素
        System.out.println(list);
        list.addAll(list2); //将list2中所有元素都添加到list。
        System.out.println(list);
        list.removeAll(list2); //从list中删除同时在list和list2中存在的元素
        System.out.println(list);
        list.retainAll(list2); //取list和list2的交集
        System.out.println(list);
    }
}
public class TestList {
    public static void main(String[] args) {
        test();
    }


List中操作索引的常用方法

public class TestList {
    public static void main(String[] args) {
        test03();
    }
    public static void test() {
        List list = new ArrayList();
        list.add("A");
        list.add("B");
        list.add("C");
        list.add("D");
        System.out.println(list); // [A, B, C, D]
        list.add(2, "1");
        System.out.println(list); // [A, B, 1, C, D]
        list.remove(2);
        System.out.println(list); // [A, B, C, D]
        list.set(2, "2");
        System.out.println(list); // [A, B, 2, D]
        System.out.println(list.get(1)); // 返回:B
        list.add("B");
        System.out.println(list); // [A, B, c, D, B]
        System.out.println(list.indexOf("B")); // 1 从头到尾找到第一个"B"的位置
        System.out.println(list.lastIndexOf("B")); // 4 从尾到头找到第一个"B"的位置
    }
}

Vector向量

Vector底层是用数组实现的List,相关的方法都加了同步检查,因此“线程安全,效率低”。

比如,indexOf方法就增加了synchronized同步标记。

Set接口

Set接口继承自Collection,Set接口中没有新增方法,方法和Collection保持完全一致。我们在前面通过List学习的方法,在Set中仍然适用。

Set容器特点:无序、不可重复。

无序:指Set中的元素没有索引,我们只能遍历查找;

不可重复:指不允许加入重复的元素。更确切地讲,新元素如果和Set中某个元素通过equals()方法对比为true,则不能加入;甚至,Set中也只能放入一个null元素,不能多个。

 HashSet的使用

public class Test {
    public static void main(String[] args) {
        Set s = new HashSet();
        s.add("hello");
        s.add("world");
        System.out.println(s);
        s.add("hello"); //相同的元素不会被加入
        System.out.println(s);
        s.add(null);
        System.out.println(s);
        s.add(null);
        System.out.println(s);
    }
}


Map接口

Map就是用来存储“键(key)-值(value) 对”的。 Map类中存储的“键值对”通过键来标识,所以“键对象”不能重复。

Map接口中的常用方法

public class TestMap {
    public static void main(String[] args) {
        Map m1 = new HashMap();
        Map m2 = new HashMap();
        m1.put(1, "one");
        m1.put(2, "two");
        m1.put(3, "three");
        m2.put(1, "一");
        m2.put(2, "二");
        System.out.println(m1.size());
        System.out.println(m1.containsKey(1));
        System.out.println(m2.containsValue("two"));
        m1.put(3, "third"); //键重复了,则会替换旧的键值.
        Map m3 = new HashMap();
        m3.putAll(m1);
        m3.putAll(m2);
        System.out.println("m1:" + m1);
        System.out.println("m2:" + m2);
        System.out.println("m3:" + m3);
    }
}

//结果
3
true
flase
m1:{1=one,2=two,2=thrid}
m2:{1=一,2=二}
m3:{1=一,2=二,3=third}

HashMap采用哈希算法实现,是Map接口最常用的实现类。 由于底层采用了哈希表存储数据,我们要求键不能重复,如果发生重复,新的键值对会替换旧的键值对。 HashMap在查找、删除、修改方面都有非常高的效率。

HashTable类和HashMap用法几乎一样,底层实现几乎一样,只不过HashTable的方法添加了synchronized关键字确保线程同步检查,效率较低。

HashMap与HashTable的区别

      1. HashMap: 线程不安全,效率高。允许key或value为null。

      2. HashTable: 线程安全,效率低。不允许key或value为null。

ArrayList

为了解决数组的局限性,引入容器类的概念。 最常见的容器类就是ArrayList。容器的容量"capacity"会随着对象的增加,自动增长,只需要不断往容器里增加即可,不用担心会出现数组的边界问题。

常用方法:

增加:add 有两种用法
第一种是直接add对象,把对象加在最后面
对象.add(new 类(" "));

// 把5个对象加入到ArrayList中
        for (int i = 0; i < 5; i++) {
            对象.add(new 类(" "));
        }
        System.out.println(对象);

第二种是在指定位置加对象
对象.add(3,对象);

// 在指定位置增加对象
        类 对象 = new 类(" ");
        对象1.add(3, 对象2);
        System.out.println(对象1.toString());


判断是否存在:
通过方法contains 判断一个对象是否在容器中
判断标准: 是否是同一个对象,而不是名字是否相同

public static void main(String[] args) {
        ArrayList 对象X = new ArrayList();
        // 初始化5个对象
        for (int i = 0; i < 5; i++) {
            对象x.add(new 类名(" " + i));
        }
        类名 对象Y = new 类名(" ");
        对象X.add(对象Y);
        System.out.println(对象X);
        // 判断一个对象是否在容器中
        // 判断标准: 是否是同一个对象,而不是名字是否相同
        System.out.print("虽然一个新的对象名字也叫  1,但是contains的返回是:");
        System.out.println(对象X.contains(new 类(" 1")));
        System.out.print("而对对象Y的判断,contains的返回是:");
        System.out.println(对象X.contains(对象Y));
    }


获取指定位置的对象:
通过get获取指定位置的对象,如果输入的下标越界,一样会报错

System.out.println(对象.get(5));


获取对象所处的位置:
indexOf用于判断一个对象在ArrayList中所处的位置
与contains一样,判断标准是对象是否相同,而非对象的name值是否相等

  System.out.println(对象.get(5));

删除:
remove用于把对象从ArrayList中删除:
1)remove可以根据下标删除ArrayList的元素

对象.remover(2)


2)也可以根据对象删除

对象1.remove(对象2)


替换:
set用于替换指定位置的元素

对象.set(5, new 类名(" XX"));

获取大小:
size 用于获取ArrayList的大小

System.out.println(对象.size());


转换为数组:
toArray可以把一个ArrayList对象转换为数组。
需要注意的是,如果要转换为一个数组,那么需要传递一个对应数组类型的对象给toArray(),这样toArray方法才知道,你希望转换为哪种类型的数组,否则只能转换为Object数组

类名 t[] = (类名[])对象.toArray(new 类名[]{});

加入对象:

addAll把另一个容器所有对象都加进来

对象1.addAll(对象2);

清空:
clear 清空一个ArrayList

对象.clear();


因为ArrayList实现了List接口,所以List接口的方法ArrayList都实现了。

ArrayList底层是用数组实现的存储。

特点:查询效率高,增删效率低,线程不安全。但我们一般使用它  


 

通配符

? extends
ArrayList B 表示这是一个类A泛型或者其子类泛型
B 的泛型可能是类A及A的子类

所以 可以确凿的是,从B取出来的对象,一定是可以转型成A的


? super
ArrayList B 表示这是一个A泛型或者其父类泛型
B的泛型可能是A或A的父类

可以往里面插入A以及A的子类
但是取出来有风险,因为不确定取出来是A还是A的父类


总结
如果希望只取出,不插入,就使用? extends Hero
如果希望只插入,不取出,就使用? super Hero
如果希望,又能插入,又能取出,就不要用通配符。

泛型转换

根据面向对象学习的知识,子类转父类 是一定可以成功的,父类转子类要进行强转

而对于泛型来说子类泛型不可以转换为父类泛型,父类泛型也不能转型为子类泛型。

转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/919963.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号