反射

反射是Java中一种强大的工具,允许程序在运行时获取类的结构信息并进行操作。本文介绍了反射的概念,如何取得Class对象,以及反射在实例化对象和改善工厂模式中的应用,强调了反射在减少代码耦合方面的优势。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

反射的概念:

每个类加载到运行时数据区的时候会将类的结构信息保存到方法区中(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

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值