java基础知识(十一)java反射机制(上)

时间:2023-01-29 22:04:50

java.lang.Class类详解

java Class类详解

一、class类

  Class类是java语言定义的特定类的实现,在java中每个类都有一个相应的Class对象,以便java程序运行时系统(JVM)对所有对象进行运行时类型标识,即Class对象,JVM可以通过该对象操作相应的类(如选准正确的方法执行)。

  Class类用于封装被装入JVM中类(类或接口)的信息(类名、类型属于class、interface、enum还是annotation),是java反射机制的基础,通过Class类我们可以获得关于一个类的相关信息。

  在程序运行时,如果需要生成某个对象,这时JVM首先检测这个类的Class对象是否已经加载(关于类 的加载会咋后面讲到),如果没有,JVM就会根据文件名查找.class文件将其载入,用于创建所需要的实例。JVM为每个类管理一个独一无二的Class对象(前提使用了同一个类加载器)。

  基本数据类型(boolean、byte、char、short、int、long、float 和 double)和关键字void也对应一个Class对象。另外,每个数组属于被映射为 Class 对象的一个类,所有具有相同元素类型和维数的数组都共享该 Class 对象。

  Class 没有公共构造方法。Class 对象是在加载类时由 Java 虚拟机以及通过调用类加载器中的 defineClass 方法自动构造的,因此不能显式地声明一个Class对象。

1、获取某个类对应的Class对象的三种方法

  要想对JVM中Class对象封装的类信息进行访问,首先的获取对应类的Class对象,我们可以通过以下三种方式实现:

  a、通过Object的getClass()方法获取(所有的java对象都具备这个方法)

  b、使用.class的方式(使用类名加“.class”的方式即会返回与该类对应的Class对象,不需要创建该类的对象)

  c、使用Class.forName()方法,该方法据类名(字符串,包括类所在的包,如com.baidu.User)获取与该类关联的Class对象。

  下面是一段代码示例:

public class ObtainClass {

    public static void main(String[] args) {
try {
String str1 = "abc";
System.out.println("通过Object的getClass()方法获取 : " + str1.getClass());
System.out.println("使用.class的方式获取 : " + String.class);
System.out.println("使用Class.forName()方法获取 : " + Class.forName("java.lang.String"));
System.out.println(str1.getClass() == String.class);
System.out.println(str1.getClass() == Class.forName("java.lang.String"));
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
} }

  由上面代码可以看出,每个类都对应唯一的Class对象。

2、Class类的常用方法

public class ClassTest {
public static void main(String[] args) {
try {
System.out.println("返回与带有给定字符串名的类或接口相关联的 Class 对象 : " + Class.forName("com.classTest.classload.CTest"));
System.out.println("以 String 的形式返回此 Class 对象所表示的实体(类、接口、数组类、基本类型或 void)名称 : " + Class.forName("com.classTest.classload.CTest").getName());
System.out.println("获取此类的包 : " + Class.forName("com.classTest.classload.CTest").getPackage());
System.out.println("使用给定的类加载器,返回与带有给定字符串名的类或接口相关联的 Class 对象 : " + Class.forName("com.classTest.classload.CTest", true, ClassLoader.getSystemClassLoader()));
System.out.println("返回表示此 Class 所表示的实体(类、接口、基本类型或 void)的超类的 Class : " + Class.forName("com.classTest.classload.CTest").getSuperclass());
System.out.println("返回源代码中给出的底层类的简称 : " + Class.forName("com.classTest.classload.CTest").getSimpleName());
System.out.println("获取此类的标记 : " + Class.forName("com.classTest.classload.CTest").getSigners()); CTest ct = new CTest();
System.out.println("如果存在该元素的指定类型的注释,则返回这些注释,否则返回 null : " + ct.annotationType());
System.out.println("返回 Java Language Specification 中所定义的底层类的规范化名称 : " + Class.forName("com.classTest.classload.CTest").getCanonicalName());
System.out.println("返回一个包含某些 Class 对象的数组,这些对象表示属于此 Class 对象所表示的类的成员的所有公共类和接口 : " + Class.forName("com.classTest.classload.CTest").getClasses());
System.out.println("返回该类的类加载器 : " + Class.forName("com.classTest.classload.CTest").getClassLoader());
System.out.println("返回表示数组组件类型的 Class : " + Class.forName("com.classTest.classload.CTest").getComponentType()); System.out.println("返回一个 Constructor 对象,它反映此 Class 对象所表示的类的指定公共构造方法 : " + Class.forName("com.classTest.classload.CTest"));
System.out.println("返回一个包含某些 Constructor 对象的数组,这些对象反映此 Class 对象所表示的类的所有公共构造方法 : " + Class.forName("com.classTest.classload.CTest").getConstructors().length); System.out.println("返回一个 Field 对象,该对象反映此 Class 对象所表示的类或接口的指定已声明字段 : " + Class.forName("com.classTest.classload.CTest").getDeclaredField("age").getName());
System.out.println("返回 Field 对象的一个数组,这些对象反映此 Class 对象所表示的类或接口所声明的所有字段 : " + Class.forName("com.classTest.classload.CTest").getDeclaredFields().length);
System.out.println("返回一个 Field 对象,它反映此 Class 对象所表示的类或接口的指定公共成员字段 : " + Class.forName("com.classTest.classload.CTest").getField("str"));
System.out.println("返回一个包含某些 Field 对象的数组,这些对象反映此 Class 对象所表示的类或接口的所有可访问公共字段 : " + Class.forName("com.classTest.classload.CTest").getFields().length); System.out.println("返回一个 Method 对象,该对象反映此 Class 对象所表示的类或接口的指定已声明方法 : " + Class.forName("com.classTest.classload.CTest").getDeclaredMethod("annotationType").getName());
System.out.println("返回 Method 对象的一个数组,这些对象反映此 Class 对象表示的类或接口声明的所有方法,包括公共、保护、默认(包)访问和私有方法,但不包括继承的方法 : " + Class.forName("com.classTest.classload.CTest").getDeclaredMethods().length);
System.out.println("如果此 Class 对象表示某一方法中的一个本地或匿名类,则返回 Method 对象,它表示底层类的立即封闭方法 : " + Class.forName("com.classTest.classload.CTest").getEnclosingMethod());
System.out.println("返回一个 Method 对象,它反映此 Class 对象所表示的类或接口的指定公共成员方法 : " + Class.forName("com.classTest.classload.CTest").getMethod("annotationType"));
System.out.println("返回一个包含某些 Method 对象的数组,这些对象反映此 Class 对象所表示的类或接口(包括那些由该类或接口声明的以及从超类和超接口继承的那些的类或接口)的公共 member 方法 : " + Class.forName("com.classTest.classload.CTest").getMethods().length); System.out.println("返回此类或接口以整数编码的 Java 语言修饰符 : " + Class.forName("com.classTest.classload.CTest").getModifiers()); System.out.println("如果此 Class 对象表示一个注释类型则返回 true : " + Class.forName("com.classTest.classload.ETest").isAnnotation());
System.out.println("当且仅当底层类是匿名类时返回 true : " + Class.forName("com.classTest.classload.ETest").isAnonymousClass());
System.out.println("判定此 Class 对象是否表示一个数组类 : " + Class.forName("com.classTest.classload.ETest").isArray());
System.out.println("判定此 Class 对象所表示的类或接口与指定的 Class 参数所表示的类或接口是否相同,或是否是其超类或超接口 : " + Class.forName("com.classTest.classload.ETest").isAssignableFrom(Class.forName("com.classTest.classload.ETest")));
System.out.println("当且仅当该类声明为源代码中的枚举时返回 true : " + Class.forName("com.classTest.classload.ETest").isEnum());
System.out.println("判定指定的 Object 是否与此 Class 所表示的对象赋值兼容 : " + Class.forName("com.classTest.classload.CTest").isInstance(Class.forName("com.classTest.classload.CTest").newInstance()));
System.out.println("判定指定的 Class 对象是否表示一个接口类型 : " + Class.forName("com.classTest.classload.CTest").isInterface());
System.out.println("当且仅当底层类是本地类时返回 true : " + Class.forName("com.classTest.classload.CTest").isLocalClass());
System.out.println("当且仅当底层类是成员类时返回 true : " + Class.forName("com.classTest.classload.CTest").isMemberClass());
System.out.println("判定指定的 Class 对象是否表示一个基本类型 : " + Class.forName("com.classTest.classload.CTest").isPrimitive());
System.out.println("如果此类是复合类,则返回 true,否则 false : " + Class.forName("com.classTest.classload.CTest").isSynthetic());
System.out.println("创建此 Class 对象所表示的类的一个新实例 : " + Class.forName("com.classTest.classload.CTest").newInstance().toString());
} catch (ClassNotFoundException e) {
e.printStackTrace();
} catch (NoSuchFieldException e) {
e.printStackTrace();
} catch (NoSuchMethodException e) {
e.printStackTrace();
} catch (InstantiationException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
}
}
} class CTest implements Annotation{
private int age;
private String name;
public String str; public Class<? extends Annotation> annotationType() {
return CTest.class;
} @Override
public String toString() {
return "CTest{" +
"age=" + age +
", name='" + name + '\'' +
", str='" + str + '\'' +
'}';
}
} enum ETest{
CN,
EN
}

二、Method类

  Method 提供关于类或接口上单独某个方法(以及如何访问该方法)的信息。所反映的方法可能是类方法或实例方法(包括抽象方法)。

public class MethodTest {

    public static void main(String[] args) throws Exception {
Class clazz = Class.forName("com.classTest.classload.MT");
Method[] m = clazz.getMethods();
for (Method mh : m) {
System.out.print(mh.getName() + " | " + mh.getDefaultValue() + " | " + mh.getReturnType());
Class[] c = mh.getParameterTypes();
System.out.print(" | len = " + c.length + " | ");
for (Class tv : c) {
System.out.print(" " + tv.getName());
}
System.out.println();
} Method method = clazz.getMethod("mt", String.class);
method.invoke(clazz.newInstance(), "test method");// 对带有指定参数的指定对象调用由此 Method 对象表示的底层方法
} } class MT {
public String mt(String str) {
System.out.println(str);
return str;
}
}

三、Field类

  Field 提供有关类或接口的单个字段的信息,以及对它的动态访问权限。反射的字段可能是一个类(静态)字段或实例字段。

public class FieldTest {

    public static void main(String[] args) throws Exception {
Class clazz = Class.forName("com.classTest.classload.FT");
Field[] f = clazz.getFields();
for(Field fd : f) {
System.out.println(fd.getName() + " | " + fd.getType() + " | " + fd.getModifiers() + " | " + fd.get(""));
} } } class FT{
public static String name = "name";
public static int age = 11;
}