反射探讨(上)

此处我会提供代码来说明

以前的正向操作:实例化对象:通过类的构造方法实例化对象。
反射:根据对象来取得对象的来源信息,通过实例化对象获取创建该对象的类。
获得class类对象的三种方法:
(1)在java.lang.Object类中有一个方法:getClass()方法,所有的java对象都可以调用该方法,返回该对象所属类对应的Class对象。
(2)类名.class 调用某个类的class属性来获取该类对应的Class对象。例:Student.class将返回Student类对应的Class对象。
(3)使用Class类的forName(String className)静态方法。public static Class<?> forName(String className) throws ClassNotFoundException。
注:同一个类加载器中,一个类的Class对象只有一个。

public static void main(String[] args) {
        Date date=new Date();// 创建对象
        //class 关键字   Class 类型
        Class class1=date.getClass();  //1.getClass()方法
        System.out.println(class1);
        System.out.println(date instanceof Date);  //若date是Date类,返回true,否则返回false
        Class class2=Date.class;   //2.通过属性来获取对象.类名.class
        System.out.println(class2);

        //通过Class.forName  类的全限定名
        try{
            Class class3=Class.forName("java.util.Date");   //3.forName()
            System.out.println(class3);

            System.out.println("=====>");

            //当前三个Class对象都是描述iava.util.Date
            System.out.println(class1==class2);
            System.out.println(class2==class3);
        }catch(ClassNotFoundException e){
            e.printStackTrace();
        }
          }

三个对象描述的都是同一个
运行结果
在这里插入图片描述
工厂模式:
传统工厂模式:每增加⼀个接⼝的⼦类就需要修改⼯⼚类,违背了OCP原则
通过反射处理,就可以解决该问题
在此之前,我们所需要了解到的知识点:
(1)类可以通过构造方法实例化对象
(2)通过反射创建类的实例化对象
a.通过类的Class对象的newInstance()方法获取实例化对象(类具有无参数的构造方法)
b.类的Class对象获取构造方法的Constructor对象,通过Constructor的newInstance(…)实例化对象
工厂的实现:

   interface Clothes{
            void wear();
        }
        class Shirt implements Clothes{
            @Override
            public void wear() {
                System.out.println("穿衬衫");
            }
        }
        class Skirt implements Clothes{

            @Override
            public void wear() {
                System.out.println("穿短袖");
            }
        }
        class Pants implements Clothes{

            @Override
            public void wear() {
                System.out.println("穿牛仔裤");
            }
        }
        class ClothesFactory{
            private ClothesFactory(){

            }
            public static Clothes getClothesInstance(String className){  //工厂返回的是接口类型
                //new->具体类型耦合
                try{
                    Class class1=Class.forName(className);
                    return (Clothes)class1.newInstance();  //获取实例化对象
                } catch (IllegalAccessException e) {
                    e.printStackTrace();
                } catch (InstantiationException e) {
                    e.printStackTrace();
                } catch (ClassNotFoundException e) {
                    e.printStackTrace();
                }
                throw new RuntimeException("Factory生产不了"+className);
            }
        }
public class Factory {
        public static void main(String[] args) {
            Clothes clothes=ClothesFactory.getClothesInstance("com.zh.reflect.Skirt");
            clothes.wear();
        }
    }

引⼊反射后,每当新增接⼝⼦类,⽆需去修改⼯⼚类代码就可以很⽅便的进⾏接⼝⼦类扩容。

反射与类的操作:
在这里插入图片描述
1.取得父类信息
getPackage().getName():取得包名
getSuperclass().getName();取得类的全限定名 包名.类名
getSimpleName():只取得类名
getInterfaces():取得接口
代码实现:

public static void main(String[] args) {
    Class class1 = Test1.class; //类名.class
    System.out.println("包名:" + class1.getPackage().getName());
    System.out.println("父类:" + class1.getSuperclass().getName());//类的全限定名  包名.类名
    System.out.println("父类:" + class1.getSuperclass().getSimpleName());//只是类名
    System.out.println("========>");
    System.out.println("接口: ");
    Class[] interfaces = class1.getInterfaces();
    for (Class cls : interfaces) {
        System.out.println(cls.getName());
        System.out.println(cls.getSimpleName());
    }
}

接口以及实现接口的类和构造方法:

interface Clothes1{}
interface Message1{}
class Test1 implements Clothes1, Message1{
        public Test1(Integer a, Integer b) {  }
          public Test1(Integer a, String b) { }
        public Test1(Integer a) { }
   public Test1() { }
}

结果:
在这里插入图片描述
2.Class类通过反射实例化类对象的时候,只能够调⽤类中的⽆参构造。如果现在类中没有⽆参构造则⽆法使⽤Class类调⽤,只能够通过明确的构造调⽤实例化处理。
通过Constructor的newInstance(…)实例化对象
具体实现如下:
代码实现:

public static void main(String[] args) {
        //获取所有的构造方法
        Class class1 = Test1.class; //类名.class
        Constructor[] constructors=class1.getConstructors();
        System.out.println("获取所有的构造方法");
        for(Constructor c:constructors){
            Class[] parameterCls=c.getParameterTypes();
            String parameter= Arrays.toString(parameterCls);
            System.out.println(c.getName()+"(" + parameter + ")");
        }
        System.out.println("获取指定的构造方法");
        try{
            Constructor constructor=class1.getConstructor(Integer.class,String.class);
            System.out.println(constructor);
            //通过Constructor实例化对象
            //new Test(...)
            Object object=constructor.newInstance(20,"zhanghao"); //实例化对象
            System.out.println(object.getClass());
        }
        catch (NoSuchMethodException e) {
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        } catch (InstantiationException e) {
            e.printStackTrace();
        } catch (InvocationTargetException e) {
            e.printStackTrace();
        }
    }
}

运行结果:
在这里插入图片描述
3.反射调用普通方法:
getMethods():获取包括父类的所有方法
getDeclaredMethods():获取自己的所有方法
获取指定的方法:
步骤:
(1)用newInstance获取对象
(2)获取对象的方法,并且调用
Method method = class1.getMethod(“setName”, String.class);
Object returnVal = method.invoke(person, “zhanghao”);
此时返回的值是null,只是修改了,并没有传入值
(3)获取对象的方法,并且调用
Method getNameMethod = class1.getMethod(“getName”);
Object returnName = getNameMethod.invoke(person);
此时取值了,返回输入的值。
具体代码实现:
(1)父类和子类的属性,构造方法,普通方法实现

class Person {
    private int age;
    public String name;
    public Person() {
    }
    public Person(int age, String name) {
        this.age = age;
        this.name = name;
    }
    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{" +
                "age=" + age +
                ", name='" + name + '\'' +
                '}';
    }
}

class Student extends Person {
    private String school;
    private String skill;
    private LocalDateTime birthday;
    public String getSchool() {
        return school;
    }

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

    public String getSkill() {
        return skill;
    }

    public void setSkill(String skill) {
        this.skill = skill;
    }

    public LocalDateTime getBirthday() {
        return birthday;
    }
    public void setBirthday(LocalDateTime birthday) {
        this.birthday = birthday;
    }
    @Override
    public String toString() {
        return "Student{" +
                "school='" + school + '\'' +
                ", skill='" + skill + '\'' +
                ", birthday=" + birthday +
                "} " + super.toString();
    }

(2)获取方法的具体实现:

 public static void main1(String[] args)  {
        Class class1 = Person.class;
        System.out.println("获取包括父类的所有的方法:");
        Method[] methods = class1.getMethods();
        for (Method method : methods) {
            System.out.println(method);
        }
        System.out.println("=======>");
        System.out.println("获取自己的所有的方法: ");
        Method[] methods1 = class1.getDeclaredMethods();
        for (Method method : methods1) {
            System.out.println(method);
        }
        System.out.println("======>");
        System.out.println("获取指定的方法: ");
        try {
            Person person = (Person) class1.newInstance(); //1.获取对象
            System.out.println("before Person :" + person);
            System.out.println("=======>");
            //2.获取对象的方法,并且调用(修改)
            Method method = class1.getMethod("setName", String.class);
            Object returnVal = method.invoke(person, "zhanghao");
            System.out.println(returnVal);//null
            System.out.println("after Person: " + person);
            System.out.println("====>");
            //3.获取对象的方法,并且调用(取值)
            Method getNameMethod = class1.getMethod("getName");
            Object returnName = getNameMethod.invoke(person);
            System.out.println(returnName);
        } catch (NoSuchMethodException e) {
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        } catch (InvocationTargetException e) {
            e.printStackTrace();
        } catch (InstantiationException e) {
            e.printStackTrace();

        }
    }

运行结果:
在这里插入图片描述
(4)反射调用属性
子类继承父类的所有结构,是否能否访问取决于访问修饰符
类中的所有属性⼀定在类对象实例化之后才会进⾏空间分配,所以此时如果要想调⽤类的属性,必须保证有实例化对象。
1.getFields():返回父类和子类的公开属性
2.getDeclaredFields():返回子类的所有属性
3.public Method getDeclaredMethod(String nameClass<?>… parameterTypes):获取类中名称指定的属性,获得指定属性的具体实现看如下代码

public static void main(String[] args) {
   Class class1=Student.class;
    System.out.println("获取属性");
    System.out.println("1.====>");
    System.out.println("父类和子类的公开属性: ");
    Field[] fileds=class1.getFields() ;//返回父类和子类的公开属性
    for(Field field:fileds){
        System.out.println(field.getType() + " " + field.getName());
        System.out.println(field);
    }
    System.out.println("2====>");
    System.out.println("子类的所有属性");
    Field[] fields1=class1.getDeclaredFields() ;//返回子类的所有属性
    for(Field field:fields1){
        System.out.println(field.getType() + " " + field.getName());
        System.out.println(field);
    }

    System.out.println("=====>");
    System.out.println("获取指定属性");
    try {
        Field skillField = class1.getDeclaredField("skill");
        System.out.println(skillField);

        //使用属性
        Student student = new Student();
        student.setSkill("yuwen,shuxue,english");
        student.getSkill();
        //true表示可以访问私有的属性
        skillField.setAccessible(true);
        //get 获取
        Object skillValue = skillField.get(student);
        System.out.println(skillValue);
        //set 修改
        skillField.set(student, "pysh");  //修改
        System.out.println(student);
    } catch (NoSuchFieldException e) {
        e.printStackTrace();
    } catch (IllegalAccessException e) {
        e.printStackTrace();
    }

}

运行结果:
在这里插入图片描述

  • 5
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 3
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值