反射的概念:
每个类加载到运行时数据区的时候会将类的结构信息保存到方法区中(JDK1.8之前的概念),再在堆中创建一个与被加载的类对应的特殊的对象,这个对象封装方法区中类的数据结构,可以使用该对象操作类的结构信息,这种使用Class对象操作方法区中对应的类的信息的方式就叫做反射机制
取得Class类对象:
既然要使用这个特殊的对象区操作类的信息,那么就先要取得这个对象,取得这个对象有三种方式:
1.使用类的普通对象的getClass()方法取得,该方法是继承 自Object类
2.使用Class类的静态方法forName(“类的全名称”);
3.使用“类名.Class”取得
取得Date类的Class类对象:
1.使用getClass()方法:
public class Test {
public static void main(String[] args) throws Exception {
//实例化一个Date类对象
Date date = new Date();
//使用getClass()方法取得Date类对应的Class<Date>对象
Class<?> dateClass = date.getClass();
System.out.println(dateClass);
}
}
2.使用Class类的forName()取得
public class Test {
public static void main(String[] args) throws Exception {
//使用Class<T>的静态方法forName()取得Date类对应的Class<Date>对象
Class<?> dateClass = Class.forName("java.util.Date");
System.out.println(dateClass);
}
}
3.使用Date.Class的方式取得
public class Test {
public static void main(String[] args) throws Exception {
//使用Date.class方式取得Date类对应的Class<Date>对象
Class<?> dateClass = Date.class;
System.out.println(dateClass);
}
}
以上输出的信息作用不大,只是输出之后表示该Class对象已经取得了
反射的简单实使用:
public class Test {
public static void main(String[] args) throws Exception {
//使用Date.class方式取得Date类对应的Class<Date>对象
Class<?> dateClass= Date.class;
//使用Class类对象实例化一个普通对象
Date date=(Date)dateClass.newInstance();
System.out.println(date);
}
}
此时使用反射实例化了一个Date类型的对象,那么使用new关键字不是更好用呢?分析下面的代码就知道使用反射的好处了
package com.sxt;
public class Test {
public static void main(String[] args) throws Exception {
Animal animal=AnimalFacoty.getInstance("pig");
animal.eat();
}
}
interface Animal{
public void eat();
}
//定义出子类
class Bird implements Animal{
@Override
public void eat() {
System.out.println("吃虫子");
}
}
class Pig implements Animal{
@Override
public void eat() {
System.out.println("吃食");
}
}
//定义工厂
class AnimalFacoty{
public static Animal getInstance(String animal){
if("bird".equals(animal)){
return new Bird();
}else if("pig".equals(animal)){
return new Pig();
}
return null;
}
}
以上的工厂存在什么问题呢? 假如有一万个子类,那么需要在工厂中使用if else if判断一万次,这样代码肯定不好,脆弱,应变性不高。接下来使用反射解决这个问题。
反射改善工厂:
package com.sxt;
public class Test {
public static void main(String[] args) throws Exception {
Animal animal = AnimalFacoty.getInstance("com.sxt.Bird");
animal.eat();
}
}
interface Animal{
public void eat();
}
//定义出子类
class Bird implements Animal{
@Override
public void eat() {
System.out.println("吃虫子");
}
}
class Pig implements Animal{
@Override
public void eat() {
System.out.println("吃食");
}
}
//定义工厂
class AnimalFacoty {
/**
* 使用反射实例化动物对象返回
*
* @param className 类的全名称
* @return
*/
public static Animal getInstance(String className) {
try {
//取得反射的对象(堆区中的Class<T>类对象)
Class<?> classObj = Class.forName(className);
//实例化动物对象
return (Animal) classObj.newInstance();
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
}
此时如果以后再继续增加Animal接口的 的子类也不需要再去修改工厂了,解决一定程度的耦合(在之前是使用抽象工厂解决的)
总结:
1、反射的概念:使用加载类的时候在堆区创建的与被加载的类对象的Class对象操作类的属性、方法、构造方法、注解等信息的方式叫做反射机制。
2、取得堆区中Class类对象的方式有三种:
getClass()
Class.forName()
类名.class