Java 反射机制允许你在运行时获取类的详细信息,并且调用对象的方法。它的主要作用包括:
以下代码展示了如何使用反射获取类的所有属性:
javapackage org.example;
import java.lang.reflect.Field;
import java.lang.reflect.Modifier;
public class Main {
public static void main(String[] args) {
try {
// 获取类
Class<?> c = Class.forName("java.lang.String");
// 获取所有属性
Field[] fields = c.getDeclaredFields();
StringBuffer sb = new StringBuffer();
sb.append(Modifier.toString(c.getModifiers()) + " class " + c.getSimpleName() + " {\n");
// 遍历每个属性
for (Field field : fields) {
sb.append("\t");
sb.append(Modifier.toString(field.getModifiers()) + " ");
sb.append(field.getType().getSimpleName() + " ");
sb.append(field.getName() + ";\n");
}
sb.append("}\n");
System.out.println(sb);
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
}
}
运行后,你会看到 String
类的所有属性,例如:
textpublic final class String { private final byte[] value; private final byte coder; private int hash; private boolean hashIsZero; private static final long serialVersionUID; static final boolean COMPACT_STRINGS; private static final ObjectStreamField[] serialPersistentFields; private static final char REPL; public static final Comparator CASE_INSENSITIVE_ORDER; static final byte LATIN1; static final byte UTF16; }
这些方法可以帮助你在运行时获取和操作类的信息:
javagetName():获得类的完整名字。
getFields():获得类的 public 类型的属性。
getDeclaredFields():获得类的所有属性。
getMethods():获得类的 public 类型的方法。
getDeclaredMethods():获得类的所有方法。
getMethod(String name, Class<?>... parameterTypes):获得特定的方法。
getConstructors():获得类的 public 类型的构造方法。
getConstructor(Class<?>... parameterTypes):获得特定的构造方法。
newInstance():通过类的无参构造方法创建一个新对象。
以下代码展示了如何动态调用方法:
java// 获取方法
Method method = activityClass.getMethod("setContentView", int.class);
// 调用方法
method.invoke(activity, layoutId);
javapublic Object invokeMethod(Object owner, String methodName, Object[] args) throws Exception {
Class<?> ownerClass = owner.getClass();
Class<?>[] argsClass = new Class<?>[args.length];
for (int i = 0; i < args.length; i++) {
argsClass[i] = args[i].getClass();
}
Method method = ownerClass.getMethod(methodName, argsClass);
return method.invoke(owner, args);
}
public Object invokeStaticMethod(String className, String methodName, Object[] args) throws Exception {
Class<?> ownerClass = Class.forName(className);
Class<?>[] argsClass = new Class<?>[args.length];
for (int i = 0; i < args.length; i++) {
argsClass[i] = args[i].getClass();
}
Method method = ownerClass.getMethod(methodName, argsClass);
return method.invoke(null, args);
}
Java中反射相关的类包括:
textjava.lang.Class: 代表类文件的对象 java.lang.reflect.Constructor: 代表构造方法 java.lang.reflect.Field: 代表成员变量 java.lang.reflect.Method: 代表成员方法 java.lang.reflect.Modifier: 判断方法类型 java.lang.annotation.Annotation: 代表注解
注解是Java的元数据,可以为代码提供信息。注解本身通过反射进行解释和处理。常见注解如 @Override
表示方法重写。
java@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface MyAnnotation {
String value();
}
元注解有如下类型:
java@Retention(RetentionPolicy.SOURCE) // 编译时丢弃
@Retention(RetentionPolicy.CLASS) // 默认类型,编译时可用
@Retention(RetentionPolicy.RUNTIME) // 运行时可通过反射获取
java@Target(ElementType.TYPE) // 作用于类
@Target(ElementType.FIELD) // 作用于字段
@Target(ElementType.METHOD) // 作用于方法
@Target(ElementType.PARAMETER) // 作用于参数
@Target(ElementType.CONSTRUCTOR) // 作用于构造方法
@Target(ElementType.ANNOTATION_TYPE) // 作用于注解
@Target(ElementType.PACKAGE) // 作用于包
在Android中,注解可以简化代码,尤其是视图绑定,如下所示:
java@ContentView(R.layout.activity_main)
public class MainActivity extends AppCompatActivity {
@ViewInject(R.id.button1)
private Button button1;
@ViewInject(R.id.button2)
private Button button2;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
AnnotateUtils.inject(this);
button1.setText("Button 1");
button2.setText("Button 2");
}
}
java@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
public @interface ContentView {
int value();
}
@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
public @interface ViewInject {
int value();
}
public class AnnotateUtils {
public static void inject(Activity activity) {
injectContentView(activity);
injectViews(activity);
}
private static void injectContentView(Activity activity) {
Class<? extends Activity> clazz = activity.getClass();
ContentView contentView = clazz.getAnnotation(ContentView.class);
if (contentView != null) {
try {
Method method = clazz.getMethod("setContentView", int.class);
method.invoke(activity, contentView.value());
} catch (Exception e) {
e.printStackTrace();
}
}
}
private static void injectViews(Activity activity) {
Class<? extends Activity> clazz = activity.getClass();
Field[] fields = clazz.getDeclaredFields();
for (Field field : fields) {
ViewInject viewInject = field.getAnnotation(ViewInject.class);
if (viewInject != null) {
try {
field.setAccessible(true);
field.set(activity, activity.findViewById(viewInject.value()));
} catch (Exception e) {
e.printStackTrace();
}
}
}
}
}
以上代码展示了如何通过注解简化视图绑定,从而减少冗余代码。这样可以使代码更简洁易读。
本文作者:Dong
本文链接:
版权声明:本博客所有文章除特别声明外,均采用 CC BY-NC。本作品采用《知识共享署名-非商业性使用 4.0 国际许可协议》进行许可。您可以在非商业用途下自由转载和修改,但必须注明出处并提供原作者链接。 许可协议。转载请注明出处!