高手才进来:怎样通过hascode来得到符合这个hashcode的对象?

时间:2022-11-15 22:03:03
如题,

例如

Class MyClass
{
   String name;
  
  public void setName(String s)
  { 
     this.name=s;
  }

  public String getName()
  {
    return this.s;
  }

}

public class TMain
{

   public static void main(String args[])
   {
      MyClass myclass=new MyClass();
      myclass.setName("Terry");
      System.out.println("hashcode:"+myclass.hashcode());
      MyClass myclass1=getClassFromHashCode(myclass.hascode()); //通过hashcode重新得到这个对象
      System.out.println("name:"+myclass1.getName());//这里应该显示出Terry
    
   }

   public static Object getClassFromHashCode(int hascode)
  {
      //就是这个方法不知怎么写
  }

}

能解决的,我加分再结贴。谢谢

28 个解决方案

#1


你真的搞了多年的开发吗??

汗!狂汗!

#2


mark!

---------------------
代表城管来接分。
不给就抢,一天一次...

#3


你这个理论上是行不通的

#4


这个倒不是没有办法,不过需要修改一下代码

#5


class XObject{
    private final static Map<Integer,XObject> map=Collections.synchronizedMap(new HashMap<Integer,XObject>());
    public static XObject getObjectByRawHashCode(Integer hashCode){
        return map.get(hashCode);
    }
    XObject(){
        map.put(System.identityHashCode(this),this);
    }
}
class MyClass extends XObject
{
   String name;
  
  public void setName(String s)
  { 
     this.name=s;
  }

  public String getName()
  {
    return this.name;
  }

}


main:

 MyClass myclass=new MyClass();
        myclass.setName("Terry");
        System.out.println("hashcode:"+myclass.hashCode());
        MyClass myclass1=(MyClass) XObject.getObjectByRawHashCode(myclass.hashCode()); //通过hashcode重新得到这个对象
        System.out.println("name:"+myclass1.getName());//这里应该显示出Terry

#6


TO hbwhwang: J2EE方面的开放经验绝对比你这个开班授课的江湖游医要丰富. 想做老师, 就多回答问题,不会回答别混分.把等级搞上去了才有说服力.

#7


treeroot(旗鲁特) ( ) 
你的这个方法是要预先定义好才能得到的,如果里面数据有变化,那么hashcode肯定会变化,这个时候你又取不出来了
所以,应该不能用你的那种方法来从 hashcode取出对象

#8


terry_yip(搞了几年开发,现在才来恶补基础,请别见笑!):

没想到那句“汗,狂汗”伤害了你的自尊~
抱歉了,兄弟!
=======
你的问题在JAVA DOC中有答案,Object类的hashCode()方法里面有这个方法的详细说明。
我英文不好,就不给你翻译了,你自己看看吧。

#9


谢谢treeroot的详尽代码,不过以那种原理来看,应该要改Object类的代码,才能使所有的对象都能通过hashcode取到吧?

#10


TO hbwhwang:从你说推荐我看Java Doc中的Object类的hashCode方法,我就觉得你都没看清我的这个问题问什么,这个问题是问从hashcode取得Object的问题,而不是问hashcode用来做什么的,如果是google一下或查看JDK文档就找到答案的,我也不会发贴问.你有可能是说hashcode不是唯一的这个问题, 这个可能性我考虑过,得到了Object后,用getClass()方法就可以知道是不是我想要的Object了. 总之,用"你真的搞了多年的开发吗??汗!狂汗!"来回答一个你没看清楚的问题,是"针对人而不是针对技术问题 ", 有点不合适的,是吧?
  

#11


算啦, 说明了问题就OK了,我的水平也不是好到哪儿去. 别跑题了, 大家继续讨论主题上的问题吧.贴子先加十分.


#12


terry_yip(搞了几年开发,现在才来恶补基础,请别见笑!) :
你错了,我看清楚了你的问题才说那句话的。

你题目中的类MyClass没有继承,那么就是继承自JAVA的Object。因此你所说的hashCode就是Object的hashCode。
关于Object的hashCode,在JAVA DOC中,有这段话:
     * As much as is reasonably practical, the hashCode method defined by 
     * class <tt>Object</tt> does return distinct integers for distinct 
     * objects. (This is typically implemented by converting the internal 
     * address of the object into an integer, but this implementation 
     * technique is not required by the 
     * Java<font size="-2"><sup>TM</sup></font> programming language.)
也就是说:Object的hashCode,(一般)是根据对象的内部地址(internal address)转化(计算)而来的。
从理论上(我说的是理论上,而实际上除非你非常深入了解JVM),如果我们如果找到了这个内部地址,那么我们还是有办法取回对象的。可是这个算法可能(我是说可能,我也没看过源码)是不可逆的,也就是说,你不一定能通过hashCode反算出internal address。

当然现在唯一的一条路就显示出来了:
1、java的hashCode算法必须可逆
2、有办法把变量myclass1刷成你得到的internal address

=============
我说的“汗,狂汗”没有别的意思,也不是为了捞分!(没见过接分的这么说话的吧)
我只是感叹于你写的“搞了几年开发”
我个人认为“搞了几年开发”的技术人员不可能不知道上面的内容。



#13


我还是觉得从hashcode转化成对象不太可能

#14


解决方案还是有的吧,例如添加一个实时map,记录hashcode和对象引用
直接似乎是不行的

#15


TO hbwhwang:你说对了,搞了几年开发的人,不可道不知道上面内容,我六年前就知道Object类是所有类的超类,所有的对象中都默认继承Object类的方法. 我不知道我说过的内容中,你从哪里看出来我是不知道上面这个知识点的.你的JavaDoc的内容,在Eclipse上,随便Ctrl+点击"Object"这个单词都可以看到,至于hashCode()是一个native方法,我也知道,但不代表native方法中实现的东西,就不能提取出来,万一sun另外做了另一个native方法,可以让你提取,而我们平时少用不知道呢? 又或者sun没有提供,但有人可以通过别的算法实现呢? 我就是因为有这个猜测所以才发贴问.   

     就像前面treeroot所说的,他讲的也是一个解决办法,不过他要继承一个自定义的类,如果要把JVM中所有的类都找得到,就得改变所有类的超类----Object类的源代码,上面我都讲过了这个问题了,证明我是很清楚Object是所有类的超类这个知识点的.我很谢谢他的回贴,虽然不是最好的,但起码他是提供了一个可行的解决方法.

我可以这样讲,通过hashcode返过来找到hashcode对应对象,是可以实现的,Spring中已经有相似的这个功能, 我没空研究它的源码,所以才想请教一下大家.

#16


了解,算了不吵了,如果我言语不慎伤害了你,再次跟你说声抱歉~

既然你认可treeroot(旗鲁特) 的办法,那我也可以给你一种办法,不用继承,但是得用工厂。
public MyClassFactory{
    static Map<Integer,MyClass> map=new HashMap<Integer,MyClass>(); 
    private MyClassFactory(){}
    public synchronized static MyClass getInstance(){
          MyClass m=new MyClass();
          map.put(m.hashCode(),m);
          return m;
    }
    public synchronized static Object getClassFromHashCode(int hascode){
        return map.get(new Integer(hashCode)); 
    }
}

在你每次需要MyClass对象的时候,不要new,而是这样:
MyClass myclass=MyClassFactory.getInstance();
然后你就可以:
MyClass myclass2=MyClassFactory.getClassFromHashCode(myclass.hashCode());

#17


OK,我的言论也有点过激,我也say sorry.

在这里,其实我说明一下我的设想,我们做项目做多了,就会发现,很多时候,出现的错误都是很隐蔽的,有时客户对你说:"我好像先按这里,再按那里,然后输入什么什么,再进去, 就报错了",但你到现场时,却怎么也发现不了错误,你要客户方的人再模拟一次,好像又没错,这个问题真的很烦,最后我们最终解决问题时发现,多数都是对象中的某些变量值不规范造成的,程序员的水平也有高有低,同一个人的精神状态也有好有差,你不可能要求程序一做出来,就有足够的健壮性去处理各种不规范的变量值的,所以我就设想出这样一种模式来处理-----当JVM抛出不能处理的Exception时, 马上得到抛出Exception的对象, 并把这个对象用ObjectOutPutStream记录在文本或者数据库中, 于是, 我们通过log4j的报错时间,就可以定位到记录这个错误对象的媒介,并把它还原, 从而就跟踪到这个对象里面的所有变量的值, 那么查起错来就容易多了.

    我之所以问本贴的这个问题,其实就是发现Exception中,可以得到抛出错误的对象的hashcode, (用Thowable里面的getStackTrace()得到StackTraceElement,然后调用StackTraceElement.hashcode()得到抛出错误的对象的hashcode),然后我就想把Exception的构造方法改一下,进一步通过hashcode来得到发生错误的对象,然后再把这个对象持久化了,当然,这个对象要实现Serialisable接口, 这就是我的想法. TreeRoot的方法可以实现,但需要再把Object类的代码改一下.hbwhwang的方法其实和treeroot的原理是一样的,都是先把对象和hashcode存在一个静态的Map里面, 只不过换成了工厂模式.

   我两个月前已经发贴问过这个问题,结果用Plain Java的API得不到实现方法, 后来用Spring的ExceptionInterceptor来实现了, 但是我不满足于功能的实现,我还想知道实现的原理.



  

#18


如果用Map来分别存放hashcode ,Object的这种方法,是可行,但会有一个问题,随着系统的运行,Map中的Object越来越多,而不释放,这就有危险了。

#19


起始修改java.lang.Object源码是行的通的,但是绝对不推荐
只要自己写一个java.lang.Object.java,重新定义一些方法,要么重新打包rt.jar里面
要么启动的时候放到bootclasspath前面,这样引导类加载器就会加载你实现的Object,
儿忽略掉rt.jar中的Object(不过这个参数不是标准参数)
java -Xboolclasspath/p myobject.jar 


#20


haha, 大师们都跑这开会来啦?兄弟搬个板凳来学习学习  ^_^

楼主提出这个问题的初衷实在让兄弟感到钦佩,难能可贵!

如果楼主能在一开始就把背景交待一下就更好了。现在经常看到一些帖子,上来就问一个看似比较离奇的问题,等纠缠到最后发现他遇到的问题根本就不应该用他想的思路去解决。我当然不是说本帖,只是说如果一开始就交待清楚的话,能避免不少误会。

楼主说的“项目中纠错”的问题,的确是个问题。以前我没想到还可以用这种手段处理,以后得多想想了  *_*

#21


maquan('ma:kju) :

别太当回事~~
你去研究一下,就不会滔滔江水了~~

#22


呵呵,如果我一开始就说得那么详细,恐惊很多人一看就觉得太复杂,没人回贴,贴子很快就沉下去了。

#23


使用AspectJ,例:

public interface HashCode
{
  public int hashCode();
}

@Aspect
public class HashCodeImpl implements HashCode
{

  public int hashCode()
  {
     //...在这里将对象和它的hasCode值进行缓存
  }

  @DeclareParents ( value = "foo.MyClass1" , defaultImpl = HashCodeImpl.class )
  //这时的foo.MyClass是需要通过hasCode来获取原对象的类
  private HashCode h1 ;

  //如果有多个类需要处理,如下添加
  @DeclareParents ( value = "foo.MyClass2" , defaultImpl = HashCodeImpl.class )
  private HashCode h2 ;

  ....

}


使用AspectJ编译(可以是jar或java文件)后就可以只对需要的类进行这样的处理,
此方法对原代码没有任何改变

#24


AspectJ编译后的字节码实际上给所有经过处理的类加上了接口HashCode,接口的方法实现是HashCodeImpl中的实现

#25


mark!

#26


原来AspactJ是这样用的,谢谢flyxxxx让我们长了见识~~!!!^-^

TO treeroot:你说“要么启动的时候放到bootclasspath前面,这样引导类加载器就会加载你实现的Object,”

能不能具体讲一下,怎么把myobject.jar 启动的时候放到bootclasspath前面?你的那句命令不能运行,我在google粗略地找了一下,也没有相关的资料。谢谢了。

贴子再加10分。

#27


http://blog.csdn.net/treeroot/archive/2006/07/22/960778.aspx

#28


先收藏再研究

#1


你真的搞了多年的开发吗??

汗!狂汗!

#2


mark!

---------------------
代表城管来接分。
不给就抢,一天一次...

#3


你这个理论上是行不通的

#4


这个倒不是没有办法,不过需要修改一下代码

#5


class XObject{
    private final static Map<Integer,XObject> map=Collections.synchronizedMap(new HashMap<Integer,XObject>());
    public static XObject getObjectByRawHashCode(Integer hashCode){
        return map.get(hashCode);
    }
    XObject(){
        map.put(System.identityHashCode(this),this);
    }
}
class MyClass extends XObject
{
   String name;
  
  public void setName(String s)
  { 
     this.name=s;
  }

  public String getName()
  {
    return this.name;
  }

}


main:

 MyClass myclass=new MyClass();
        myclass.setName("Terry");
        System.out.println("hashcode:"+myclass.hashCode());
        MyClass myclass1=(MyClass) XObject.getObjectByRawHashCode(myclass.hashCode()); //通过hashcode重新得到这个对象
        System.out.println("name:"+myclass1.getName());//这里应该显示出Terry

#6


TO hbwhwang: J2EE方面的开放经验绝对比你这个开班授课的江湖游医要丰富. 想做老师, 就多回答问题,不会回答别混分.把等级搞上去了才有说服力.

#7


treeroot(旗鲁特) ( ) 
你的这个方法是要预先定义好才能得到的,如果里面数据有变化,那么hashcode肯定会变化,这个时候你又取不出来了
所以,应该不能用你的那种方法来从 hashcode取出对象

#8


terry_yip(搞了几年开发,现在才来恶补基础,请别见笑!):

没想到那句“汗,狂汗”伤害了你的自尊~
抱歉了,兄弟!
=======
你的问题在JAVA DOC中有答案,Object类的hashCode()方法里面有这个方法的详细说明。
我英文不好,就不给你翻译了,你自己看看吧。

#9


谢谢treeroot的详尽代码,不过以那种原理来看,应该要改Object类的代码,才能使所有的对象都能通过hashcode取到吧?

#10


TO hbwhwang:从你说推荐我看Java Doc中的Object类的hashCode方法,我就觉得你都没看清我的这个问题问什么,这个问题是问从hashcode取得Object的问题,而不是问hashcode用来做什么的,如果是google一下或查看JDK文档就找到答案的,我也不会发贴问.你有可能是说hashcode不是唯一的这个问题, 这个可能性我考虑过,得到了Object后,用getClass()方法就可以知道是不是我想要的Object了. 总之,用"你真的搞了多年的开发吗??汗!狂汗!"来回答一个你没看清楚的问题,是"针对人而不是针对技术问题 ", 有点不合适的,是吧?
  

#11


算啦, 说明了问题就OK了,我的水平也不是好到哪儿去. 别跑题了, 大家继续讨论主题上的问题吧.贴子先加十分.


#12


terry_yip(搞了几年开发,现在才来恶补基础,请别见笑!) :
你错了,我看清楚了你的问题才说那句话的。

你题目中的类MyClass没有继承,那么就是继承自JAVA的Object。因此你所说的hashCode就是Object的hashCode。
关于Object的hashCode,在JAVA DOC中,有这段话:
     * As much as is reasonably practical, the hashCode method defined by 
     * class <tt>Object</tt> does return distinct integers for distinct 
     * objects. (This is typically implemented by converting the internal 
     * address of the object into an integer, but this implementation 
     * technique is not required by the 
     * Java<font size="-2"><sup>TM</sup></font> programming language.)
也就是说:Object的hashCode,(一般)是根据对象的内部地址(internal address)转化(计算)而来的。
从理论上(我说的是理论上,而实际上除非你非常深入了解JVM),如果我们如果找到了这个内部地址,那么我们还是有办法取回对象的。可是这个算法可能(我是说可能,我也没看过源码)是不可逆的,也就是说,你不一定能通过hashCode反算出internal address。

当然现在唯一的一条路就显示出来了:
1、java的hashCode算法必须可逆
2、有办法把变量myclass1刷成你得到的internal address

=============
我说的“汗,狂汗”没有别的意思,也不是为了捞分!(没见过接分的这么说话的吧)
我只是感叹于你写的“搞了几年开发”
我个人认为“搞了几年开发”的技术人员不可能不知道上面的内容。



#13


我还是觉得从hashcode转化成对象不太可能

#14


解决方案还是有的吧,例如添加一个实时map,记录hashcode和对象引用
直接似乎是不行的

#15


TO hbwhwang:你说对了,搞了几年开发的人,不可道不知道上面内容,我六年前就知道Object类是所有类的超类,所有的对象中都默认继承Object类的方法. 我不知道我说过的内容中,你从哪里看出来我是不知道上面这个知识点的.你的JavaDoc的内容,在Eclipse上,随便Ctrl+点击"Object"这个单词都可以看到,至于hashCode()是一个native方法,我也知道,但不代表native方法中实现的东西,就不能提取出来,万一sun另外做了另一个native方法,可以让你提取,而我们平时少用不知道呢? 又或者sun没有提供,但有人可以通过别的算法实现呢? 我就是因为有这个猜测所以才发贴问.   

     就像前面treeroot所说的,他讲的也是一个解决办法,不过他要继承一个自定义的类,如果要把JVM中所有的类都找得到,就得改变所有类的超类----Object类的源代码,上面我都讲过了这个问题了,证明我是很清楚Object是所有类的超类这个知识点的.我很谢谢他的回贴,虽然不是最好的,但起码他是提供了一个可行的解决方法.

我可以这样讲,通过hashcode返过来找到hashcode对应对象,是可以实现的,Spring中已经有相似的这个功能, 我没空研究它的源码,所以才想请教一下大家.

#16


了解,算了不吵了,如果我言语不慎伤害了你,再次跟你说声抱歉~

既然你认可treeroot(旗鲁特) 的办法,那我也可以给你一种办法,不用继承,但是得用工厂。
public MyClassFactory{
    static Map<Integer,MyClass> map=new HashMap<Integer,MyClass>(); 
    private MyClassFactory(){}
    public synchronized static MyClass getInstance(){
          MyClass m=new MyClass();
          map.put(m.hashCode(),m);
          return m;
    }
    public synchronized static Object getClassFromHashCode(int hascode){
        return map.get(new Integer(hashCode)); 
    }
}

在你每次需要MyClass对象的时候,不要new,而是这样:
MyClass myclass=MyClassFactory.getInstance();
然后你就可以:
MyClass myclass2=MyClassFactory.getClassFromHashCode(myclass.hashCode());

#17


OK,我的言论也有点过激,我也say sorry.

在这里,其实我说明一下我的设想,我们做项目做多了,就会发现,很多时候,出现的错误都是很隐蔽的,有时客户对你说:"我好像先按这里,再按那里,然后输入什么什么,再进去, 就报错了",但你到现场时,却怎么也发现不了错误,你要客户方的人再模拟一次,好像又没错,这个问题真的很烦,最后我们最终解决问题时发现,多数都是对象中的某些变量值不规范造成的,程序员的水平也有高有低,同一个人的精神状态也有好有差,你不可能要求程序一做出来,就有足够的健壮性去处理各种不规范的变量值的,所以我就设想出这样一种模式来处理-----当JVM抛出不能处理的Exception时, 马上得到抛出Exception的对象, 并把这个对象用ObjectOutPutStream记录在文本或者数据库中, 于是, 我们通过log4j的报错时间,就可以定位到记录这个错误对象的媒介,并把它还原, 从而就跟踪到这个对象里面的所有变量的值, 那么查起错来就容易多了.

    我之所以问本贴的这个问题,其实就是发现Exception中,可以得到抛出错误的对象的hashcode, (用Thowable里面的getStackTrace()得到StackTraceElement,然后调用StackTraceElement.hashcode()得到抛出错误的对象的hashcode),然后我就想把Exception的构造方法改一下,进一步通过hashcode来得到发生错误的对象,然后再把这个对象持久化了,当然,这个对象要实现Serialisable接口, 这就是我的想法. TreeRoot的方法可以实现,但需要再把Object类的代码改一下.hbwhwang的方法其实和treeroot的原理是一样的,都是先把对象和hashcode存在一个静态的Map里面, 只不过换成了工厂模式.

   我两个月前已经发贴问过这个问题,结果用Plain Java的API得不到实现方法, 后来用Spring的ExceptionInterceptor来实现了, 但是我不满足于功能的实现,我还想知道实现的原理.



  

#18


如果用Map来分别存放hashcode ,Object的这种方法,是可行,但会有一个问题,随着系统的运行,Map中的Object越来越多,而不释放,这就有危险了。

#19


起始修改java.lang.Object源码是行的通的,但是绝对不推荐
只要自己写一个java.lang.Object.java,重新定义一些方法,要么重新打包rt.jar里面
要么启动的时候放到bootclasspath前面,这样引导类加载器就会加载你实现的Object,
儿忽略掉rt.jar中的Object(不过这个参数不是标准参数)
java -Xboolclasspath/p myobject.jar 


#20


haha, 大师们都跑这开会来啦?兄弟搬个板凳来学习学习  ^_^

楼主提出这个问题的初衷实在让兄弟感到钦佩,难能可贵!

如果楼主能在一开始就把背景交待一下就更好了。现在经常看到一些帖子,上来就问一个看似比较离奇的问题,等纠缠到最后发现他遇到的问题根本就不应该用他想的思路去解决。我当然不是说本帖,只是说如果一开始就交待清楚的话,能避免不少误会。

楼主说的“项目中纠错”的问题,的确是个问题。以前我没想到还可以用这种手段处理,以后得多想想了  *_*

#21


maquan('ma:kju) :

别太当回事~~
你去研究一下,就不会滔滔江水了~~

#22


呵呵,如果我一开始就说得那么详细,恐惊很多人一看就觉得太复杂,没人回贴,贴子很快就沉下去了。

#23


使用AspectJ,例:

public interface HashCode
{
  public int hashCode();
}

@Aspect
public class HashCodeImpl implements HashCode
{

  public int hashCode()
  {
     //...在这里将对象和它的hasCode值进行缓存
  }

  @DeclareParents ( value = "foo.MyClass1" , defaultImpl = HashCodeImpl.class )
  //这时的foo.MyClass是需要通过hasCode来获取原对象的类
  private HashCode h1 ;

  //如果有多个类需要处理,如下添加
  @DeclareParents ( value = "foo.MyClass2" , defaultImpl = HashCodeImpl.class )
  private HashCode h2 ;

  ....

}


使用AspectJ编译(可以是jar或java文件)后就可以只对需要的类进行这样的处理,
此方法对原代码没有任何改变

#24


AspectJ编译后的字节码实际上给所有经过处理的类加上了接口HashCode,接口的方法实现是HashCodeImpl中的实现

#25


mark!

#26


原来AspactJ是这样用的,谢谢flyxxxx让我们长了见识~~!!!^-^

TO treeroot:你说“要么启动的时候放到bootclasspath前面,这样引导类加载器就会加载你实现的Object,”

能不能具体讲一下,怎么把myobject.jar 启动的时候放到bootclasspath前面?你的那句命令不能运行,我在google粗略地找了一下,也没有相关的资料。谢谢了。

贴子再加10分。

#27


http://blog.csdn.net/treeroot/archive/2006/07/22/960778.aspx

#28


先收藏再研究