黑马程序员——java中的反射

——Java培训、Android培训、iOS培训、.Net培训、期待与您交流! ——-

Class类

Java类用于描述一类事物的共性,该类事物有什么属性,没有什么属性。至于这些属性的值是什么,则是由于这个类的实例来确定,不同的实例对象间有不同的属性值。那么我们思考一下?java中有着各种不同的java类,在编写程序时还自定义了很多新的类,而这些类是否属于同一类事物,,是不是也可以用一个类来描述这一类事物。在Java中,这一个类的名称就是Class。
Class
在Java中把类看作一类事物,而该类事物所对应的的类是就是Class,该Class生成的对象就是对应java虚拟机加载的类字节码。
Class 没有公共构造方法。Class 对象是在加载类时由 Java 虚拟机以及通过调用类加载器中的 defineClass 方法自动构造的,因此不能显式地声明一个Class对象。
虚拟机为每种类型管理一个独一无二的Class对象。也就是说,每个类(型)都有一个Class对象。运行程序时,Java虚拟机(JVM)首先检查是否所要加载的类对应的Class对象是否已经加载。如果没有加载,JVM就会根据类名查找.class文件,并将其Class对象载入。每一类只有一份字节码。
基本的 Java 类型(boolean、byte、char、short、int、long、float 和 double)和关键字 void 也都对应一个 Class 对象。
每个数组属于被映射为 Class 对象的一个类,所有具有相同元素类型和维数的数组都共享该 Class 对象。
我们要注意到,该Class与class是不同的。既然说Class是对java类的描述,那么Class描述了java类中的哪一些属性呢?那就要看Java类中有什么属性,类名、类的包名、字段名称、方法名称等等,也就是说在Class 中定义了对这些属性的操作方法。

三种获获得字节码的方法
1、通过对象获得类字节码:
String str = “abc”;
Class cla1 = str.getClass();

2、通过类名的到类字节码:
Class cla2 = String.class;

3、通过字符串得到到指定字节码
Class cla3 = Class.forName(“java.lang.String”);

Class的部分方法
getConstructors():
返回一个包含某些 Constructor 对象的数组,这些对象反映此 Class 对象所表示的类的所有公共构造方法。
getField(String name):
返回一个 Field 对象,它反映此 Class 对象所表示的类或接口的指定公共成员字段
getMethods():
返回一个包含某些 Method 对象的数组,这些对象反映此 Class 对象所表示的类或接口(包括那些由该类或接口声明的以及从超类和超接口继承的那些的类或接口)的公共 member 方法。
getClassLoader():
返回该类的类加载器。

一个简单的程序理解Class:

public class ReflectTest {

    /**
     * Class的部分代码演示
     */
    public static void main(String[] args) {
        // TODO Auto-generated method stub
        //得到字节码的方法
          String str = "abc";
          Class  cla1 = str.getClass();
          Class cla2 = String.class;
          Class cla3 = null;
          try {
              cla3 = Class.forName("java.lang.String");
        } catch (ClassNotFoundException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
          //判断是否是同一字节码
          System.out.println(cla1==cla2);
          System.out.println(cla2==cla3);
          //基本数据类型的Class与引用类型的Class不同
          System.out.println(int.class ==Integer.class);
          System.out.println(int.class.isPrimitive());
          //数组被映射为 Class 对象的一个类
          System.out.println(int[].class.isPrimitive());
    }

运行效果:
这里写图片描述

对于类中的方法的 具体操作在反射中介绍:

反射

一个Java类用是一个Class对象的来表示,类中的组成部分:成员变量、成员方法、构造函数、包等信息,把这些类的组成部分都看着对象,他们都有各自对应的类,Field、Methed、Contructor、Package等等。每一个对象通过Class 类的方法可以得到这些成员实例对象。

Constructor类
把类中的构造函数的看作一个对象,该对象所对应的类的就是Constructor类,通过Class对象中的getConstructor 方法可以获得构造函数对象,该类通过了一些方便操作构造函数的方法。
getName() : 以字符串形式返回此构造方法的名称。
newInstance(Object… initargs) :使用此 Constructor 对象表示的构造方法来创建该构造方法的声明类的新实例,并用指定的初始化参数初始化该实例。

/**
 *  利用反射生成对象
 *
 */
public class ReflectTest {


    public static void main(String[] args)   {
         //普通的方法生成对象
        Person p1 = new Person("李四");
        System.out.println(p1);
        //获得Class对象
          Class<Person> cla = Person.class;  
            try {
                 //获得Person的构造方法指定的构造方法对象
                Constructor<Person> constr = cla.getConstructor(String.class);
                 //用构造方法对象生成实例对象
                Person p2 = constr.newInstance("张三");
                System.out.println(p2);
            } catch ( Exception e) {

                e.printStackTrace();
            }  


    }

}
class Person
{
    private String name = null;
    public Person(String name)
    {
        this.name = name;
    }
    @Override
    public String toString() {

        return name;
    }
}

运行结果
这里写图片描述

Field类
Feid类的对象是指的是Java类中的定义的属性字段,也就是说类中的成员变量就是Field类的对象。Field类的对象代表的是类上的的属性字段,而不是表示某一对象的成员变量值。通过Class类中的getField 可以获得指定名称的成员变量的对象。
Field类中部分方法:
getName():返回此 Field 对象表示的字段的名称
get(Object obj): 返回指定对象上此 Field 表示的字段的值
set(Object obj, Object value): 将指定对象变量上此 Field 对象表示的字段设置为指定的新值。

/**
 *  Field的演示操作
 *
 */
public class ReflectTest {


    public static void main(String[] args)   {

          Person person = new Person("张三");
          Class  cla =  person.getClass();
          try {
              //得到指成员变量对象
            Field fname = cla.getField("name");
            //通过Field对象获得指定对象的成员变量值
            System.out.println(fname.get(person));
            //修改对象的成员变量值
            fname.set(person, "李四");
            System.out.println(person);
        } catch ( Exception e) {

            e.printStackTrace();
        }  

    }

}
class Person
{
    public  String name = null;
    public Person(String name)
    {
        this.name = name;
    }
    @Override
    public String toString() {

        return name;
    }
}

运行结果
这里写图片描述

Method类
表示的是java类中成员方法对象的类,与Field类相同,
基本方法:
invoke(Object obj, Object… args): 对带有指定参数的指定对象调用由此 Method 对象表示的底层方法。

/**
 *  Method的演示操作
 *
 */
public class ReflectTest {


    public static void main(String[] args)   {

          Person person = new Person("张三");

          Class  cla =  person.getClass();
           try {
               //得到指定方法对象
            Method  method = cla.getMethod("show");
            //调用指定对象的方法
            method.invoke(person);

        } catch ( Exception e) {

            e.printStackTrace();
        }     
    }

}
class Person
{
    public  String name = null;
    public Person(String name)
    {
        this.name = name;
    }
    public void show()
    {
        System.out.println(name);
    }


}

暴力反射

现在我们已经学习了Java类中的各成员所对应的类(Constructor、Field`、Method),要注意到类中的每一个成员都有修饰符,对于公共成员、默认(打包)访问成员、受保护成员和私有成员,在分别使用 Field、Method 或 Constructor 对象来设置或获取字段、调用方法,或者创建和初始化类的新实例的时候,会执行访问修饰检查。我们只能够对公共的进行访问,这也就限制了反射的访问范围。AccessibleObject 类是 Field、Method 和 Constructor 对象的基类。它提供了将反射的对象标记为在使用时取消默认 Java 语言访问控制检查的能力,这也既可以用反射访问到类中的不可见成员,这也的过程操作被称为暴力反射。

/**
 *  利用暴力反射创建实例对象
 *
 */
public class ReflectTest {


    public static void main(String[] args)   {
        //获得单例对象
         Person p1 = Person.getPerson();
         //用反射创建对象
         try {
             //得到构造函数
            Constructor<Person> con = Person.class.getDeclaredConstructor(String.class);
            //设计为可访问对象
            con.setAccessible(true);
            //生成对象
            Person p2 = con.newInstance("李四");
            //判断是否为同一对象
            System.out.println(p1==p2);
        } catch ( Exception e) {

            e.printStackTrace();
        }  
    }  

}
//单例模式,不能能创建实例对象
class Person
{
       private final  static Person person = new Person("张三");
       private String name = null;
        private Person(String name)
        {
            this.name = name;
        }
        static public Person getPerson()
        {
            return person;
        }
}

运行效果
这里写图片描述

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值