什么是反射
反射指的是对象的反向处理操作。
范例:观察正常处理
默认情况下,必须先导入一个包,而后才能产生类的实例化对象
import java.util.Date;
public class HelloB {
public static void main(String[] args) {
Date data=new Date();
}
}
所谓的反就是根据对象来取得对象的来源信息
Object类的一个方法,取得Class对象:
public final native Class<?> getClass();
范例:
import java.util.Date;
public class HelloB {
public static void main(String[] args) {
Date data=new Date();
//通过对象取得对象的来源
System.out.println(data.getClass());
}
}
所以在反射的世界里,看重的不再是一个对象,而是对象身后的组成(类,构造,普通,成员等)
Class类对象的三种实例化模式
Class类是描述整个类的概念,也是整个反射的操作源头,在使用Class类的时候需要关注的依然是这个类的对象。而这个类的对象的产生模式一共有三种:
- 任何类的实例化对象可以通过Object类中的getClass()方法取得Class类对象。
- “类.class”:直接根据某个具体的类来取得Class类的实例化对象。
- 使用Class类提供的方法:public static Class<?> forName(String className) throws ClassNotFoundException
范例:使用Class.forName方法
public class HelloB {
public static void main(String[] args)throws ClassNotFoundException {
Class<?> cls= Class.forName("java.util.Date");
//通过对象取得对象的来源
System.out.println(cls.getClass());
}
}
范例:使用类.class
import java.util.Date;
public class HelloB {
public static void main(String[] args)throws ClassNotFoundException {
//通过对象取得对象的来源
System.out.println(Date.class.getClass());
}
}
在以上给出的三个方法中我们可以发现,除了第一种方法会产生Date类的实例化对象之外,其他的两种都不会产生Date类的实例化对象。
反射实例化对象
于是取得了Class类对象有一个最直接的好处:可以通过反射实例化对象,在Class类中定义有如下方法:
public T newInstance()
throws InstantiationException, IllegalAccessException
范例:反射实例化对象
public class HelloB {
public static void main(String[] args)throws ClassNotFoundException,InstantiationException,IllegalAccessException {
Class<?> cls=Class.forName("java.util.Date");//产生类对象
System.out.println(cls);
Object obj=cls.newInstance();// 实例化对象,等价于 new java.util.Date() ;
System.out.println(obj);
}
}
我们发现除了关键字new之外,对于对象的实例化模式有了第二种做法,通过反射进行
取得了Class对象就意味着取得了一个指定类的操作权
反射与工厂模式
详细工厂模式可参考之前的文章,简单工厂模式每加一个产品的种类就要修改一次工厂类。我们可以通过反射来完成处理。
范例:
package hhh.Test;
import java.util.Date;
interface IFruit {
public void eat() ;
}
class Apple implements IFruit {
@Override
public void eat() {
System.out.println("[Apple] 吃苹果 ");
}
}
class Orange implements IFruit {
@Override
public void eat() {
System.out.println("[Orange] 吃橘子 ");
}
}
class FruitFactory{
private FruitFactory(){}
public static IFruit getInstance(String className){
IFruit fruit=null;
try {
fruit=(IFruit)Class.forName(className).newInstance();
} catch (InstantiationException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
return fruit;
}
}
public class HelloB {
public static void main(String[] args)throws ClassNotFoundException,InstantiationException,IllegalAccessException {
IFruit fruit=FruitFactory.getInstance("hhh.Test.Orange");
fruit.eat();
}
}
引入反射后,每当新增接口子类,无需去修改工厂类代码就可以很方便的进行接口子类扩容。
反射与类操作
取得父类信息
在java中任何的程序类都一定会有父类,在Class类中就可以通过如下方法来取得父类或者实现的父接口:
1.取得类的包名称: public Package getPackage();
范例:取得包名称
interface IFruit {}
interface IMessage{}
class CLS implements IFruit,IMessage{}
public class HelloB {
public static void main(String[] args)throws ClassNotFoundException,InstantiationException,IllegalAccessException {
Class<?> cls=CLS.class;//取得Class类对象
System.out.println(cls.getPackage().getName());
}
}
2.取得父类的Class对象: public native Class<? super T> getSuperclass();
3.取得实现的父接口:public Class<?>[] getInterfaces()
interface IFruit {}
interface IMessage{}
class CLS implements IFruit,IMessage{}
public class HelloB {
public static void main(String[] args)throws ClassNotFoundException,InstantiationException,IllegalAccessException {
Class<?> cls=CLS.class;//取得Class类对象
//取得包名
System.out.println(cls.getPackage().getName());
//取得父类名称
System.out.println(cls.getSuperclass().getName());
//取得实现的父类接口对象
Class<?>[] iClass=cls.getInterfaces();
for(Class<?> class1:iClass){
System.out.println(class1.getName());
}
}
}
反射调用构造
1.取得指定参数类型的构造:
public Constructor<T> getConstructor(Class<?>... parameterTypes)
throws NoSuchMethodException, SecurityException
2.取得类中的所有构造方法
public Constructor<?>[] getConstructors() throws SecurityException
以上两个方法返回的类型都是java.lang.reflect.Constructor类的实例化对象,这个类之中大家只需要关注一个方法
实例化对象:
public T newInstance(Object ... initargs)
throws InstantiationException, IllegalAccessException,
IllegalArgumentException, InvocationTargetException
范例:
import java.lang.reflect.Constructor;
import java.util.Date;
class Person{
public Person(){}
public Person(String name){}
public Person(String name,int age){}
}
public class HelloB {
public static void main(String[] args)throws ClassNotFoundException,InstantiationException,IllegalAccessException {
Class<?> cls=Person.class;//取得Class类对象
Constructor<?>[] con=cls.getConstructors();
for(Constructor<?> tmp:con){
System.out.println(tmp);
}
}
}
范例:
class Person{
private String name;
private int age;
public Person(String name, int age) {
this.name = name;
this.age = age;
}
@Override
public String toString() {
return "Person [name=" + name + ", age=" + age + "]";
}
}
public class HelloB {
public static void main(String[] args)throws ClassNotFoundException,InstantiationException,IllegalAccessException {
Class<?> cls=Person.class;//取得Class类对象
System.out.println(cls.newInstance());
}
}
所以在定义简单java类的时候一定要保留有一个无参构造。Class类通过反射实例化类对象的时候,只能够调用类中的无参构造。如果现在类中没有无参构造则无法使用Class类调用,只能够通过明确的构造调用实例化处理。
范例:通过Constructor类实例化对象
package hhh.Test;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
import java.util.Date;
class Person{
private String name;
private int age;
public Person(String name, int age) {
this.name = name;
this.age = age;
}
@Override
public String toString() {
return "Person [name=" + name + ", age=" + age + "]";
}
}
public class HelloB {
public static void main(String[] args) throws ClassNotFoundException, InstantiationException, IllegalAccessException, InvocationTargetException, NoSuchMethodException {
Class<?> cls=Person.class;//取得Class类对象
Constructor<?> con=cls.getConstructor(String.class,int.class);
System.out.println(con.newInstance("HL",18));
}
}
反射调用普通方法(核心)
1.取得全部普通方法:
public Method[] getMethods() throws SecurityException
2.取得指定普通方法
public Method getMethod(String name, Class<?>... parameterTypes)
以上两个方法范辉的类型是java.lang.reflect.Method类的对象,在此类中提供有一个调用方法的支持
public Object invoke(Object obj, Object... args)throws IllegalAccessException,
IllegalArgumentException,InvocationTargetException
范例:取得一个类中的全部普通方法
package hhh.Test;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.Date;
class Person{
private String name;
private int age;
public Person(String name, int age) {
this.name = name;
this.age = age;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
@Override
public String toString() {
return "Person [name=" + name + ", age=" + age + "]";
}
}
public class HelloB {
public static void main(String[] args) throws ClassNotFoundException, InstantiationException, IllegalAccessException, InvocationTargetException, NoSuchMethodException {
Class<?> cls=Person.class;//取得Class类对象
Method[] methods=cls.getMethods();
for(Method method:methods){
System.out.println(method);
}
}
}
范例:通过反射调用setter、getter
package hhh.Test;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.Date;
class Person{
private String name;
private int age;
public Person(){}
public Person(String name, int age) {
this.name = name;
this.age = age;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
@Override
public String toString() {
return "Person [name=" + name + ", age=" + age + "]";
}
}
public class HelloB {
public static void main(String[] args) throws ClassNotFoundException, InstantiationException, IllegalAccessException, InvocationTargetException, NoSuchMethodException {
// Class<?> cls=Class.forName("hhh.Test.Person");//取得Class类对象
Class<?> cls=Person.class;
Object obj=cls.newInstance();//实例化类对象
//取得setName这个方法的实例化对象,设置方法名称和参数模型
Method setMethod=cls.getMethod("setName",String.class);
// 随后需要通过Method类对象调用指定的方法,调用方法需要有实例化对象
// 同时传入参数
setMethod.invoke(obj,"HL");// 相当于Person对象.setName("HL") ;
Method getMethod=cls.getMethod("getName");
Object result=getMethod.invoke(obj);
System.out.println(result);
}
}
反射调用类中属性
类中的所有属性一定在类对象实例化之后才会进行空间分配,所以此时如果要想调用类的属性,必须保证有实例化对象。通过反射的newInstance()可以直接取得实例化对象(Object类型)
在Class类中提供有两组取得属性的方法:
- 第一组(父类中)-取得类中全部属性: public Field[] getFields() throws SecurityException
- 第一组(父类中)-取得类中指定名称属性: public Field getField(String name) throws
NoSuchFieldException, SecurityException- 第二组(本类中)-取得类中全部属性: public Field[] getDeclaredFields() throws SecurityException
- 第二组(本类中)-取得类中指定名称属性 : public Method getDeclaredMethod(String name, Class<?.. parameterTypes) throws NoSuchMethodException, SecurityException
范例:取得类中全部属性
package hhh.Test;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.Date;
class Person{
public String name;
public int age;
public Person(){}
public Person(String name, int age) {
this.name = name;
this.age = age;
}
}
class Student extends Person{
private int id;
public Student(){}
}
public class HelloB {
public static void main(String[] args) throws ClassNotFoundException, InstantiationException, IllegalAccessException, InvocationTargetException, NoSuchMethodException {
Class<?> cls=Student.class; //取得Class类对象
//如果父类成员变量是private属性,那么就不会被子类取得
{//普通代码块
Field[] fields=cls.getFields();
for(Field field:fields){
System.out.println(field);
}
}
System.out.println("*********************");
{
Field[] fields=cls.getDeclaredFields();
for(Field field:fields){
System.out.println(field);
}
}
}
}
属性的核心描述类:java.lang.reflect.Field,在这个类之中有两个重要方法:
- 设置属性内容 : public void set(Object obj, Object value) throws IllegalArgumentException,IllegalAccessException
- 取得属性内容 : public Object get(Object obj) throws IllegalArgumentException,IllegalAccessException
范例:通过反射操作属性
package hhh.Test;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.Date;
class Person {
public String name;
public int age;
public Person() {
}
public Person(String name, int age) {
this.name = name;
this.age = age;
}
}
public class HelloB {
public static void main(String[] args) throws ClassNotFoundException, InstantiationException, IllegalAccessException, InvocationTargetException, NoSuchMethodException, NoSuchFieldException {
Class<?> cls=Person.class; //取得Class类对象
Object obj=cls.newInstance();//实例化类对象
Field nameField=cls.getDeclaredField("name");//获取对象的成员变量
nameField.set(obj,"HL");//设置指定的变量
System.out.println(nameField.get(obj));//取得指定变量的值
}
}