码迷,mamicode.com
首页 > 其他好文 > 详细

反 射

时间:2019-11-06 19:55:34      阅读:76      评论:0      收藏:0      [点我收藏+]

标签:type   throw   引用数据类型   方法区   如何使用   const   double   zha   name   

一.概述
反射的学习,是便于能更好的理解框架编程。 目前主流的框架技术底层都是反射的机制,如:struts、spring、hibernate等
 
反射本质上就是一种动态编程的技术,可以在运行阶段动态地创建对象以及动态地调用方法,具体由实参决定。
 
 
引出:
若想在写代码的时候,不能确定需要创建Person对象 还是 Student对象。而是希望程序到了运行阶段,能够自行动态地决定创建具体的那个所需对象。
那么此时,就需要用到反射技术!
 
如:
Person p = new Person(); - 只能创建Person类型的对象。
Student s = new Student(); - 只能创建Student类型的对象。
 
void show(){ }
void show(int i){ }
void show(double d){ }
 
如何使用 反射 ?
要用反射技术,需要借助一个类: Java.lang.Class
 
二,Class 类
 
1、基本概念
java.lang.Class类的实例代表应用程序的类和接口,通俗来说,就是该类的实例代表一种数据类型。
(不是内存空间中堆区中普通对象的一块内存空间)
 
  区别于: Person p =new Person();
Person的一个实例, 代表的是 堆区中的一块内存空间。 而java.lang.Class类的实例代表一种数据类型。
 
 
该类没有公共的构造方法(自个不能new这个类的对象),
class对象是在加载类的时候,由Java虚拟机,以及通过调用类加载器中的defineClass( )方法自动构造的。【构造出来即代表一种数据类型】
 
那么要想使用Class这个类,则需要得到该类的引用!
 

如何获取该类的引用?
2.Class对象的获取方式(4种)
 
a. 使用 数据类型.class 的方式可以获取该类型的Class对象。(引用数据类型,基本数据类型都适用
b. 使用 对象.getClass() 的方式可以获取该类型的Class对象。(只适用于引用数据类型)
【万物皆对象。所以,任何一个类都可以用 对象.getClass()方法区获取 它的class对象】
c. 使用 包装类的TYPE属性 获取该包装类对应基本数据类型的Class对象。
d.使用Class类的 forName() 方法获取参数类型的Class对象。 【forName()中,包名 不能省略】 (底层框架中,这种方式最常用)
 
基本数据类型 获取class对象的途径3种:a c d
引用数据类型 获取class对象的途径3种:a b d
  代码测试:ClassObjectTest .java
package com.moneky1024;

public class ClassObjectTest {

    public static void main(String[] args) throws ClassNotFoundException {
        //1.使用数据类型.class的方式来获取该类型的Class对象
                //class java.lang.String 
                System.out.println(String.class);//自动调用toString()方法
                System.out.println(int.class);   //int
                System.out.println(void.class);  //void
                System.out.println();
                
                //2.使用对象.getClass()的方式来获取该类型的Class对象
                String s1 = new String("GoodMorning");
                System.out.println(s1.getClass());//class java.lang.String
                
                Integer it1 = new Integer(66);
                System.out.println(it1.getClass());//class java.lang.Integer
                
                //int num = 118;
                //System.out.println(num.getClass()); error
                System.out.println();
                
                //3.使用包装类的TYPE属性来获取基本数据类型的Class对象
                System.out.println(Integer.TYPE); // int
                System.out.println(Integer.class);//class java.lang.Integer
                System.out.println();
                
                //4.使用Class类的forName()方法获取Class对象
                //class java.lang.String
                System.out.println(Class.forName("java.lang.String"));
                //System.out.println(Class.forName("int")); error

    }

}

 

 
 

 
常用方法:
static Class forName(String className) - 获取参数指定类型的Class对象。
T newInstance( ) - 根据Class对象创建新实例。
 
Constructor<T> getConstructor(Class<?>... parameterTypes) - 用于获取当前Class对象对应类中指定的公共构造方法。 (获取单个)
Constructor<?>[ ] getConstructors( ) - 获取对应类中所有的公共构造方法。 (获取多个,数组接收)
 
Field getDeclaredField(String name) - 获取对应类中指定的成员变量。
Field[ ] getDeclaredFields() - 获取对应类中所有的成员变量。
 
Method getMethod(String name, Class... parameterTypes) - 用于获取对应类中指定的公共成员方法。
Method[ ] getMethods() - 用于获取对应类中所有的公共成员方法。
 
代码:
package com.moneky1024;

public class Person {
    
    private String name;
    private int age;
    
    public Person() {
        super();
    }
    public Person(String name, int age) {
        super();
        setName(name);
        setAge(age);
    }
    
    @Override
    public String toString() {
        return "Person [name=" + name + ", age=" + 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;
    }
    
    
    

}

 

测试类:
package com.moneky1024;

import java.lang.reflect.Constructor;

public class Test {
    
    public static void main(String[] args) throws Exception {
        //1.创建Person类型的对象
        Person p = new Person();   //调用无参构造方法
        System.out.println(p);    //null 0
        System.out.println();
        
        //2.获取Person类的Class对象并创建实例打印  null 0
        System.out.println(Class.forName("xdl.day21.Person").newInstance());
        System.out.println();
        
        Person p2 = new Person("zhangfei", 30);
        System.out.println(p2); //zhangfei 30
        System.out.println();
        
        //1.获取Class对象,使用forName()方法
        Class c1 = Class.forName("xdl.day21.Person");
        //2.获取对应类中的构造方法,形参类型分别为:String 和 int        
        Constructor cs1 = c1.getConstructor(String.class, int.class);
        //3.调用该构造方法创建新实例,并指定初始值,打印新实例的结果
        System.out.println(cs1.newInstance("guanyu", 35));//guanyu 35   
    }
}

 

结果:
class java.lang.String
int
void

class java.lang.String
class java.lang.Integer

int
class java.lang.Integer

class java.lang.String

 

 

解析代码:
    public Person(String name, int age) {
        super();
        setName(name);
        setAge(age);
    }

 

Person类中的形参类型分别为: String 和 int 。
而在getConstructor(Class<?>...parameterTypes) 中 参数要的是 class类型
 
 Constructor cs1 = c1.getConstructor(String.class, int.class);

 

即,getConstructor(String.class, int.class);

提出问题:
 在class这个类中,提供了 无参的构造 形式。但是没有 提供 有参的构造形式 去创建新实例,那如果 想创建有参的对象,怎么办?
 
1、利用Class类中提供的 getConstructor( )方法;
它的作用: 获取括号中填写参数,指定的类的构造方法的信息。 拿出来后,封装到 Constructor <T> 类里面。
即, Constructor 类的对象,专门代表获取的构造方法。
 
2、获取到构造方法后,需要再借助一个 newInstance( )方法 :
 
调用 newInstance()的对象,使用 之前获取到的 构造方法 去构造这个新实例。

三、 Constructor类
java.lang.reflect.Constructor类 用于描述获取到的构造方法
 
T newInstance(Object... initargs) - 调用当前描述的构造方法去创建新实例。
 

四、Field类
 
java.lang.reflect.Field 类 用于描述获取到的成员变量
 
常用方法:
Object get(Object obj) - 用于获取指定对象中此成员变量的数值。
void setAccessible(boolean flag) - 参数为true表示可以访问私有成员。
void set(Object obj, Object value) - 用于修改指定对象中当前成员变量的数值。
 
代码:
 
先编写一个Person.java类 (同上)
FieldTest.java类测试:
package com.monkey1024;

import java.lang.reflect.Field;

public class FieldTest {
    
    public static void main(String[] args) throws Exception{
        //1.获取Class对象括号中 是   包名+类名
        Class<?> c1 = Class.forName("com.monkey1024.Person");
        
        //2.创建一个Person类型的对象,并传递实参   //为了得到对应的构造方法       // 传参
        Person p = (Person) c1.getConstructor(String.class,int.class).newInstance("zhangfei", 30);   
        
        //3.获取对应类中指定的成员变量
        Field f1 = c1.getDeclaredField("name");     //提供 指定的成员变量 名,获得该指定的变量
        
        //4.设置可以访问私有成员变量
        f1.setAccessible(true);    //若这行代码没有,则私有变量 不能被成功访问
        
        //5.获取指定对象中此成员变量的数值并打印出来
        System.out.println(f1.get(p)); // zhangfei      f1.get(p)表示 去这个p对象中,找到名字为 name 的成员变量,并返回 这个变量
        
        //6.修改指定对象中此成员变量的数值修改为"guanyu"
        f1.set(p, "guanyu");
        System.out.println(f1.get(p)); // guanyu
    }

    

}

 

结果:
zhangfei
guanyu

 

 
 

五、Method类
 
java.lang.reflect.Method类 用于描述获取到的成员方法
 
常用方法:
Object invoke(Object obj, Object... args) - 用于obj对象调用当前方法,并传递args作为实参。
 
代码:
package com.monkey1024;

import java.lang.reflect.Method;

public class MethodTest {


    public static void main(String[] args) throws Exception {
        
        //1.获取Class对象
        Class c1 = Class.forName("com.monkey1024.Person");
        
        //2.使用有参构造方法创建该类的实例
        Person p = (Person) c1.getConstructor(String.class, int.class).newInstance("zhangfei", 30);
        
        //3.获取对应类中指定的成员方法
        Method m1 = c1.getMethod("toString");
        
        //4.使用该对象调用此方法,并打印结果
        System.out.println(m1.invoke(p));// zhangfei 30
    }

}

 

 
结果:
Person [name=zhangfei, age=30]

 

反 射

标签:type   throw   引用数据类型   方法区   如何使用   const   double   zha   name   

原文地址:https://www.cnblogs.com/penguin1024/p/11808149.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!