说说反射的用途及实现

一,Java的反射框架主要提供以下功能:

1.在运行时判断任意一个对象所属的类;

2.在运行时构造任意一个类的对象;

3.在运行时判断任意一个类所具有的成员变量和方法(通过反射甚至可以调用私有方法);

4.在运行时调用任意一个对象的方法

二,主要用途:

如图1所示,反射最重要的用途就是开发各种通用框架。

三,基本反射功能的实现(反射相关的类一般都在java.lang.relfect包里):

1,获得类对象

      使用类类的forName静态方法,直接获取某一个对象的类,调用某个对象的getClass()方法

2,判断是否为某个类的实例

     用的instanceof关键字来判断是否为某个类的实例

3,创建实例

      使用类对象的的newInstance()方法来创建类对象对应类的实例。

      先通过类对象获取指定的构造对象,再调用构造对象的的newInstance()方法来创建实例。

4,获取方法

    getDeclaredMethods()

5,获取构造器信息

     getDeclaredMethods()

     的getMethods()

     getMethod()

6,获取类的成员变量(字段)信息

     getFiled:访问公有的成员变量

     getDeclaredField:所有已声明的成员变量但不能得到其父类的成员变量

     getFileds和getDeclaredFields用法

7,调用方法

       调用()

8,利用反射创建数组

    Array.newInstance()

 

Java的机制反射的英文一个非常强大的功能,在很多大型项目比如春天,MyBatis的都可以看见反射的身影。通过反射机制我们可以在运行期间获取对象的类型信息,利用这一特性我们可以实现工厂模式和代理等模式设计模式,同时也可以解决的Java泛型擦除等令人苦恼的问题。本文我们就从实际应用的角度出发,来应用一下的Java的反射机制。

反射基础

在应用反射机制之前,首先我们先来看一下如何获取一个对象对应的反射类Class,在Java的中我们有三种方法可以获取一个对象的反射类

通过的getClass方法

在的Java中,一个每Object都有一个getClass方法,通过的getClass方法我们可以获取到这个对象对应的反射类

String s = "ziwenxie";
Class<?> c = s.getClass();

通过的forName方法

也。我们可以调用Class类的静态方法forName

Class<?> c = Class.forName("java.lang.String");

使用的.class

或者我们也可以直接使用.class

Class<?> c = String.class;

获取类型信息

在文章开头我们就提到反射的一大好处就是可以允许我们在运行期间获取对象的类型信息,下面我们通过一个例子来具体看一下。

我们首先在typeinfo.interfacea包下面新建一个接口A

package typeinfo.interfacea;
public interface A { void f(); }

我们接着在typeinfo.packageaccess包下面新建一个接口C,接口C继承自接口A,并且我们还另外创建了几个用于测试的方法,注意下面几个方法的权限都是不同的

package typeinfo.packageaccess;
import typeinfo.interfacea.A;
class C implements A {
    public void f() { System.out.println("public C.f()"); }
    public void g() { System.out.println("public C.g()"); }
    protected void v () { System.out.println("protected C.v()"); }
    void u() { System.out.println("package C.u()"); }
    private void w() { System.out.println("private C.w()"); }
}
public class HiddenC {
    public static A makeA() { return new C(); }
}

callHiddenMethod()方法中我们用到了几个新的API,其中getDeclaredMethod()根据方法名用于电子杂志类类指代对象的某个方法,我们然后通过调用invoke()方法传入实际的对象就可以触发对象的相关方法:

package typeinfo;
import typeinfo.interfacea.A;
import typeinfo.packageaccess.HiddenC;
import java.lang.reflect.Method;
public class HiddenImplementation {
    public static void main(String[] args) throws Exception {
        A a = HiddenC.makeA();
        a.f();
        System.out.println(a.getClass().getName());
        // Oops! Reflection still allows us to call g():
        callHiddenMethod(a, "g");
        // And even methods that are less accessible!
        callHiddenMethod(a, "u");
        callHiddenMethod(a, "v");
        callHiddenMethod(a, "w");
    }
    static void callHiddenMethod(Object a, String methodName) throws Exception {
        Method g = a.getClass().getDeclaredMethod(methodName);
        g.setAccessible(true);
        g.invoke(a);
    }
}

从输出结果我们可以看出来,不管是publicdefaultprotect还是pricate方法,通过反射类我们都可以自由调用。当然这里我们只是为了显示反射的强大威力,在实际开发中这种技巧还是不提倡

public C.f()
typeinfo.packageaccess.C
public C.g()
package C.u()
protected C.v()
private C.w()

应用实践

我们有下面这样一个业务场景,我们有一个泛型集合类List<Class<? extends Pet>>,需要我们出统计集合这个类中每种具体的Pet有多少个。由于Java的的泛型擦除,类似注意List<? extends Pet>的做法肯定的英文不行的,因为编译器做了静态类型检查之后,到了运行期间JVM会将集合中的对象都视为Pet,但是并知道不会Pet代表的究竟的英文Cat还是Dog,所以到了运行期间对象的类型信息其实全部丢失了

为了实现我们上面的例子,我们先来定义几个类:

public class Pet extends Individual {
    public Pet(String name) { super(name); }
    public Pet() { super(); }
}
public class Cat extends Pet {
    public Cat(String name) { super(name); }
    public Cat() { super(); }
}
public class Dog extends Pet {
    public Dog(String name) { super(name); }
    public Dog() { super(); }
}
public class EgyptianMau extends Cat {
    public EgyptianMau(String name) { super(name); }
    public EgyptianMau() { super(); }
}
public class Mutt extends Dog {
    public Mutt(String name) { super(name); }
    public Mutt() { super(); }
}

上面的Pet类继承自IndividualIndividual类的的实现稍微复杂一点,我们实现了Comparable接口,重新自定义了类的比较规则,如果不是很明白的话,也没有关系,我们已经将它抽象出来了,所以不理解实现原理也没有关系。

public class Individual implements Comparable<Individual> {
    private static long counter = 0;
    private final long id = counter++;
    private String name; // name is optional
    public Individual(String name) { this.name = name; }
    public Individual() {}
    public String toString() {
        return getClass().getSimpleName() + (name == null ? "" : " " + name);
    }
    public long id() { return id; }
    public boolean equals(Object o) {
        return o instanceof Individual && id == ((Individual)o).id;
    }
    public int hashCode() {
        int result = 17;
        if (name != null) {
            result = 37 * result + name.hashCode();
        }
        result = 37 * result + (int) id;
        return result;
    }
    public int compareTo(Individual arg) {
        // Compare by class name first:
        String first = getClass().getSimpleName();
        String argFirst = arg.getClass().getSimpleName();
        int firstCompare = first.compareTo(argFirst);
        if (firstCompare != 0) {
            return firstCompare;
        }
        if (name != null && arg.name != null) {
            int secendCompare = name.compareTo(arg.name);
            if (secendCompare != 0) {
                return secendCompare;
            }
        }
        return (arg.id < id ? -1 : (arg.id == id ? 0 : 1));
    }
}

下面创建了一个抽象类PetCreator,以后我们通过调用arrayList()方法便可以直接电子杂志相关Pet类的集合。这里使用到了我们上面没有提及的newInstance()方法,它会返回类类所真正指代的类的实例,这是什么意思呢?声明比如说new Dog().getClass().newInstance()状语从句:直接new Dog()的英文等价的。

public abstract class PetCreator {
    private Random rand = new Random(47);
    // The List of the different getTypes of Pet to create:
    public abstract List<Class<? extends Pet>> getTypes();
    public Pet randomPet() {
        // Create one random Pet
        int n = rand.nextInt(getTypes().size());
        try {
            return getTypes().get(n).newInstance();
        } catch (InstantiationException e) {
            throw new RuntimeException(e);
        } catch (IllegalAccessException e) {
            throw new RuntimeException(e);
        }
    }
    public Pet[] createArray(int size) {
        Pet[] result = new Pet[size];
        for (int i = 0; i < size; i++) {
           result[i] = randomPet();
        }
        return result;
    }
    public ArrayList<Pet> arrayList(int size) {
        ArrayList<Pet> result = new ArrayList<Pet>();
        Collections.addAll(result, createArray(size));
        return result;
    }
}

接下来我们来实现上面这一个抽象类,解释一下下面的代码,在下面的代码中,我们声明了两个集合类,allTypestypes,其中allTypes中所有游戏了我们呢上面所声明的所有类,但是我们具体的实际上类型只有两种即Mutt状语从句:EgypianMau,我们所以需要真正new出来的宠物只是types中所所有游戏的类型,我们以后通过调用getTypes()便可以得到types中所所有游戏的所哟类型。

public class LiteralPetCreator extends PetCreator {
    @SuppressWarnings("unchecked")
    public static final List<Class<? extends Pet>> allTypes = Collections.unmodifiableList(
        Arrays.asList(Pet.class, Dog.class, Cat.class, Mutt.class, EgyptianMau.class));
    private static final List<Class<? extends Pet>> types = allTypes.subList(
        allTypes.indexOf(Mutt.class), allTypes.size());
    public List<Class<? extends Pet>> getTypes() {
        return types;
    }
}

总体的逻辑已经完成了,我们求最后实现用来统计集合中相关Pet类个数的TypeCounter类。一下解释isAssignalbeFrom()方法,它可以判断一个反射类是某个反射类的子类或者间接子类。而getSuperclass()顾名思义就是得到某个反射类的父类了。

public class TypeCounter extends HashMap<Class<?>, Integer> {
    private Class<?> baseType;
    public TypeCounter(Class<?> baseType) {
        this.baseType = baseType;
    }
    public void count(Object obj) {
        Class<?> type = obj.getClass();
        if (!baseType.isAssignableFrom(type)) {
            throw new RuntimeException(
                obj + " incorrect type " + type + ", should be type or subtype of " + baseType);
        }
        countClass(type);
    }
    private void countClass(Class<?> type) {
        Integer quantity = get(type);
        put(type, quantity == null ? 1 : quantity + 1);
        Class<?> superClass = type.getSuperclass();
        if (superClass != null && baseType.isAssignableFrom(superClass)) {
            countClass(superClass);
        }
    }
    @Override
    public String toString() {
        StringBuilder result = new StringBuilder("{");
        for (Map.Entry<Class<?>, Integer> pair : entrySet()) {
            result.append(pair.getKey().getSimpleName());
            result.append("=");
            result.append(pair.getValue());
            result.append(", ");
        }
        result.delete(result.length() - 2, result.length());
        result.append("} ");
        return result.toString();
    }
}

转自:http//www.hello-code.com/blog/java/201703/6278.html

反射机制是指在运行时动态地获取类的信息并操作类的属性、方法和构造函数,而不需要提前知道类的具体信息。通过反射,我们可以在运行时获取类的成员、调用方法、创建对象等操作,使得程序具备更大的灵活性和扩展性。 反射实现原理主要依赖于Java中的java.lang.reflect包下的一些类和接口。主要的类和接口包括Class、Field、Method、Constructor等。 1. Class类:Class类是Java反射机制的核心,它表示一个类的字节码对象。通过Class类,可以获取类的各种信息,如成员变量、方法、构造函数等。 2. Field类:Field类用于描述类的成员变量,可以获取和设置成员变量的值。 3. Method类:Method类用于描述类的方法,可以调用方法并获取返回值。 4. Constructor类:Constructor类用于描述类的构造函数,可以创建类的实例。 在反射实现过程中,主要步骤如下: 1. 获取Class对象:通过某种方式获取要操作的类的Class对象,可以使用Class.forName()方法、Object.getClass()方法等。 2. 获取类的成员:通过Class对象的getFields()、getMethods()、getDeclaredFields()、getDeclaredMethods()等方法获取类的成员变量和方法。 3. 操作成员:通过Field对象和Method对象可以对类的成员进行读取和修改,可以调用方法并获取返回值。 4. 创建对象:通过Constructor对象可以创建类的实例。 通过这些步骤,反射机制能够在运行时动态地获取类的信息并操作类的成员,从而实现对类的灵活操作。但是需要注意,反射机制的使用应该谨慎,因为它会导致一些性能上的损失,并且违背了面向对象设计原则中的封装性。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值