黑马程序员——反射

------- android培训java培训、期待与您交流! ----------


Java反射机制是在运行状态中,对于任意一个类,都能够知道这个类中的所有属性和方法;对于任意一个对象,都能够调用它的任意一个方法和属性;这种动态获取的信息以及动态调用对象的方法的功能称为java语言的反射机制。

动态获取类中信息,就是java反射 。可以理解为对类的解剖。


Class类

如果要完成反射,那么必须了解Class类

实例1:通过对象取得包名和类名

 

package org.siu;
 
class Test {
     
}
 
public class Demo {
    public static void main(String[]args) {
        Testt = new Test();
        System.out.println(t.getClass());
        System.out.println(t.getClass().getName());
    }
}
 
 


在java中,Object类是所有类的父类,同样,所有类的实例化对象也都是Class类的实例

因此,这样一来就会牵扯到向上转型和向下转型的概念

由于向下转型的不安全因素,在这里泛型也会接踵而来

 

实例2:Class类的实例化

由于Class类没有构造方法,所以实例化Class类的方式有点特殊,有三种方式:

对象.getClass( )

类.Class

forName( )

 

class Test {
     
}
 
public class Demo {
    public static void main(String[]args) {
        //方式一:
        Testt = new Test();
        Class<? extends Test>c1 = t.getClass();
        System.out.println(c1);
         
        //方式二:
        //为了避免特殊性,这里不用Test类,而用java库中的String类
        Class<String>c2 = String.class;
        System.out.println(c2);
         
        //方式三:
        //forName()方法会抛出异常
        Class<?>c3 = null;
        try {
            c3= Class.forName("Test");
        } catch (ClassNotFoundExceptione) {
            e.printStackTrace();
        }
        System.out.println(c3);
    }
}
 


其中,forName( )方法需要重点掌握,因为它可以在类不确定的情况下实例化Class,更具灵活性

 

 

Class类的应用

Class类中有一个方法叫做newInstance(),它可以用来创建一个Class类对象的新实例

怎么说呢?Class对象包含的内容就是反射好的那个类,我们要构造那个类的新实例(新对象)


实例3:Class类的无参构造对象

public class Demo {
    public static void main(String[]args) {
        //实例化Class对象,forName()方法会抛异常
        Class<?>c = null;
        try {
            //这里需要完整的包名和类名
            c= Class.forName("java.lang.String");
        } catch (ClassNotFoundExceptione) {
            e.printStackTrace();
        }
         
        //生成一个字符串的引用
        Strings = null;
        try {
            //将构造好的对象向下转型为String类
            //newInstance()方法会抛异常
            s= (String) c.newInstance();
        } catch (InstantiationExceptione) {
            e.printStackTrace();
        } catch (IllegalAccessExceptione) {
            e.printStackTrace();
        }
        System.out.println("字符串长度: " + s.length());
    }
}
 


这样就通过无参数的形式构造了一个新的对象,如同正常模式中

通过无参构造方法来构造新对象一样

我们知道,类中除了有无参构造方法,还会存在有参数的构造方法

那在反射中如何通过有参数的形式构造对象呢?接着看

 

实例4:Class类的有参构造对象

 

import java.lang.reflect.Constructor;
 
public class Demo {
    //下面的几个方法抛出来的异常太多,为了代码的紧凑性,这里就直接抛给虚拟机了
    public static void main(String[]args) throws Exception {
        Class<?>c = null;
        try {
            c= Class.forName("java.lang.String");
        } catch (ClassNotFoundExceptione) {
            e.printStackTrace();
        }
        char[]ch = {'h','e','l','l','o'};
        Strings = null;
        //获得Class类对象的有参构造方法,括号里面参数的写法是:类型.class
        Constructor<?>con = c.getConstructor(char[].class);
        //用此构造方法构造一个新的字符串对象,参数为一个char数组
        s= (String) con.newInstance(ch);
        System.out.println("构造的字符串:" + s);
    }
}
 


我们还是使用String类做例,因为String类用的比较多,便于理解

这里需要注意的是,构造方法需要使用getConstructor()方法获得

至于参数类型则是:原有类型.class

 

还有一点,无论是有参还是无参,这里所使用的构造方法,原本的类里面必须对应存在

那么,如何才能知道原有类里面的构造方法,普通方法,继承的父类等详细信息呢?接着看

 

实例5:取得类的构造方法

获取类的结构

要通过反射获取类的结构我们这里要导入一个新的包java.lang.reflect

import java.lang.reflect.Constructor;
import java.util.Arrays;
 
public class Demo {
    //下面的几个方法抛出来的异常太多,为了代码的紧凑性,这里就直接抛给虚拟机了
    public static void main(String[]args) throws Exception {
        Class<?>c = null;
        try {
            c= Class.forName("java.lang.Boolean");
        } catch (ClassNotFoundExceptione) {
            e.printStackTrace();
        }
        //这里的getConstructors()方法返回的是一个Constructor数组
        Constructor<?>[]cons = c.getConstructors();
        //打印的方式你可以自己写,为了方便我用Arrays.toString(),凑合着看
        System.out.println(Arrays.toString(cons));
    }
}
 


实例6:取得类所实现的接口

import java.util.Arrays;
 
public class Demo {
    public static void main(String[]args) throws Exception {
        Class<?>c = null;
        try {
            c= Class.forName("java.lang.Boolean");
        } catch (ClassNotFoundExceptione) {
            e.printStackTrace();
        }
        Class<?>[]in = c.getInterfaces();
        System.out.println(Arrays.toString(in));
    }
}
 


实例7:取得父类

 

public class Demo {
    public static void main(String[]args) throws Exception {
        Class<?>c = null;
        try {
            c= Class.forName("java.lang.Boolean");
        } catch (ClassNotFoundExceptione) {
            e.printStackTrace();
        }
        //注意了,这里不会是数组,why?
        Class<?>su = c.getSuperclass();
        System.out.println(su);
    }
}


 

实例8:取得类的全部方法

 

import java.lang.reflect.Method;
 
public class Demo {
    public static void main(String[]args) throws Exception {
        Class<?>c = null;
        try {
            c= Class.forName("java.lang.Boolean");
        } catch (ClassNotFoundExceptione) {
            e.printStackTrace();
        }
        Method[]m = c.getMethods();
     
        for (int i= 0; i < m.length; i++) {
            System.out.println(m[i]);
        }
    }
}
 


实例9:取得本类的全部属性

import java.lang.reflect.Field;
 
class Person {
    private Stringname;
    private int age;
}
 
public class Demo {
    public static void main(String[]args) throws Exception {
        Class<?>c = null;
        try {
            c= Class.forName("Person");
        } catch (ClassNotFoundExceptione) {
            e.printStackTrace();
        }
        Field[]f = c.getDeclaredFields();
        for (int i= 0; i < f.length; i++) {
            System.out.println(f[i]);
        }
    }
}
 


实例10:获取本类中属性的值

import java.lang.reflect.Field;
 
class Person {
    public Stringname;
    private int age;
     
    public Person(Stringname, int age) {
        this.name= name;
        this.age= age;
    }
}
 
public class Demo {
    public static void main(String[]args) throws Exception {
        Personp = new Person("zhangsan",12);
 
        Class<?>c = p.getClass();
         
        //获取公共属性的值
        Fieldf1 = c.getField("name");
        //get(p)表明要获取是哪个对象的值
        Stringstr = (String) f1.get(p);
        System.out.println("姓名: " + str);
         
        //获取私有属性的值
        Fieldf2 = c.getDeclaredField("age");
        //age是私有属性,所以要设置安全检查为true
        f2.setAccessible(true);
        int age= (int) f2.get(p);
        System.out.println("年龄: " + age);
    }
}
 


反射的应用

实例11:通过反射修改属性

import java.lang.reflect.Field;
 
class Person {
    private Stringname;
     
    public Person(Stringname) {
        this.name= name;
    }
     
    public StringtoString() {
        return "姓名: " + this.name;
    }
}
 
public class Demo {
    public static void main(String[]args) throws Exception {
        Personp = new Person("王二狗");
        System.out.println(p);
        Class<?>c = p.getClass();
     
        //定义要修改的属性
        Fieldf = c.getDeclaredField("name");
        f.setAccessible(true);
        //修改属性,传入要设置的对象和值
        f.set(p, "张二蛋");
        System.out.println(p);
    }
}


 

实例12:通过反射调用方法

import java.lang.reflect.Method;
 
class Person {
    public void print(int i){
        System.out.println("我在写数字: " + i);
    }
     
    public static void say(Stringstr) {
        System.out.println("我在说: " + str);
    }
}
 
public class Demo {
    public static void main(String[]args) throws Exception {
        Personp = new Person();
        Class<?>c = p.getClass();
     
        //getMethod()方法需要传入方法名,和参数类型
        Methodm1 = c.getMethod("print", int.class);
        //invoke()表示调用的意思,需要传入对象和参数
        m1.invoke(p, 10);
         
        Methodm2 = c.getMethod("say", String.class);
        //这里的null表示不由对象调用,也就是静态方法
        m2.invoke(null, "你妹");
    }
}


实例13:通过反射操作数组

import java.lang.reflect.Array;
 
public class Demo {
    public static void main(String[]args) throws Exception {
        int[]arr = {1,2,3,4,5};
        Class<?>c = arr.getClass().getComponentType();
         
        System.out.println("数组类型: " + c.getName());
        int len= Array.getLength(arr);
        System.out.println("数组长度: " + len);
        System.out.print("遍历数组: ");
        for (int i= 0; i < len; i++) {
            System.out.print(Array.get(arr,i) + " ");
        }
        System.out.println();
        //修改数组
        System.out.println("修改前的第一个元素: " + Array.get(arr, 0));
        Array.set(arr, 0, 3);
        System.out.println("修改后的第一个元素: " + Array.get(arr, 0));
    }
}
 
 


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值