反射
1. 反射的引入
//正向操作(根据类new出对象)
class Test1 {
public static void main(String[] args) {
Date date = new Date();
System.out.println(date);
}
}
在之前我们一直使用的是 new类名()来获取对象,即在上例中所谓的“正向操作”。那么我们如何根据对象来获取对象的信息呢,接下来我们就将引入反射机制。
反射:即根据已有类的对象反推类的组成,是所有Java框架的基础,没有反射就没有JavaEE框架。“反”指的是根据对象来获取对象的来源信息,此操作核心在于Object类的的一个方法:getClass()方法:获取Class对象。
class与Class:
class:定义类的关键字。
Class:(class Class)是一个类,描述具体类的组成信息。Class类由JVM产生,当类加载的时候,JVM会产生该类的唯一Class类对象。
类加载过程:反射的基本原理与Class对象
class Test1 {
public static void main(String[] args){
Date date1 = new Date();
Date date2 = new Date();
System.out.println(date1.getClass() == date2.getClass());
}
}
运行结果:true(因为是由同一个类产生的对象)
2. 反射的使用
(1)获取Class对象的三种方式
a. 使用Object类的getClass()方法获取当前对象的Class实例
b. 使用类的class属性(任何数据类型(包括基本数据类型)都有一个静态的class属性)
c. 调用Class对象的静态方法:forName(“类的全名称”)
在运行期间,一个类只有一个Class对象产生。
/*
* 获取Class对象的三种方式(以Date类为例)
* */
public class Test1{
public static void main(String[] args) {
//new后产生一个Date()对象和一个Class对象
Date date = new Date();
//1.使用Object类的getClass()方法获取当前对象的Class实例
Class<?> class1 = date.getClass();
System.out.println(class1.getName());
//2.使用类的class属性获取当前对象的Class实例
Class<?> class2 = Date.class;
//判断第一种方式获取的Class对象是否和本次获取的为同一对象
System.out.println(class1.getName() ==class2.getName());
//3.调用Class对象的静态方法:forName(“类的全名称”)获取当前对象的Class实例
try {
//方法中的字符串必须是真实名称带包名的类路径,即 包名.类名
Class<?> class3 = Class.forName("java.util.Date");
//判断第二次获取的Class对象是否和本次获取的为同一对象
System.out.println(class2.getName() == class3.getName());
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
}
}
(2)利用反射创建对象
创建对象的方式:
正向处理:利用new 类名( ) 操作。
反射处理:利用Class对象的newInstance()操作。
public class Test1{
public static void main(String[] args) {
//正向创建对象
Date date1 = new Date();
System.out.println(date1);
//获取Class对象
Class<?> class1 = date1.getClass();
try {
//通过反射进行类实例化对象的创建
Object object = class1.newInstance();
System.out.println(object);
} catch (InstantiationException | IllegalAccessException e) {
e.printStackTrace();
}
}
}
3. 反射与类操作
利用反射可以做出一个对象的所有操作行为,关键是这一切都基于Object进行。
(1)取得父类信息
在Java中任何类都有父类,在Class类中就可以通过如下方式得到父类或实现的父接口信息。
a. 取得包名称:public Package getPackage() 方法
b. 取得父类信息:public native Class<?> super <? super T> getSuperclass()
c. 取得所有父接口信息:public Class<?> [ ] getInterfaces()
/*
* 反射与类操作
* */
//取得父类信息
interface IFruit{}
interface IMessage{}
class Apple1 {}
class Apple extends Apple1 implements IFruit,IMessage{}
public class Test1{
public static void main(String[] args) {
//取得Apple对象
Class<?> class1 = Apple.class;
System.out.println(class1.getName());
//取得包名(返回值为package类型) class.包名
Package package1 = class1.getPackage();
System.out.println("包名: "+ package1.getName());
//取得父类信息(返回值仍为Class)
Class<?> superClassName = class1.getSuperclass();
System.out.println("父类:"+ superClassName.getName());
//取得所有接口信息(返回值为Class数组)
Class<?> [] classes = class1.getInterfaces();
for(Class<?> class0:classes) {
System.out.println("接口: "+ class0.getName());
}
}
}
(2)反射调用构造方法
一个类中可以有多个构造方法,我们可以使用Class类中的如下方来获取构造方法。
以下方法返回的类型都是java.lang.reflect.Constructor类的实例化对象。
a. 取得指定参数的构造方法:
取得类中指定参数访权限为public的构造方法:
public Constructor<T> getConstructor(Class<?>... parameterTypes)
取得类中指定参数的构造方法(任意访问权限):
Public Constructor<T> getDeclaredConstructor(Class<?>... parameterTypes)
b. 取得类中所有构造方法
取得类中所有访问权限为public的构造方法:
public Constructor<?>[] getConstructors() throws SecurityException
取得类中所有的构造方法(任意访问权限):
public Constructor<?>[] getDeclaredConstructors() throws SecurityException
//反射调用构造
class Person{
private String name;
int age;
char gender;
//默认的构造方法
Person(String string){
System.out.println("默认构造方法"+string);
}
//无参构造方法
public Person() {
super();
System.out.println("调用公有的无参构造");
}
//带一个参数的构造方法
public Person(char gender) {
super();
this.gender = gender;
System.out.println("调用公有的带一个参数的有参构造");
}
//带多个参数的构造方法
public Person(String name, int age) {
super();
this.name = name;
this.age = age;
System.out.println("调用公有的带多个参数的有参构造");
}
//受保护的构造方法
protected Person(boolean n){
System.out.println("受保护的构造方法 n = " + n);
System.out.println("调用受保护的有参构造");
}
//私有构造方法
private Person(int age) {
super();
this.age = age;
System.out.println("调用私有的有参构造");
}
}
public class Test1{
public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException, SecurityException {
Class<?> class2 = Person.class;
Object object = null;
try {
//默认调用类的无参构造,若不含有无参构造则会报错 java.lang.InstantiationException
object = class2.newInstance();
System.out.println(object);
} catch (InstantiationException | IllegalAccessException e) {
e.printStackTrace();
}
System.out.println();
//通过Constructor类创建实例化对象
//加载Class对象
Class<?> class1 = Class.forName("reflect.Person");
//取得类中指定参数访权限为public的构造方法
Constructor<?> constructor = class1.getConstructor(String.class,int.class);
System.out.println("\n**************获得访问权限为public的指定构造方法************\n");
System.out.println(constructor);
//取得类中指定参数的构造方法(任意访问权限)
Constructor<?> constructor2 = class1.getDeclaredConstructor(boolean.class);
System.out.println("\n**************获得任意访问权限的指定构造方法************\n");
System.out.println(constructor2);
//取得类中所有访问权限为public的构造方法
Constructor<?> [] constructors = class1.getConstructors();
System.out.println("\n**************获得访问权限为public的所有构造方法************\n");
for (Constructor<?> constructor1 : constructors) {
System.out.println(constructor1);
}
//取得类中所有的构造方法(任意访问权限)
Constructor<?> [] constructors2 = class1.getDeclaredConstructors();
System.out.println("\n**************获得任意访问权限的所有构造方法************\n");
for (Constructor<?> constructor1 : constructors2) {
System.out.println(constructor1);
}
}
}
以上的操作是直接利用了Constructor类中的toString()方法取得了构造方法的完整信息(包含方法权限,参数列 表),而如果你只使用了getName()方法,只会返回构造方法的包名.类名。