java中的集合



为什么出现集合类:
面向对象语言对事物的体现都是以对象的形式所以为了方便对对象的操作,就对对象进行存储,集合就是存储对象常用的一种方式
数组和集合类同是容器,有何区别:
数组虽然也可以存储对象,但长度是固定的,集合长度是可变的。数组中可以存储基本数据类型,集合只能存储对象,且存储的都是对象的引用地址
集合的特点:
集合只用于存储对象,集合长度是可变的,集合可以存储不同类型的对象
为什么会出现这么多的容器呢?
因为每个容器对数据的存储方式都有不同,这个存储方式称之为:数据结构
对Collection集合操作的一些常见操作:
add();添加元素
remove()删除元素
clear()清空集合
contains()判断是否存在某元素
isEmpty()判断集合是否为空
size()返回集合长度
retainAll()取两个集合的交集
removeAll(Collection<?>)移除此集合与另一个集合的交集部分
iterator()迭代器,用于取出集合中的元素
toArray()返回此集合中所包含元素的数组
equals()对比是否相同
hashCode()返回该对象的哈希码值
迭代器Iterator是集合内部的类,为什么要定义在内部呢?
因为取出方式定义在内部,这样取出方式就可以直接访问集合中的元素,便于取出,要想获得集合中的对象可以用iterator()方法获得。
List集合的特有方法:
List集合是Collection类的子集,他们都是接口类
List特有方法:凡是可以操作角标的方法都是该体系特有的方法,它是有序的,可以存入重复数据
增:add(index,element)    add(index,collection);
删:remove(index);
改:set(index,element)
查:get(index)   subList(from,to)   listIterator();indexOf(element)
List集合特有的迭代器,ListIterator是Iterator的子接口在迭代时,不可以通过集合对象的方法操作集合元素因为会发生ConcurrentModificationException(并发修改异常)
所以,在迭代的时候只能用迭代的方法操作元素,可是Iterator方法是有限的,只能对元素进行判断取出和删除因为他只有三个方法(hasNext()、next()、remove()),如果想要其他操作入添加、修改等就要用子接口ListIterator并且这个接口只能通过List集合获取
List中常见的子类:
ArrayList:底层使用的数据结构为数组结构,特点是查询速度快但是增删速度稍慢点(是不同步的,线程不安全)
对ArrayList使用的例子:
class ArrayListTest{
    public void run(){
        ArrayList al=new ArrayList();
        al.add(new Person("zjdPerson",12));
        al.add(new Person("zjdPerson",12));
        al.add(new Person("zjdPerson",12));
        al.add(new Person("zjdPerson",12));
        al.add(new Student("zjdStudent",13));
        al.add(new Student("zjdStudent",13));
        al.add(new Student("zjdStudent",13));
        al.add(new Student("zjdStudent",13));
        for(Iterator it=al.iterator();it.hasNext();){
            Object obj=it.next();
                System.out.println(obj);
        }
        al.remove(new Person("zjdPerson",12));//移除一个
        al.remove(new Student("zjdStudent",13));//和上面做对比看是否移除了
        sop(al.contains(new Person("zjdPerson",12)));//输出是否存在此数据

        sop(al.contains(new Student("zjdStudent",13));//和上面做对比看是否返回true

            for(Iterator it=al.iterator();it.hasNext();){
            Object obj=it.next();
                System.out.println(obj);
        }
    }
    public void sop(Object obj){
        System.out.println(obj);
    }
}
//定义一个Person类用于存储数据
class Person{
    String name;
    int age;
    Person(String name,int age){
        this.name=name;
        this.age=age;
    }
    public boolean equals(Object obj)//覆盖equals方法
    {
        if(!(obj instanceof Person))
            return false;
        Person p=(Person)obj;
        return p.name.equals(this.name)&&this.age==p.age;
    }
}
//定义一个Student类用于和Person作比较
class Student{
    String name;
    int age;
    Student(String name,int age){
        this.name=name;
        this.age=age;
    }
}

通过上面的例子所得到的结果可以看出对于List集合中用到的remove和contains方法的判断机制都是用到对象中的equals方法来实现的;

LinkedList:底层使用的是俩表数据结构特点:增删速度很快,查询稍慢点(不同步)
LinkedList特有的方法:
addFirst()//从集合开始位置添加元素
addLast()//从集合结尾添加元素
getFirst()//从得到集合开始位置的元素但不删除
getLast()//得到集合结尾处的元素但不删除,如果列表为空时会抛出异常
removeFirst()//得到集合开始位置的元素,并且删除
removeLast()//得到集合结尾处的元素,并且删除,如果列表为空时会抛出异常(NoSuchElementException)
在JDK1.6之后出现了替代的方法:
offerFirst()//和addFirst一致
offerLast()//和addLast一致
peekFirst()//和getFirst一致只是当列表为空时返回null
peekLast()//和getLast一致只是当列表为空时返回null
pollFirst()//和removeFirst一致只是当列表为空时返回null
pollLast()//和removeLast一致只是当列表为空时返回null
Vector:底层也是数组结构,是同步的,他被ArrayList所替代
Vector有一个特有的取出方式就用到了枚举例如:

    Vector v=new Vector();//创建一个Vector集合
    v.add(122);//添加数据
      v.add(23);
    v.add("1z");
    for(Enumeration en=v.elements();en.hasMoreElements();){//通过for循环输出,这里用的是Vector特有的取数方式
        sop(en.nextElement());
    }
当过上面可以看出枚举和迭代器很像,其实枚举和迭代器是一样的,因为枚举的名称以及方法的名称都过于太长所以被迭代器取代了
Set类:它是无序的元素不可以重复的,存入和取出的顺序不一定一致,它的功能和Collection是一致的
他下面有两个常用的子类
HashSet:底层数据结构是哈希表。线程是非同步的
HashSet保持元素的唯一性原理:
是通过元素的hashCode和equals方法来完成的
如果元素的HashCode值相同,才会判断equals是否为true
如果元素的hashCode值不同,不会调用equals
注意:对元素判断是否存在,以及删除等操作,依赖的是方法元素的hashCode和equals方法

class SetTest{
    public void run(){
        Set hs=new HashSet();
        hs.add(new Person("zjd",23));//添加数据
        hs.add(new Person("zxm",22));
        hs.add(new Person("zjd",23));
        hs.add(new Person("zxm",22));
        hs.add(new Person("zjd",23));
        hs.add(new Person("zxm",22));
        for(Iterator it=hs.iterator();it.hasNext();){//遍历添加上的数据
            Object obj=it.next();
            Person p=null;
            if(obj instanceof Person){//判断为Person的时候输出信息
                 p=(Person)obj;
            sop(p.name+":"+p.age);}
        }
    }
    public void sop(Object obj){
        System.out.println(obj);
    }
}
class Person{
    String name;
    int age;
    Person(String name,int age){
        this.name=name;
        this.age=age;
    }
    public int hashCode(){//覆盖hashCode方法,它的返回值类型是int类型,切记
        return this.name.hashCode()+this.age*37;//让其判断年龄和姓名的hashCode值是否相等,而不是判断整个对象引用的hashCode值
    }
    public boolean equals(Object obj)//这个地方一定要注意参数一定是Object类型,否则不能重载Object中的equals方法
    {
        if(!(obj instanceof Person))//判断obj是否是Person类如果不是则返回
            return false;
        Person p=(Person)obj;
        return p.name.equals(this.name)&&this.age==p.age;
    }
}
上面的程序结果为
zjd:23
zxm:22
可以看出确实是由hashCode和equals方法来控制的从而也验证了判断元素唯一性原理就是:先判断元素hashCode值是否相同,如果相同还会判断元素equals是否为true
TreeSet:可以对Set集合中的元素进行排序,他底层结构是二叉树,他保证元素的唯一性依据是通过comparetTo方法实现的
它的排序有两种方式:
第一种:让元素自身具备比较性,元素需要实现Comparable接口,覆盖compareTo方法这种方式也就是元素的自然顺序或者叫做默认顺序
class Student implements Comparable{//实现Comparable接口
    String name;
    int age;
    Student(String name,int age){
        this.name=name;
        this.age=age;
    }
    public int compareTo(Object obj){//覆盖compareTo方法
          if(!(obj instanceof Student))
             throw new RuntimeException("不是学生对象");
         Student stu=(Student)obj;
         if(stu.age<this.age)
            return 1;
        if(stu.age==this.age)//当年龄相同时通过姓名进行比较
            return this.name.compareTo(stu.name);
        return -1;
    }
}
class TreeSetTest{
    public void run(){
        TreeSet<Student> ts=new TreeSet<Student>();//创建存储学生信息的TreeSet集合
        ts.add(new Student("zjd",24));//添加数据
        ts.add(new Student("zxm",24));
        ts.add(new Student("zjd",25));
        ts.add(new Student("zjd",26));
        ts.add(new Student("zxm",24));
        ts.add(new Student("zxm",25));
        for(Iterator<Student> it=ts.iterator();it.hasNext();){//遍历结果
            Student stu=it.next();
            sop(stu.name+":"+stu.age);
        }
    }
    public void sop(Object obj){
        System.out.println(obj);
    }
}
第二种:当元素自身不具备比较性或者具备的比较性不是所需要的,这时就需要让集合自身具备比较性
class TreeSetTest2{
    public void run(){
        TreeSet ts=new TreeSet(new MyCompare());//将自定义比较器传入集合中
        ts.add("adasdsa");//添加测试数据
        ts.add("bada");
        ts.add("caaa");
        ts.add("dadaaaa");
        ts.add("eadaaaaaa");
        ts.add("saca");
        ts.add("fadafds");
        ts.add("aasssdas");
        for(Iterator it=ts.iterator();it.hasNext();){//遍历输出结果
            sop(it.next());
        }
    }
    public void sop(Object obj){
        System.out.println(obj);
    }
}
class MyCompare implements Comparator{
    public int compare(Object obj1,Object obj2){//覆盖compare方法
        String s1=(String)obj1;
        String s2=(String)obj2;
        int num=new Integer(s1.length()).compareTo(s2.length());
        if(num==0)
            return s1.compareTo(s2);
        return num;
    }
}
当两种排序都存在时以比较器为主
注意:对于上面两种比较方法如果没有对接口定义泛型那么覆盖中的类一定要是Object,如果定义了,那么要是定义的类型
泛型的概述:(generic)
泛型是1.5版本之后出现的新特性,用于解决安全问题,是一个类型安全机制
泛型类定义的泛型,在整个类中有效,如果被方法使用,那么泛型类对象明确要操作的具体类型后,所有要操作的类型就已经固定了,为了让不同方法可以操作不同类型,而且类还不确定,那么可以将泛型定义在方法上,在方法上的泛型类型要放在返回值类型之前修饰符之后

好处:

1、将运行时期出现的问题ClassCastException,转移到编译时期,方便了程序员解决问题,让运行时问题减少,变得安全了

2、避免了强制转化的麻烦
泛型格式:通过<>来定义要操作的引用数据类型
在什么时候使用泛型?
通常在集合框架中很常见,只要见到<>就要定义泛型,其实<>就是用来接收类型的,当使用集合时将集合中要存储的数据类型作为参数传递到<>即可
什么时候定义泛型:
当类中要操作的引用数据类型不确定时(早起定义Object来完成扩展,现在用泛型)
泛型特殊之处:
静态方法不可以访问类上定义的泛型。如果静态方法操作的应用数据类型不确定,可以将泛型定义在方法上。
class GenericTest
{
    public static void main(String[] args)
    {
        Demo<String> d=new Demo<String>();
        d.print("sadasd");
        //d.print(new String[]{"asa","asdas"});//编译不能通过
        d.show(1234);
        d.show(new String[]{"asa","asdas"});
        d.method(new String[]{"asa","asdas"});
        d.method(1234);
    }
}
class Demo<T>{
    public void print(T t){
        System.out.println(t);
    }
    public <Q> void show(Q q){//可以用类上的泛型也可以不用
        System.out.println(q);
    }
    public static <M> void method(M m){//不可以用类上的泛型否则编译失败
        System.out.println(m);
    }
}

通过上面的程序还能看出只有在定义的时候才会在方法上写泛型,在调用的时候不需要再方法上写泛型,而对于类及创建对象来说都要写上泛型,在类上不需要指明,再对象上需要指明类型
对于下面几种方式的判断:
当class A<T>{}时
class B<T> extends A<T>{}
class B<T> extends A{}
class B extends A{}
以上三种方式都是对的
但是下面这种不对
class B extends A<T>{}
当class A{}时
只有class B<T> extends A{}是对的
接口和上面也一样
泛型的通配符"?":
泛型限定:
 ? extends E 接收E类或其子类,是上限
? super  E 接收E类或其父类,是下限
一道比较纠结的问题:
class GenericTest
{
    public static void main(String[] args)
    {
        ArrayList<Person> al=new ArrayList<Person>();
        al.add(new Person());
        al.add(new Person());
        show(al);
        ArrayList<Student>a1=new ArrayList<Student>();
        a1.add(new Student());
        a1.add(new Student());
        show(a1);
    }
    public static void show(Collection<? extends Person> c){//对于这个地方这样写是正确的,但是如果将其改为? super Student并将下面Iterator也改掉之后
                Iterator<? extends Person> it=c.iterator(); //就会编译错误无法找到run方法,但是将run去掉就能编译通过并且能够输出对象引用地
        while(it.hasNext()){                                //址,从这个看来还是尽量不要用super容易出现问题
            it.next().run();
        }
    }
}
class Person{
    void run(){
        System.out.println("Person");
    }
}
class Student extends Person{
    void run(){
        System.out.println("Student");
    }
}
class Demo1 extends Student{
}

Map的概述:

接口Map<K,V>

Map集合存储键值对,是一对一对往里存的,而且要保证键的唯一性,他的键的唯一性也是同过hashCode和equals来实现的

1、添加:

put(K key,V value);

put(Map<? extends k,? extends V> m);

在添加时如果有相同的键,那么添加的值会覆盖原来的值,并返回原来的值

class Add{
    public void run(){
        HashMap<Integer,String> hm=new HashMap<Integer,String>();//泛型上定义的一定是引用类型,不可以用基本数据类型定义
        hm.put(1,"233");
        hm.put(2,"zjd");
                System.out.println(hm.put(2,"zxm"));//当执行此句是将打印zjd,并且将于自己键值相等的值覆盖
                //System.out.println(hm.put(3,"zxm"));//当执行此句时将打印null                 

                Set<Integer> s=hm.keySet();

                 Iterator<Integer> it=s.iterator();

                 while(it.hasNext()){Integer key=it.next();                      

              System.out.println(key+":"+hm.get(key));
                }
             }
      }
2、删除

clear()从此映射中移除所有映射关系
remove(key)移除键值为key的映射
3、判断
contaionsKey(key)
contaionsValue(value)
isEmpty()
4、获取
get(key)//得到键值为key对应的value值
size()//得到此集合中键值对的映射数目
values()//返回集合中映射包含的值的collection视图
entrySet()//返回此映射中包含的映射关系的 set视图。
keySet()// 返回此映射中包含的键的set视图

        //keySet的用法
                Set<Integer> s=hm.keySet();
        Iterator<Integer> it=s.iterator();
        while(it.hasNext()){
            Integer key=it.next();
            System.out.println(key+":"+hm.get(key));
        }
                //values的用法
        Collection<String> cl=hm.values();
        Iterator<String> it1=cl.iterator();
        while(it1.hasNext()){
            System.out.println(it1.next());
        }
                //entrySet的用法
        Set<Map.Entry<Integer,String>> s1=hm.entrySet();
        Iterator<Map.Entry<Integer,String>> it2=s1.iterator();
        while(it2.hasNext()){
            Map.Entry<Integer,String> me=it2.next();
            System.out.println(me.getKey()+":"+me.getValue());
        }
其中Map.Entry也是一个接口他是Map内部的一个接口
Map中常用的数据结构有HashTable、HashMap、TreeMap
HashTable:底层的是哈希表数据结果,不可以存入null值和null键,此集合是线程同步的效率低
HashMap:底层是哈希表数据结构,允许使用null键和null键,该集合是不同步的效率高
TreeMap:底层是二叉树数据结构。线程不同步,可以用于给Map集合的键进行排序其实Set底层就是使用了Map集合
面试题HashTable和HashMap的区别:答上面的就可以了





  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Java 集合写入数据库,可以将集合的每个元素作为一条记录插入到数据库表。具体实现方法如下: 1. 连接数据库 使用 JDBC API 连接到数据库,获取 Connection 对象。连接数据库的代码示例: ```java String url = "jdbc:mysql://localhost:3306/test"; String user = "root"; String password = "password"; Connection conn = DriverManager.getConnection(url, user, password); ``` 2. 创建 SQL 语句 创建 SQL 插入语句,将集合的元素插入到数据库表。SQL 语句示例: ```java String sql = "INSERT INTO users (name, age) VALUES (?, ?)"; ``` 3. 创建 PreparedStatement 对象 创建 PreparedStatement 对象,用于执行 SQL 语句。这里需要将 SQL 语句作为参数传入 PreparedStatement 的构造函数,示例代码: ```java PreparedStatement pstmt = conn.prepareStatement(sql); ``` 4. 遍历集合,设置 SQL 参数并执行 SQL 语句 遍历集合,将每个元素的属性值设置为 SQL 语句的参数,并执行 SQL 语句。示例代码: ```java for (User user : userList) { pstmt.setString(1, user.getName()); pstmt.setInt(2, user.getAge()); pstmt.executeUpdate(); } ``` 5. 关闭 PreparedStatement 和 Connection 对象 执行完 SQL 语句后,需要关闭 PreparedStatement 和 Connection 对象,示例代码: ```java pstmt.close(); conn.close(); ``` 完整代码示例: ```java import java.sql.Connection; import java.sql.DriverManager; import java.sql.PreparedStatement; import java.sql.SQLException; import java.util.List; public class CollectionToDatabase { public static void main(String[] args) { // 数据库连接信息 String url = "jdbc:mysql://localhost:3306/test"; String user = "root"; String password = "password"; // SQL 语句 String sql = "INSERT INTO users (name, age) VALUES (?, ?)"; // 用户集合 List<User> userList = ...; try { // 加载数据库驱动 Class.forName("com.mysql.cj.jdbc.Driver"); // 建立数据库连接 Connection conn = DriverManager.getConnection(url, user, password); // 创建 PreparedStatement 对象 PreparedStatement pstmt = conn.prepareStatement(sql); // 遍历集合,设置 SQL 参数并执行 SQL 语句 for (User user : userList) { pstmt.setString(1, user.getName()); pstmt.setInt(2, user.getAge()); pstmt.executeUpdate(); } // 关闭 PreparedStatement 和 Connection 对象 pstmt.close(); conn.close(); } catch (ClassNotFoundException e) { e.printStackTrace(); } catch (SQLException e) { e.printStackTrace(); } } } ``` 注意,如果集合的元素数量很大,插入数据的时间会很长,这时可以考虑使用批处理(batch processing)来提高性能。具体实现方法是在遍历集合时,将每个元素的参数设置好后,调用 PreparedStatement 的 addBatch() 方法,将其添加到批处理,最后调用 executeBatch() 方法一次性执行所有的 SQL 语句。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值