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--); } } }; }
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++); } } }; }
当然不合理了,一模一样的内容,你何必定义两个?为什么要“代码重用”,想过没有?代价的问题,我不管一样不一样,通过反射解析即可,你要分析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你怎么办?
我还是这个问题, 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
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--);
}
}
};
}
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++);
}
}
};
}
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);
}
}
一样吗,不一样吗?
如果问的是一个技术问题,我觉得在技术层面思考最好,有没有意义,怎么断言?需求背景: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,请不要回复了。
你的回答强调实际项目,以你的经验出发,可你有没有想过,你的经验可能是主观的。
我觉得回答一个技术问题,客观的分析,JDK,JVM,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你怎么办?
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
匿名类,代码相同很正常,不然就得使用变量,代码会UGLY。
然后,看下class文件格式,看看会不会有点启发。
CAFEBABE没什么好看的
我要做的的确要和scala集成,所以会有类脚本的语法。但这些和这个问题都没有关系,我想比较两个类语义上的相等,纯技术问题,和OO啥的有什么关系
如果不是基于一个类的匿名类,比较有什么意义。public class O {
Object o1 = new Object(){
public String toString(){
return "o2";
}
};
Object o2 = new Object(){
public String toString(){
return "o2";
}
};
}
你需要好好了解下匿名内部类出现的历史,假设没有匿名内部类的存在
而有一个这样的方法someMethod(SomeInterface o)
那么在调用这个方法的时候必须先写一个类
class SomeInterfaceImpl implements SomeInterface {
...
}
然后调用someMethod(new SomeInterfaceImpl())
而在GUI程序中添加事件监听时,大量地需要这种参数为某个接口的方法,而这个类通常只会生成一个对象,也就是作为方法的参数,并且其它代码不会再需要访问这个类,那么用上述的调用方式会使代码里的类数量增加,而且这些类只有一个目的,就是生成一个对象来作为参数,于是java针对这种情况引入了匿名内部类,你不再需要指定类名,编译器会自动生成类似outerClass$1、outerClass$2这样的类,并且外部无法访问,这样可以减少命名类的数量,并且代码更紧凑(例如你addMouseListener()时,在这个语句的附近就可以直接看到实现代码,而不需要到另一个类里去寻找)
不过从LZ的经历看来,很显然匿名内部类好心办了坏事,也许是太多的别人的代码模板以及IDE的自动生成,让一些人误以为当接口(或者抽象类)作为参数时,必须要用
someMethod(new SomeInterface{
...
});
这种方式来调用,而不知道最本质的方式,正如26所说,如果你两个匿名内部类的实现完全一样,那就不应当把它作为匿名的了,你仍然可以用内部类,保留内部类的一些优点,但是请给他一个类名
像你说的匿名类的好处,很对,这也是为什么要用它。至于内部类,你声明在哪一个类里呢,其它的类引用了怎么办?就会产生类的关联。
大家OO的思想很正统,但java真的老了,OO也是。代码的可维护性,应该是根据功能来的,功能足够内聚,逻辑就不会扩散。单文件,无依赖,个人认为要比深度抽像继承引用更好。
====================================================
IMHO,just MHO, “单文件,无依赖”与“正统的OO”一样,都不适合。最简单的道理,好多语言,虽然很少有像java这样经典学院派的,everything in classes,但是都是在逐渐演变的过程中,加上了类的支持。所以oo思想不是万能的,但是常见开发过程,没有oo却是万万不能的。
我要做的是让JAVA更简单的支持类RAILS的持久方式,匿名类的用处相当于查询条件,对于 where id = 1。这样的语句,重复不是很正常的么?不了解需求,请不要断言。
如果在不同域中,从原则上来说,它们就是不同的两个Class,虽然读取的是同一个.class源文件,如果你需要认为他们相同也很简单只要比较他们的名字即可class1.getName.equals(class2.getName)
1、你的目的是找出定义完全一样的类,那么引出问题2
2、为什么会有“定义完全一样”的类存在?极有可能的根源就是某些调用者在调用一些参数为某个接口或抽象类的方法时,由于思维定势的原因,导致不会使用普通类,而只会写成匿名内部类的形式,于是产生了这样的“定义完全一样”的类
3、就像经济学考虑问题要假设所有人都是理性经济人一样,我们不妨假设调用这些方法的程序员有95%是理性的,知道在上述情况下应该独立地定义一个命名类,有5%经验不足,写出了很多定义完全一样的匿名内部类
4、你现在需要对这5%的情况去进行推断并优化,那就像某些程序补丁一样,不是去解决本质问题,而是采用某些方法绕过它
5、最致命的问题在于,假设你真的完成了这个工作,但是对于上面提到的95%来说,如果某一天他真的写了两个定义完全一样的类,那应该是他有足够的理由把这两个类视为不同的类,而你做的优化却破坏了他的本意
6、对于第5点可以举个更浅显的例子,假设某天你发现有的人会忘记写case后面的break,于是你做了个优化(不考虑能不能实现以及通过什么来实现),使得每个case里面即使没有写break也会自动加上break,通过这个优化,使得那些忘记写break的人的程序也能按照他们所想的逻辑来运行,带来了便利,但是如果有人明确知道自己不写break的case就是要继续往下的,却有可能被你错误地优化了
说了这么多,要表达的意思就是,应该约束少部分人去不要把本应该作为一个类的写成多个类,而不是付出更高的代价来给他们打补丁,既然大家都遵守“完全限定名是一个类的唯一标识”这个规则,就不要去给少部分人开绿灯
下面提供我写的代码,不过个人认为这种比较没有意义。水平有限,错误之处在所难免,还望见谅。
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));
}
两年了 再回CSDN 依然不适合我混啊 呵呵
两个txt里面的内容会比较吗?
把两个.java文件当作流读出来,把第一个“{”和最后一个“}”去掉(可自己设置规则)。剩下的内容拼成一个string。
比较两个string
两个class相同不仅要“字面上”一样,而且加载它们的classloader也是同一个。
不知道你的需求要不要考虑这一点。
且不论你运行时拿的到拿不到src,如果两个文件一个用空格一个用tab缩进,你怎么办?
/**
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) { } }}