本文属原创,转载请注明出处:http://www.cnblogs.com/robinjava77/p/5481608.html  (Robin)

QuoteTest(引用对象技巧)

 import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map; /**
* Created by robin on 2016/4/13.
* 引用型对向操作总结:
* 1.被引用的对象,值改变时,会直接改变引用源的值;
* 2.当引用的对象,改变其引用源时,对其操作,只会改变新的引用源的值,并不会影响之前的引用源的值
* 3.从map中获取的引用不存在时,需要将新的引用put到map中,map中该位置的值,才会被引入
* @author robin
*/
public class QuoteTest { public static void main(String args[]){
Map<String,List<String>> map = new HashMap<String, List<String>>();
for (int i =0;i< 5;i++){
List<String> datalist = new ArrayList<String>();
for (int j=0;j<10;j++){
datalist.add(i*10+""+j);
}
map.put(""+i,datalist);
}
for (List<String> list:map.values()){
System.out.println(listToString(list));
}
System.out.println("----------分隔线1-----------");
List<String> tempList = map.get("3");
tempList.add("avc");
tempList.remove("300");
for (List<String> list:map.values()){
System.out.println(listToString(list));
}
System.out.println("----------分隔线2-----------");
List<String> tempList2 = map.get("2");//tempList 获得map中 key为2的引用
List<String> replaceList = new ArrayList<String>();
tempList2 = replaceList;////tempList 获得其他list的引用,失去map中 key为2的引用,此时对templist2做任何操作,影响的时replaceList引用的区域
tempList2.add("replaceList的值被改变");
for (List<String> list:map.values()){
System.out.println(listToString(list));
}
System.out.println("replaceList的值:"+listToString(replaceList));
System.out.println("----------分隔线3-----------");
List<String> tempList3 = map.get("2");
tempList3 = replaceList;
map.put("2",tempList3);
for (List<String> list:map.values()){
System.out.println(listToString(list));
}
System.out.println("----------分隔线4-----------");
List<String> notExistList = map.get("5");
if(notExistList == null){
notExistList = new ArrayList<String>();
}
notExistList.add("第5行数据添加进来...");
for (List<String> list:map.values()){
System.out.println(listToString(list));
}
System.out.println("----------分隔线5-----------");
List<String> notExistList2 = map.get("6");
if(notExistList2 == null){
notExistList2 = new ArrayList<String>();
}
notExistList2.add("第6行数据添加进来...");
map.put("6",notExistList2);
for (List<String> list:map.values()){
System.out.println(listToString(list));
}
System.out.println("----------分隔线5-----------"); Map<String,Map<String,String>> mapOne = new HashMap<String, Map<String, String>>();
String keyss = "mapTest";
Map<String,String> mapTwo = new HashMap<String, String>();
mapOne.put(keyss,mapTwo);
System.out.println("mapOne的数据:" + mapToString(mapOne));
System.out.println("----------分隔线6-----------");
mapTwo.put("aaa", "aaav");
mapTwo.put("bbb", "bbbv");
mapTwo.put("ccc","cccv");
System.out.println("mapOne的数据:"+mapToString(mapOne));
System.out.println("----------分隔线7-----------");
} private static String listToString(List<String> list){
StringBuilder sb = new StringBuilder("");
for (String s:list){
sb.append("["+s+"] ");
}
return sb.toString();
} private static String mapToString(Map<?,?> map){
StringBuilder sb = new StringBuilder("");
for(Map.Entry entry:map.entrySet()){
sb.append("[key:"+entry.getKey()+";value:"+entry.getValue()+"]");
}
return sb.toString();
} }

---------------------

引用对象易产生的bug:

2016.05.11

关于引用对象,使用不恰当,很容易给自己挖坑,产生非常严重的bug,进而导致整个系统实际业务的崩溃,而且这种bug很难被查出来。(如果日志记录不够详细,分析不够彻底,要找出这种bug,只能靠上帝保佑)

下面先上bug 代码 demo

 import java.util.Iterator;
import java.util.List;
import java.util.Vector; /**
* Created by robin on 2016/5/11.
*
* @author robin
*/
public class QuoteBugDemo { private static List<Integer> publicNums = new Vector<Integer>(); public static void main(String args[]) throws InterruptedException {
initPublicNums();//初始化公共数据源 timeTask(1);//模拟执行定时任务1 timeTask(2);//模拟执行定时任务2 } private static void initPublicNums(){
for (int i =0;i < 10;i++){
publicNums.add(i);
}
} /**
* 这块代码模拟的逻辑:
* 1.每天获取配置好10个的数据源;
* 2.检查这10个数据源,当数据源的数据准备好后,开始执行数据同步;
* 3.从当天的带同步数据源list删除已经同步的数据;
* @param mark
* @throws InterruptedException
*/
private static void timeTask(int mark) throws InterruptedException {
final long start = System.currentTimeMillis();//程序开始运行时间
//每天待同步数据源
List<Integer> dataSources = publicNums;
StringBuffer sb = new StringBuffer("mark("+mark+");公共数据源数目:"+dataSources.size()+";数据源列表[");
for (Integer i:dataSources){
sb.append(i+",");
}
sb.append("]");
System.out.println("日志【"+sb.toString()+"】");
while(true){
long seconds = (System.currentTimeMillis() - start) / 1000;
if(seconds > 15l){
System.out.println("运行超过限定时间:15秒,退出");
break;
}
Iterator<Integer> ite = dataSources.iterator();
while (ite.hasNext()){//
int dataSource = ite.next();
boolean flag = isOk(dataSource);
if(flag){//数据源数据已准备好
System.out.println("对数据源:"+dataSource+"进行数据处理。");//同步数据
ite.remove();//待同步数据源删除该数据源
}
}
if(dataSources.size() != 0){
Thread.sleep(1000);
}else{
break;
}
}
System.out.println("定时任务mark["+mark+"]已经执行完毕");
} /**
* 模拟检查数据源是否OK
* @param dataSource
* @return
*/
private static boolean isOk(int dataSource){
if(dataSource%2 == 0){
return true;
}
return false;
} }

执行结果:

 日志【mark(1);公共数据源数目:10;数据源列表[0,1,2,3,4,5,6,7,8,9,]】
对数据源:0进行数据处理。
对数据源:2进行数据处理。
对数据源:4进行数据处理。
对数据源:6进行数据处理。
对数据源:8进行数据处理。
运行超过限定时间:15秒,退出
定时任务mark[1]已经执行完毕
日志【mark(2);公共数据源数目:5;数据源列表[1,3,5,7,9,]】
运行超过限定时间:15秒,退出
定时任务mark[2]已经执行完毕

定时任务2,执行的时候,数据源只剩1,3,5,7,9。

改进方案:将公共数据源保护起来,仅提供公共数据源的副本:shallow copy和deep copy

核心代码:

 /**
* 改进方案1:获取公共数据源对象的副本
* shallow copy:list中 元素引用 仍然是相同的
* @return
*/
private static List<Integer> getPublicNums(){
List<Integer> clone = new ArrayList<Integer>(publicNums);
return clone;
}

改进后全部代码:

 import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.Vector; /**
* Created by robin on 2016/5/11.
*
* @author robin
*/
public class QuoteBugDemo { private static List<Integer> publicNums = new Vector<Integer>(); public static void main(String args[]) throws InterruptedException {
initPublicNums();//初始化公共数据源 timeTask(1);//模拟执行定时任务1 timeTask(2);//模拟执行定时任务2 } private static void initPublicNums(){
for (int i =0;i < 10;i++){
publicNums.add(i);
}
} /**
* 改进方案1:获取公共数据源对象的副本
* shallow copy:list中 元素引用 仍然是相同的
* @return
*/
private static List<Integer> getPublicNums(){
List<Integer> clone = new ArrayList<Integer>(publicNums);
return clone;
} /**
* 这块代码模拟的逻辑:
* 1.每天获取配置好10个的数据源;
* 2.检查这10个数据源,当数据源的数据准备好后,开始执行数据同步;
* 3.从当天的带同步数据源list删除已经同步的数据;
* @param mark
* @throws InterruptedException
*/
private static void timeTask(int mark) throws InterruptedException {
final long start = System.currentTimeMillis();//程序开始运行时间
//每天待同步数据源
List<Integer> dataSources = getPublicNums();//改进方案1
StringBuffer sb = new StringBuffer("mark("+mark+");公共数据源数目:"+dataSources.size()+";数据源列表[");
for (Integer i:dataSources){
sb.append(i+",");
}
sb.append("]");
System.out.println("日志【"+sb.toString()+"】");
while(true){
long seconds = (System.currentTimeMillis() - start) / 1000;
if(seconds > 15l){
System.out.println("运行超过限定时间:15秒,退出");
break;
}
Iterator<Integer> ite = dataSources.iterator();
while (ite.hasNext()){//
int dataSource = ite.next();
boolean flag = isOk(dataSource);
if(flag){//数据源数据已准备好
System.out.println("对数据源:"+dataSource+"进行数据处理。");//同步数据
ite.remove();//待同步数据源删除该数据源
}
}
if(dataSources.size() != 0){
Thread.sleep(1000);
}else{
break;
}
}
System.out.println("定时任务mark["+mark+"]已经执行完毕");
} /**
* 模拟检查数据源是否OK
* @param dataSource
* @return
*/
private static boolean isOk(int dataSource){
if(dataSource%2 == 0){
return true;
}
return false;
} }

执行结果:

 日志【mark(1);公共数据源数目:10;数据源列表[0,1,2,3,4,5,6,7,8,9,]】
对数据源:0进行数据处理。
对数据源:2进行数据处理。
对数据源:4进行数据处理。
对数据源:6进行数据处理。
对数据源:8进行数据处理。
运行超过限定时间:15秒,退出
定时任务mark[1]已经执行完毕
日志【mark(2);公共数据源数目:10;数据源列表[0,1,2,3,4,5,6,7,8,9,]】
对数据源:0进行数据处理。
对数据源:2进行数据处理。
对数据源:4进行数据处理。
对数据源:6进行数据处理。
对数据源:8进行数据处理。
运行超过限定时间:15秒,退出
定时任务mark[2]已经执行完毕

已达预期。

------------------------------------------

shallow copy 和 deep copy 的区别详见我的另一篇博客:http://www.cnblogs.com/robinjava77/p/5481874.html

引用对象的使用和易产生bug的示例的更多相关文章

  1. struts2:遍历自定义字符串数组,遍历Action实例所引用对象中的数组

    在struts2:OGNL表达式,遍历List.Map集合:投影的使用一文中已经讲述了OGNL遍历List.Map集合等功能. 本文简单写一个遍历数组的示范程序. 1. 遍历自定义字符串数组 < ...

  2. 理解Java的引用对象

    SoftReferenceWeakReference 的特性基本一致, 最大的区别在于 SoftReference会尽可能长的保留引用,不会在GC时就回收对象,而是直到JVM 内存不足时才会被回收(虚 ...

  3. Andorid Binder进程间通信---Binder本地对象,实体对象,引用对象,代理对象的引用计数

    本文參考<Android系统源码情景分析>,作者罗升阳. 一.Binder库(libbinder)代码: ~/Android/frameworks/base/libs/binder --- ...

  4. C++实现引用和被引用对象分离

    上一篇博客简单介绍了C++中引用的底层实现,接下来,通过简单的代码验证如何将引用和被引用对象分离. 代码如下; #include <iostream> #include<string ...

  5. Effective Java 第三版——64. 通过对象的接口引用对象

    Tips 书中的源代码地址:https://github.com/jbloch/effective-java-3e-source-code 注意,书中的有些代码里方法是基于Java 9 API中的,所 ...

  6. 浅谈String中的==和对象中引用对象类型的==

    @Test public void test02() { StringBuffer sb = new StringBuffer(); sb.append('a'); sb.append(11); Sy ...

  7. 使用引用类型变量来访问所引用对象的属性和方法时,Java 虚拟机绑定规则

    通过引用类型变量来访问所引用对象的属性和方法时,Java 虚拟机将采用以下绑定规则: 实例方法与引用变量实际引用的对象的方法进行绑定,这种绑定属于动态绑定,因为是在运行时由 Java 虚拟机动态决定的 ...

  8. Python中的变量引用对象需注意的几点

    Python中的变量引用对象需注意的几点 分类:Python (55)  (0) 普通引用: Python中,变量的作用仅仅是一个标识,只有赋值后才被创建,它可以引用任何类型的对象,而且在引用之前必须 ...

  9. 使用NSHashTable存储引用对象

    NSHashTable 我们使用集合(NSArray,NSMutableArray,NSDictionary,NSMutableDictionary,NSSet,NSMutableSet)存储对象时会 ...

随机推荐

  1. Object有哪些公用方法?

    protected Object clone() 创建并返回此对象的一个副本.public boolean equals(Object obj) 指示其他某个对象是否与此对象"相等" ...

  2. 跟我学Windows Azure 三 使用vs2013创建windows azure web site

    首先我们需要登陆我们的windows azure上,然后访问 https://manage.windowsazure.cn/publishsettings/index 他会让我们下载我们的订阅证书文件 ...

  3. linux下jdk的安装(tar包)

    1.查看jdk安装路径 [root@localhost ~]# whereis javajava: /usr/bin/java /etc/java /usr/lib/java /usr/share/j ...

  4. facebook darkforest围棋ai测试

    0.darkforest说明 darkforest是facebook田渊栋博士开发的深度学习围棋程序,2016的uec cup得了第二名(http://jsb.cs.uec.ac.jp/~igo/en ...

  5. 查看死锁 的存储过程 ,工具存储过程 sp_who_lock

    http://blog.sina.com.cn/s/blog_95b5eb8c010162jp.html if exists (select * from dbo.sysobjects where i ...

  6. SQL Server Profiler

    一.SQL Profiler工具简介 SQL Profiler是一个图形界面和一组系统存储过程,其作用如下: 图形化监视SQL Server查询: 在后台收集查询信息: 分析性能: 诊断像死锁之类的问 ...

  7. RabbitMQ3.6.3集群搭建+HAProxy1.6做负载均衡

    目录 [TOC] 1.基本概念 1.1.RabbitMQ集群概述   通过 Erlang 的分布式特性(通过 magic cookie 认证节点)进行 RabbitMQ 集群,各 RabbitMQ 服 ...

  8. asp.net gridview 鼠标悬浮提示信息

    使用场景: gridview绑定数据,某列数据太多,故超过一定字符,隐藏起来,同时鼠标移到指定列显示其明细信息: 知识点: 1,oderListTbl_DataBound事件中,添加,oderList ...

  9. cWeb开发框架,基于asp.net的cWeb应用开发平台介绍(二)

    cWeb是基于微软的.Net Framework 4框架,数据库是sql server 2008 r2. cWeb开发框架下载,点击这里去下载. cWeb开发框架借鉴三层架构理论分为三层,分别是:cD ...

  10. <<redis设计和实现>>读书笔记

    redis如何实现主从同步的高效率?? 主从复制的同步有一个命令数据的同步文本,然后利用两个不同服务器的偏移量来进行进行同步,避免每次都是全部同步(并非会保存所有的命令数据,而是会有一个缓冲区(比如1 ...