📄 classfile.java
字号:
/* * Javassist, a Java-bytecode translator toolkit. * Copyright (C) 1999-2006 Shigeru Chiba. All Rights Reserved. * * The contents of this file are subject to the Mozilla Public License Version * 1.1 (the "License"); you may not use this file except in compliance with * the License. Alternatively, the contents of this file may be used under * the terms of the GNU Lesser General Public License Version 2.1 or later. * * Software distributed under the License is distributed on an "AS IS" basis, * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License * for the specific language governing rights and limitations under the * License. */package javassist.bytecode;import java.io.DataInputStream;import java.io.DataOutputStream;import java.io.IOException;import java.util.ArrayList;import java.util.LinkedList;import java.util.List;import java.util.ListIterator;import java.util.Map;import javassist.CannotCompileException;/** * <code>ClassFile</code> represents a Java <code>.class</code> file, which * consists of a constant pool, methods, fields, and attributes. * * @see javassist.CtClass#getClassFile() */public final class ClassFile { int major, minor; // version number ConstPool constPool; int thisClass; int accessFlags; int superClass; int[] interfaces; ArrayList fields; ArrayList methods; LinkedList attributes; String thisclassname; // not JVM-internal name String[] cachedInterfaces; String cachedSuperclass; /** * Constructs a class file from a byte stream. */ public ClassFile(DataInputStream in) throws IOException { read(in); } /** * Constructs a class file including no members. * * @param isInterface * true if this is an interface. false if this is a class. * @param classname * a fully-qualified class name * @param superclass * a fully-qualified super class name */ public ClassFile(boolean isInterface, String classname, String superclass) { major = 45; minor = 3; // JDK 1.1 or later constPool = new ConstPool(classname); thisClass = constPool.getThisClassInfo(); if (isInterface) accessFlags = AccessFlag.SUPER | AccessFlag.INTERFACE | AccessFlag.ABSTRACT; else accessFlags = AccessFlag.SUPER; initSuperclass(superclass); interfaces = null; fields = new ArrayList(); methods = new ArrayList(); thisclassname = classname; attributes = new LinkedList(); attributes.add(new SourceFileAttribute(constPool, getSourcefileName(thisclassname))); } private void initSuperclass(String superclass) { if (superclass != null) { this.superClass = constPool.addClassInfo(superclass); cachedSuperclass = superclass; } else { this.superClass = constPool.addClassInfo("java.lang.Object"); cachedSuperclass = "java.lang.Object"; } } private static String getSourcefileName(String qname) { int index = qname.lastIndexOf('.'); if (index >= 0) qname = qname.substring(index + 1); return qname + ".java"; } /** * Eliminates dead constant pool items. If a method or a field is removed, * the constant pool items used by that method/field become dead items. This * method recreates a constant pool. */ public void compact() { ConstPool cp = compact0(); ArrayList list = methods; int n = list.size(); for (int i = 0; i < n; ++i) { MethodInfo minfo = (MethodInfo)list.get(i); minfo.compact(cp); } list = fields; n = list.size(); for (int i = 0; i < n; ++i) { FieldInfo finfo = (FieldInfo)list.get(i); finfo.compact(cp); } attributes = AttributeInfo.copyAll(attributes, cp); constPool = cp; } private ConstPool compact0() { ConstPool cp = new ConstPool(thisclassname); thisClass = cp.getThisClassInfo(); String sc = getSuperclass(); if (sc != null) superClass = cp.addClassInfo(getSuperclass()); if (interfaces != null) { int n = interfaces.length; for (int i = 0; i < n; ++i) interfaces[i] = cp.addClassInfo(constPool.getClassInfo(interfaces[i])); } return cp; } /** * Discards all attributes, associated with both the class file and the * members such as a code attribute and exceptions attribute. The unused * constant pool entries are also discarded (a new packed constant pool is * constructed). */ public void prune() { ConstPool cp = compact0(); LinkedList newAttributes = new LinkedList(); AttributeInfo invisibleAnnotations = getAttribute(AnnotationsAttribute.invisibleTag); if (invisibleAnnotations != null) { invisibleAnnotations = invisibleAnnotations.copy(cp, null); newAttributes.add(invisibleAnnotations); } AttributeInfo visibleAnnotations = getAttribute(AnnotationsAttribute.visibleTag); if (visibleAnnotations != null) { visibleAnnotations = visibleAnnotations.copy(cp, null); newAttributes.add(visibleAnnotations); } ArrayList list = methods; int n = list.size(); for (int i = 0; i < n; ++i) { MethodInfo minfo = (MethodInfo)list.get(i); minfo.prune(cp); } list = fields; n = list.size(); for (int i = 0; i < n; ++i) { FieldInfo finfo = (FieldInfo)list.get(i); finfo.prune(cp); } attributes = newAttributes; cp.prune(); constPool = cp; } /** * Returns a constant pool table. */ public ConstPool getConstPool() { return constPool; } /** * Returns true if this is an interface. */ public boolean isInterface() { return (accessFlags & AccessFlag.INTERFACE) != 0; } /** * Returns true if this is a final class or interface. */ public boolean isFinal() { return (accessFlags & AccessFlag.FINAL) != 0; } /** * Returns true if this is an abstract class or an interface. */ public boolean isAbstract() { return (accessFlags & AccessFlag.ABSTRACT) != 0; } /** * Returns access flags. * * @see javassist.bytecode.AccessFlag */ public int getAccessFlags() { return accessFlags; } /** * Changes access flags. * * @see javassist.bytecode.AccessFlag */ public void setAccessFlags(int acc) { accessFlags = acc | AccessFlag.SUPER; } /** * Returns access and property flags of this nested class. * This method returns -1 if the class is not a nested class. * * <p>The returned value is obtained from <code>inner_class_access_flags</code> * of the entry representing this nested class itself * in <code>InnerClasses_attribute</code>>. */ public int getInnerAccessFlags() { InnerClassesAttribute ica = (InnerClassesAttribute)getAttribute(InnerClassesAttribute.tag); if (ica == null) return -1; String name = getName(); int n = ica.tableLength(); for (int i = 0; i < n; ++i) if (name.equals(ica.innerClass(i))) return ica.accessFlags(i); return -1; } /** * Returns the class name. */ public String getName() { return thisclassname; } /** * Sets the class name. This method substitutes the new name for all * occurrences of the old class name in the class file. */ public void setName(String name) { renameClass(thisclassname, name); } /** * Returns the super class name. */ public String getSuperclass() { if (cachedSuperclass == null) cachedSuperclass = constPool.getClassInfo(superClass); return cachedSuperclass; } /** * Returns the index of the constant pool entry representing the super * class. */ public int getSuperclassId() { return superClass; } /** * Sets the super class. * * <p> * This method modifies constructors so that they call constructors declared * in the new super class. */ public void setSuperclass(String superclass) throws CannotCompileException { if (superclass == null) superclass = "java.lang.Object"; try { this.superClass = constPool.addClassInfo(superclass); ArrayList list = methods; int n = list.size(); for (int i = 0; i < n; ++i) { MethodInfo minfo = (MethodInfo)list.get(i); minfo.setSuperclass(superclass); } } catch (BadBytecode e) { throw new CannotCompileException(e); } cachedSuperclass = superclass; } /** * Replaces all occurrences of a class name in the class file. * * <p> * If class X is substituted for class Y in the class file, X and Y must * have the same signature. If Y provides a method m(), X must provide it * even if X inherits m() from the super class. If this fact is not * guaranteed, the bytecode verifier may cause an error. * * @param oldname * the replaced class name * @param newname * the substituted class name */ public final void renameClass(String oldname, String newname) { ArrayList list; int n; if (oldname.equals(newname)) return; if (oldname.equals(thisclassname)) thisclassname = newname; oldname = Descriptor.toJvmName(oldname); newname = Descriptor.toJvmName(newname); constPool.renameClass(oldname, newname); list = methods; n = list.size(); for (int i = 0; i < n; ++i) { MethodInfo minfo = (MethodInfo)list.get(i); String desc = minfo.getDescriptor(); minfo.setDescriptor(Descriptor.rename(desc, oldname, newname)); } list = fields; n = list.size(); for (int i = 0; i < n; ++i) { FieldInfo finfo = (FieldInfo)list.get(i); String desc = finfo.getDescriptor(); finfo.setDescriptor(Descriptor.rename(desc, oldname, newname)); } } /** * Replaces all occurrences of several class names in the class file. * * @param classnames * specifies which class name is replaced with which new name. * Class names must be described with the JVM-internal * representation like <code>java/lang/Object</code>. * @see #renameClass(String,String) */ public final void renameClass(Map classnames) { String jvmNewThisName = (String)classnames.get(Descriptor .toJvmName(thisclassname)); if (jvmNewThisName != null) thisclassname = Descriptor.toJavaName(jvmNewThisName); constPool.renameClass(classnames);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -