黑马程序员-反射

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

Class类----反射的基石

Class类代表一类事物  

java类用于描述一类事物的共性,该事物有什么属性,没有什么属性,至于这个属性的值是什么,则由这个类的实例对象来确定。Java中的各个java类,他们是否属于同一类事物,是不是可以用一个类来描述这类事物呢,这个类名就是Class

Class类描述了哪些信息呢——类的名字,类的访问属性,类所属的包名,字段名称的列表,方法名称的列表


九个预定义的Class实例对象

基本的 Java 类型(booleanbytecharshortintlongfloatdouble)和关键字void 也表示为 Class 对象。

例子    Class cl = void.class;

isPrimitive() 方法
          判定指定的 Class 对象是否表示一个基本类型。

Int.class == Integer.TYPE   TYPE代表一个常量,就是基本类似所代表的字节码


数组类型的Class实例对象

Int[].class.isArray() 也是基本类型

结果true 

总之,只要在源程序中出现的类型都有自己的Classs实例对象


反射

 反射就是把java类中的各种成分映射成相应的java类


Constructor类

代表某个类中的一个构造方法

得到某个类所有的构造方法

Constructor    constructor[]   =

Class.forName(“java.lang.String”).getConstructor()

 

得到某个类所有的一个方法

Constructor    constructor[]   =

Class.forName(“java.lang.String”).getConstructor(StringBuffer.class)

//获得方法时要用到类型

 

创建实例对象

 

一般方式

String str1 = new String (new StringBuffer("abc"));

 

反射方式  classàconstrutorànew object

Constructor constructor1 = String.class.getConstructor(StringBuffer.class);

String str2 =

(String) constructor1.newInstance(newStringBuffer("abc"));

//调用获得的方法时要用到上面相同类型的实例对象

 

Class.newInstance()方法  不带参数的构造方法

例子:String str = (String)Class.forName(“java.lang.String”) .newInstance

该方法内部先得到默认的构造方法,然后用该构造方法创建实例对象

 

成员变量的反射

Filed类 代表某个类中的一个成员变量

       ReflectPoint pt1 = new ReflectPoint(3,5);

       //获取一个字段,fieldY代表字节码身上的变量,没有对应到对象身上所以fieldY的值不是5

       Field filedY = pt1.getClass().getField("y");

       //取出变量在某个对象上的值

        System.out.println(filedY.get(pt1));

获取私有的

       //x是私有的    会返回java.lang.NoSuchFieldException: x错误

       //Field filedX =pt1.getClass().getField("x");//getField只能的到可见的

       Field filedX = pt1.getClass().getDeclaredField("x");//getDeclaredFields可以获取不可见的

       //getDeclaredFields虽然可以看见了但是不可以使用,

       filedX.setAccessible(true);

       //取出变量在某个对象上的值

       System.out.println(filedX.get(pt1));


将任意一个对象中的所有String类型的成员变量所对应的字符串内容中的”b”改成”a”

    //定义String类型
    public String str1 = "ball";
    public String str2 = "basketball";
    public String str3 = "itcast";
   
    public String toString(){
       return str1+"::"+str2 +"::" + str3;
    }
 
 
 
       //将字符串中的b改变成a
       changeStringValue(pt1);    
       System.out.println(pt1);
       }
 
    private static void changeStringValue(Object obj) throwsIllegalArgumentException, IllegalAccessException {
       Field[] fields = obj.getClass().getFields();
       for(Field field : fields){
           //获取类型
/*         field.getType().equals(String.class)  字节码应该用等号比*/ 
           if(field.getType() == (String.class)){
              //获取变量的值
              String oldValue = (String) field.get(obj);
              //b改变成a 获取新值
              String newValue = oldValue.replace("b", "a");
              //对象的字段还没有改
              field.set(obj, newValue);
           }
    }
    }
 

成员方法的反射

Method类代表某个类中的成员方法

String str1 = "abcs";
       Method charAt = Class.forName("java.lang.String").getMethod("charAt", int.class);
       //JDK1.5多个可变参数
       System.out.println(charAt.invoke(str1, 1));//如果invoke(str1,1));里的对象为null则代表为静态的
       //JDK1.4                                      //静态方法调用不需要对象
       System.out.println(charAt.invoke(str1,new Object[]{1}));


用反射方式执行某个类中的main方法

目标:写一个程序,这个程序能够根据用户名提供的类名,去执行该类中的main方法

public class GetMainDemo {
 
    public static void main(String[] args) throws Exception {
       // TODO Auto-generatedmethod stub
       //一般调用方法
       //MainDemo.main(newString[]{"114","12r5"});
       //反射方法
       //假设这里面的第一个参数就是那个类的名字
       String className = args[0];
       Method methodCharAt = Class.forName(className).getMethod("main", String[].class);
       methodCharAt.invoke(null,(Object)(new String[]{"114","12r5"}));   
    }
}
 
class MainDemo{
    public  static void main(String[]args){//传了一些参数,执行我的方法的时候,这个方法里面就带有去
       for(String arg : args){         //启动哪个类。假设这里面的第一个参数就是那个类的名字
           System.out.println(arg);
       }
    }
}


数组的反射

    public static void main(String[] args) {
       // TODO Auto-generatedmethod stub
       Object obj = null;
       printObject("saab");
       String [] a = {"Ag","agw"};
       printObject(a);
    }
 
    private static void printObject(Object obj) {
       // TODO Auto-generatedmethod stub
       //获取obj的字节码
       Class cl = obj.getClass();
       if(cl.isArray()){
           //获取obj的长度
           int leg = Array.getLength(obj);
           for(int x=0; x<leg; x++){//获取obj
              System.out.println(Array.get(obj, x));
           }
       }else{
           System.out.println(obj);
       }
    }
 
结果
saab
Ag
agw


HashCoad的作用

提高从集合中查找元素的效率,这种方式将集合分成若干个存储区域,每个对象可以计算出一个哈希码,可以将哈希码分组,每组分别对应若干个区域存储,根据一个对象的哈希码就可以确定该对象对应存储在哪个区域

当一个对象被存储进HashSet集合中以后,就不能修改这个对象中的那些参与运算的哈希值字段了,否则,对象修改后的哈希值与最初存储进HashSet集合中时的哈希值就不同了。在这种情况下,即使在contains方法使用该对象的当前引用作为的参数与HashSet集合中检索对象,也将返回找不到对象的结果,这样会导致无法从HashSet集合中单独删除当前对象,从而造成内存溢出

反射的作用--à实现框架功能

框架:

    我做房子卖给用户住,由用户自己安装门窗和空调,我做的房子就是框架,用户需要使用我的框架,把门窗插入进我提供的框架中。

框架与工具类的区别:

    工具类被用户的类调用,而框架则是调用用户提供的类

框架要解决的核心问题

    因为写程序时无法知道要被调用的类名,所以,在程序中无法直接new出来某个类的实例对象,而要用反射方式来做


用反射的方式来做HashSet 和ArrayList

 //加载config.properties文件
       FileInputStream fis = new FileInputStream("config.properties");
       //Properties可以把自己内存中的键值对存到硬盘里,也可以把硬盘中的键值对直接读取
       Properties props = new Properties();
       props.load(fis);
       fis.close();
       String className = props.getProperty("className");
       //new一个Collection对象
       Collection collections = (Collection)Class.forName(className).newInstance();
      
       ReflectPoint rp1 = new ReflectPoint(3,4);
       ReflectPoint rp2 = new ReflectPoint(4,4);
       ReflectPoint rp3 = new ReflectPoint(5,4);
       ReflectPoint rp4 = new ReflectPoint(3,4);
       collections.add(rp1);
       collections.add(rp2);
       collections.add(rp3);
       collections.add(rp4);
      
       System.out.println(collections.size());

用类加载器的方式管理资源和配置文件

类加载器把.class文件加载到内存中去

方法一:

一定要用完整的路径,但完整的路径不是硬编码,而是运算出来的

方法二:                     

ArrayDemo2.class.getClassLoader().getResourceAsStream("目录文件名");

                     //类加载器 //加载普通文件,在classPath目录查找文件

ArrayDemo2.class.getResourceAsStream("文件名");

没有\只取相对路径,相对于包而言。有\则是代表据对路径,需要写上完整的地址

   ArrayDemo2.class.getResourceAsStream("\路径文件名");


内省-àIntorSpector

用于对JavaBean操作,JavaBean是特殊的java类。主要用于传递数据信息。方法的名字符合某种既定规则。

规则就是方法都是以get,set开头的。

javaBean的属性就是方法名去掉get,set后面的单词。如果第二个子母小写就把第一个子母变小写  ,如果第二个子母是大的就保持原样

如:setgAge()   在javaBean中的属性就是age


对javaBean简单内省操作   获取和修改点的X和Y

      

 //把对象当作javaBean来操作
       ReflectPoint rp = new ReflectPoint(3,5);
       //一般方法获取X的值
       String propertyName = "x";
       //属性描述符 PropertyDescriptor  获取javaBean的属性
       PropertyDescriptor pd =
new PropertyDescriptor(propertyName,rp.getClass());//属性名,和java类
       //获取读写方法  pd.getReadMethod();  pd.getWriteMethod();
       //获取X属性的读方法
       Method getMethodX = pd.getReadMethod();
       Object retVal = getMethodX.invoke(rp);
       System.out.println(retVal);
       //修改x的属性
        Method setMethodX =pd.getWriteMethod();
       setMethodX.invoke(rp,4);
       System.out.println(rp.getX());

获取

方法一

//把对象当作javaBean来操作
       ReflectPoint rp = new ReflectPoint(3,5);
       //方法一
       /*//一般方法获取X的值
       String propertyName = "x";
       //属性描述法 PropertyDescriptor  获取javaBean的属性
       PropertyDescriptor pd = newPropertyDescriptor(propertyName,rp.getClass());//属性名,和java类
       //获取读写方法   pd.getReadMethod();   pd.getWriteMethod();
       //获取X属性的读方法
       Method getMethodX = pd.getReadMethod();
       Object retVal = getMethodX.invoke(rp);
       System.out.println(retVal);
              */

方法二      //重构 Refactor---> Extract Mathod

//方法二
       String propertyNameX = "x";
       //对哪个对象身上的哪个属性进行获取
       Object retVal = getProperty(rp, propertyNameX);
       System.out.println(retVal);
 
//重构 Refactor---> Extract Mathod
    private static Object getProperty(Object rp, String propertyName)throws Exception {
      
       PropertyDescriptor pd = newPropertyDescriptor(propertyName,rp.getClass());
       Method getMethodX = pd.getReadMethod();
       Object retVal = getMethodX.invoke(rp);
       return retVal;
    }

设置

方法一

      

 //修改Y的属性   方法一
       String propertyNameY = "y";
       Object value = 4;
       PropertyDescriptor pd = newPropertyDescriptor(propertyNameY,rp.getClass());
       Method setMethodY = pd.getWriteMethod();
       setMethodY.invoke(rp,value);
       System.out.println(rp.getY());

方法二  重构

     

  //方法二
       String propertyNameY = "y";
       Object value = 4;
       setProperty(rp, propertyNameY, value);
       System.out.println(rp.getY());

    private static void setProperty(Object rp, String propertyNameY,
           Object value) throws Exception{
       PropertyDescriptor pd = newPropertyDescriptor(propertyNameY,rp.getClass());
       Method setMethodY = pd.getWriteMethod();
       setMethodY.invoke(rp,value);
    }

BeanUtils工具包

       System.out.println(BeanUtils.getProperty(rp, "x"));

       BeanUtils.setProperty(rp,"y", "9");

 


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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值