List

来源:互联网 发布:网络质量监控 美团 编辑:程序博客网 时间:2024/06/05 06:20

项目需求中遇到一个问题。需要将一个复杂的对象复制一个数据一样内存不一样的出来。

Java中的复制貌似是除了数据类型之外,其他的都是传递对象内存地址。当你的这个对象中嵌套了list<T>(T是一个class,不是数据类型)的时候,即便你用新的list去接收。

但是list里面的数据对象的内存地址还是一样,当你对新的list进行操作的时候。其实操作的还是老的list中的数据对象,应为他们内存地址一样。

为了避免这种情况,网上找了很多方法,有的说用clone,尝试过之后还是不行,个人觉得是对稍微简单的对象操作应该是没有问题,

如果说对象里面嵌套了list可能就不能达到预期的效果.有的说用collection.copy,但是最终还是浅拷贝,也不能达到预期效果。最终找到上面这个,简单好用,不过需要你的class能

实现Serializable接口。这个方法返回的数据对象就是一个全新的对象,内存地址不同

1.add其实不是深度复制,而是添加引用指向对象

import java.io.ByteArrayInputStream;  import java.io.ByteArrayOutputStream;  import java.io.IOException;  import java.io.ObjectInputStream;  import java.io.ObjectOutputStream;    public abstract class BeanCloneUtil {      @SuppressWarnings("unchecked")      public static <T> T cloneTo(T src) throws RuntimeException {          ByteArrayOutputStream memoryBuffer = new ByteArrayOutputStream();          ObjectOutputStream out = null;          ObjectInputStream in = null;          T dist = null;          try {              out = new ObjectOutputStream(memoryBuffer);              out.writeObject(src);              out.flush();              in = new ObjectInputStream(new ByteArrayInputStream(memoryBuffer.toByteArray()));              dist = (T) in.readObject();          } catch (Exception e) {              throw new RuntimeException(e);          } finally {              if (out != null)                  try {                      out.close();                      out = null;                  } catch (IOException e) {                      throw new RuntimeException(e);                  }              if (in != null)                  try {                      in.close();                      in = null;                  } catch (IOException e) {                      throw new RuntimeException(e);                  }          }          return dist;      }  }  

Java集合主要分为三种类型:Set(集)、List(列表)和Map(映射)。

下面具体说下集合(Collection:List、Set,Map:HashMap、TreeMap)


Set、List、Map

二、细说Java集合


详细介绍: 
List特点:元素有序,元素可重复 
Map特点:元素按键值对存储,无序(key不可重复,重复会覆盖之前的,value可以重复) 
Set特点:元素无放入顺序,元素不可重复(注意:元素虽然无放入顺序,但是元素在set中的位置是有该元素的HashCode决定的,其位置其实是固定的)
ArrayList : 由数组实现的List。数组增删慢,查找快。

LinkedList:底层基于链表实现。链表增删快,查找慢 。

排序:

数组:

一.Array 排序

Arrays.sort(int[] a)中的排序是用的是快速排序一般顺序是升序的,字母也是A~Z这种排序的。

Arrays.sort(T[], Comparator < ? super T > c),自定义排序,自定义算法写在第二个参数里面。

Comparable和Comparator区别

Comparable可以认为是一个内比较器,自然排序  Comparator可以认为是是一个外比较器,比较器排序  

Comparable:假设我们通过 x.compareTo(y) 来“比较x和y的大小”。
若返回“负数”,意味着“x比y小”;返回“零”,意味着“x等于y”;返回“正数”,意味着“x大于y”。

Comparator:int compare(T o1, T o2) 是“比较o1和o2的大小”。返回“负数”,意味着“o1比o2小”;返回“零”,意味着“o1等于o2”;返回“正数”,意味着“o1大于o2”。

demo:

Comparable示例程序

import java.util.ArrayList;import java.util.Collections;import java.util.List;public class StudentComparable implements Comparable<StudentComparable> {      private String name;      private int age;      public StudentComparable(String name, int age) {            this.name = name;            this.age = age;      }      public void setName(String name) {            this.name = name;      }      public void setAge(int age) {            this.age = age;      }      public String getName() {            return name;      }      public int getAge() {            return age;      }      @Override      public boolean equals(Object o) {            if (this == o) {      return true;    }    if (o == null || getClass() != o.getClass()) {      return false;    }            StudentComparable that = (StudentComparable) o;            if (getAge() != that.getAge()) {      return false;    }            return getName() != null ? getName().equals(that.getName()) : that.getName() == null;      }      @Override      public int hashCode() {            int result = getName() != null ? getName().hashCode() : 0;            result = 31 * result + getAge();            return result;      }      @Override      public int compareTo(StudentComparable o) {            if (this.name.compareTo(o.getName()) > 0) {                  return 1;            }else if (this.name.compareTo(o.getName()) < 0) {                  return -1;            }            return 0;      }      @Override      public String toString() {            return "StudentComparable{" + "name='" + name + '\'' + ", age=" + age + '}';      }      public static void main(String[] args) {            List<StudentComparable> list = new ArrayList<>();            list.add(new StudentComparable("Jack", 16));            list.add(new StudentComparable("Mike", 25));            list.add(new StudentComparable("Summer", 17));            list.add(new StudentComparable("Bob", 19));            Collections.sort(list);            for (StudentComparable stu : list) {                  System.out.println(stu);            }      }}

Comparator示例代码

import java.util.*;class A implements Comparator<String> {      @Override      public int compare(String s1, String s2) {            int len1 = s1.length();            int len2 = s2.length();            if (len1 > len2) {                  return 1;            }else if (len1 < len2) {                  return -1;            }else {                  return 0;            }      }}public class ComparatorTest {      public static void main(String[] args) {            List<String> list = new ArrayList<>();            list.add("cat");            list.add("fish");            list.add("dog");            list.add("panda");            Collections.sort(list, new A());            System.out.println(list);      }}

注意

  • 在Comparable接口的实现类里,我们要必须重写compareTo()方法,看需求是否需要重写hashCode()方法和equals()方法 。

  • 在Comparator接口的实现类里,我们必须重写compare()方法,看需求是否需要重写hashCode()方法和equals()方法 。

  • 其实上述的hashCode()方法和equals()方法不重写也是可以的。

题外话:HashSet和HashMap一直都是JDK中最常用的两个类,HashSet要求不能存储相同的对象,HashMap要求不能存储相同的键。 

根据这两个规范,可以得到如下推论: 
1、如果两个对象equals,Java运行时环境会认为他们的hashcode一定相等。 
2、如果两个对象不equals,他们的hashcode有可能相等。 
3、如果两个对象hashcode相等,他们不一定equals。 
4、如果两个对象hashcode不相等,他们一定不equals。 

这样我们就可以推断Java运行时环境是怎样判断HashSet和HastMap中的两个对象相同或不同了。我的推断是:先判断hashcode是否相等,再判断是否equals。

这方面的文章参考:http://blog.csdn.net/chy800/article/details/7239838

区别:

  • Comparable接口是在集合内部定义的方法实现的排序。

  • Comparator接口是在集合外部实现的排序。

  • 简单来说,comparable接口是通过类自己完成比较,而comparator接口是通过外部程序实现比较。


  • 结论

1、如果实现类没有实现Comparable接口,又想对两个类进行比较(或者实现类实现了Comparable接口,但是对compareTo方法内的比较算法不满意),那么可以实现Comparator接口,自定义一个比较器,写比较算法

2、实现Comparable接口的方式比实现Comparator接口的耦合性 要强一些,如果要修改比较算法,要修改Comparable接口的实现类,而实现Comparator的类是在外部进行比较的,不需要对实现类有任何修 改。从这个角度说,其实有些不太好,尤其在我们将实现类的.class文件打成一个.jar文件提供给开发者使用的时候。实际上实现Comparator 接口的方式后面会写到就是一种典型的策略模式Comparator好处是可以不改变类的情况下去排序(如某个jar包里面的类没有实现Comparable接口但是我们有需要去排序那么COmparator就派上用场了,而Comparable的话,对象需要去实现Comparable接口

如果同时有自然排序和比较器排序,以比较器排序为主  

比较标准的写法。判空

Collections.sort(riskFactorNameList, new Comparator<RiskFactorName>() {    @Override    public int compare(RiskFactorName o1, RiskFactorName o2) {        if(o1.getSortNo() == null) {            return -1;        }        if(o2.getSortNo() == null) {            return 1;        }        if (o1.getSortNo() > o2.getSortNo()) {            return 1;        }        if (o1.getSortNo() == o2.getSortNo()) {            return 0;        }        if (o1.getSortNo() < o2.getSortNo()) {            return -1;        }        return 0;    }});

  1.  @Override  
  2.     public int compareTo(Object o) {  
  3.         if(this ==o){  
  4.             return 0;              
  5.         }  
  6.         else if (o!=null && o instanceof User) {     
  7.             User u = (User) o;   
  8.             if(id<=u.id){  
  9.                 return -1;  
  10.             }else{  
  11.             return 1;  
  12.         }  
  13.     }else{  
  14.         return -1;  
  15.     }  
  16. }

使用 String.compareTo 方法:
1、如果字符串相等返回值0
2、如果第一个字符和参数的第一个字符不等,结束比较,返回他们之间的差值(ascii码值)(负值前字符串的值小于后字符串,正值前字符串大于后字符串)
3、如果第一个字符和参数的第一个字符相等,则以第二个字符和参数的第二个字符做比较,以此类推,直至比较的字符或被比较的字符有一方全比较完,这时就比较字符的长度.

例:
String s1 = "abc";
String s2 = "abcd";
String s3 = "abcdfg";
String s4 = "1bcdfg";
String s5 = "cdfg";
System.out.println( s1.compareTo(s2) ); // -1 (前面相等,s1长度小1)
System.out.println( s1.compareTo(s3) ); // -3 (前面相等,s1长度小3)
System.out.println( s1.compareTo(s4) ); // 48 ("a"的ASCII码是97,"1"的的ASCII码是49,所以返回48)
System.out.println( s1.compareTo(s5) ); // -2 ("a"的ASCII码是97,"c"的ASCII码是99,所以返回-2)
但是可能受到语言的影响,所以区分语言
Collator 类执行区分语言环境的 String 比较。使用此类可为自然语言文本构建搜索和排序例程。 
public class StudentComparator implements Comparator<Student> {
 
    public int compare(Student o1, Student o2) {
        if (o1.getScore() != o2.getScore()) {
            return o2.getScore() - o1.getScore();
        else {
            Collator instance = Collator.getInstance(Locale.CHINA);
            return instance.compare(o1.getName(), o2.getName());
        }
    }
     
}
比较大小的时候equals里面做判空。
@Overridepublic boolean equals(Object o) {    if (this == o) return true;    if (o == null || getClass() != o.getClass()) return false;    RiskFactorName that = (RiskFactorName) o;    return name != null ? name.equals(that.name) : that.name == null;}


原创粉丝点击