Java反射机制(一)

一、认识反射机制

1.初识反射

反射是对对象的反向处理操作。

下面我们观察正向创建对象和反向创建对象的操作,进一步加深对反射的理解。

//正向获取Date对象
Date date=new Date();
//反向获取Date对象
Class classz=Date.class;
Object date=claz.newInstance();

正向获取对象就是通过对已知的一个类,直接new出一个对象。而反向创建对象是先获取该类的class对象,然后通过class对象的newInstance()来获取Date对象。那么,这两种方式得到的对象有什么联系吗?看看下面的代码

 Date date=new Date();
 Class claz=Date.class;
 Object date1=claz.newInstance();
 System.out.println(date==date1);//false

这段代码运行的结果为false,说明通过正向创建和反向创建获取的不是同一个对象。其实这也不难理解,因为一个类(除单例外)可以有多个对象,我们不断new 和调用class对象的newInstance()得到的对象始终是一个新的对象,和之前创建的对象没有任何关系。但是这并不是说它们没有任何关系,毕竟它们都是Date类,再看下面的代码

public final native Class<?> getClass();//获取类对象

        Date date=new Date();
        Class claz=Date.class;
        Object date1=claz.newInstance();
        Class class2=date1.getClass();
        Class class1=date.getClass();
        System.out.println(class1==class2);//true

这段代码运行的结果为true,说明这两个对象的类对象是相同的。因为它们是由Date类创建的。我们说,在同一个类加载器中,Class类对象有且只有一个。

“反”的本质:通过对象取得对象的来源

在反射的世界里,看重的不再是一个对象,而是对象身后的组成(类、构造方法、普通方法、属性)。

2.Class类对象的三种获取方式

方式一:通过类名.class获取

方式二:通过Class.forName(类名)获取

方式三:通过对象的getClass()获取

import java.util.Date;

public class TestRefection {
    public static void main(String[] args) throws  ClassNotFoundException {
       Class class1=java.util.Date.class;//方式一
       Class class2=Class.forName("java.util.Date");//方式二
        Date date=new Date();//方式三
        Class class3=date.getClass();
    }
}

3.反射与工厂模式

下面将使用通过class对象获取实例化对象改进传统工厂。

package com.com.company.reflection;

import java.util.Date;

public class TestRefection {
    public static void main(String[] args) throws  ClassNotFoundException {
        //传统工厂
        FastFood fastFood1= FastFactory1.getInstance("Hamburger");
        fastFood1.eat();
        //改进工厂(通过class对象的newInstance()获取对象)
        try {
            FastFood fastFood2=FastFactory2.getInstance("com.com.company.reflection.Pizza");//这里使用类的全限定名(包名.类名)
            fastFood2.eat();
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        } catch (InstantiationException e) {
            e.printStackTrace();
        }

    }
}
//定义一个制造产品的抽象类
interface FastFood{
    void eat();
}
//定义汉堡类实现产品抽象类
class Hamburger implements FastFood{

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

//定义披萨类实现产品抽象类
class Pizza implements FastFood{

    @Override
    public void eat() {
        System.out.println("吃披萨");
    }
}
//定义一个工厂生产产品
//传统工厂    缺点:不能直接根据foodName生产产品,需要和已有的产品进行比较。如果新增产品,就需要改变工厂生产产品的方法。
class FastFactory1{
    public static FastFood getInstance(String foodName){
        FastFood fastFood=null;
     if(foodName.equals("Hamburger")){
        fastFood=new Hamburger();
        }else if(foodName.equals("Pizza")){
         fastFood=new Pizza();
     }
        return fastFood;
    }
}
//改进传统工厂    使用class对象的newInstance()获取对象,当新增产品时,不需要对工厂生产产品的方法进行改动。
class FastFactory2{
    public static FastFood getInstance(String foodName) throws ClassNotFoundException, IllegalAccessException, InstantiationException {
        FastFood fastFood=null;
        Class cls=Class.forName(foodName);//获取对象的class对象,通过class对象的newInstance()获取对象。
        fastFood=(FastFood)cls.newInstance();
        return fastFood;
    }
}

结果:

二、反射与类操作

1.取得父类信息

在Java中的任何程序中都会有父类Class类中就有通过下面的方法获取父类信息

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

使用及结果:

package com.com.company.reflection;

import java.util.Date;

public class TestRefection {
    public static void main(String[] args){
    Son son=new Son();
    Class cls=son.getClass();

    System.out.println(cls.getPackage());//获取包名
    System.out.println(cls.getSuperclass());//获取Son的父对象
        Daughter daughter=new Daughter();
        Class dcls=daughter.getClass();
        Class[] classes=dcls.getInterfaces();
        //获取Daughter实现的父接口
        for(Class c:classes){
            System.out.println(c.getName());
        }

    }
}
interface A{
    void methodA();
}
interface B{
    void methodB();
}
class Father {

}
class Son extends Father{ }
class Daughter implements A,B{

    @Override
    public void methodA() {

    }

    @Override
    public void methodB() {

    }
}

结果:

2.反射调用构造

在上面的class对象的newInstance()中,获取的是一个无参构造函数产生的对象。如果想要用有参构造函数,Class类中也提供了有参构造方法及调用。

构造方法:

public Constructor<T> getConstructor(Class<?>... parameterTypes) throws NoSuchmethodException,SecurityException;取得指定参数类型的构造
public Constructor<?>[] getConstructors() throw SecurityException;取得类中的所有构造

获取类中的所有构造方法

package com.com.company.reflection;

import java.lang.reflect.Constructor;
import java.util.Date;
class Person{
    private int age;
    private String name;
    public Person(){}
    public Person(int age){
        this.age=age;
    }
    public Person(int age,String name){
        this.age=age;
        this.name=name;
    }
}
public class TestRefection {
    public static void main(String[] args) {
        Person person = new Person();
        Class pclass = person.getClass();
        Constructor[] constructor = pclass.getConstructors();
        for (Constructor c : constructor) {
            System.out.println(c.toString());
        }
    }
}



结果:

上面两个方法的返回类型都是java.lang.reflent.Constructor类的实例化对象,我们只需要关注一个方法。

public T newInstance(Object... initargs) throws InstantiationException,IllegalAccessException,IllegalArgumentException,InvocationTargetException;获取实例化对象

Class类中的newInstance()只提供了无参的构造方法实例化对象,如果我们想要通过实例化对象时赋予某种属性,这时我们就可以使用getConstructor(),给构造方法指定参数类型,从而实例化对象。

package com.com.company.reflection;

import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
class Person{
    private int age;
    private String name;
    public Person(int age){
        this.age=age;
    }
    public Person(int age,String name){
        this.age=age;
        this.name=name;
    }
    public String toString(){
        return "姓名:"+this.name+",年龄:"+this.age;
    }
}
public class TestRefection {
    public static void main(String[] args) {
        Class pclass=Person.class;
        try {
            //取得指定参数类型的构造方法
            Constructor constructor=pclass.getConstructor(int.class,String.class);
            try {
                //通过新得到的构造方法实例化对象
                Object person=constructor.newInstance(45, " 张三");
                System.out.println(person.toString());
            } catch (InstantiationException e) {
                e.printStackTrace();
            } catch (IllegalAccessException e) {
                e.printStackTrace();
            } catch (InvocationTargetException e) {
                e.printStackTrace();
            }

        } catch (NoSuchMethodException e) {
            e.printStackTrace();
        }
    }
}



结果:

3.反射调用普通方法(核心)

3.1 通过Class对象取得全部普通方法

public Method[] getMethods() throws SecurityException;

3.2 通过Class对象取得指定普通方法

public Method getMethod(String name,Class<?>... parameterTypes);

3.3 调用方法(由Method对象调用,第一个参数是设置的对象,后面的是参数列表)

public Object invoke(Object obj,Object... args) throws IllegalAccessException,llegalArgumentException,InvocationTargetException;

使用示例:

package com.com.company.reflection;

import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.Date;
class Person{
    private int age;
    private String name;
    public Person(){}
    public Person(int age){
        this.age=age;
    }
    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 toString(){
        return "姓名:"+this.name+",年龄:"+this.age;
    }
}
public class TestRefection {
    public static void main(String[] args) throws IllegalAccessException, InstantiationException, NoSuchMethodException, InvocationTargetException {
        Class pclass=Person.class;

            //通过类对象实例化Person对象
        Person person=(Person)pclass.newInstance();

        //取得类的全部普通方法(包括继承自Object类的方法)
        Method[] methods=pclass.getMethods();
        for(Method m:methods){
            System.out.println(m);
        }

        //取得指定普通方法
        Method setAgeMethod=pclass.getMethod("setAge", int.class);
        //调用方法
        setAgeMethod.invoke(person,35);
        System.out.println(person.getAge());
    }
}



结果:

4.反射调用类中属性

public Field[] getFields() throws SecurityException; 取得类中被public修饰的全部属性(包括父类中的)(Class对象调用)
public Field getField(String name) throws NoSuchFieldException,SecurityException
;取得类中指定名称属性(Class对象调用)
public Field[] getDeclaredFields() throws SecurityException;取得本类中全部属性(Class对象调用)
public Method getDeclaredField(String name) throws NoSuchFieldException,SecurityException;
取得本类中指定名称全部属性(Class对象调用)

public void set(Object obj,Object value) throws (IllegalArgumentException,IllegalAccessException;设置属性内容(由获取得到的Field对象调用)
public Object get(Object obj) throws IllegalArgumentException,IllegalAccessException;取得属性内容(由获取得到的Field对象调用)

使用示例:

package com.com.company.reflection;

import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.Date;
class Person{
    public int age;
    public String name;
    public String toString(){
        return "姓名:"+this.name+",年龄:"+this.age;
    }
}
class Student extends Person{
    public String teacherName;
}
public class TestRefection {
    public static void main(String[] args) throws IllegalAccessException, InstantiationException, NoSuchMethodException, InvocationTargetException, NoSuchFieldException {
        Class pclass=Student.class;
        Person student= (Person) pclass.newInstance();
        //获取类(包括父类)中被public修饰的全部属性
        Field[] fields=pclass.getFields();
        for(Field field:fields) {
            System.out.println(field.toString());
        }
        System.out.println("-------------------------------------");
        //取得类中指定名称属性(包括父类)
        Field myField=pclass.getField("age");
        System.out.println(myField.toString());
        System.out.println("-------------------------------------");
        //取得本类中全部属性
        Field[] sfields=pclass.getDeclaredFields();
        for(Field f:sfields){
            System.out.println(f.toString());
        }
        System.out.println("-------------------------------------");
        //取得本类中指定名称属性(如果指定的是父类中的属性,将不会显示)
        Field sfield=pclass.getDeclaredField("teacherName");
        System.out.println(sfield.toString());
        System.out.println("-------------------------------------");
        //设置属性内容(通过获取得到的属性名称)
        sfield.set(student,"Peter");
        System.out.println(sfield.get(student));
    }
}

结果为:

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值