比如两个内部类 类名不一样 但内容可能一样 怎么比较?
有什么API可以用么?ClassComparator.compare(new Object(){}).to(new Object(){}) == true.

解决方案 »

  1.   

    package test;public   class   RunnableTest{
    private int i;
    public   static   void   main(String[]   args){
    MyThread1   mt1   =   new   MyThread1();
    MyThread2   mt2   =   new   MyThread2();
    System.out.println(mt1.getClass());
    System.out.println(mt2.getClass());
    }
    } class   MyThread1   implements   Runnable{
    Thread   th   =   new   Thread(this);
    public   void   run(){
    for   (int   i   =   0;   i   <   10;   i++){
    System.out.println(i--);
    }
    }
    } class   MyThread2{
    Thread   th   =   new   Thread(){
    public   void   run(){
    for   (int   i   =   0;   i   <   10;   i++){
    System.out.println(i--);
    }
    }
    };
    }
      

  2.   

    package test;public   class   RunnableTest{
    private int i;
    public   static   void   main(String[]   args){
    MyThread1   mt1   =   new   MyThread1();
    MyThread2   mt2   =   new   MyThread2();
    System.out.println(mt1.getClass());
    System.out.println(mt2.getClass());
    System.out.println(mt1.equals(mt2));;
    }
    } class   MyThread1   implements   Runnable{
    Thread   th   =   new   Thread(this);
    public   void   run(){
    for   (int   i   =   0;   i   <   10;   i++){
    System.out.println(i--);
    }
    }
    } class   MyThread2{
    Thread   th   =   new   Thread(){
    public   void   run(){
    for   (int   i   =   0;   i   <   10;   i++){
    System.out.println(i++);
    }
    }
    };
    }
      

  3.   

    首先我没说这个问题和编译器相关,表这么武断!再说和编译器智能又有啥关系。类似hibernate callback之类的回调类内容一样不正常么?我要缓存回调内部类处理的部分结果,ASM或者decompile肯定是可以的,如果有API的话,可以快速写个测试,看看效率。
      

  4.   

    1 你这个问题没有意义,实际项目中,今天可能“一样”,明天A就升级了
    2 如何定义一样?
    class A {
      void foo() {
      }
    }class B {
      void foo() {
        System.out.println();
      }
    }
    class A {
      void foo() {
        int count = 0;
        for (int i = 0; i < 10; i++) {
          count+= i;
        }
      }
    }class B {
      void foo() {
        int count = 0;
        for (int i = 10; i-- > 0; count+= i);
      }
    }
    一样吗,不一样吗?
      

  5.   

    可能我没表达好,或者大家习惯了回答新手问题。
    如果问的是一个技术问题,我觉得在技术层面思考最好,有没有意义,怎么断言?需求背景:WEB开发中去除DAO层,所以需要好用的助手类,比如Data.with(object).persist()。
    类似于动态语言生成实体的WRAPPER。
    查询,Data.with(Class<T>).mapper(new DataMapper()).filter(new DataFilter(){
       filter(T o){
           return o.name == "name";
       }
    }).list();
    这部分的底层实现需要检查bytecode,生成对应的SQL,生成的过程肯定冗杂,所以我需要跟据Mapper和Filter来缓存生成的SQL。如果想问为什么不用JDO或JPA,请不要回复了。
      

  6.   

    那直接用java.lang.Class/java.beans.PropertyDescriptor,去看你需要动态生成的有多少field/property,现在当前对象的值是不是空或者说哪些需要隐去
      

  7.   

    你思考缓存“相同”的class,出发点是好的,但是实际是没有意义的。试想,如果一个项目中,内容相同的class有N个,那这个项目的主管,就该打屁股了BTW,只要你动态生成的时候,能够通过判断当前值是否为空,为空就不生成,或者类似手段,理论上,你就不应该出现相同的class
      

  8.   

    我看懂了,并且真诚的告诉你,实际项目中,真有N多个class内容一致(继而生成的sql)以至于需要把这N个class视作一体的情况,真的不多见,或者说得不偿失——如果你能判断,花费的代价,还不如把他们当作不同class,直接解析
      

  9.   

    我们撇开这个问题不谈。
    你的回答强调实际项目,以你的经验出发,可你有没有想过,你的经验可能是主观的。
    我觉得回答一个技术问题,客观的分析,JDK,JVM,bytecode,不要很真诚的告诉别人,代价是什么。如果技术的代价,哪怕能让解决方案完美一小点。不值么?
    再说 我真的没有问这个需求成不成,合不合理
      

  10.   

    当然不合理了,一模一样的内容,你何必定义两个?为什么要“代码重用”,想过没有?代价的问题,我不管一样不一样,通过反射解析即可,你要分析bytecode,还要替换其中的类名,如果
    class A extends B ; class B extends C; class C extends D;
    class AA extends BB ; class BB extends CC; class CC extends DD;A == AA and so on你怎么办?
      

  11.   

    难道你们平时工程的时候,相同的代码都是ctrl-c ctrl-v,而不是归纳整理,复用?然后当功能需要调整的时候,找到这1000处相同的地方,分别修改,一不小心,改了998个,还有1个忘记了,一个改错了?
      

  12.   

    我还是这个问题,
    class A extends B ; class B extends C; class C extends D;
    class AA extends BB ; class BB extends CC; class CC extends DD;D == DD and so on
    这个例子,我问你,你怎么判断A == AA?解析A和AA,然后发现继承了B BB,如果你递归去判断父类B和BB。代价当然会很大,而得不偿失。如果你不递归判断父类,那么,你实现的半拉子工程,有什么实际意义?第二,bytecode一样情况,真的只可能是ctrl-c ctrl-v
      

  13.   

    你怎么知道,错了的那个找出来,打哭,再ctrl+x,然后关电脑!
      

  14.   

    最后回复下,我得做正经事了:)
    匿名类,代码相同很正常,不然就得使用变量,代码会UGLY。
    然后,看下class文件格式,看看会不会有点启发。
      

  15.   

    如果一样,就不该再用匿名类,而是变成外部类,参数化很正常,否则才是ugly。
    CAFEBABE没什么好看的
      

  16.   

    我们是在做一个项目,而不是helloworld。helloworld想怎么玩都可以,而做项目,就要有一定的规范。不是说不该有匿名内部类或者使用类似脚本语言的方式进行开发。而是说,当有若干个内部类(或者其他代码段)完全雷同,而且数量之多,需要你考虑到对不同class但内容相同的部分视作一体进行缓存的时候,就说明,你们的项目必须考虑把这些代码抽象出来,进行复用,否则,你们的代码将无法维护。
      

  17.   

    难道编程就只有项目和helloworld么,不可以有research性质的试探么
    我要做的的确要和scala集成,所以会有类脚本的语法。但这些和这个问题都没有关系,我想比较两个类语义上的相等,纯技术问题,和OO啥的有什么关系
      

  18.   

    我说你不懂,是因为你以你的经验为依据,跟本没看我的问题。
    如果不是基于一个类的匿名类,比较有什么意义。public class O {
    Object o1 = new Object(){
    public String toString(){
    return "o2";
    }
    };

    Object o2 = new Object(){
    public String toString(){
    return "o2";
    }
    };
    }
      

  19.   

    如果你需要写两个完全一样的类,设计上一定有问题
    你需要好好了解下匿名内部类出现的历史,假设没有匿名内部类的存在
    而有一个这样的方法someMethod(SomeInterface o)
    那么在调用这个方法的时候必须先写一个类
    class SomeInterfaceImpl implements SomeInterface {
    ...
    }
    然后调用someMethod(new SomeInterfaceImpl())
    而在GUI程序中添加事件监听时,大量地需要这种参数为某个接口的方法,而这个类通常只会生成一个对象,也就是作为方法的参数,并且其它代码不会再需要访问这个类,那么用上述的调用方式会使代码里的类数量增加,而且这些类只有一个目的,就是生成一个对象来作为参数,于是java针对这种情况引入了匿名内部类,你不再需要指定类名,编译器会自动生成类似outerClass$1、outerClass$2这样的类,并且外部无法访问,这样可以减少命名类的数量,并且代码更紧凑(例如你addMouseListener()时,在这个语句的附近就可以直接看到实现代码,而不需要到另一个类里去寻找)
    不过从LZ的经历看来,很显然匿名内部类好心办了坏事,也许是太多的别人的代码模板以及IDE的自动生成,让一些人误以为当接口(或者抽象类)作为参数时,必须要用
    someMethod(new SomeInterface{
    ...
    });
    这种方式来调用,而不知道最本质的方式,正如26所说,如果你两个匿名内部类的实现完全一样,那就不应当把它作为匿名的了,你仍然可以用内部类,保留内部类的一些优点,但是请给他一个类名
      

  20.   

    看你回复这么多,谢谢
    像你说的匿名类的好处,很对,这也是为什么要用它。至于内部类,你声明在哪一个类里呢,其它的类引用了怎么办?就会产生类的关联。
    大家OO的思想很正统,但java真的老了,OO也是。代码的可维护性,应该是根据功能来的,功能足够内聚,逻辑就不会扩散。单文件,无依赖,个人认为要比深度抽像继承引用更好。
      

  21.   

    单文件,无依赖,个人认为要比深度抽像继承引用更好。
    ====================================================
    IMHO,just MHO, “单文件,无依赖”与“正统的OO”一样,都不适合。最简单的道理,好多语言,虽然很少有像java这样经典学院派的,everything in classes,但是都是在逐渐演变的过程中,加上了类的支持。所以oo思想不是万能的,但是常见开发过程,没有oo却是万万不能的。
      

  22.   

    呵呵 说了这不是公司的项目 说了试验的目的 国内哪家公司让你scala script 
    我要做的是让JAVA更简单的支持类RAILS的持久方式,匿名类的用处相当于查询条件,对于 where id = 1。这样的语句,重复不是很正常的么?不了解需求,请不要断言。
      

  23.   

    对于Class对象的比较,在同一个域中(一般都是同一个域),只要class1==class2就可以了,虚拟机不会在同一个域中建立两个相同的Class对象,也不会重复加载两次(自己实现类装载可能会,但是Class对象只有一个)。
    如果在不同域中,从原则上来说,它们就是不同的两个Class,虽然读取的是同一个.class源文件,如果你需要认为他们相同也很简单只要比较他们的名字即可class1.getName.equals(class2.getName)
      

  24.   

    再重新整理一下思路
    1、你的目的是找出定义完全一样的类,那么引出问题2
    2、为什么会有“定义完全一样”的类存在?极有可能的根源就是某些调用者在调用一些参数为某个接口或抽象类的方法时,由于思维定势的原因,导致不会使用普通类,而只会写成匿名内部类的形式,于是产生了这样的“定义完全一样”的类
    3、就像经济学考虑问题要假设所有人都是理性经济人一样,我们不妨假设调用这些方法的程序员有95%是理性的,知道在上述情况下应该独立地定义一个命名类,有5%经验不足,写出了很多定义完全一样的匿名内部类
    4、你现在需要对这5%的情况去进行推断并优化,那就像某些程序补丁一样,不是去解决本质问题,而是采用某些方法绕过它
    5、最致命的问题在于,假设你真的完成了这个工作,但是对于上面提到的95%来说,如果某一天他真的写了两个定义完全一样的类,那应该是他有足够的理由把这两个类视为不同的类,而你做的优化却破坏了他的本意
    6、对于第5点可以举个更浅显的例子,假设某天你发现有的人会忘记写case后面的break,于是你做了个优化(不考虑能不能实现以及通过什么来实现),使得每个case里面即使没有写break也会自动加上break,通过这个优化,使得那些忘记写break的人的程序也能按照他们所想的逻辑来运行,带来了便利,但是如果有人明确知道自己不写break的case就是要继续往下的,却有可能被你错误地优化了
    说了这么多,要表达的意思就是,应该约束少部分人去不要把本应该作为一个类的写成多个类,而不是付出更高的代价来给他们打补丁,既然大家都遵守“完全限定名是一个类的唯一标识”这个规则,就不要去给少部分人开绿灯
      

  25.   

    要比较Class的内容是否一样可以分别比较Class的字段名和字段类型、方法名和方法类型(包括返回类型和参数类型)。
    下面提供我写的代码,不过个人认为这种比较没有意义。水平有限,错误之处在所难免,还望见谅。
    import java.lang.reflect.Field;
    import java.lang.reflect.Method;
    public class ClassComparator
    {
        public static boolean equals(Class one, Class two)
        {
            Field[] fOnes = one.getDeclaredFields();
            Field[] fTwos = two.getDeclaredFields();
            if(null == fOnes || null == fTwos || fOnes.length != fTwos.length)
            {
                return false;
            }
            for(int i = 0; i < fOnes.length; i++)
            {
                boolean ok = false;
                for(int j = 0; j < fTwos.length; j++)
                {
                    if(!"this$0".equals(fOnes[i].getName()) && !"this$0".equals(fTwos[i].getName()))
                    {
                        if(fOnes[i].getName().equals(fTwos[j].getName()))
                        {
                            if(fOnes[i].getType().equals(fTwos[j].getType()))
                            {
                                ok = true;
                                break;
                            }
                        }
                    }
                    else
                    {
                        ok = true;
                        break;
                    }
                }
                if(!ok)
                {
                    return false;
                }
            }
            Method[] mOnes = one.getDeclaredMethods();
            Method[] mTwos = two.getDeclaredMethods();
            if(null == mOnes || null == mTwos || mOnes.length != mTwos.length)
            {
                return false;
            }
            for(int i = 0; i < mOnes.length; i++)
            {
                boolean ok = false;
                for(int j = 0; j < mOnes.length; j++)
                {
                    if(mOnes[i].getName().equals(mTwos[j].getName()))
                    {
                        Class[] tOnes = mOnes[i].getParameterTypes();
                        Class[] tTwos = mTwos[i].getParameterTypes();
                        
                        if(tOnes.length != tTwos.length)
                        {
                            return false;
                        }
                        
                        if(0 == tOnes.length)
                        {
                            ok = true;
                            break;
                        }
                        
                        for(int k = 0; k < tOnes.length; k++)
                        {
                            if(tOnes[k] != tTwos[k])
                            {
                                return false;
                            }
                            else
                            {
                                ok = true;
                                break;
                            }
                        }
                    }
                }
                if(!ok)
                {
                    return false;
                }
            }
            return true;
        }
        public static void main(String[] args)
        {
            Class one = CA.AC.class;
            Class two = BA.AB.class;
            System.out.println(equals(one, two));
        }
      

  26.   

    我结贴了 我不是有意这么说的 我把分平分给你和shine333 当是补偿 
    两年了 再回CSDN 依然不适合我混啊 呵呵 
      

  27.   

     恩。 你试着将类序列化..然后比较byte数组行不行呢? 
      

  28.   

    LZ 如果是比较源码 可以看下JJTREE 用JJTREE分析语法树然后比较
      

  29.   

    楼层太多了,没看完。
    两个txt里面的内容会比较吗?
    把两个.java文件当作流读出来,把第一个“{”和最后一个“}”去掉(可自己设置规则)。剩下的内容拼成一个string。
    比较两个string
      

  30.   

    神马反射,神马分析,都是浮云。
    两个class相同不仅要“字面上”一样,而且加载它们的classloader也是同一个。
    不知道你的需求要不要考虑这一点。
      

  31.   


    且不论你运行时拿的到拿不到src,如果两个文件一个用空格一个用tab缩进,你怎么办?
      

  32.   

    很简单的实现,很多指令没有处理。
    /**
    package app.util;import java.io.BufferedInputStream;
    import java.io.ByteArrayOutputStream;
    import java.io.DataOutputStream;
    import java.io.IOException;
    import java.util.Arrays;
    import java.util.LinkedList;
    import java.util.List;import junit.framework.Assert;import org.junit.Test;
    import org.objectweb.asm.AnnotationVisitor;
    import org.objectweb.asm.Attribute;
    import org.objectweb.asm.ClassReader;
    import org.objectweb.asm.ClassVisitor;
    import org.objectweb.asm.FieldVisitor;
    import org.objectweb.asm.Label;
    import org.objectweb.asm.MethodVisitor;/**
     * @author feic
     *
     */
    public class Object0Test {
    @Test
    public void test(){
    boolean equal = Object0.compared(new Object(){
    public String toString(){
    return               "Hello ASM";
    }
    }).to(new Object(){
    public String toString(){
    return "Hello ASM";
    }
    });

    Assert.assertTrue(equal);

    equal = Object0.compared(new Object(){
    public String toString(){
    return "Hello Java";
    }
    }).to(new Object(){
    public String toString(){
    return "Hello ASM";
    }
    });
    Assert.assertFalse(equal);
    }
    }class Object0 {
    public static Object0 compared(Object o1){
    return new Object0(o1);
    }
    private Object o1; public Object0(Object object1) {
    super();
    this.o1 = object1;
    } public boolean to(Object o2){
    ClassReader cr1 = new ClassReader(this.getByteCode(o1.getClass()));
    ClassReader cr2 = new ClassReader(this.getByteCode(o2.getClass()));
    SortedMethodClassVisitor cv1 = new SortedMethodClassVisitor();
    cr1.accept(cv1, 0);

    SortedMethodClassVisitor cv2 = new SortedMethodClassVisitor();
    cr2.accept(cv2, 0);

    return Arrays.equals(cv1.methods.get(1), cv2.methods.get(1));
    } byte[] getByteCode(Class<?> type){
    try{
    ByteArrayOutputStream out = new ByteArrayOutputStream();
    BufferedInputStream in = new BufferedInputStream(type.getClassLoader().getResourceAsStream(type.getName().replaceAll("\\.", "/") + ".class"));
    byte[] buffer = new byte[4096];
    int read = -1;
    while((read = in.read(buffer)) != -1){
    out.write(buffer, 0, read);
    }
    in.close();
    return out.toByteArray();
    }catch(Exception e){
    throw new RuntimeException(e);
    }
    }
    class SortedMethodClassVisitor implements ClassVisitor{
    List<byte[]> methods = new LinkedList<byte[]>(); @Override
    public void visit(int arg0, int arg1, String arg2, String arg3,
    String arg4, String[] arg5) {
    } @Override
    public AnnotationVisitor visitAnnotation(String arg0, boolean arg1) {
    return null;
    } @Override
    public void visitAttribute(Attribute arg0) {
    } @Override
    public void visitEnd() {
    } @Override
    public FieldVisitor visitField(int arg0, String arg1, String arg2,
    String arg3, Object arg4) {
    return null;
    } @Override
    public void visitInnerClass(String arg0, String arg1, String arg2,
    int arg3) {
    } @Override
    public MethodVisitor visitMethod(int arg0, String arg1, String arg2,
    String arg3, String[] arg4) {
    final ByteArrayOutputStream dump = new ByteArrayOutputStream();
    MethodVisitor methodVisitor = new MethodVisitor(){
    public DataOutputStream dumpWrapper = new DataOutputStream(dump);
    @Override
    public AnnotationVisitor visitAnnotationDefault() {
    return null;
    } @Override
    public AnnotationVisitor visitAnnotation(String desc,
    boolean visible) {
    return null;
    } @Override
    public AnnotationVisitor visitParameterAnnotation(
    int parameter, String desc, boolean visible) {
    return null;
    } @Override
    public void visitAttribute(Attribute attr) {
    } @Override
    public void visitCode() {
    } @Override
    public void visitFrame(int type, int nLocal, Object[] local,
    int nStack, Object[] stack) {
    } @Override
    public void visitInsn(int opcode) {
    try {
    dumpWrapper.write(opcode);
    } catch (IOException e) {
    throw new RuntimeException(e);
    }
    } @Override
    public void visitIntInsn(int opcode, int operand) {
    try {
    dumpWrapper.write(opcode);
    dumpWrapper.write(operand);
    } catch (IOException e) {
    throw new RuntimeException(e);
    }
    } @Override
    public void visitVarInsn(int opcode, int var) {
    try {
    dumpWrapper.write(opcode);
    dumpWrapper.write(var);
    } catch (IOException e) {
    throw new RuntimeException(e);
    }
    } @Override
    public void visitTypeInsn(int opcode, String type) {
    try {
    dumpWrapper.write(opcode);
    dumpWrapper.write(type.getBytes());
    } catch (IOException e) {
    throw new RuntimeException(e);
    }
    } @Override
    public void visitFieldInsn(int opcode, String owner,
    String name, String desc) {
    try {
    dumpWrapper.write(opcode);
    dumpWrapper.write(owner.getBytes());
    dumpWrapper.write(name.getBytes());
    dumpWrapper.write(desc.getBytes());
    } catch (IOException e) {
    throw new RuntimeException(e);
    }
    } @Override
    public void visitMethodInsn(int opcode, String owner,
    String name, String desc) {
    try {
    dumpWrapper.write(opcode);
    dumpWrapper.write(owner.getBytes());
    dumpWrapper.write(name.getBytes());
    dumpWrapper.write(desc.getBytes());
    } catch (IOException e) {
    throw new RuntimeException(e);
    }
    } @Override
    public void visitJumpInsn(int opcode, Label label) { } @Override
    public void visitLabel(Label label) {
    } @Override
    public void visitLdcInsn(Object cst) {
    try {
    dumpWrapper.write(String.valueOf(cst).getBytes());
    } catch (IOException e) {
    throw new RuntimeException(e);
    }
    } @Override
    public void visitIincInsn(int var, int increment) {
    try {
    dumpWrapper.write(var);
    dumpWrapper.write(increment);
    } catch (IOException e) {
    throw new RuntimeException(e);
    }
    } @Override
    public void visitTableSwitchInsn(int min, int max, Label dflt,
    Label[] labels) {
    } @Override
    public void visitLookupSwitchInsn(Label dflt, int[] keys,
    Label[] labels) {
    } @Override
    public void visitMultiANewArrayInsn(String desc, int dims) {
    } @Override
    public void visitTryCatchBlock(Label start, Label end,
    Label handler, String type) {
    } @Override
    public void visitLocalVariable(String name, String desc,
    String signature, Label start, Label end, int index) {
    } @Override
    public void visitLineNumber(int line, Label start) {
    } @Override
    public void visitMaxs(int maxStack, int maxLocals) {
    } @Override
    public void visitEnd() {
    methods.add(dump.toByteArray());
    }
    }; try{
    dump.write(arg1.getBytes());
    }catch(Exception e){
    throw new RuntimeException(e);
    } return methodVisitor;
    } @Override
    public void visitOuterClass(String arg0, String arg1, String arg2) { } @Override
    public void visitSource(String arg0, String arg1) { } }}