ClassWriter만 사용해서 클래스를 만들수 있다.

        ClassWriter cw = new ClassWriter(0);
        cw.visit(V1_5, ACC_PUBLIC + ACC_ABSTRACT + ACC_INTERFACE,
                “pkg/Comparable”, null, “java/lang/Object”,
                new String[]{“pkg/Mesurable”});
        cw.visitField(ACC_PUBLIC + ACC_FINAL + ACC_STATIC, “LESS”, “I”,
                null, new Integer(-1)).visitEnd();
        cw.visitField(ACC_PUBLIC + ACC_FINAL + ACC_STATIC, “EQUAL”, “I”,
                null, new Integer(0)).visitEnd();
        cw.visitField(ACC_PUBLIC + ACC_FINAL + ACC_STATIC, “GREATER”, “I”,
                null, new Integer(1)).visitEnd();
        cw.visitMethod(ACC_PUBLIC + ACC_ABSTRACT, “compareTo”,
                “(Ljava/lang/Object;)I”, null, null).visitEnd();
        cw.visitEnd();
        byte[] b = cw.toByteArray();
한 줄씩 살펴보자.
ClassWriter cw = new ClassWriter(0);
– ClassWriter 객체를 생성한다. 인자값 0에 대해서는 다음에 설명한단다. 다음에 읽지 뭐… @_@;
cw.visit(V1_5, ACC_PUBLIC + ACC_ABSTRACT + ACC_INTERFACE, “pkg/Comparable”, null, “java/lang/Object”, new String[]{“pkg/Mesurable”});
– 저 상수들은 import static org.objectweb.asm.Opcodes.*; 이 안에 담겨있다.
– 첫번째 인자(V1_5)는 자바 클래스 버전이다. 자바 1.5 버전으로 컴파일한 클래스를 만들게 될 것이다.
– 두번째 인자(ACC_PUBLIC + ACC_ABSTRACT + ACC_INTERFACE)는 public interface에 해당한다. 객체를 생성할 수 없으니 abstract를 선택한다.(이부분은 좀 애매함. INTERFACE인데 ABSTRACT가 꼭 들어가야 하나;;)
– 세번째 인자(“pkg/Comparable”)는 클래스 이름인데 풀패키지 경로로 설정해 줘야 한다. 그렇다고 타입명(Type descriptor)은 아니고 internal name으로 표기해준다.
– 네번째 인자(null)는 제네릭이다.
– 다섯번째 인자(“java/lang/Object”)는 상위 클래스이다. 이 때는 internal name으로 표기해준다.
– 마지막(new String[]{“pkg/Mesurable”})은 구현할 인터페이스 목록이다. 여기서도 클래스 이름을 internal name으로 표기한다.
– visit 메서드는 리턴 타입이 void다.

cw.visitField(ACC_PUBLIC + ACC_FINAL + ACC_STATIC, “LESS”, “I”

null, new Integer(-1)).visitEnd();

– 첫번째 인자는 패스.
– 두번째 인자는 필드 이름
– 세번째 인자는 타입 (여기선 int)
– 네번째 인자는 Generic
– 다섯번째 인자는 값 (여기서는 final static 값이니까 설정했지. 보통은 null)
– visitFiled 메서드의 리턴 타입은 FieldVisitor 타입 객체다. 이 뒤에 반환받은 객체로 할 일이 없으니 visitEnd() 호출한다.
cw.visitMethod(ACC_PUBLIC + ACC_ABSTRACT, “compareTo”

“(Ljava/lang/Object;)I”, null, null).visitEnd();

– 첫번째 인자는 패스
– 두번째 인자는 메서드 이름
– 세번째 인자는 메서드 시그너처 (Object를 인자로 받고 int 타입을 반환 한다.)
– 네번째는 Generic
– 다섯번째는 해당 메서드에서 던지는 예외 타입 목록
– visitMethod 메서드의 리턴 타입은 MethodVisitor 타입 객체다. 이 뒤에 반환받은 객체로 할 일이 없으니 visitEnd() 호출한다.

cw.visitEnd();
– ClassWriter로 할 일 다 했으니 visitEnd() 호출한다.

byte[] b = cw.toByteArray();
– toByteArray()를 호출하여 생성된 클래스를 바이트 배열 형태로 얻을 수 있다. 이 녀석을 ClassLaoder의 defineClass에 넘겨주면 Class 타입을 받아서 사용할 수 있다.