Java学习笔记18-反射

什么是反射?

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

 1.反射的实现功能

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

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

        ③在运行时判断任意一个类所具有的成员变量和方法;

        ④在运行时调用任意一个对象的方法;

        ⑤生成动态代理;

2.获取源头Class(重点)

         Class<T> Class类型的实例可以用来表示java中运行期间的一个类型,这个 Class 实例可以理解为类的模子,就是包含了类的结构信息。

获取(反射的源头)Class对象的方式:

                                 1.类名.class              

                                 2.Class.forName(权限定名) 权限定名:包名.类名 -->推荐

                                 3.对象.getClass()

:Class对象在类第一次加载到内存后就已经存在的,唯一的,不变的,每一个类型只有一个

Class对象可以操作这个类的所有内容(属性方法构造器...)

//实例代码-获取反射原头Class对象的三种方式
public class Class002_Reflect {
    public static void main(String[] args) throws ClassNotFoundException {
        //1.类名.class
        Class<String> cls1 = String.class;
        System.out.println(cls1.toString());

        //2.Class.forName(权限定名)
        Class cls2 = Class.forName("java.lang.String");
        System.out.println(cls2);

        //3.对象.getClass()
        Class cls3 = "abc".getClass();
        System.out.println(cls3);

        //获取当前Class对象所表示类型的父类的Class对象
        Class cls4 = cls1.getSuperclass();
        System.out.println(cls4);

        //获取基本数据类型的Class对象
        System.out.println(Integer.class);
        System.out.println(int.class);
        System.out.println(int.class==Integer.class);
        System.out.println(Integer.TYPE);
        System.out.println(Integer.TYPE==int.class);
    }
}

3.构造器

        根据Class对象,我们可以获得构造器,为实例化对象做准备

Constructor<T>

getConstructor(类<?>... parameterTypes)

返回一个Constructor对象,该对象反应Constructor对象表示的类的指定的公共函数

Constructor<?>[]

getConstructors()

返回包含一个数组Constructor对象反射由此表示的类的所有公共构造类对象

        

//实例代码-通过创建Class对象获取构造器
public class Class003_Reflect {
    public static void main(String[] args) throws IllegalAccessException, InstantiationException, NoSuchMethodException, InvocationTargetException {

        //获取构造器(只能获取被public修饰的公共的构造函数)
        Class<User> cls = User.class;
        Constructor[] cons =  cls.getConstructors();
        for(Constructor con:cons){
            System.out.println(con);
        }
        //获取构造器对象的数组, 构造器对象反映由此类对象表示的类声明的所有构造函数(包括类中私有的)
        Constructor<User> con = cls.getDeclaredConstructor(String.class,int.class);
        System.out.println(con);

        //创建对象
        //1)
        User user =  User.class.newInstance();
        System.out.println(user);
        //2) 私有内容需要忽略权限使用
        con.setAccessible(true);  //忽略权限
        User user2 = con.newInstance("laopei",1234);
        System.out.println(user2);
    }
}
class User{
    private String name;
    private int pwd;
    //公共的
    public User() {
    }
    public User(String name) {
        this.name = name;
    }
    //私有的
    private User(String name, int pwd) {
        this.name = name;
        this.pwd = pwd;
    }
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }

    public int getPwd() {
        return pwd;
    }
    public void setPwd(int pwd) {
        this.pwd = pwd;
    }
    @Override
    public String toString() {
        return "User{" +
                "name='" + name + '\'' +
                ", pwd=" + pwd +
                '}';
    }
}

4.实例化对象

创建对象的方式,有new 、克隆、反序列化,再加一种,根据Class对象,使用 newInstance() 或者构 造器实例化对象。

T newInstance()   默认调用类型的空构造为对象初始化信息 -->不推荐使用

:不能确定一个类型是否存在空构造,极有可能遇到运行时异常)

T newInstance(Object... initargs)    创建对象的同时调用当前构造器为对象初始化信

 5.属性和方法

获取所有属性(包括父类或接口) ,使用 Field 即可操作, Field 作为描述属性的对象

         Field                  getDeclaredField(String nname)

                                   返回一个Field对象,它反映此表示的类或接口的指定已声明字段,类对象

         Field[ ]               getDeclaredFields( )

                                   返回的数组Field对象反应此表示的类或接口声明的所有字段,类对象

         Field                  getField(String name)

                                    返回一个Field对象,它反映此表示的类或接口的指定公共成员字段,类对象

         Field[ ]               getFields( )

                                  返回包含一个数组Field对象反射由此表示的类或接口的所有可烦跟我的公共字段,类对象

 获取所有方法(包括父类或接口),使用 Method 即可。 Method 即作为描述方法的对象

  • 方法 getMethod(String name, 类<?>... parameterTypes)  返回 方法对象,该对象反映此 类对象表示的类或接口的指定公共成员方法。
  • 方法[] getMethods() 返回一个包含 方法对象的数组, 方法对象反映此 类对象所表示的类或接口的所有公共方法,包括由类或接口声明的那些以及从超类和超接口继承的那些。
  • 方法 getDeclaredMethod(String name, 类<?>... parameterTypes) 返回 方法对象,该对象反映此 类对象表示的类或接口的指定声明方法。
  • 方法[] getDeclaredMethods() 返回一个包含 方法对象的数组, 方法对象反映此 类对象表示的类或接口的所有已声明方法,包括public,protected,default(package)访问和私有方法,但不包括继承的方法。
//实例代码-反射操作属性和方法
public class Class004_Reflect {
    public static void main(String[] args) throws NoSuchFieldException, IllegalAccessException, NoSuchMethodException, InvocationTargetException {
        User user = new User("zhangsan");
        //User类的Class对象
        Class<User> cls = User.class;
        testMethod(cls,user);
    }
    //测试方法
    public static void testMethod(Class<User> cls,User user) throws NoSuchMethodException, InvocationTargetException, IllegalAccessException {
        Method[] methods = cls.getMethods();
        for(Method m:methods){
            System.out.println(m);
        }
        //私有方法
        Method method = cls.getDeclaredMethod("haha",int.class);
        //调用方法
        method.setAccessible(true);
        System.out.println(method.invoke(user,100));;
        System.out.println(method.invoke(null,100));;
        Method m = cls.getMethod("getName");
        System.out.println(m.invoke(user));
    }
    //测试属性
    public static void testField(Class<User> cls,User user) throws NoSuchFieldException, IllegalAccessException {
        Field field = cls.getDeclaredField("name");
        System.out.println(field.getName());
        System.out.println(field.getType());
        //忽略权限
        field.setAccessible(true);
        field.set(user,"zhangsanfeng");
        System.out.println(field.get(user));
    }
}

6.反射操作数组

        操作数组需要借助Array类。

  • static Object newInstance(类<?> componentType, int length) 创建具有指定组件类型和长度的新数组。
  • static Object get(Object array, int index) 返回指定数组对象中索引组件的值。
  • static void set(Object array, int index, Object value) 将指定数组对象的索引组件的值设置为指定的新值。
//实例代码-反射操作数组
public class Class005_Reflect {
    public static void main(String[] args) throws Exception {
        //调用方法
        testArray();
        test(String.class);
    }
    public static void test(Class<String> cls){
        //int getModifiers() 返回此类或接口的Java语言修饰符,以整数编码。
        System.out.println(cls.getModifiers());
        System.out.println(Modifier.toString(cls.getModifiers()));

        //类<?>[] getInterfaces() 返回由此对象表示的类或接口直接实现的接口。
        System.out.println(Arrays.toString(cls.getInterfaces()));

        //String getName() 返回此 类对象表示的实体名称(类,接口,数组类,基本类型或void),作为 String 。
        System.out.println(cls.getName());

        //String getSimpleName() 返回源代码中给出的基础类的简单名称。
        System.out.println(cls.getSimpleName());
    }

    //简单操作数组
    public static void testArray(){
        int[] arr = (int[]) Array.newInstance(int.class,5);
        Array.set(arr,2,200);
        System.out.println(Arrays.toString(arr));
        System.out.println(Array.get(arr,2));
    }
}

 

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值