热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

引用对象的使用和易产生bug的示例

本文属原创,转载请注明出处:http:www.cnblogs.comrobinjava77p5481608.html(Robin)QuoteTest(引用对象技巧)1impor

本文属原创,转载请注明出处: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 List datalist = 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 (List list:map.values()){
26 System.out.println(listToString(list));
27 }
28 System.out.println("----------分隔线1-----------");
29 List tempList = map.get("3");
30 tempList.add("avc");
31 tempList.remove("300");
32 for (List list:map.values()){
33 System.out.println(listToString(list));
34 }
35 System.out.println("----------分隔线2-----------");
36 List tempList2 = map.get("2");//tempList 获得map中 key为2的引用
37 List replaceList = new ArrayList();
38 tempList2 = replaceList;////tempList 获得其他list的引用,失去map中 key为2的引用,此时对templist2做任何操作,影响的时replaceList引用的区域
39 tempList2.add("replaceList的值被改变");
40 for (List list:map.values()){
41 System.out.println(listToString(list));
42 }
43 System.out.println("replaceList的值:"+listToString(replaceList));
44 System.out.println("----------分隔线3-----------");
45 List tempList3 = map.get("2");
46 tempList3 = replaceList;
47 map.put("2",tempList3);
48 for (List list:map.values()){
49 System.out.println(listToString(list));
50 }
51 System.out.println("----------分隔线4-----------");
52 List notExistList = map.get("5");
53 if(notExistList == null){
54 notExistList = new ArrayList();
55 }
56 notExistList.add("第5行数据添加进来...");
57 for (List list:map.values()){
58 System.out.println(listToString(list));
59 }
60 System.out.println("----------分隔线5-----------");
61 List notExistList2 = map.get("6");
62 if(notExistList2 == null){
63 notExistList2 = new ArrayList();
64 }
65 notExistList2.add("第6行数据添加进来...");
66 map.put("6",notExistList2);
67 for (List list: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 Map mapTwo = 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(List list){
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 List publicNums = 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 List dataSources = 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 Iterator ite = 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 List getPublicNums(){
7 List clOne= 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 List publicNums = 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 List getPublicNums(){
37 List clOne= 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 List dataSources = 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 Iterator ite = 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 

 


推荐阅读
  • 个人学习使用:谨慎参考1Client类importcom.thoughtworks.gauge.Step;importcom.thoughtworks.gauge.T ... [详细]
  • Java容器中的compareto方法排序原理解析
    本文从源码解析Java容器中的compareto方法的排序原理,讲解了在使用数组存储数据时的限制以及存储效率的问题。同时提到了Redis的五大数据结构和list、set等知识点,回忆了作者大学时代的Java学习经历。文章以作者做的思维导图作为目录,展示了整个讲解过程。 ... [详细]
  • 本文详细介绍了Java中vector的使用方法和相关知识,包括vector类的功能、构造方法和使用注意事项。通过使用vector类,可以方便地实现动态数组的功能,并且可以随意插入不同类型的对象,进行查找、插入和删除操作。这篇文章对于需要频繁进行查找、插入和删除操作的情况下,使用vector类是一个很好的选择。 ... [详细]
  • [大整数乘法] java代码实现
    本文介绍了使用java代码实现大整数乘法的过程,同时也涉及到大整数加法和大整数减法的计算方法。通过分治算法来提高计算效率,并对算法的时间复杂度进行了研究。详细代码实现请参考文章链接。 ... [详细]
  • Java太阳系小游戏分析和源码详解
    本文介绍了一个基于Java的太阳系小游戏的分析和源码详解。通过对面向对象的知识的学习和实践,作者实现了太阳系各行星绕太阳转的效果。文章详细介绍了游戏的设计思路和源码结构,包括工具类、常量、图片加载、面板等。通过这个小游戏的制作,读者可以巩固和应用所学的知识,如类的继承、方法的重载与重写、多态和封装等。 ... [详细]
  • 本文介绍了OC学习笔记中的@property和@synthesize,包括属性的定义和合成的使用方法。通过示例代码详细讲解了@property和@synthesize的作用和用法。 ... [详细]
  • 本文介绍了如何在给定的有序字符序列中插入新字符,并保持序列的有序性。通过示例代码演示了插入过程,以及插入后的字符序列。 ... [详细]
  • JavaSE笔试题-接口、抽象类、多态等问题解答
    本文解答了JavaSE笔试题中关于接口、抽象类、多态等问题。包括Math类的取整数方法、接口是否可继承、抽象类是否可实现接口、抽象类是否可继承具体类、抽象类中是否可以有静态main方法等问题。同时介绍了面向对象的特征,以及Java中实现多态的机制。 ... [详细]
  • 本文讨论了一个关于cuowu类的问题,作者在使用cuowu类时遇到了错误提示和使用AdjustmentListener的问题。文章提供了16个解决方案,并给出了两个可能导致错误的原因。 ... [详细]
  • importjava.util.ArrayList;publicclassPageIndex{privateintpageSize;每页要显示的行privateintpageNum ... [详细]
  • 关键词:Golang, Cookie, 跟踪位置, net/http/cookiejar, package main, golang.org/x/net/publicsuffix, io/ioutil, log, net/http, net/http/cookiejar ... [详细]
  • 标题: ... [详细]
  • Java学习笔记之面向对象编程(OOP)
    本文介绍了Java学习笔记中的面向对象编程(OOP)内容,包括OOP的三大特性(封装、继承、多态)和五大原则(单一职责原则、开放封闭原则、里式替换原则、依赖倒置原则)。通过学习OOP,可以提高代码复用性、拓展性和安全性。 ... [详细]
  • Java中包装类的设计原因以及操作方法
    本文主要介绍了Java中设计包装类的原因以及操作方法。在Java中,除了对象类型,还有八大基本类型,为了将基本类型转换成对象,Java引入了包装类。文章通过介绍包装类的定义和实现,解答了为什么需要包装类的问题,并提供了简单易用的操作方法。通过本文的学习,读者可以更好地理解和应用Java中的包装类。 ... [详细]
  • 本文介绍了在CentOS上安装Python2.7.2的详细步骤,包括下载、解压、编译和安装等操作。同时提供了一些注意事项,以及测试安装是否成功的方法。 ... [详细]
author-avatar
喏焿你一辈子_997
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有