概述
将类的各个组成部分封装成其他对象,称作反射机制,反射被称作是框架设计的灵魂,通过反射这面镜子来窥探类的结构,java.lang.reflect类库里面主要的类
类名 | 说明 |
---|---|
Class | 每个类都要一个对应的Class对象 |
Field | 类中的成员的变量 |
Method | 类中的方法 |
Constructor | 类的构造方法 |
Array | 提供了动态的创建数组和访问数组元素的静态方法 |
作用
在运行时判断任意一个对象所属的类。
在运行时判断任意一个类所具有的成员变量和方法。
在运行时任意调用一个对象的方法
在运行时构造任意一个类的对象
Class
Java的Class类是java反射机制的基础,通过Class类我们可以获得关于一个类的相关信息
Java.lang.Class是一个比较特殊的类,它用于封装被装入到JVM中的类(包括类和接口)的信息。当一个类或接口被装入的JVM时便会产生一个与之关联的java.lang.Class对象,可以通过这个Class对象对被装入类的详细信息进行访问。
虚拟机为每种类型管理一个独一无二的Class对象。也就是说,每个类(型)都有一个Class对象。运行程序时,Java虚拟机(JVM)首先检查是否所要加载的类对应的Class对象是否已经加载。如果没有加载,JVM就会根据类名查找.class文件,并将其Class对象载入。
**
Class类也是类的一种,Class类只有一个私有的构造函数,只有JVM可以创建Class类的实例
public final class Class<T> implements java.io.Serializable,
GenericDeclaration,
Type,
AnnotatedElement {}
Class 是首字母大写,不同于class小写,class是定义类的关键字
Java除了基本类型其他都是Class,包括interface,String,Object Runnable,Exception
Class的本质是数据类型Type,
无继承关系的数据类型无法赋值
class/insterface的数据类型是Class
每加载一个class,JVM就为其创建一个Class类型的实例,并关联起来。
JVM持有的每个Class实例都指向一个数据类型
Class对象
同一个字节码文件(*.class)在一次程序运行过程中,只会被加载一次,无论通过哪一种方式获取的Class对象都是同一个。JVM中只有唯一一个和类相对应的Class对象来描述其类型信息。
获取Class对象的三种方式:
方法 | 说明 |
---|---|
类名.class | 通过一个 Class 的静态变量 class 获取 |
对象实例.getClass () | 有该类的对象实例,该方法由 java.lang.Object 类提供 |
Class.forName (“包名.类名”) | 如果知道一个类的完整包名,可以通过 Class 类的静态方法 forName() 获得 Class 对象 |
Class.forName()
Class类的静态方法forName,Class.forName,传入参数一个类的全限定名称,它包括包名+类名,即
Class.forName("全类名")
eg:
try {
Class<?> aClass = Class.forName("cn.bx.reflect.Foo");
System.out.println(aClass);
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
类名.class
通过类名的class属性获取,主要用于参数传递
System.out.println(Foo.class);
System.out.println(int.class);
System.out.println(String.class);
输出结果
class cn.bx.reflect.Foo
int
class java.lang.String
对象.getClass()
getClass()方法在object类中定义 ,通过一个类的实例的 getClass() 方法就能获取到它的 Class。这种方法不适合基本类型如 int、float 等基本数据类型。
package cn.bx.reflect;
class Foo {
}
public class ClassObject {
public static void main(String[] args) {
Foo foo = new Foo();
Class<? extends Foo> aClass = foo.getClass();
System.out.println(aClass);
}
}
Class方法
getName()// 获取全类名
getSimpleName()
getPackage()
Class<Foo> fooClass = Foo.class;
System.out.println(fooClass.getName());
System.out.println(fooClass.getSimpleName());
System.out.println(fooClass.getCanonicalName());
Field
通过Class实例获取字段field信息:
getField(name):获取某个public的field(包括父类)
getDeclaredField(name):获取当前类的某个field(不包括父类)
getFields():获取所有public的field(包括父类)
getDeclaredFields():获取当前类的所有field(不包括父类)
class Person{
public int id;
private String name;
}
class Student extends Person{
String school;
private String grade;
protected String className;
}
public class ClassObject {
public static void main(String[] args) {
Class<Student> studentClass = Student.class;
try {
Field name = studentClass.getDeclaredField("grade");
System.out.println(name);
} catch (NoSuchFieldException e) {
e.printStackTrace();
System.out.println("getDeclaredField "+e.getMessage());
}
try {
Field name = studentClass.getField("id");
System.out.println(name);
} catch (NoSuchFieldException e) {
e.printStackTrace();
System.out.println("getField "+e.getMessage());
}
Field[] filed1 = studentClass.getDeclaredFields();
for ( Field f : filed1 ) {
System.out.println("Declared Field :"+f.getName());
}
Field[] filed2 = studentClass.getFields();
for ( Field f : filed2 ) {
System.out.println("Field :"+f.getName());
}
}
}
打印结果
private java.lang.String cn.bx.reflect.Student.grade
public int cn.bx.reflect.Person.id
Declared Field :school
Declared Field :grade
Declared Field :className
Field :id
getFields 只能获取public的方法
Class c = Person.class;
Field[] fields = c.getFields();
for (Field f :fields){
System.out.println(f);
}
getDeclaredFields()可以获取所有的成员变量 修饰符对其不影响。
Class c = Person.class;
Field[] fields = c.getDeclaredFields();
for(Field f :fields){
System.out.println(f);
}
Field对象包含一个field的所有信息:
getName()
getType()
getModifiers() // 获取修饰符
获取和设置field的值:
get(Object obj)// 获取一个实例对象的该字段的值
set(Object, Object)// 设置一个实例对象的该字段的值
Person p = new Person();
p.setGender("male");
Field f = Person.class.getField("gender");
Object value = f.get(p);
System.out.println(value);
f.set(p,"female");
System.out.println(p.getGender());
对私有变量的修改,暴力反射setAccessible(true)
Person p = new Person();
p.setName("xiaoming");
Field f = Person.class.getDeclaredField("name");
f.setAccessible(true);
Object value = f.get(p);
System.out.println(value);
f.set(p,"xiaowang");
System.out.println(p.getName());
Constructor构造方法
Java 类java.lang.reflect.Constructor实例是对类构造器(Constructor)的反射。Constructor类继承自通用抽象父类Executable,其自身是不可变(Immutable)类。
public final class Constructor<T> extends Executable
方法 | 描述 |
---|---|
Constructor<?>[] getConstructors() | 返回目标类中所有公开(public)构造方法,返回值为构造器对象数组Constructor<?>[]。 |
Constructor<?>[] getDeclaredConstructors() | 返回目标类中所有(public、private、protected、default)构造方法,返回值为构造器对象数组Constructor<?>[] |
Constructor |
根据构造方法名与参数类型取得目标构造方法对象Constructor,如果构造方法不存在,则抛出NoSuchMethodException异常 |
Constructor |
根据参数类型获取构造方法。 |
构造函数创建对象newInstance
Constructor constructor = Person.class.getConstructor(String.class,int.class);
Object p = constructor.newInstance("xiaoming",20);
Methord成员方法
Methods []getMethods // 获取所有的public成员方法(包括父类方法)
Method getMethod(String name,类<?>...parameterTypes)
Method[] getDeclaredMethods()
Method[] methods = Person.class.getDeclaredMethods();
获取方法赋值invoke
Method setName = Person.class.getMethod("setName",String.class);
Person p = new Person();
setName.invoke(p,"xiaoming");
获取成员方法名称
Method[] methods = Person.class.getMethods();
for(Method m :methods){
System.out.println(m.getName());
}
修饰符
Java 开发中定义一个类,往往是要通过许多修饰符来配合使用的。它们大致分为 4 类。
- 用来限制作用域,如 public、protected、priviate。
- 用来提示子类复写,abstract。
- 用来标记为静态类 static。
注解。
public class ClassObject {
private class Foo {
}
protected static class Bar{
}
public static void main(String[] args) {
Class<Foo> fooClass = Foo.class;
System.out.println(fooClass.getModifiers());
System.out.println(Modifier.toString(fooClass.getModifiers()));
System.out.println(Modifier.toString(Bar.class.getModifiers()));
System.out.println(Modifier.isPublic(fooClass.getModifiers()));
}
}
返回值
2
private
protected static
false
修饰符返回的是一个数字,用一个 int 数值来记录所有的修饰符,然后不同的位对应不同的修饰符
public class Modifier {
public static final int PUBLIC = 0x00000001;
public static final int PRIVATE = 0x00000002;
public static final int PROTECTED = 0x00000004;
public static final int STATIC = 0x00000008;
public static final int FINAL = 0x00000010;
public static final int SYNCHRONIZED = 0x00000020;
public static final int VOLATILE = 0x00000040;
public static final int TRANSIENT = 0x00000080;
public static final int NATIVE = 0x00000100;
public static final int INTERFACE = 0x00000200;
public static final int ABSTRACT = 0x00000400;
public static final int STRICT = 0x00000800;
public static String toString(int mod) {
StringBuilder sb = new StringBuilder();
int len;
if ((mod & PUBLIC) != 0) sb.append("public ");
if ((mod & PROTECTED) != 0) sb.append("protected ");
if ((mod & PRIVATE) != 0) sb.append("private ");
/* Canonical order */
if ((mod & ABSTRACT) != 0) sb.append("abstract ");
if ((mod & STATIC) != 0) sb.append("static ");
if ((mod & FINAL) != 0) sb.append("final ");
if ((mod & TRANSIENT) != 0) sb.append("transient ");
if ((mod & VOLATILE) != 0) sb.append("volatile ");
if ((mod & SYNCHRONIZED) != 0) sb.append("synchronized ");
if ((mod & NATIVE) != 0) sb.append("native ");
if ((mod & STRICT) != 0) sb.append("strictfp ");
if ((mod & INTERFACE) != 0) sb.append("interface ");
if ((len = sb.length()) > 0) /* trim trailing space */
return sb.toString().substring(0, len-1);
return "";
}
}