掌握通过反射获得类名
掌握通过反射实例化其他类的对象
掌握通过反射获得其他类中的全部构造函数
掌握获得其他类中的全部属性
掌握调用其他类中的方法
掌握通过反射操作属性
掌握通过反射取得数组的信息
Java 语言的反射机制
- 在Java运行时环境中,对于任意一个类对象,能否知道这个类有哪些属性和方法?对于任意一个对象,能否调用它的任意一个方法?答案是肯定的。这种动态获取类的信息以及动态调用对象的方法的功能来自于Java 语言的反射(Reflection)机制。
- Java 反射机制主要提供了以下功能
在运行时判断任意一个对象所属的类。
在运行时构造任意一个类的对象。
在运行时判断任意一个类所具有的成员变量和方法。
在运行时调用任意一个对象的方法
- Reflection 是Java被视为动态(或准动态)语言的一个关键性质。这个机制允许程序在运行时透过Reflection APIs取得任何一个已知名称的class的内部信息,包括其modifiers(诸如public, static 等权限)、superclass(例如Object)、实现interfaces(例如Serializable),也包括fields(属性)和methods(方法)的所有信息,并可于运行时改变fields内容或调用methods
- 一般而言,开发者社群说到动态语言,大致认同的一个定义是:“程序运行时,允许改变程序结构或变量类型,这种语言称为动态语言”。从这个观点看,Perl,Python,Ruby是动态语言,C++,Java,C#不是动态语言
- 尽管在这样的定义与分类下Java不是动态语言,它却有着一个非常突出的动态相关机制:Reflection。这个字的意思是“反射、映象、倒影”,用在Java身上指的是我们可以于运行时加载、探知、使用编译期间完全未知的classes。换句话说,Java程序可以加载一个运行时才得知名称的class,获悉其完整构造(但不包括methods定义),并生成其对象实体、或对其fields设值、或唤起其methods。这种“看透class”的能力(the ability of the program to examine itself)被称为introspection(内省、内观、反省)。Reflection和introspection是常被并提的两个术语
Java Reflection API 简介
- 在JDK中,主要由以下类来实现Java反射机制,这些类(除了Class类在java.lang包),其他类都位于java.lang.reflect包中
Class类:代表一个类。
Field 类:代表类的成员变量(成员变量也称为类的属性)。
Method类:代表类的方法。
Constructor 类:代表类的构造方法。
Array类:提供了动态创建数组,以及访问数组的元素的静态方法 - 在java.lang.Object 类中定义了getClass()方法,因此对于任意一个Java对象,都可以通过此方法获得对象的类型。Class类是Reflection API 中的核心类,它有以下方法
getName():获得类的完整名字。
getFields():获得类的public类型的属性。
getDeclaredFields():获得类的所有属性。
getMethods():获得类的public类型的方法。
getDeclaredMethods():获得类的所有方法。 - getMethod(String name, Class[] parameterTypes):获得类的特定方法,name参数指定方法的名字,parameterTypes 参数指定方法的参数类型。
- getConstructors():获得类的public类型的构造方法。
- getConstructor(Class[] parameterTypes):获得类的特定构造方法,parameterTypes 参数指定构造方法的参数类型。
- newInstance():通过类的不带参数的构造方法创建这个类的一个对象。
- (2)通过默认构造方法创建一个新对象
Object objectCopy=classType.getConstructor(new Class[]{}).newInstance(new Object[]{});
以上代码先调用Class类的getConstructor()方法获得一个Constructor 对象,它代表默认的构造方法,然后调用Constructor对象的newInstance()方法构造一个实例。 - (3)获得对象的所有属性:
Field fields[]=classType.getDeclaredFields();
Class 类的getDeclaredFields()方法返回类的所有属性,包括public、protected、默认和private访问级别的属性
获取类中的成员方法和成员变量
public static void main(String[] args) {
try {
//第一种方法
//根据类名.class属性获取该类的字节码类对象,该类对象是在虚拟机加载类时创建
Class<Student> s1 = Student.class;
Class<Student> s2 = Student.class;
//第二种方法
//调用class的静态方法,通过类的完整名称字符串forName,获取Class实例。?是不知道那个类
Class<?> s3 = Class.forName("com.test.demo46_反射.test.Student");
//第三种方法
Student s = new Student();
Class<? extends Student> s4 = s.getClass();
//获取该类中所有的公共属性
System.out.println("--------------------所有公共属性------------------");
Field[] fields = s1.getFields();
for (Field field : fields) {
System.out.println(field.getName());
}
//获取类中的所有属性
System.out.println("--------------------所有属性------------------");
Field[] fields1 = s1.getDeclaredFields();
Arrays.stream(fields1).forEach(ss -> {
System.out.print("属性修饰词 "+ Modifier.toString(ss.getModifiers()));
System.out.print("属性类型 "+ss.getType().getSimpleName());
System.out.print("属性名称 "+ss.getName());
System.out.println("\n");
});
//获取类中所有的公共方法
System.out.println("--------------------所有公共方法------------------");
Method[] methods = s1.getMethods();
Arrays.stream(methods).forEach(ss -> {
System.out.print("属性修饰词 "+ Modifier.toString(ss.getModifiers()));
System.out.print("属性类型 "+ss.getReturnType().getSimpleName());
System.out.print("属性名称 "+ss.getName());
Class<?>[] parameterTypes = ss.getParameterTypes();
System.out.print("--------------参数列表--------------");
Arrays.stream(parameterTypes).forEach(sss->{
System.out.print("属性名称 "+sss.getSimpleName());
});
System.out.println("\n");
});
//获取类中所有的方法
System.out.println("--------------------所有方法------------------");
Method[] methods1 = s1.getDeclaredMethods();
Arrays.stream(methods1).forEach(ss -> {
System.out.print("属性修饰词 "+ Modifier.toString(ss.getModifiers()));
System.out.print("属性类型 "+ss.getReturnType().getSimpleName());
System.out.print("属性名称 "+ss.getName());
System.out.println("\n");
});
System.out.println(s1 == s2);//true 单例模式
System.out.println(s1 == s3);//true 单例模式
System.out.println(s1 == s4);//true 单例模式
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
}
调用实例对象的构造方法
public static void main(String[] args) {
Class<Student> c = Student.class;
try {
// //获取公共默认无参的构造方法
// Constructor<Student> con = c.getConstructor();
// //通过构造方法生成对象
// Student student = con.newInstance();
// System.out.println(student);
// //获取公共有参数的构造方法
// Constructor<Student> con = c.getConstructor(String.class,String.class,Integer.class);
// Student student = con.newInstance("张三", "女的", 10);
// System.out.println(student);
//获取所有(包括私有)构造方法
Constructor<Student> gdc = c.getDeclaredConstructor(String.class, String.class, Integer.class);
gdc.setAccessible(true);//提供权限能够访问私有的方法
Student student = gdc.newInstance("张三", "女的", 10);
System.out.println(student);
} catch (NoSuchMethodException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (InstantiationException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
e.printStackTrace();
}
}
调用实例对象的成员方法
public static void main(String[] args) {
try {
//通过类的全限定名获取Class实例对象,
Class<?> c = Class.forName("com.entor.test.demo46_反射.test.Student");
//获取所有(包括私有)构造方法
Constructor<?> gdc = c.getDeclaredConstructor(String.class, String.class, Integer.class);
//创建类对象
gdc.setAccessible(true);
Object o = gdc.newInstance("张三", "男的", 10);
//通过反射获取指定的方法
Method setName = c.getDeclaredMethod("setName", String.class);
Method getName = c.getDeclaredMethod("getName");
getName.setAccessible(true);//私有方法需要设置访问权限
//调用方法 o 为指定到那个对象
Object in = setName.invoke(o,"乌龟");
Object invoke = getName.invoke(o);
System.out.println(invoke);
} catch (ClassNotFoundException e) {
e.printStackTrace();
} catch (NoSuchMethodException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (InstantiationException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
e.printStackTrace();
}
}