黑马程序员——JAVA高新技术---反射--概述,类中构造方法、字段、方法和数组的反射,框架原理,JavaBean简述

-----------android培训java培训、java学习型技术博客、期待与您交流!------------

第一讲.概述

  1. Class类:Java中对类这个抽象概念的描述,是一个“描述类的类”,说起来比较哲学。。
  2. Class类存放在java.lang包中,同样的像构造器(Constructor),字段(Field),方法(Method)这些抽象概念也被一一描述并存放在这里。当然它们都是Class类的属性了,都存在java.lang.reflect包中。
  3. JVM在使用某个类之前需要对其进行加载,也就是说把这个类对应的Class对象加载进内存中(也可以说是把编译生成的.class字节码文件加载进内存中),通过这个Class对象映射出这个类的实例。而反射呢,就是一种反溯的过程了。
  4. 有三种方法得到Class对象(就以String为例了):
    String str = "abc";
    //第一种:利用实例的getClass()方法
    Class cls1 = str.getClass();
    //第二种:利用类的class属性,当然这些方法属性都是从Object继承的	
    Class cls2 = String.class;	
    //第三种:用Class的forName静态方法,类名需是完整的
    Class cls3 = Class.forName("java.lang.String"); 
    //Class类的对象在内存中是唯一的(类加载器什么的。。),所以下列判断皆为真,
    System.out.println(cls1 == cls2);
    System.out.println(cls2 == cls3);
  5. Class对象中一些基本的判断型方法:
    //isPrimitive()基本类型,isArray()是否为数组
    System.out.println(cls1.isPrimitive());
    System.out.println(int.class.isPrimitive());
    //基本类型与其包装类不是相同的。。基本类型甚至都不是Object。。
    System.out.println(int.class == Integer.class);
    //八大基本类型的包装类中有TYPE字段,标识出其基本类型
    System.out.println(int.class==Integer.TYPE);
    //数组类型就是数组类型啦~
    System.out.println(int[].class.isPrimitive());
    System.out.println(int[].class.isArray());

第二讲. 构造方法、字段、方法的反射

  1. 构造方法的反射
    //得到构造方法 Constructior getConstructor(Class class);
    Constructor constructor1 = String.class.getConstructor(StringBuffer.class);
    //编译时不知道返回结果类型,所以用强制类型转换
    str = (String)constructor1.newInstance(new StringBuffer("abcd"));
    //甚至连constructor1是谁的哪一个构造方法都不知道,所以可以说反射把报错的时机都推迟到运行时了。。。
    System.out.println(str);
  2. 字段的反射
    //获得属性字段:Field getField(String name)
    ReflectPoint rp1 = new ReflectPoint(3,5);
    Field fieldY = rp1.getClass().getField("y");
    System.out.println(fieldY.get(rp1));
    Field fieldX = rp1.getClass().getDeclaredField("x");
    //暴力反射,x是private字段,设置为可以访问
    fieldX.setAccessible(true);
    System.out.println(fieldX.get(rp1));
    //其中的ReflectPoint是这么定义的:
    class ReflectPoint
    {
    	private int x;
    	public int y;
    	ReflectPoint(int x,int y){
    		this.x=x;
    		this.y=y;
    	}
    }
  3. 练习:将任意一个对象中所用String类型成员变量中的"b"变为"a"
    //练习一:将任意一个对象中所用String类型成员变量中的"b"变为"a"
    //在main中这么写:
    Test test = new Test("badboy","balabala");
    test_1(test);
    System.out.println(test);
    //test_1如下:
    private static void test_1(Object obj)throws Exception
    {
    	Field[] fields = obj.getClass().getDeclaredFields();
    	String str = null;
    	for(Field item:fields){
    		//可以用Field的getType方法返回字段类型,详见JDK
    		if(item.getType()==String.class)
    		{
    			item.setAccessible(true);
    			str = (String)item.get(obj);
    			str = str.replace("b","a");
    			item.set(obj,str);
    		}
    	}
    }
  4. 方法的反射
    //获得方法  Method getMethod(String name,Class class)
    Method methodCharAt = String.class.getMethod("charAt",int.class);
    System.out.println(methodCharAt.invoke(str,1));//等同于str.charAt(1);
    //若invoke的第一个参数为null,则method为静态方法
  5. 练习:动态调用其他类中的main方法
    //练习二:调用其他类的main方法,通过主函数的args参数传入想要动态调用的类
    //下面代码效果如同:TestArguments.main(new String[]{"11","22"});
    //主函数里写:
    String className = args[0];
    Method mainMethod = Class.forName(className).getMethod("main",String[].class);
    mainMethod.invoke(null,new Object[]{new String[]{"11","22"}});//main为静态的
    //这里涉及到java为了兼容1.4以前版本,会自动对数组类型参数进行拆包(因为1.5有了可变参数)
    //这么做也行:mainMethod.invoke(null,(Object)new String[]{"11","22"});
    //TestArguments如下:
    class TestArguments
    {
    	public static void main(String[] args){
    		for(String str:args)
    			System.out.println(str);
    	}
    }
  6. 数组的反射
    //数组的反射
    int[] a = new int[]{1,2,3};//注意int[]并不是Object[]
    String[] b = new String[]{"a","b"};
    System.out.println(a.getClass().getName());
    //getSuperclass()可以获得父类Class对象,下面两句运行结果都是java.lang.Object
    System.out.println(a.getClass().getSuperclass().getName());
    System.out.println(b.getClass().getSuperclass().getName());
    //但是注意,这里int[]并不能解析为Object[],拆包操作是只会把它当成单个Object处理
    //所以下面语句打印int[]的a还是类型加哈希值,而b就会正常打印数组元素
    System.out.println(Arrays.asList(a));
    System.out.println(Arrays.asList(b));
  7. 数组反射应用:模拟Java中的数组拆包操作。(注:由于1.5中可变参数的引入,java为了兼容1.4以前版本,会自动对数组类型参数进行拆包)
    //主函数对printObject()进行如下的测试:
    printObject("xyz");
    printObject(new String[]{"x","y","x"});
    //printObject如下:
    private static void printObject(Object obj){
    	Class cls = obj.getClass();
    	//如果是数组的话,注意这里java.lang.reflect.Array的使用
    	if(cls.isArray()){
    		int len = Array.getLength(obj);
    		for (int i=0;i<len ;i++ )
    			System.out.println(Array.get(obj,i));
    	}
    	//否则就是只能解析成单个Object或者基本类型
    	else
    		System.out.println(obj);
    }

第三讲. 基于反射的框架

  1. 张孝祥老师的视频里,有一段hashCode()的深入讲解,代码如下,ReflectPoint类就是上面那个。有一点,我们知道HashSet通过hashCode()和equals()判断元素是否相等,哈希值不一样,元素就会被散列到不同的区间去,肯定不同了。pt1和pt2逻辑上是相同的。所以应该重写哈希算法,使得pt1和pt2的哈希值相同。但此时,如果元素存入HashSet后再对其进行修改,必然导致哈希值的变化,这就将导致这个元素无法被remove(),不意识到这一点而对集合反复增删时,就会发生内存泄露。
    import java.io.*;
    import java.lang.reflect.*;
    import java.util.*;
    class ReflectEx 
    {
    	public static void main(String[] args) throws Exception
    	{
    		Collection c = new HashSet();//new ArrayList();
    		//对于HashSet和ArrayList分别测试
    		ReflectPoint pt1 = new ReflectPoint(3,3);
    		ReflectPoint pt2 = new ReflectPoint(2,4);
    		ReflectPoint pt3 = new ReflectPoint(3,3);
    		c.add(pt1);
    		c.add(pt2);
    		c.add(pt3);
    		//我们知道Set是不允许添加重复元素的,List可以
    		c.add(pt1);
    		//HashSet的size为3;ArrayList为4
    		System.out.println(c.size());
    	}
    }

  2. 反射的应用:实现框架功能。简单来说,我们使用框架和工具是不一样的:使用者去使用工具,它替我们做了内部的事情;而框架是去调用使用者,它替我们做了外面(框架嘛~)的事情。
  3. 接下来就要把上面的代码做成一个框架的形式。在config.properties中存入className=java.util.ArrayList ,那么运行下面的代码就会输出size为4;把ArrayList改为HashSet就会得到size为3;整个过程用户只需对配置文件config.properties进行修改即可,无需再编译下面的代码~这则小例子体现了框架的优越性。
    import java.io.*;
    import java.lang.reflect.*;
    import java.util.*;
    class ReflectEx 
    {
    	public static void main(String[] args) throws Exception
    	{
    		InputStream in = new FileInputStream("config.properties");
    		Properties props = new Properties();
    		props.load(in);
    		in.close();
    		String className = props.getProperty("className");
    		Class cls = Class.forName(className);
    		Constructor cons = cls.getConstructor();
    		Collection c = (Collection)cons.newInstance();
    		ReflectPoint pt1 = new ReflectPoint(3,3);
    		ReflectPoint pt2 = new ReflectPoint(2,4);
    		ReflectPoint pt3 = new ReflectPoint(3,3);
    		c.add(pt1);
    		c.add(pt2);
    		c.add(pt3);
    		c.add(pt1);
    		System.out.println(c.size());
    	}
    }

第四讲.JavaBean简述

  1. JavaBean是一种特殊的Java类:有getter、setter。getter即int getAge()这种获取字段的方法;setter即getAge(int age)这种写入字段的方法。它们拥有明确的命名方法:get+属性名、set+属性名,当然为了满足匈牙利命名法则首字母变大写。
  2. 由于类中存储的数据(字段)一般是受保护(私有)的,对外不可见。只对外提供getter、setter方法,JavaBean中的属性名干脆就利用getter和setter的函数名进行推断。推断过程例如:getAge-->Age-->如果第二个字母是小的,则把第一个字母变成小的-->age。
  3. 反过来,知道属性名的前提下,也可以轻松获得getter、setter函数名,并且利用反射对字段进行修改和获取,JDK也是提供了相关api来简化这种操作。
    import java.beans.*;//JavaBean相关api所在的包
    import java.lang.reflect.*;
    class  JavaBeanDemo
    {
    	public static void main(String[] args) throws Exception
    	{
    		Point p = new Point(3,4);
    		Object retVal = getProperty(p,"x");
    		System.out.println(retVal);
    		setProperty(p,"x",7);
    		System.out.println(p.getX());
    	}
    	private static Object getProperty(Object obj,String propertyName)throws Exception
    	{//通过任一JavaBean类中getter方法获得指定字段的值
    		//获得属性描述对象PropertyDescriptor,可以通过属性得到setter、getter方法
    		PropertyDescriptor dp = new PropertyDescriptor(propertyName,obj.getClass());
    		Method methodGetX = dp.getReadMethod();
    		Object retVal = methodGetX.invoke(obj);
    		return retVal;
    	}
    	private static void setProperty(Object obj,String propertyName,Object value)throws Exception
    	{//通过任一JavaBean类中setter来设置指定字段的值
    		//替我们完成了x-->X-->setX-->在目标类中查找对应函数名的Method对象,这一系列动作
    		PropertyDescriptor dp = new PropertyDescriptor(propertyName,obj.getClass());
    		Method methodSetX = dp.getWriteMethod();
    		methodSetX.invoke(obj,value);
    	}
    }
    class Point
    {
    	private int x;
    	private int y;
    	Point(int x,int y){this.x = x;this.y = y;}
    	//注意:这里的public是必须加的。。。
    	public void setX(int x){this.x = x;}
    	public void setY(int y){this.y = y;}
    	public int getX(){return x;}
    	public int getY(){return y;}
    }
  4. 通过java.beans包中的Introspector内省(内窥镜)类,得到BeanInfo,可以获得所有满足JavaBean条件的字段的PropertyDescriptor对象数组。进而也可以通过遍历这些PropertyDescriptor对象来完成上面的功能。
    private static Object getProperty(Object obj,String propertyName)throws Exception
    {//通过任一JavaBean类的getter方法获取指定字段的值
    	BeanInfo beaninfo = Introspector.getBeanInfo(obj.getClass());
    	PropertyDescriptor[] pds = beaninfo.getPropertyDescriptors();
    	Object retVal=null;
    	//遍历所有满足JavaBean规则的属性描述对象
    	for (PropertyDescriptor pd:pds)
    	{
    		if(pd.getName().equals(propertyName))
    		{
    			Method methodGetX = pd.getReadMethod();
    			retVal = methodGetX.invoke(obj);
    		}
    	}
    	return retVal;
    }
  5. 张孝祥老师视频中还介绍了JavaBeanUtils工具包的应用等。






  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
智慧农业是一种结合了现代信息技术,包括物联网、大数据、云计算等,对农业生产过程进行智能化管理和监控的新模式。它通过各种传感器和设备采集农业生产中的关键数据,如大气、土壤和水质参数,以及生物生长状态等,实现远程诊断和精准调控。智慧农业的核心价值在于提高农业生产效率,保障食品安全,实现资源的可持续利用,并为农业产业的转型升级提供支持。 智慧农业的实现依赖于多个子系统,包括但不限于设施蔬菜精细化种植管理系统、农业技术资料库、数据采集系统、防伪防串货系统、食品安全与质量追溯系统、应急追溯系统、灾情疫情防控系统、农业工作管理系统、远程诊断系统、监控中心、环境监测系统、智能环境控制系统等。这些系统共同构成了一个综合的信息管理和服务平台,使得农业生产者能够基于数据做出更加科学的决策。 数据采集是智慧农业的基础。通过手工录入、传感器自动采集、移动端录入、条码/RFID扫描录入、拍照录入以及GPS和遥感技术等多种方式,智慧农业系统能够全面收集农业生产过程中的各种数据。这些数据不仅包括环境参数,还涵盖了生长状态、加工保存、检验检疫等环节,为农业生产提供了全面的数据支持。 智慧农业的应用前景广阔,它不仅能够提升农业生产的管理水平,还能够通过各种应用系统,如库房管理、无公害监控、物资管理、成本控制等,为农业生产者提供全面的服务。此外,智慧农业还能够支持政府监管,通过发病报告、投入品报告、死亡报告等,加强农业产品的安全管理和质量控制。 面对智慧农业的建设和发展,存在一些挑战,如投资成本高、生产过程标准化难度大、数据采集和监测的技术难题等。为了克服这些挑战,需要政府、企业和相关机构的共同努力,通过政策支持、技术创新和教育培训等手段,推动智慧农业的健康发展。智慧农业的建设需要明确建设目的,选择合适的系统模块,并制定合理的设备布署方案,以实现农业生产的智能化、精准化和高效化。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值