本文属原创,转载请注明出处:http://www.cnblogs.com/robinjava77/p/5481608.html (Robin)
QuoteTest(引用对象技巧)
1 import java.util.ArrayList;
2 import java.util.HashMap;
3 import java.util.List;
4 import java.util.Map;
5
6 /**
7 * Created by robin on 2016/4/13.
8 * 引用型对向操作总结:
9 * 1.被引用的对象,值改变时,会直接改变引用源的值;
10 * 2.当引用的对象,改变其引用源时,对其操作,只会改变新的引用源的值,并不会影响之前的引用源的值
11 * 3.从map中获取的引用不存在时,需要将新的引用put到map中,map中该位置的值,才会被引入
12 * @author robin
13 */
14 public class QuoteTest {
15
16 public static void main(String args[]){
17 Map> map = new HashMap >();
18 for (int i =0;i<5;i++){
19 Listdatalist = new ArrayList ();
20 for (int j=0;j<10;j++){
21 datalist.add(i*10+""+j);
22 }
23 map.put(""+i,datalist);
24 }
25 for (Listlist:map.values()){
26 System.out.println(listToString(list));
27 }
28 System.out.println("----------分隔线1-----------");
29 ListtempList = map.get("3");
30 tempList.add("avc");
31 tempList.remove("300");
32 for (Listlist:map.values()){
33 System.out.println(listToString(list));
34 }
35 System.out.println("----------分隔线2-----------");
36 ListtempList2 = map.get("2");//tempList 获得map中 key为2的引用
37 ListreplaceList = new ArrayList ();
38 tempList2 = replaceList;////tempList 获得其他list的引用,失去map中 key为2的引用,此时对templist2做任何操作,影响的时replaceList引用的区域
39 tempList2.add("replaceList的值被改变");
40 for (Listlist:map.values()){
41 System.out.println(listToString(list));
42 }
43 System.out.println("replaceList的值:"+listToString(replaceList));
44 System.out.println("----------分隔线3-----------");
45 ListtempList3 = map.get("2");
46 tempList3 = replaceList;
47 map.put("2",tempList3);
48 for (Listlist:map.values()){
49 System.out.println(listToString(list));
50 }
51 System.out.println("----------分隔线4-----------");
52 ListnotExistList = map.get("5");
53 if(notExistList == null){
54 notExistList = new ArrayList();
55 }
56 notExistList.add("第5行数据添加进来...");
57 for (Listlist:map.values()){
58 System.out.println(listToString(list));
59 }
60 System.out.println("----------分隔线5-----------");
61 ListnotExistList2 = map.get("6");
62 if(notExistList2 == null){
63 notExistList2 = new ArrayList();
64 }
65 notExistList2.add("第6行数据添加进来...");
66 map.put("6",notExistList2);
67 for (Listlist:map.values()){
68 System.out.println(listToString(list));
69 }
70 System.out.println("----------分隔线5-----------");
71
72 Map> mapOne= new HashMap >();
73 String keyss = "mapTest";
74 MapmapTwo = new HashMap ();
75 mapOne.put(keyss,mapTwo);
76 System.out.println("mapOne的数据:" + mapToString(mapOne));
77 System.out.println("----------分隔线6-----------");
78 mapTwo.put("aaa", "aaav");
79 mapTwo.put("bbb", "bbbv");
80 mapTwo.put("ccc","cccv");
81 System.out.println("mapOne的数据:"+mapToString(mapOne));
82 System.out.println("----------分隔线7-----------");
83 }
84
85 private static String listToString(Listlist){
86 StringBuilder sb = new StringBuilder("");
87 for (String s:list){
88 sb.append("["+s+"] ");
89 }
90 return sb.toString();
91 }
92
93 private static String mapToString(Map,?> map){
94 StringBuilder sb = new StringBuilder("");
95 for(Map.Entry entry:map.entrySet()){
96 sb.append("[key:"+entry.getKey()+";value:"+entry.getValue()+"]");
97 }
98 return sb.toString();
99 }
100
101 }
---------------------
引用对象易产生的bug:
2016.05.11
关于引用对象,使用不恰当,很容易给自己挖坑,产生非常严重的bug,进而导致整个系统实际业务的崩溃,而且这种bug很难被查出来。(如果日志记录不够详细,分析不够彻底,要找出这种bug,只能靠上帝保佑)
下面先上bug 代码 demo
1 import java.util.Iterator;
2 import java.util.List;
3 import java.util.Vector;
4
5 /**
6 * Created by robin on 2016/5/11.
7 *
8 * @author robin
9 */
10 public class QuoteBugDemo {
11
12 private static ListpublicNums = new Vector ();
13
14 public static void main(String args[]) throws InterruptedException {
15 initPublicNums();//初始化公共数据源
16
17 timeTask(1);//模拟执行定时任务1
18
19 timeTask(2);//模拟执行定时任务2
20
21 }
22
23
24 private static void initPublicNums(){
25 for (int i =0;i <10;i++){
26 publicNums.add(i);
27 }
28 }
29
30 /**
31 * 这块代码模拟的逻辑:
32 * 1.每天获取配置好10个的数据源;
33 * 2.检查这10个数据源,当数据源的数据准备好后,开始执行数据同步;
34 * 3.从当天的带同步数据源list删除已经同步的数据;
35 * @param mark
36 * @throws InterruptedException
37 */
38 private static void timeTask(int mark) throws InterruptedException {
39 final long start = System.currentTimeMillis();//程序开始运行时间
40 //每天待同步数据源
41 ListdataSources = publicNums;
42 StringBuffer sb = new StringBuffer("mark("+mark+");公共数据源数目:"+dataSources.size()+";数据源列表[");
43 for (Integer i:dataSources){
44 sb.append(i+",");
45 }
46 sb.append("]");
47 System.out.println("日志【"+sb.toString()+"】");
48 while(true){
49 long secOnds= (System.currentTimeMillis() - start) / 1000;
50 if(seconds > 15l){
51 System.out.println("运行超过限定时间:15秒,退出");
52 break;
53 }
54 Iteratorite = dataSources.iterator();
55 while (ite.hasNext()){//
56 int dataSource = ite.next();
57 boolean flag = isOk(dataSource);
58 if(flag){//数据源数据已准备好
59 System.out.println("对数据源:"+dataSource+"进行数据处理。");//同步数据
60 ite.remove();//待同步数据源删除该数据源
61 }
62 }
63 if(dataSources.size() != 0){
64 Thread.sleep(1000);
65 }else{
66 break;
67 }
68 }
69 System.out.println("定时任务mark["+mark+"]已经执行完毕");
70 }
71
72 /**
73 * 模拟检查数据源是否OK
74 * @param dataSource
75 * @return
76 */
77 private static boolean isOk(int dataSource){
78 if(dataSource%2 == 0){
79 return true;
80 }
81 return false;
82 }
83
84
85 }
执行结果:
1 日志【mark(1);公共数据源数目:10;数据源列表[0,1,2,3,4,5,6,7,8,9,]】
2 对数据源:0进行数据处理。
3 对数据源:2进行数据处理。
4 对数据源:4进行数据处理。
5 对数据源:6进行数据处理。
6 对数据源:8进行数据处理。
7 运行超过限定时间:15秒,退出
8 定时任务mark[1]已经执行完毕
9 日志【mark(2);公共数据源数目:5;数据源列表[1,3,5,7,9,]】
10 运行超过限定时间:15秒,退出
11 定时任务mark[2]已经执行完毕
定时任务2,执行的时候,数据源只剩1,3,5,7,9。
改进方案:将公共数据源保护起来,仅提供公共数据源的副本:shallow copy和deep copy
核心代码:
1 /**
2 * 改进方案1:获取公共数据源对象的副本
3 * shallow copy:list中 元素引用 仍然是相同的
4 * @return
5 */
6 private static ListgetPublicNums(){
7 ListclOne= new ArrayList (publicNums);
8 return clone;
9 }
改进后全部代码:
1 import java.util.ArrayList;
2 import java.util.Iterator;
3 import java.util.List;
4 import java.util.Vector;
5
6 /**
7 * Created by robin on 2016/5/11.
8 *
9 * @author robin
10 */
11 public class QuoteBugDemo {
12
13 private static ListpublicNums = new Vector ();
14
15 public static void main(String args[]) throws InterruptedException {
16 initPublicNums();//初始化公共数据源
17
18 timeTask(1);//模拟执行定时任务1
19
20 timeTask(2);//模拟执行定时任务2
21
22 }
23
24
25 private static void initPublicNums(){
26 for (int i =0;i <10;i++){
27 publicNums.add(i);
28 }
29 }
30
31 /**
32 * 改进方案1:获取公共数据源对象的副本
33 * shallow copy:list中 元素引用 仍然是相同的
34 * @return
35 */
36 private static ListgetPublicNums(){
37 ListclOne= new ArrayList (publicNums);
38 return clone;
39 }
40
41 /**
42 * 这块代码模拟的逻辑:
43 * 1.每天获取配置好10个的数据源;
44 * 2.检查这10个数据源,当数据源的数据准备好后,开始执行数据同步;
45 * 3.从当天的带同步数据源list删除已经同步的数据;
46 * @param mark
47 * @throws InterruptedException
48 */
49 private static void timeTask(int mark) throws InterruptedException {
50 final long start = System.currentTimeMillis();//程序开始运行时间
51 //每天待同步数据源
52 ListdataSources = getPublicNums();//改进方案1
53 StringBuffer sb = new StringBuffer("mark("+mark+");公共数据源数目:"+dataSources.size()+";数据源列表[");
54 for (Integer i:dataSources){
55 sb.append(i+",");
56 }
57 sb.append("]");
58 System.out.println("日志【"+sb.toString()+"】");
59 while(true){
60 long secOnds= (System.currentTimeMillis() - start) / 1000;
61 if(seconds > 15l){
62 System.out.println("运行超过限定时间:15秒,退出");
63 break;
64 }
65 Iteratorite = dataSources.iterator();
66 while (ite.hasNext()){//
67 int dataSource = ite.next();
68 boolean flag = isOk(dataSource);
69 if(flag){//数据源数据已准备好
70 System.out.println("对数据源:"+dataSource+"进行数据处理。");//同步数据
71 ite.remove();//待同步数据源删除该数据源
72 }
73 }
74 if(dataSources.size() != 0){
75 Thread.sleep(1000);
76 }else{
77 break;
78 }
79 }
80 System.out.println("定时任务mark["+mark+"]已经执行完毕");
81 }
82
83 /**
84 * 模拟检查数据源是否OK
85 * @param dataSource
86 * @return
87 */
88 private static boolean isOk(int dataSource){
89 if(dataSource%2 == 0){
90 return true;
91 }
92 return false;
93 }
94
95
96 }
执行结果:
1 日志【mark(1);公共数据源数目:10;数据源列表[0,1,2,3,4,5,6,7,8,9,]】
2 对数据源:0进行数据处理。
3 对数据源:2进行数据处理。
4 对数据源:4进行数据处理。
5 对数据源:6进行数据处理。
6 对数据源:8进行数据处理。
7 运行超过限定时间:15秒,退出
8 定时任务mark[1]已经执行完毕
9 日志【mark(2);公共数据源数目:10;数据源列表[0,1,2,3,4,5,6,7,8,9,]】
10 对数据源:0进行数据处理。
11 对数据源:2进行数据处理。
12 对数据源:4进行数据处理。
13 对数据源:6进行数据处理。
14 对数据源:8进行数据处理。
15 运行超过限定时间:15秒,退出
16 定时任务mark[2]已经执行完毕
已达预期。
------------------------------------------
shallow copy 和 deep copy 的区别详见我的另一篇博客:http://www.cnblogs.com/robinjava77/p/5481874.html