1.认识反射
反射定义:指的是对象的反向处理。根据对象倒推类的组成。
-
【反射核心处理在于Object类的方法】:取得类的class对象。
public final native Class<?> getClass();
Class类描述各个类的组成(成员变量、方法、构造方法、包等等信息,利用反射技术可以对一个类进行解剖,把个个组成部分映射成一个个对象。)。
1.1 Class对象的三种实例化方式
任何一个类的Class对象由JVM加载类后产生(该对象在JVM中全局唯一,有且只有一个),用户只能调用指定方法来取得该对象。
- 任何类的对象可以通过调用Object类提供的getClass()取得该类Class对象。
- “类名称.class”可以直接根据某个具体类来取得其Class对象。
- 调用Class类的静态方法Class.forName(String className)传入类的全名称来取得其Class对象。
对照下面例子看一下:
//根据类正向产生对象
Date date = new Date();
//1.通过类对象.getClass()
System.out.println(date.getClass());
//2.通过类名称.Class
System.out.println(Date.class);
//3.通过调用Class类提供的静态方法forName(String className)
System.out.println(Class.forName("java.util.Date"));
:class java.util.Date
class java.util.Date
class java.util.Date
取得一个类的Class对象后:可以通过反射来实例化对象。
注意:在运行期间,一个类,只有一个Class对象产生。
三种方式常用第三种,第一种对象都有了还要反射干什么。第二种需要导入类的包,依赖太强,不导包就抛编译错误。一般都第三种,一个字符串可以传入也可写在配置文件中等多种方法。
- 在Class 类中有如下方法:只能调用类中无参构造且无参构造必须是public权限。
Date date = new Date();
1.取得类的Class对象
Class<Date> cls = (Class<Date>) Class.forName("java.util.Date");
2.通过反射取得Date类实例化对象
Date date = cls.newInstance();
System.out.println(date);
2.反射与类操作
2.1 反射取得父类、父接口信息
class Person{}
interface INews{}
interface IMessage{}
class Student extends Person implements INews,IMessage{}
public class Test3{
public static void main(String[] args) {
//--------------- 首先取得Class对象 ------------------
Class<Student> cls = Student.class;
//-------------- 2.1.1 取得类的包名称 ----------------
System.out.println("取得类的包名称:"+cls.getPackage().getName());
//-------------- 2.1.2 取得父类的Class对象 ------------
System.out.println("取得父类的Class对象:"+cls.getSuperclass().getName());
//-------------- 2.1.3 取得实现的父接口 -----------------
Class<?>[] classes = cls.getInterfaces();
for(Class cla : classes){
System.out.println("取得实现的父接口:"+cla.getName());
}
}
}
运行结果:
取得类的包名称:www.bit
取得父类的Class对象:www.bit.Person
取得实现的父接口:www.bit.INews
取得实现的父接口:www.bit.IMessage
2.1.1 取得类的包名称
- public Package getPackage()
2.1.2 取得父类的Class对象
- public native Class<? super T> getSuperclass();
2.1.3 取得实现的父接口
- public Class<?>[ ] getInterfaces();
特殊情况:基本类型都有自己的Class对象。
public class Test3{
public static void main(String[] args) {
Class<?> cls = int.class; //基本类型,八大基本类型都有自己的class对象
Class<?>cls1 = Integer.class;
System.out.println(cls);
System.out.println(cls1);
}
}
运行结果:
int
class java.lang.Integer
2.2 反射调用构造方法—Constructor(描述类中构造方法)
class Student {
//------------------构造方法------------------
//--- 默认的构造方法
Student(String str) {
System.out.println("(默认)的构造方法 s=" + str);
}
//--- 公有无参的构造方法
public Student() {
System.out.println("公有无参方法。");
}
//--- 公有有参的构造方法
public Student(char name) {
System.out.println("姓名: " + name);
}
//--- 有多个参数的构造方法
public Student(String name, int age) {
System.out.println("姓名:" + name + "年龄:" + age);
}
//--- 受保护的构造方法
protected Student(boolean n) {
System.out.println("受保护的有参构造 n = " + n);
}
//--- 私有有参构造方法
private Student(int age) {
System.out.println("私有的构造方法 年龄:" + age);
}
}
public class Test3{
public static void main(String[] args)throws Exception {
//首先要加载Class对象
Class<Student> cls = Student.class;
System.out.println("------------获取公有、无参的构造方法----------");
{
Constructor con = cls.getConstructor(null);
//1>、因为是无参的构造方法所以类型是一个null,不写也可以:这里需要的是一个参数的类型,切记是类型
//2>、返回的是描述这个无参构造函数的类对象。
System.out.println("con = " + con);
}
System.out.println("---------------获取公有的有参构造---------");
{
Constructor con = cls.getConstructor(char.class);
System.out.println(con);
}
System.out.println("--------------获取私有的有参构造------------");
{
Constructor con = cls.getDeclaredConstructor(int.class);
System.out.println(con);
}
System.out.println("-------------取得类中所有public构造方法-------");
{
Constructor<?>[] con = cls.getConstructors();
for(Constructor constructor : con){
System.out.println(constructor);
}
}
System.out.println("------------取得类中全部构造方法-----------");
{
Constructor<?>[] con = cls.getDeclaredConstructors();
for(Constructor constructor :con){
System.out.println(constructor);
}
}
System.out.println("-------------class类提供了实例化对象的方法---------");
{
Student per = (Student) cls.newInstance(); //第一种方式
//Object obj = cls.newInstance(); //第二种方式
}
System.out.println("************Constructor获取私有构造方法,并调用***************");
{
Constructor con = cls.getDeclaredConstructor(int.class);
System.out.println(con);
//调用构造方法
con.setAccessible(true);//暴力访问(忽略掉访问修饰符)
Object obj = con.newInstance(20);
}
}
}
运行结果:
------------获取公有、无参的构造方法----------
con = public www.bit.Student()
---------------获取公有的有参构造 a1 ---------
public www.bit.Student(char)
--------------获取所有类型(这里是私有)的有参构造 a2 ------------
private www.bit.Student(int)
-------------取得类中所有public构造方法 b1 ------
public www.bit.Student(java.lang.String,int)
public www.bit.Student(char)
public www.bit.Student()
------------取得类中全部构造方法 b2 -----------
private www.bit.Student(int)
protected www.bit.Student(boolean)
public www.bit.Student(java.lang.String,int)
public www.bit.Student(char)
public www.bit.Student()
www.bit.Student(java.lang.String)
-------------class类提供了实例化对象的方法---------
公有无参方法。
************Constructor获取私有构造方法,并调用***************
private www.bit.Student(int)
私有的构造方法 年龄:20
a) 取得类中指定参数类型的构造
- public Constructor getConstructor(Class<?> … parameterTypes):
- public Constructor getDeclaredConstructor(Class<?> … parameterTypes)
b) 取得类中所有构造方法
- public Constructor<?>[ ] getConstructors() throws SecurityException:
只能取得类中public权限的构造方法 - public Constructor<?>[ ] getDeclaredConstructors() throws SecurityException
可以取得类中全部构造方法,包含私有构造
c) Constructor类提供了实例化对象的方法:
- public T newInstance(Object … initargs):可以调用类中其他有参构造
2.3 反射调用普通方法(核心)—Method(描述类中普通方法)
a) 取得类中指定名称的普通方法
-
public Method getMethod(String name,Class<?> … parameterTypes)
需要传入<名称,参数类型>因为方法有重载
在本类以及父类中找指定参数的的Public权限 -
public Method getDeclaredMethod(String name,Class<?> … parameterTypes)
在本类中找指定参数和名称的任何权限的方法
b) 取得类中全部普通方法
-
public Method[] getMethods() throws SecurityException
取得本类以及父类中所有public方法 -
public Method[] getDeclaredMethods() throws SecurityException
取得本类中全部普通方法,包含私有方法
拿到方法之后就要进行调用,否则光拿到就没有任何意义。所以请看下面的方法
c) Method 类中提供调用类中普通方法的API
- public Object invoke(Object obj,Object … args)
2.4 反射调用类中普通属性—Field(描述类中普通属性)
a) 取得类中指定属性
-
public Field getField(String name)throws NoSuchFieldException,SecurityException
-
public Field getDeclaredFields()throws NoSuchFieldException,SecurityException
b) 取得类中全部属性
- public Field[] getFileds() throws SecurityException
取得本类以及父类中所有public属性 - public Field[] getDeclaredFields() throws SecurityException
取得本类中全部普通属性,包含私有属性
c) Field类提供设置与取得属性方法
设置属性:
- public void set(Object obj,Object value)
取得属性: - public Object get(Object obj)
取得属性类型: - public Class<?> getType()
2.5 动态设置封装
Constructor、Method、Field类都是AccessibleObject的子类。
AccessibleObject提供动态设置封装方法: (在本次JVM进程中有效,且只能通过反射,可以多次调用)
- public void setAccessible(boolean flag) throws SecurityException
true就可以访问。