反射

25 篇文章 0 订阅

在说反射之前,我们先来思考一个具有争议的问题:
Java到底是不是纯面向对象语言?

如何判断呢?
只要Java中的元素能够被类所描述、能够通过实例化获取到对象,就说这是面向对象的。

因为Java中的8大基本数据类型是不能实例化对象的,比如:int a = 8;我们是不能通过a调用一个方法的,所以会有人说Java不是纯面向对象的语言。但其实Java就是一个纯面向对象的语言,因为基本类型它又有包装类型,可以调用它的包装类,这是一个类,所以它就是一个面向对象的语言,那既然有包装类,为什么还要有基本数据类型呢?这是为了体现Java的高性能,在使用的时候不用实例化对象。

首先什么是反射
反射就是通过一个类对象获取到它的类。

例:

import java.util.Date;

public class Test{
    public static void main(String[] args) {
        Date date = new Date();//通过类实例化对象
        Class ret = date.getClass();
        System.out.println(ret.getName());
    }
}

在这里插入图片描述
Class是一个泛型,那ret到底是哪一个Class呢?这就根据等号右边的对象是哪个类来判断了,如果它是Person类,那ret就是Class的Person类。

所有的类都抽象到了Class这个类中。

我们来看看下边这段代码,思考这两个Class对象是否相等。
如果相等,则一个Class类所表示的对象只有一个;如果不相等,则一个Class类所表示的对象有多个。

import java.util.Date;

public class Test{
    public static void main(String[] args) {
        Date date = new Date();//通过类实例化对象
        Class ret = date.getClass();
        System.out.println(ret.getName());

        Date date2 = new Date();//通过类实例化对象
        Class ret2 = date.getClass();
        System.out.println(ret2.getName());

        System.out.println(ret == ret2);
    }
}

在这里插入图片描述
一个class对象,在同一个类加载器中,表示同一个类的时候,它的对象只能有且只有一个

有了反射,我们构造一个对象的时候,可以不再用new构造了,可以通过Class对象的方法获取实例化对象。
例:

import java.util.Date;

public class Test{
    public static void main(String[] args) {
        Date date = new Date();//通过类实例化对象
        Class ret = date.getClass();
        //通过Class对象的方法获取实例化对象
        try {
        	//用Object类型的参数接收是因为,目前不知道是什么类型,Object是所有类的父类
            Object object = ret.newInstance();
            //判断object是不是Date类的对象
            System.out.println(object instanceof java.util.Date);
        } catch (InstantiationException e) {
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        }
    }
}

在这里插入图片描述

那如果它返回多个实例化对象,这些实例化对象是同一个吗?
我们可以验证一下:

import java.util.Date;

public class Test{
    public static void main(String[] args) throws IllegalAccessException, InstantiationException {
        Date date = new Date();//通过类实例化对象
        Class ret = date.getClass();
        Class ret2 = date.getClass();
        System.out.println(ret.newInstance() == ret2.newInstance());
    }
}

在这里插入图片描述
会发现不是同一个实例化对象,说明每次实例化的时候都会实例化一个新的对象出来。

这就是反射,不再是通过一个类创建一个对象,而是通过调用对象方法创建一个对象;可以通过对象的getClass()方法获取到Class对象。

获取Class对象的方法可不止那一个,有如下:

  1. 通过对象调用getClass()获取
Class ret = date.getClass();
  1. 通过类的全限定名.class获取
Class ret = java.util.Date.class;
  1. 通过类的全限定名字符串获取
Class ret = Class.forName("java.util.Date");

那既然可以通过对象方法就实例化一个类对象,那我们就可以想起工厂设计模式的缺陷,每添加一个新的产品就需要修改工厂类,给它new一个新添加的类的对象,但如果我们使用反射,只需要在子类中实例化一个类对象,然后传入工厂类中,这样不管你新增多少个子类,工厂类都可以不用改变。

我们以前传统的工厂设计模式:

interface IFruit{
    void eat();
}

class AppleImpl implements IFruit {

    @Override
    public void eat() {
        System.out.println("吃苹果");
    }
}

class FruitFactory{
    public static AppleImpl getInstance(String className){
        if("apple".equals(className)){
            return new AppleImpl();
        }
        return null;
    }
}

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

如果再加一个香蕉类,那它的工厂类也是要变化的:

interface IFruit{
    void eat();
}

class AppleImpl implements IFruit {

    @Override
    public void eat() {
        System.out.println("吃苹果");
    }
}

class BananaImpl implements IFruit{

    @Override
    public void eat() {
        System.out.println("吃香蕉");
    }
}

class FruitFactory{
    public static IFruit getInstance(String className){
        if("apple".equals(className)){
            return new AppleImpl();
        }else if("banana".equals(className)){
            return new BananaImpl();
        }
        return null;
    }
}

public class Test{
    public static void main(String[] args) throws IllegalAccessException, InstantiationException {
        IFruit fruit = FruitFactory.getInstance("banana");
        fruit.eat();
    }
}

这样是不是很麻烦呢?如果我们要加100类新产品,那工厂类就得new100次。

但有了反射,我们不管再加多少新种类,工厂类都可以不用变了。

interface IFruit{
    void eat();
}

class AppleImpl implements IFruit {

    @Override
    public void eat() {
        System.out.println("吃苹果");
    }
}

class BananaImpl implements IFruit{

    @Override
    public void eat() {
        System.out.println("吃香蕉");
    }
}

class FruitFactory{
    public static IFruit getInstance(String className) throws ClassNotFoundException, IllegalAccessException, InstantiationException {
        IFruit fruit = (IFruit)Class.forName(className).newInstance();
        return fruit;
    }
}

public class Test{
    public static void main(String[] args) throws IllegalAccessException, InstantiationException, ClassNotFoundException {
        IFruit fruit = FruitFactory.getInstance("www.bit.java.test.AppleImpl");
        fruit.eat();
    }
}

如果添加新类,只需要增加子类和改变传进入的类全名称即可。

如何取得类信息

取得包名称:

public class Test{
    public static void main(String[] args) {
        //获取类的包名
        Class cl = Test.class;
        Package pa = cl.getPackage();
        System.out.println("Test类的包名是:"+pa.getName());
    }
}

在这里插入图片描述

取得父类:

package www.bit.com;

class TestParent{

}

public class Test extends TestParent{
    public static void main(String[] args) {
       //获取类的包名
        Class cl = Test.class;
        Package pa = cl.getPackage();
        System.out.println("Test类的包名是:"+pa.getName());

        //获取类的父类
        Class supperClass = cl.getSuperclass();
        //获取父类的全名称
        System.out.println("Test父类的全名称为:"+supperClass.getName());
        //获取父类名称
        System.out.println("Test父类的名称为"+supperClass.getSimpleName());

        //获取类的实现接口
        Class[] interfaceArray = cl.getInterfaces();
        for(Class c : interfaceArray){
            System.out.println("Tset类实现的接口有:"+c.getName());
        }
    }
}

在这里插入图片描述

取得构造

取得构造方法的好处是什么呢?
可以通过一个Constructor对象实例化一个对象不用new,是一个通用的方法,不管是有无参的还是有参的都能处理。

import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;

class TestParent{

}

interface interface1{

}

interface interface2{

}

public class Test extends TestParent implements interface1, interface2{
    private int a;
    public Test(){

    }

    public Test(int a){
        this.a = a;
    }

    public Test(int a, String s){

    }

    public int getA(){
        return a;
    }

    public static void main(String[] args) {
        //获取类的包名
        Class cl = Test.class;
        Package pa = cl.getPackage();
/获取所有的构造方法
        //通过构造方法实例化对象,解决class.newInstance()只调用无参构造的问题
        Constructor[] constructors = cl.getConstructors();
        for(Constructor c : constructors){
            StringBuilder sb = new StringBuilder();
            for(Class classe : c.getParameterTypes()){
                sb.append(classe.getName()).append(",");
            }
            sb.setLength(sb.length() == 0 ? 0 : sb.length() - 1);
            System.out.println(c.getName() + "(" + sb.toString() + ")");
        }

        //获取某一个构造方法
        try {
            Constructor constructor = cl.getConstructor(int.class);
            Object obj = constructor.newInstance(6);
            System.out.println(obj.getClass().getName());
            Test test = (Test) obj;
            System.out.println(test.getA());
        } catch (NoSuchMethodException e) {
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        } catch (InstantiationException e) {
            e.printStackTrace();
        } catch (InvocationTargetException e) {
            e.printStackTrace();
        }
    }
}

在这里插入图片描述

通过类对象取得类方法

Method[] getMethods();
package www.bit.com;

import java.lang.reflect.Method;

class Person{
    private Integer age;
    private String name;

    public Person(){

    }

    public Person(int age, String name){
        this.age = age;
        this.name = name;
    }

    public Integer getAge() {
        return age;
    }

    public void setAge(Integer age) {
        this.age = age;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    @Override
    public String toString() {
        return "Person{" +
                "age=" + age +
                ", name='" + name + '\'' +
                '}';
    }
}

public class Test{
    public static void main(String[] args) {
        Class cl = Person.class;
        //获取cl对象的方法
        Method[] methods = cl.getMethods();
        for(Method method : methods){
            System.out.println(method.getName());
        }
    }
}

在这里插入图片描述
我们通过输出结果可以发现这些方法不仅仅只是Person类中的方法,还包括它父类的方法。
所以Method[] getMethods()这个方法获得的是取得全部的普通方法

Method[] getDeclaredMethods();//只获取自己的普通方法
package www.bit.com;

import java.lang.reflect.Method;

class Person{
    private Integer age;
    private String name;

    public Person(){

    }

    public Person(int age, String name){
        this.age = age;
        this.name = name;
    }

    public Integer getAge() {
        return age;
    }

    public void setAge(Integer age) {
        this.age = age;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    @Override
    public String toString() {
        return "Person{" +
                "age=" + age +
                ", name='" + name + '\'' +
                '}';
    }
}

public class Test{
    public static void main(String[] args) {
        Class cl = Person.class;
        //获取cl对象本类的方法
        Method[] methods = cl.getDeclaredMethods();
        for(Method method : methods){
            System.out.println(method.getName());
        }
    }
}

在这里插入图片描述

反射调用类中属性

Field[] getFields();----取得所有public权限的属性,包括父类
package www.bit.com;

import java.io.File;
import java.lang.reflect.Field;
import java.lang.reflect.Method;

class Person{
    public Integer age;
    public String name;

    public Person(){

    }

    public Person(int age, String name){
        this.age = age;
        this.name = name;
    }

    public Integer getAge() {
        return age;
    }

    public void setAge(Integer age) {
        this.age = age;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    @Override
    public String toString() {
        return "Person{" +
                "age=" + age +
                 ", name='" + name + '\'' +
                '}';
    }
}

class Student extends Person{
    public String school;

    public String getSchool() {
        return school;
    }

    public void setSchool(String school) {
        this.school = school;
    }
}

public class Test{
    public static void main(String[] args) {
        Class cl = Student.class;
        try {
            //实例化一个Student类对象
            Object studentObject = cl.newInstance();
            //获取字段
            Field[] files = cl.getFields();
            for(Field field : files) {
                System.out.println(field.getName()+" "+field.getType().getName());
            }
        } catch (InstantiationException e) {
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        }
    }
}

在这里插入图片描述

Field[] getDeclaredFields();---返回本类的属性(访问权限不限)
package www.bit.com;

import java.io.File;
import java.lang.reflect.Field;
import java.lang.reflect.Method;

class Person{
    public Integer age;
    public String name;

    public Person(){

    }

    public Person(int age, String name){
        this.age = age;
        this.name = name;
    }

    public Integer getAge() {
        return age;
    }

    public void setAge(Integer age) {
        this.age = age;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    @Override
    public String toString() {
        return "Person{" +
                "age=" + age +
                ", name='" + name + '\'' +
                '}';
    }
}

class Student extends Person{
    public String school;

    public String getSchool() {
        return school;
    }

    public void setSchool(String school) {
        this.school = school;
    }
}

public class Test{
    public static void main(String[] args) {
        Class cl = Student.class;
        try {
            //实例化一个Student类对象
            Object studentObject = cl.newInstance();
            //获取字段,只获取自己的属性(public和private)
            Field[] files = cl.getDeclaredFields();
            for(Field field : files) {
                System.out.println(field.getName()+" "+field.getType().getName());
            }
        } catch (InstantiationException e) {
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        }

在这里插入图片描述

我们还可以通过反射设置属性的值,即使这个属性被private封装也可以动态设置封装

动态设置封装:

public void setAccessible(boolean flag)---将flag换为true,即使该属性是私有的也可以通过反射修改

例:

package www.bit.com;

import java.io.File;
import java.lang.reflect.Field;
import java.lang.reflect.Method;

class Person{
    private String name;

    public Person(){

    }

    public Person(String name){
        this.name = name;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    @Override
    public String toString() {
        return "Person{" +
                "name='" + name + '\'' +
                '}';
    }
}

public class Test{
    public static void main(String[] args) {
        Class cl = Person.class;
        try {
            //实例化一个Student类对象
            Object studentObject = cl.newInstance();
            //操作school属性
            Field nameField = cl.getDeclaredField("name");
            //取消封装
            nameField.setAccessible(true);
            //更换属性值
            nameField.set(studentObject,"Calm");
            System.out.println(studentObject);
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        } catch (InstantiationException e) {
            e.printStackTrace();
        } catch (NoSuchFieldException e) {
            e.printStackTrace();
        }
    }
}

在这里插入图片描述

假如有Person per1 = new Person("Calm", 18) Person per2 = new Person();我们现在要把per1的属性值统统赋给per2,如果Person类的属性只有这两个还好说,但若有上百个属性呢?这样手工赋值还不得累死了。

反射就在这里闪亮登场了,把反射用在这最能体现它的作用,用反射只需要把per1中的所有属性取出来,再把per2的属性取出来,在per1中找per2中凡是在per1中出现的就把值赋过去,这样一个循环就可以搞定了。

:Person中有属性age、name、birthday,Student中有属性age、school、birthday,给Person中的所有属性手工赋值了,现在需要通过反射将Person中age、birthday赋给Student中得到age、birthday,因为Person中没有school属性,所以不能为school赋值。

package www.bit.com;

import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;

class Person {
    public int age;
    public String name;
    public Date birthday;

    public Person(int age, String name, Date birthday) {
        this.age = age;
        this.name = name;
        this.birthday = birthday;
    }

    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;
    }

    public Date getBirthday() {
        return birthday;
    }

    public void setBirthday(Date birthday) {
        this.birthday = birthday;
    }

    @Override
    public String toString() {
        return "Person{" +
                "age=" + age +
                ", name='" + name + '\'' +
                ", birthday=" + birthday +
                '}';
    }
}

class Student{
    public int age;
    public String school;
    public Date birthday;

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }

    public String getSchool() {
        return school;
    }

    public void setSchool(String school) {
        this.school = school;
    }

    public Date getBirthday() {
        return birthday;
    }

    public void setBirthday(Date birthday) {
        this.birthday = birthday;
    }

    @Override
    public String toString() {
        return "Student{" +
                "age=" + age +
                ", school='" + school + '\'' +
                ", birthday=" + birthday +
                '}';
    }
}

public class Test{
    public static void main(String[] args) throws ParseException {
        SimpleDateFormat sdf = new SimpleDateFormat("2001-07-03");
        Person per = new Person(18,"Calm", sdf.parse("2001-07-03"));
        Student stu = new Student();
        Class perClass = per.getClass();
        Class stuClass = stu.getClass();
        //取得Person类中的所有属性
        Field[] fields = perClass.getDeclaredFields();
        //取得Student类中的所有属性
        Field[] stuFields = stuClass.getDeclaredFields();
        for(Field s : stuFields){
            String stuFiledName = s.getName();
            //依次取得Student中每个属性的set方法
            String stuMethodName = "set"+stuFiledName.substring(0, 1).toUpperCase()
                    +(stuFiledName.length() > 1 ? stuFiledName.substring(1) : "");
            //依次取得每个属性
            for(Field f : fields){
                try {
                    //依次取得Person类中每个属性的值
                    Object value = f.get(per);
                    //依次取得每个属性的名称
                    String filedName = f.getName();
                    //得到每个属性的set方法名   例:setName  setAge  setBirthday...
                    String methodName = "set"+filedName.substring(0, 1).toUpperCase()
                            //如果属性名是一个字母,则只取第一个字母的大写,后边取空字符串
                            +(filedName.length() > 1 ? filedName.substring(1) : "");
                    //保证Student中的属性在Person中也有,例:school在Person中没有,就不能进行赋值
                    if(stuMethodName.equals(methodName)){
                        //获得Student中某个属性的set方法
                        Method setMethod = stuClass.getDeclaredMethod(methodName, f.getType());
                        //将Person中该属性的值赋给Student中的该属性,例:相当于调用Student中的setName(value)
                        setMethod.invoke(stu, value);
                    }
                } catch (IllegalAccessException e) {
                    e.printStackTrace();
                } catch (NoSuchMethodException e) {
                    e.printStackTrace();
                } catch (InvocationTargetException e) {
                    e.printStackTrace();
                }
            }
        }
        System.out.println(per);
        System.out.println(stu);
    }
}

在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值