Java基础:反射

反射的概述

Reflection是被视为动态语言的关键,反射机制允许程序在执行期间,借助于Reflection API取得任何类的内部信息,并能直接操作任意对象的内部属性和方法。
加载完类后,产生一个class类型的对象,包含完整的类的结果信息。
这个对象就像一面镜子,透过这个镜子看到类的结构,所以,我们形象的称之为:反射


动态语言:Object-C,C#,JavaScript,PHP,Pyehon,
静态语言:Java,C,C++



Java反射机制提供的功能:
        1.运行时判断任意一个对象所属的类
        2.运行时构造任意一个类的对象
        3.运行时判断任意一个类所具有的成员变量和方法
        4.在运行时获取泛型信息
        5.在运行时调用任意一个对象的成员变量和方法
        6.在运行时处理注解
        7.生产动态代理


反射相关的主要API
    1.java.lang.Class:代表一个类
    2.java.lang.reflect.Method:代表类的方法
    3.java.lang.reflect.Field:代表类的成员变量
    4.java.lang.reflect.Constructor:代表类的构造器
    


关于java.lang.Class类的理解
1.类的加载过程:
	程序经过javac.exe命令以后,会生成一个或多个字节码文件(.class结尾)。
	接着我们使用java.exe命令对某个字节码文件进行解释运行。相当于将某个字节码文件
	加载到内存中。此过程就称为类的加载。加载到内存中的类,我们就称为运行时类,此
	运行时类,就作为Class的一个实例。

2.换句话说,Class的实例就对应着一个运行时类。

3.加载到内存中的运行时类,会缓存一定的时间。在此时间之内,我们可以通过不同的方式
来获取此运行时类。
疑问1:通过直接new的方式或反射的方式都可以调用公共的结构,开发中到底用那个?
建议:直接new的方式。
什么时候会使用:反射的方式。 反射的特征:动态性

疑问2:反射机制与面向对象中的封装性是不是矛盾的?如何看待两个技术?
不矛盾。
封装性:是建议你哪些结构可以调用,哪些结构不需要调用
反射:是需要需要调用哪些结构

此文章所有类的为

@MyAnnotation(value="hi")
public class Person extends Creature<String> implements Comparable<String>,MyInterface{

    private String name;
    int age;
    public int id;

    public Person(){}

    @MyAnnotation(value="abc")
    private Person(String name){
        this.name = name;
    }

     Person(String name,int age){
        this.name = name;
        this.age = age;
    }
    @MyAnnotation
    private String show(String nation){
        System.out.println("我的国籍是:" + nation);
        return nation;
    }

    public String display(String interests,int age) throws NullPointerException,ClassCastException{
        return interests + age;
    }


    @Override
    public void info() {
        System.out.println("我是一个人");
    }

    @Override
    public int compareTo(String o) {
        return 0;
    }

    private static void showDesc(){
        System.out.println("我是一个可爱的人");
    }

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

public interface MyInterface {
    void info();
}

@Target({TYPE, FIELD, METHOD, PARAMETER, CONSTRUCTOR, LOCAL_VARIABLE})
@Retention(RetentionPolicy.RUNTIME)
public @interface MyAnnotation {
    String value() default "hello";

}

public class Creature<T> implements Serializable {
    private char gender;
    public double weight;

    private void breath(){
        System.out.println("生物呼吸");
    }

    public void eat(){
        System.out.println("生物吃东西");
    }

}

通过反射创建对象:可以调用私有的构造器

//获取类
Class<Person> clazz = Person.class;
//获取类的构造器
Constructor<Person> cons = clazz.getDeclaredConstructor(String.class, int.class);
//设置可以使用私有的构造器权限
cons.setAccessible(true);
//实例化
Object obj = cons.newInstance("Tom",12);
System.out.println(obj.toString());
//强转为Person
Person p = (Person)obj;
System.out.println(p);

通过反射使用类中的方法和属性:可以设置和使用私有的属性和方法

//需要先获取类的实例化
Class<Person> clazz = Person.class;
Constructor<Person> cons = clazz.getDeclaredConstructor(String.class, int.class);
cons.setAccessible(true);
Object obj = cons.newInstance("Tom",12);
System.out.println(obj.toString());
Person p = (Person)obj;
System.out.println(p);

//获取属性
Field age = clazz.getDeclareField("age");
//设置权限
age.setAccessible(true);
//设置属性:将上面实例化对象的年龄赋值为10
age.set(p,10);
System.out.println(p);


//获取方法
Method show = clazz.getDeclaredMethod("show", String.class);
//设置权限
show.setAccessible(true);
//调用方法
show.invoke(p,"中国");


通过反射获取class实例的四种方式

 Class<Person> clazz = Person.class;
 System.out.println(clazz);

 Person p1 = new Person();
 Class clazz2 = p1.getClass();
 System.out.println(clazz2);

 Class<?> clazz3 = Class.forName("Person");
 System.out.println(clazz3);

 System.out.println(clazz == clazz2);
 System.out.println(clazz == clazz3);


 //4
 ClassLoader classLoader = reflection.class.getClassLoader();
 Class<?> clazz4 = classLoader.loadClass("Person");
 System.out.println(clazz4);

系统类加载器、拓展类加载器、引导类加载器的了解

 //对于自定义类,使用系统类加载器进行加载
 ClassLoader classLoader = reflection.class.getClassLoader();
 System.out.println(classLoader);
 //调用系统类加载的getParent():获取扩展类加载器
 ClassLoader parent = classLoader.getParent();
 System.out.println(parent);
 //无法获取引导类加载器
 //引导类加载器主要负责加载java的核心内库,无法加载自定义类的
 ClassLoader parent1 = parent.getParent();
 System.out.println(parent1);

读取配置Properties文件的的方法

        //Properties:用来读取配置文件
        Properties pro = new Properties();

        //读取配置文件的方式一:
        //此时的文件默认在当前的Module下
        FileInputStream fis = new FileInputStream("jdbc.properties");
        pro.load(fis);
        String user = pro.getProperty("user");
        String password = pro.getProperty("password");
        System.out.println(user + "    password" + password);

        //读取配置文件的方式二:
        //此时文件默认在src中
        ClassLoader classLoader = reflection.class.getClassLoader();
        InputStream is = classLoader.getResourceAsStream("jdbc1.properties");
        pro.load(is);

        String user1 = pro.getProperty("user");
        String password1 = pro.getProperty("password");
        System.out.println(user1 + "    password" + password1);



通过实例体会反射的动态性

 for(int i = 0;i < 100;i++){
     int num = new Random().nextInt(3);//0,1,2
     String classPath = "";
     switch(num){
         case 0:
             classPath = "java.util.Date";
             break;
         case 1:
             classPath = "java.lang.Object";
             break;
         case 2:
             classPath = "Person";
             break;
     }

     try {
     //通过不同的字符串来创建对象
         Object obj = getInstance(classPath);
         System.out.println(obj);
     } catch (Exception e) {
         e.printStackTrace();
     }
 }



public Object getInstance(String classPath) throws Exception {
    Class clazz =  Class.forName(classPath);
    return clazz.newInstance();
}

getFields()获取public的属性 vs getDeclareFields()获取所有的属性

Class<java1.Person> clazz = java1.Person.class;
 //获取属性结构
 //getFields():获取所有pulic的属性
 Field[] field = clazz.getFields();
 for (Field f :
         field) {
     System.out.println(f);
 }

 //getDeclaredFields():获取所有属性(不包含父类中的属性)
 Field[] declaredFields = clazz.getDeclaredFields();
 for (Field f :
         declaredFields) {
     System.out.println(f);
 }

获取具体的结构:getModifiers()权限修饰符,getType()数据类型,getName()变量名

 Class<Person> clazz = Person.class;
 Field[] declaredFields = clazz.getDeclaredFields();
 for(Field f:declaredFields){
     //1.权限修饰符
     int modifiers = f.getModifiers();
     System.out.println(Modifier.toString(modifiers));
     //2.数据类型
     Class<?> type = f.getType();
     System.out.println(type.getName() + "\t");
     
     //3.变量
     String name = f.getName();
     System.out.println(name);
 }

获取方法体 和 构造器体

        Class<java1.Person> clazz = java1.Person.class;

        //获取所有的方法
        Method[] methods = clazz.getMethods();
        for (Method m :methods) {
            System.out.println(m);
        }
        System.out.println("____________________________________");
        Method[] declaredMethods = clazz.getDeclaredMethods();
        for (Method m :declaredMethods) {
            System.out.println(m);
        }
        System.out.println("**********************************");
        Constructor[] constructors = clazz.getConstructors();
        for (Constructor c :constructors) {
            System.out.println(c);
        }
        System.out.println("**********************************");
        Constructor[] declaredConstructors = clazz.getDeclaredConstructors();
        for (Constructor c :declaredConstructors) {
            System.out.println(c);
        }

获取运行时,方法的所有修饰

        Class<java1.Person> clazz = java1.Person.class;
        Method[] declaredMethods = clazz.getDeclaredMethods();
        for(Method m : declaredMethods){
            //1.获取方法声明的注解
            Annotation[] annos = m.getAnnotations();
            for(Annotation a : annos){
                System.out.println(a);
            }

            //2.权限修饰符
            System.out.print(Modifier.toString(m.getModifiers()) + "\t");

            //3.返回值类型
            System.out.print(m.getReturnType().getName() + "\t");

            //4.方法名
            System.out.print(m.getName());
            System.out.print("(");
            //5.形参列表
            Class[] parameterTypes = m.getParameterTypes();
            if(!(parameterTypes == null && parameterTypes.length == 0)){
                for(int i = 0;i < parameterTypes.length;i++){

                    if(i == parameterTypes.length - 1){
                        System.out.print(parameterTypes[i].getName() + " args_" + i);
                        break;
                    }

                    System.out.print(parameterTypes[i].getName() + " args_" + i + ",");
                }
            }

            System.out.print(")");

            //6.抛出的异常
            Class[] exceptionTypes = m.getExceptionTypes();
            if(exceptionTypes.length > 0){
                System.out.print("throws ");
                for(int i = 0;i < exceptionTypes.length;i++){
                    if(i == exceptionTypes.length - 1){
                        System.out.print(exceptionTypes[i].getName());
                        break;
                    }

                    System.out.print(exceptionTypes[i].getName() + ",");
                }
            }


            System.out.println();
        }

获取父类,带泛型的父类,父类的泛型

    @Test//p24:获取运行时类的父类
    public void test18(){
        Class<java1.Person> clazz = java1.Person.class;

        Class superclass = clazz.getSuperclass();
        System.out.println(superclass);
    }
    @Test//获取运行时类的带泛型的父类
    public void test19(){
        Class<java1.Person> clazz = java1.Person.class;

        Type genericSuperclass = clazz.getGenericSuperclass();
        System.out.println(genericSuperclass);
    }
    @Test// 获取运行时类的带泛型的父类的泛型
    public void test20(){
        Class<Person> clazz = java1.Person.class;

        Type genericSuperclass = clazz.getGenericSuperclass();
        ParameterizedType paramType = (ParameterizedType) genericSuperclass;
        //获取泛型类型
        Type[] actualTypeArguments = paramType.getActualTypeArguments();
//        System.out.println(actualTypeArguments[0].getTypeName());
        System.out.println(((Class)actualTypeArguments[0]).getName());

    }

获取接口

    @Test//获取运行时类实现的接口
    public void test21(){
        //类实现的接口
        Class<java1.Person> clazz = java1.Person.class;

        Class[] interfaces = clazz.getInterfaces();
        for(Class c : interfaces){
            System.out.println(c);
        }

        System.out.println();

        //获取运行时类的父类实现的接口
        Class[] interfaces1 = clazz.getSuperclass().getInterfaces();
        for(Class c : interfaces1){
            System.out.println(c);
        }
    }

获取运行时类所在的包

    @Test
    public void test24(){
        Class<java1.Person> clazz = java1.Person.class;

        Package pack = clazz.getPackage();
        System.out.println(pack);
    }

获取类的注解

    public void test25(){
        Class<java1.Person> clazz = java1.Person.class;

        Annotation[] annotations = clazz.getAnnotations();
        for(Annotation annos : annotations){
            System.out.println(annos);
        }
    }

通过反射调用静态方法:invoke(null)

    @Test//p27:调用运行时类中指定结构:属性、方法、构造器
    public void test2425() throws Exception{
        Class<java1.Person> clazz = java1.Person.class;
        java1.Person p = (java1.Person)clazz.newInstance();
        Method show = clazz.getDeclaredMethod("show", String.class);
        show.setAccessible(true);
        Object chn = show.invoke(p, "CHN");
        System.out.println(chn);

        System.out.println("**********如何调用静态方法");

        Method showDesc = clazz.getDeclaredMethod("showDesc");
        showDesc.setAccessible(true);
//        Object invoke = showDesc.invoke(Person.class);
        Object invoke = showDesc.invoke(null);
        System.out.println(invoke);
    }
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值