For external users, the answer is YES. For detail, it is not completely YES. The points are:
A class is loaded by a classloader and its content is constant in the Constant Pool. You can not change a class that has already been loaded in a class loader, nor you are not allowed to load the bytecode with the same symbol name in that class loader again (though HotSpot has many hacks to enable developers to breaks this rule by UNSafe ). This should be in JVM specification.
Though #1, you still can generate a bytecode class (e.g., addition, removal, modification of class fields, methods as well as their bodies,ANY CHANGE YOU WANT) at program runtime, and then define the class by a class loader. This means, you can either generate a class from scratch or from byte[] of an existing loaded class (the one from the classloader or external inputstream) without JVM reboot. The frameworks, such as JSP servlet and other dynamic JVM languages are all this case.
Some fundamental libraries can help dynamic bytecode generation (e.g., CGLib, BCEL, Javaassist and ASM). A general approach using ASM is something like (from ASM example):
ClassWriter cw = new ClassWriter(0);
cw.visit(V1_1, ACC_PUBLIC, "Example", null, "java/lang/Object", null);
MethodVisitor mw = cw.visitMethod(ACC_PUBLIC, "", "()V", null, null);
mw.visitVarInsn(ALOAD, 0);
mw.visitMethodInsn(INVOKESPECIAL, "java/lang/Object", "", "()V",
false);
mw.visitInsn(RETURN);
mw.visitMaxs(1, 1);
mw.visitEnd();
mw = cw.visitMethod(ACC_PUBLIC + ACC_STATIC, "main",
"([Ljava/lang/String;)V", null, null);
mw.visitFieldInsn(GETSTATIC, "java/lang/System", "out",
"Ljava/io/PrintStream;");
mw.visitLdcInsn("Hello world!");
mw.visitMethodInsn(INVOKEVIRTUAL, "java/io/PrintStream", "println",
"(Ljava/lang/String;)V", false);
mw.visitInsn(RETURN);
mw.visitMaxs(2, 2);
mw.visitEnd();
byte[] code = cw.toByteArray();
//Then having a class loader loads it.
The document(http://download.forge.objectweb.org/asm/asm4-guide.pdf) should be helpful though it is obsolete.
In summary, the meanings of "not completely YES" are:
1) Create a new byte[] from byte[] of an existing loaded class, and have it loaded by another class loader. The class newly generated is not completely the same instance as the existing one (the same class name, but different body maybe).
2) //Use Constant Pool Patch to redefine the same Class in one class loader (This is out of scope, I think..)..