JavaSE——反射

1.初识反射

1.1.认知反射

反射指的是对象的反向处理操作,根据对象倒推类的组成,默认情况下,必须要先导入一个包,而后才能产生类的实例化对象,如下:

import java.util.Date;
public class Test {
    public static void main(String[] args) {
        Date date = new Date() ;
    }
}

以上是我们正常的关于对象的处理流程:根据包名.类名找到类,而反射的"反"指的是根据对象来取得对象的来源信息,而这个"反"的操作核心的处理就在于Object类的一个方法:取得Class对象:

public final native Class<?> getClass();

该方法返回的是一个Class类对象,这个Class描述的就是类,调用getClass()方法示例如下:

import java.util.Date;
public class Test {
    public static void main(String[] args) {
        Date date = new Date() ;
        System.out.println(date.getClass());
    }
}

此时通过对象取得了对象的来源,这就是"反"的本质,在反射的世界里面,看重的不再是一个对象,而是对象身后的组成(类、构造、普通、成员等),Class类描述接口与类的组成,Class对象由JVM在第一次加载类时产生,并且全局唯一

1.2.取得任意类Class对象的方法

Class类是描述整个类的概念,也是整个反射的操作源头,在使用Class类的时候需要关注的是这个类对象,而这个类对象的产生模式一共有三种:

  • 调用对象的getClass()取得Class对象,该方法在Object类中
  • 类名称.class取得class对象
  • Class.forName(类全名称)取得Class对象

Class.forName方法示例:

public class Test {
    public static void main(String[] args) throws ClassNotFoundException {
        Class<?> cls = Class.forName("java.util.Date") ;
        System.out.println(cls.getName());
    }
}

1.3.反射取得实例化对象

public T newInstance():通过反射实例化类对象

public class Test {
    public static void main(String[] args) throws ClassNotFoundException,
            InstantiationException, IllegalAccessException {
        Class<?> cls = Class.forName("java.util.Date") ;
        Object obj = cls.newInstance() ; // 实例化对象,等价于 new java.util.Date() ;
    }
}

取得了Class对象就意味着取得了一个指定类的操作权,除了关键字new之外,对于对象的实例化模式有了第二种做法:反射

1.4.反射vs工厂模式

工厂设计模式原则:如果是自己编写的接口,要想取得本接口的实例化对象,最好使用工厂类来设计

传统工厂类:

interface IFruit {
    public void eat() ;
}
class Apple implements IFruit {
    @Override
    public void eat() {
        System.out.println("[Apple] 吃苹果 ");
    }
}
class FruitFactory {
    private FruitFactory() {}
    public static IFruit getInstance(String className) {
        if ("apple".equals(className)) {
            return new Apple() ;
        }
        return null ;
    }
}

public class Test {
    public static void main(String[] args) {
        IFruit fruit = FruitFactory.getInstance("apple") ;
        fruit.eat() ;
    }
}

以上传统工厂有一个很大的问题:每增加一个接口的子类就需要修改工厂类去new对应的对象,如下:

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) {
        if ("apple".equals(className)) {
            return new Apple() ;
        }else if ("orange".equals(className)) {
            return new Orange() ;
        }
        return null ;
    }
}

想解决关键字new带来的问题,最好的做法就是通过反射来完成处理,因为Class类可以使用newInstance()实例化对象,同时Class.forName()能够接收类名称:

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 | IllegalAccessException |
                ClassNotFoundException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
        return fruit ;
    }
}

public class Test {
    public static void main(String[] args) {
        IFruit fruit = FruitFactory.getInstance("xpu.edu.Orange") ;
        fruit.eat() ;
    }
}
//[Orange] 吃橘子

引入反射后,每当新增接口子类,无需去修改工厂类代码就可以很方便的进行接口子类扩容。以上这种工厂类代码我们称之为简单工厂模式,反射是简单工厂的一种实现方式

2.反射与类操作

利用反射可以做出一个对象具备的所有操作行为,最为关键的是这一切的操作都可以基于Object进行

2.1.取得父类(父接口)信息

在java中任何的程序类都一定会有父类,在Class类中就可以通过如下方法来取得父类或者实现的父接口:

  • 取得类的包名称::public Package getPackage()
  • 取得父类的Class对象:public native Class<? super T> getSuperclass()
  • 取得实现的父接口:public Class<?>[] getInterfaces()

示例如下:

interface IFruit {}
interface IMessage{}
class CLS implements IFruit,IMessage{}
public class Test {
    public static void main(String[] args) {
        // 取得类对象
        Class<?> cls = CLS.class ;
        // 取得Package名称
        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());
        }
    }
}
//xpu.edu
//java.lang.Object
//xpu.edu.IFruit
//xpu.edu.IMessage

通过反射可以取得类结构上的所有关键信息

2.2.反射调用构造——Constructor(描述类构造方法信息)

猜你喜欢

转载自blog.csdn.net/LiLiLiLaLa/article/details/94774589