黑马程序员----反射

——- android培训java培训、期待与您交流! ———-
Class 类的实例表示正在运行的 Java 应用程序中的类和接口。Class 没有公共构造方法。Class 对象是在加载类时由 Java 虚拟机以及通过调用类加载器中的 defineClass 方法自动构造的。
获得Class对象的三种方法:
1.通过Class类的静态方法forName来获取

static Class<?> forName(String className) 
          返回与带有给定字符串名的类或接口相关联的 Class 对象。 
static Class<?> forName(String name, boolean initialize, ClassLoader loader) 
          使用给定的类加载器,返回与带有给定字符串名的类或接口相关联的 Class 对象。 

2.通过其他类的类名.class(属性)来获取

Class c = String.class;

3.通过类的实例对象的getClass方法来获取;

Class<?> getClass() 
          返回此 Object 的运行时类。
基本的 Java 类型(boolean、byte、char、short、int、long、float 和 double)和关键字 void 也表示为 Class 对象;
Class类中boolean isPrimitive() :判定指定的 Class 对象是否表示一个基本类型。
包装类和Void类的静态TYPE属性;
Integer.TYPE == int.class ;     // true
Integer.class == int.class;     //false
 数组类型的Class实例对象:
Class<String[]> clz = String[].class;
Class类中 boolean isArray() :判定此 Class 对象是否表示一个数组类。 

从Class中获取构造方法

Constructor<T> getConstructor(Class<?>... parameterTypes) 
返回该Class对象表示类的指定的public构造方法。 
Constructor<?>[] getConstructors()
返回该Class对象表示类的所有public构造方法。 
Constructor<T> getDeclaredConstructor(Class<?>... parameterTypes)
返回该Class对象表示类的指定的构造方法。和访问权限无关
Constructor<?>[] getDeclaredConstructors() 
返回该Class对象表示类的所有构造方法。和访问权限无关。

从Class中获取一般方法

Method getMethod(String name, Class<?>... parameterTypes) 
返回该Class对象表示类和其父类的指定的public方法。 
Method[] getMethods():  
返回该Class对象表示类和其父类的所有public方法。 
Method getDeclaredMethod(String name, Class<?>... parameterTypes) : 
返回该Class对象表示类的指定的方法。和访问权限无关,只能是自己类的
Method[] getDeclaredMethods(): 获得类所有的方法,包括公共、保护、默认(包)访问和私有方法,但不包括继承的方法。

从Class中获取字段

Field getField(String name) 
返回该Class对象表示类和其父类的指定的public属性。  
Field[] getFields() 
返回该Class对象表示类和其父类的所有public属性。
Field getDeclaredField(String name) 
返回该Class对象表示类的指定的字段。和访问权限无关。 
Field[] getDeclaredFields()
包括公共、保护、默认(包)访问和私有字段,但不包括继承的字段    

从Class中获取注解

<A extends Annotation> A  getAnnotation(Class<A> annotationClass)  
如果存在该元素的指定类型的注释,则返回这些注释,否则返回 nullAnnotation[] getAnnotations() 
返回此元素上存在的所有注释。 
 Annotation[] getDeclaredAnnotations() 
返回直接存在于此元素上的所有注释。 

从Class中判断类型

boolean isAnnotation():
boolean isArray():
boolean isEnum():
boolean isInterface():
boolean isInstance(Object obj):如果 obj 是此类的实例,则返回 true。等价于instanceof

使用反射创建对象
1.使用Class对象的newInstance()方法创建该Class对象的实例,此时该Class对象必须要有无参数的构造方法。
2.使用Class对象获取指定的Constructor对象,再调用Constructor的newInstance()方法创建对象类的实例,此时可以选择使用某个构造方法。

忽略访问权限
在调用之前使用setAccessible(boolean flag);

package xia.wt.reflect;

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

public class Demo1_getClass {

    public static void main(String[] args) {
    //创建4个Person类型的变量,前两个使用单例类提供的或取单例对象的方法赋值,后面两个通过反射的方式获取对象
        Person p1= Person.getInstance();
        Person p2= Person.getInstance();
        Person p3 = null;
        Person p4 = null;
        try {
        //获取私有无参构造方法
            Constructor<Person> c = Person.class.getDeclaredConstructor();
            //将其设置为可访问的
            c.setAccessible(true);
            //通过此无参构造方法创建实例对象
            p3 = c.newInstance();
            //获取有参私有构造方法
            Constructor<Person> c1 = Person.class.getDeclaredConstructor(String.class,int.class);
            //将其设置为可访问
            c1.setAccessible(true);
            //通过此构造方法创建对象
            p4 = c1.newInstance("张三",12);


        } catch (NoSuchMethodException | SecurityException e) {
            e.printStackTrace();
        }catch (InstantiationException | IllegalAccessException
                | IllegalArgumentException | InvocationTargetException e) {
            e.printStackTrace();
        }
        System.out.println(p3);
        System.out.println(p4);
        System.out.println(p1==p2);
        System.out.println(p1==p3);
        System.out.println(p1==p4);
        System.out.println(p4==p3);
    }

}


class Person{
//创建一个单例类,使外界不能直接创建对象
    private String name;
    private int age;
    private static Person p = new Person();
    private Person(){};
    private Person(String name,int age){
        this.name = name;
        this.age = age;
    }

    public static Person getInstance(){
        return p;
    }

    @Override
    public String toString() {
        return ("姓名:"+name+";年龄:"+age);
    }
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    public int getAge() {
        return age;
    }
    public void setAge(int age) {
        this.age = age;
    }


}


/**
输出结果:
姓名:null;年龄:0
姓名:张三;年龄:12
true
false
false
false

*/

-调用方法
每个Method对象对应一个方法。获得Method对象后,程序可以使用Method里面的invoke方法。
Object invoke(Object obj,Object … args):obj表示调用底层方法的对象,后面的args表示调用de shiji参数 。
如果底层方法是静态的,那么可以忽略指定的 obj 参数。该参数可以为 null。
如果底层方法所需的形参个数为 0,则所提供的 args 数组长度可以为 0 或 null。
不写,null,或new Object[]{}

class Demo{
    public static void main(String[] args) {
        System.out.println("主方法");
    }
}
public class ReflectDemo {
    public static void main(String[] args) throws Exception {
        Class<Demo> clz  = Demo.class;
        Method m = clz.getMethod("main",String[].class);
        m.invoke(null, new Object[]{new String[]{"A","B"}});
        m.invoke(null, (Object)new String[]{"A","B"});
        //m.invoke(null, "A","B");//wrong number of arguments
    }
}

访问属性
Field提供两组方法访问属性:
xxx getXxx(Object obj):获取obj对象该Field的属性值,此处的xxx表示8个基本数据类型。若该属性的类型是引用数据类型则使用,Object get(Object obj) 。
void setXxx(Object obj,xxx val):将obj对象的该Field字段设置成val值,此处的xxx表示8个基本数据类型。若该属性的类型是引用数据类型则使用,void set(Object obj, Object value)

package xia.wt.reflect;

import java.lang.reflect.Field;

public class Demo3_ield {
    public static void main(String[] args) {
        //获取Person对象,并设定mane为张三
        Person p = Person.getInstance();
        p.setName("张三");
        try {
            //获取name字段对应的的Field
            Field f = p.getClass().getDeclaredField("name");
            //将该字段设置为可访问的
            f.setAccessible(true);
            //对该字段重新赋值
            f.set(p, "李四");
            //获取p的name字段值并打印
            Object name = f.get(p);
            System.out.println(name);

        } catch (NoSuchFieldException | SecurityException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }catch (IllegalArgumentException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
    }

}

String.class的类型是Class<String>,若Class对应的类未知,则使用Class<?>,通过反射中使用泛型,可避免使用反射生成的对象需要强制转换。
实例:工厂设计模式

package xia.wt.reflect;

public class Demo3_Generic {

    public static void main(String[] args) {
        String s = Factory.getInstance(String.class);

    }

}

class Factory{
    public static <T> T getInstance(Class<T> claz){
        T t =null;
        try {
            t = claz.newInstance();
        } catch (InstantiationException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
        return t;
    } 

}

通过指定对应的Class对象,程序可以获得该类里面所有的Field,不管该Field使用private 方法public。获得Field对象后都可以使用getType()来获取其类型。
Class<?> type = f.getType();//获得字段的类型
Field有泛型修饰,则不能准确得到该Field的泛型参数,如Set<String>;为了获得指定Field的泛型类型,我们采用:
Type gType = f.getGenericType();得到泛型类型
然后将Type对象强转为ParameterizedType,其表示增加泛型后的类型
Type getRawType()//返回被泛型限制的类型
Type[] getActualTypeArguments()//返回泛型参数类型

ParameterizedType 表示参数化类型,如 Collection<String>
参数化类型在反射方法首次需要时创建(在此包中指定)。当创建参数化类型 p 时,p 实例化的一般类型声明会被解析,并且按递归方式创建 p 的所有类型参数。有关类型变量创建过程的详细信息,请参阅 TypeVariable。重复创建的参数化类型无效。
实现此接口的类的实例必须实现 equals() 方法,该方法用于比较两个共享相同一般类型声明和具有相同类型参数的任何实例。
Type[] getActualTypeArguments()
返回表示此类型实际类型参数的 Type 对象的数组。
Type getOwnerType()
返回 Type 对象,表示此类型是其成员之一的类型。
Type getRawType()
返回 Type 对象,表示声明此类型的类或接口。

package xia.wt.reflect;

import java.lang.reflect.Field;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.util.Set;
import java.util.TreeSet;

public class Demo5_Generic1 {
    public static void main(String[] args) throws NoSuchFieldException, SecurityException {
        Set<String> course = new TreeSet<String>();
        course.add("java");
        course.add("c++");
        Student s = new Student(course, "赵四");
        Field f = s.getClass().getField("course");
        Type t = f.getType();
        Type gt = f.getGenericType();
        ParameterizedType pt = (ParameterizedType)gt;
        Type rt = pt.getRawType();
        Type ata[] = pt.getActualTypeArguments();
        System.out.println(t);
        System.out.println(gt);
        System.out.println(pt);
        System.out.println(rt);
        for (Type type : ata) {
            System.out.println("---->"+type);
        }

    }
}


class Student{
    public Set<String> course;
    public String name;
    public Student(Set<String> course, String name) {
        super();
        this.course = course;
        this.name = name;
    }
}

/**
打印结果:
interface java.util.Set
java.util.Set<java.lang.String>
java.util.Set<java.lang.String>
interface java.util.Set
---->class java.lang.String
*/
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值