黑马程序员 Java高新技术 三
2014-01-06 22:18
176 查看
----------------------
ASP.Net+Android+IOS开发、.Net培训、期待与您交流! ----------------------
只有存入的是具有hashCode算法的集合的,覆写hashCode()方法才有价值。如果不存入是hashCode算法的集合中,那么则不用复写此方法。
2.哈希算法的由来:
若在一个集合中查找是否含有某个对象,通常是一个个的去比较,找到后还要进行equals的比较,对象特别多时,效率很低,通过哈希算法,将集合分为若干个区域,每个对象算出一个哈希值,可将哈希值分组(一般模32为一组),每组对应某个存储区域,依一个对象的哈希码即可确定此对象对应区域,从而减少每个对象的比较,只需在指定区域查找即可,从而提高从集合中查找元素的效率。
3.只有类的实例对象要被采用哈希算法进行存入和检索时,这个类才需要按要求复写hashCode()方法,即使程序可能暂时不会用到当前类的hashCode()方法,但是为提供一个hashCode()方法也不会有什么不好,没准以后什么时候就会用到这个方法,所以通常要求hashCode()和equals()两者一并被覆盖。
4.注意:
A:若同类两对象用equals()方法比较的结果相同时,他们的哈希码也必须是相等的,但反过来就不成立了,如”BB”和”Aa”两字符串用equals()比较式不相等的,但是他们的哈希值是相等的。
B:当一个对象被存储进HashSet集合中,就不能再修改参与计算哈希值的字段,否则对象被修改后的哈希值与最初被存入的HashSet集合中的哈希值就不同了。在这种情况下,即使contains()方法是用对象的当前引用作为参数去HashSet集合中检索对象,也将返回找不到对象的结果,这也导致无法从HashSet集合中单独删除当前对象,从而造成内存泄露。
简单说,之前存入的对象和修改后的对象,是具有不同的哈希值,被认为是不同的两个对象,这样的对象不再使用,又不移除,而越来越多,就会导致内存泄露。
C:对象在调用方法时,对象会先进行一次自身hashCode()方法的调用,再进行操作方法。
内存泄露:某些对象不再使用了,占用着内存空间,并未被释放,就会导致内存泄露;也就是说当程序不断增加对象,修改对象,删除对象,日积月累,内存就会用光了,就导致内存溢出。
如房地产商造房子用户住,门窗和空调等等内部都是由用户自己安装,房子就是框架,用户需使用此框架,安好门窗等放入到房地产商提供的框架中。
框架和工具类的区别:工具类被用户类调用,而框架是调用用户提供的类。
2.框架机器要解决的核心问题:
我们在写框架(造房子的过程)的时候,调用的类(安装的门窗等)还未出现,那么,框架无法知道要被调用的类名,所以在程序中无法直接new其某个类的实例对象,而要用反射来做。
3.简单框架程序的步骤:
A:右击项目名-->File-->命名,写入键值对:className=java.util.ArrayList,等号右边的可以自己定义集合的名称,即用户可以对此记事本修改成自己的类名。
B:代码实现,加载此文件:
1:将文件读取到读取流中,一定要用完整的路径,可以使用getRealPath()方法获取路径名,再加上自己定义的文件夹名。
2:用Properties类的load()方法将流加载经内存,即提取文件中的信息。
3:关闭流:关闭的是读取流,因为流中的数据已经加载进内存。
C:通过getProperty()方法获取类名属性,将传入的类名赋值给指定变量。
D:用反射的方式,创建对象newInstance()
E:进行相关的具体操作。
2.文件的加载问题:
A:eclipse会将源程序中的所有.java文件加载成.class文件,以确保编译,然后放到classPath指定的目录中去。并且会将非.java文件原封不动的复制到.class指定的目录中去。在真正编译的时候,使用classPath目录中的文件,即放置.class文件的目录。
B:写完程序是要讲配置文件放到.class文件目录中一同打包,这些都是类加载器加载的,资源文件(配置文件)也同样加载了配置文件。
C:框架中的配置文件都要放到classPath指定的文件夹中,原因是它的内部就是用类加载器加载的文件。
3.资源文件的加载:是使用类加载器。
A:由类加载器ClassLoader的一个对象加载经内存,即用getClassLoader()方法加载。若要加载普通文件,可用getResourseAsStream(String name)在classPath的文件中逐一查找要加载的文件。
B:在.class身上也提供了方法来加载资源文件,其实它内部就是先调用了Loader方法,再加载的资源文件。
如:Reflect.class.getResourseAsStream(String name)
4.配置文件的路径问题:
A:用绝对路径,通过getRealPath()方法运算出来具体的目录,而不是内部编码出来的。
一般先得到用户自定义的总目录,在加上自己内部的路径。可以通过getRealPath()方法获取文件路径。对配置文件修改是需要要储存到配置文件中,那么就要得到它的绝对路径才行,因此,配置文件要放到程序的内部。
B:name的路径问题:
a:如果配置文件和classPath目录没关系,就必须写上绝对路径,
b:如果配置文件和classPath目录有关系,即在classPath目录中或在其子目录中(一般是资源文件夹resource),那么就得写相对路径,因为它自己了解自己属于哪个包,是相对于当前包而言的。
代码演示:
配置文件内容:
className=java.util.ArrayList
2.内省的作用:主要针对JavaBean进行操作。
3.JavaBean简述:
A:JavaBean是一种特殊的Java类,主要用于传递数据信息,这种Java类中的方法主要用于访问私有的字段,且方法都符合某种特殊的命名规则。
B:它是一种特殊的Java类,其中的方法名称等,都符合特殊的规则。只要一个类中含有get和set打头的方法,就可以将其当做JavaBean使用。
C:字段和属性:
字段就是我们定义的一些成员变量,如private String name;等
属性是具有某些功能,Bean属性,是含有get或set方法的那些属性的字段,即这个变量的get属性,set属性等。
4.JavaBean的作用:
如果要在两个模板之间传递多个信息,可将这些信息封装到一个JavaBean中,这种JavaBean的实例对象通常称之为值对象(Value Object,简称VO),这些信息在类中用私有字段来储存,如果读取或设置这些字段的值,则需要通过一些相应的方法来访问。
5.JavaBean的命名方式
JavaBean的属性是根据其中的setter和getter方法来确定的,而不是依据其中的变量,如方法名为setId,则中文意思是设置Id,getId也是如此;去掉前缀,剩余部分就是属性名称,如果剩余部分的第二个字母小写,则把剩余部分改为小写。如:getAge/setAge-->age;gettime-->time;setTime-->time;getCPU-->CPU。
6.JavaBean的好处:
A:在JavaEE开发中,经常要使用JavaBean。很多环境就要求按JavaBean的方式进行操作,别人都这么用,那么就必须要求这么做。
B:JDK中提供了对JavaBean进行操作的API,这套API称为内省,若要自己通过getX的方式来访问私有x,可用内省这套API,操作JavaBean要比使用普通的方式更方便。
代码演示:
7.对JavaBean的复杂内省操作:
A:在IntroSpector类中有getBeanInfo(Class cls)的方法。
B:获取Class对象的Bean信息,返回的是BeanInfo类型。
C:BeanInfo类中有getPropertyDescriptors()的方法,可获取所有的BeanInfo的属性信息,返回一个PropertyDescriptor[]。
D:在通过遍历的形式,找出与自己想要的那个属性信息。
2.BeanUtils可以将8种基本数据类型进行自动的转换,因此对于非基本数据类型,就需要注册转换器Converter,这就需要ConverUtils包,
3.BeanUtils工具包好处:
A:提供的set或get方法中,传入的是字符串,返回的还是字符串,因为在浏览器中,用户输入到文本框的都是以字符串的形式发送至服务器上的,所以操作的都是字符串。也就是说这个工具包的内部有自动将整数转换为字符串的操作。
B:支持属性的级联操作,即支持属性链。如可以设置:人的脑袋上的眼镜的眼珠的颜色。这种级联属性的属性连如果自己用反射,那就很困难了,通过这个工具包就可以轻松调用。
C:可以和Map集合进行相互转换:可将属性信息通过键值对的形式作为Map集合存储(通过staticjava.util.Map describe(java.lang.Object bean)的方法),也可以将Map集合转换为JavaBean中的属性信息(通过static voidpopulate(java.lang.Object bean, java.util.Map properties)的方法)。
代码演示:
1.设置和获取属性值:
2.未注册的属性值的获取和设置
3.Map集合在BeanUtils中的应用
补充:
1.BeanUtils是以字符串的形式进行操作的
2.PropertyUtils是以传入值本身的类型进行操作的。
2.java编译器、开发工具和其他应用程序就可以用反射来了解自己的类及各种元素上有无何种标记,有什么标记,就会做出相应的处理。
3.标记可以加在包、类、字段、方法、方法参数,以及局部变量上等等。
4.在java.lang包中提供了最基本的annotation,即注解。
5.格式:@注解类名()。如果有属性,则在括号中加上属性名(可省略)和属性值。
java中三种最基本的注解:
1.@SuppressWarning(”deprecation”)--->压制警告
SupressWarning是告知编译器或开发工具等提示指定的编译器警告;
”deprecation”是告知具体的信息即方法已过时。
2.@Deprecated--->提示成员等已经过时,不再推荐使用。
源代码标记@Deprecated是在JDK1.5中作为内置的annotation引入的,用于表明类(class)、方法(method)、字段(field)已经不再推荐使用,并且在以后的JDK版本中可能将其删除,编译器在默认情况下检测到有此标记的时候会提示警告信息。
例如:假定之前的某个类升级了,其中的某个方法已经过时了,不能够将过时的方法删除,因为可能会影响到调用此类的这个方法的某些程序,这是就可以通过在方法上加这个注解。
3.@Override--->提示覆盖(父类方法)
加上此注解,,可对自己类中的方法判断是否是要覆盖的父类的方法,典型的例子即在集合中覆盖equals(Object obj)方法,其中的参数类型必须是Object,才能被覆盖,若不是,加上此注解就会提示警告。
注解类
1、定义格式:@interface 名称{statement}
2、元注解(注解的注解)
一个注解有其生命周期(Retetion)和存放的位置(Taget),这就可以通过元注解说明。
A:Retetion:用于说明注解保留在哪个时期,加载定义的注解之上。
①一个注解的声明周期包含:
java源程序--(javac)-->class文件--(类加载器)-->内存中的字节码
第一、当再源程序上加了注解,javac将java源程序编译为class文件,可能会把源程序中的一些注解去掉,进行相应的处理操作,当我们拿到源程序的时候,就看不到这些注解了。
第二、假设javac把这些注解留在了源程序中(或者说留在了class文件中),当运行此class文件的时候,用类加载器将class文件调入内存中,此时有转换的过程,即把class文件中的注解是否保留下来也不一定。
注意:class文件中不是字节码,只有把class文件中的内部加载进内存,用类加载器加载处理后(进行完整的检查等处理),最终得到的二进制内容才是字节码。
②Reteton(枚举类)取值:
Retetion.Policy.SOURSE:java源文件时期,如@Overried和@SuppressWarning
Retetion.Policy.CLASS: class文件时期(默认阶段)
Retetion.Policy.RUNTIME:运行时期,如@Deprecated
B:Taget:用于说明注解存放在哪些成分上,默认值是任何元素
其值可设置为枚举类ElementType类中的任何一个,包括:包、字段、方法、方法参数、构造器、类等值。取值为:
PACKAGE(包声明)
FIELD(字段声明)
ANNOTATION_TYPE(注释类型声明)
CONSIRUCTOR(构造器声明)
METHOD(方法声明)
PARAMETER(参数声明)
TYPE(类、接口(包含注释类型)或枚举声明)
LOCAL_VARIABLE(局部变量声明)
注意:其中代表类的值是TYPE。因为class、enum、interface和@
interface等都是属于Type的。不可用CLASS表示.
3、通过反射查看其它类中的注释:
过程:
第一、注解类:@interfaceA{}
第二、应用了“注释类”的类:@Aclass B{}
第三、对“应用注释类的类”进行反射操作的类:class{...},操作如下:
B.class.isAnnotionPresent(A.class);//判断是否存在此注解类
A a = B.class.getAnnotation(a.class);//存在的话则得到这个注释类的对象
代码演示:
为注解增加基本属性
1、属性:一个注解相当于一个胸牌,但仅通过胸牌还不足以区别带胸牌的两个人,这时就需要给胸牌增加一个属性来区分,如颜色等。
2、定义格式:同接口中的方法一样:String color();定义缺省格式:Stringvalue() default ”ignal”;
3、应用:直接在注解的括号中添加自身的属性,如:
@ItcastAnnotation(color=”red”)
这个和上面的@SuppressWarnings("deprecation")是一样的,其中的"deprecation"就是属性值
1)当只有一个属性时,可直接传入属性值。如”red”
2)当含有其他属性值的时候,如果那个属性值是缺省的(default),也可以直接传入这个属性值。
为注解增加高级属性
1、可以为注解增加的高级属性的返回值类型有:
1)八种基本数据类型 2)String类型 3)Class类型
4)枚举类型 5)注解类型 6)前五种类型的数组
2、数组类型的属性:
定义:int[]arrayArr() default {1,2,3}; -->可不定义默认值
应用:@MyAnnotation(arrayArr={2,3,4}) --> 可重新赋值
注:若数组属性中只有一个元素(或重新赋值为一个元素),这时属性值部分可省略大括号。
3、枚举类型的属性:
假设定义了一个枚举类TraffLamp,它是EnumTest的内部类,其值是交通灯的三色。
定义:EnumTest.TrafficLamplamp();
应用:@MyAnnotation(lamp=EnumTestTrafficLamp.GREEN)
4、注解类型的属性:
假定有个注解类:MetaAnnotation,其中定义了一个属性:String value()
定义:MetaAnnotationannotation() default @MetaAnnotation(”xxx”);
应用:@MyAnnotation(annotation=@MetaAnnotation(”yyy”)) --> 可重新赋值
可认为上面的@MetaAnnotation是MyAnnotation类的一个实例对象,同样可以认为上面的@MetaAnnotation是MetaAnnotation类的一个实例对象,调用:
MetaAnnotation ma =MyAnnotation.annotation();
System.out.println(ma.value());
5、Class类型的属性:
定义:Class cls();
应用:@MyAnnotation(cls=ItcastAnnotion.class)
注:这里的.class必须是已定义的类,或是已有的字节码对象
6、基本数据类型的属性(以int为例):
定义:int val()default 3; -->可不定义默认值
应用:@MyAnnotation(val=7) --> 可重新赋值
----------------------
ASP.Net+Android+IOS开发、.Net培训、期待与您交流! ----------------------
ASP.Net+Android+IOS开发、.Net培训、期待与您交流! ----------------------
Java高新技术 三
HashSet和与hashCode
1.覆写hashCode()方法的意义:只有存入的是具有hashCode算法的集合的,覆写hashCode()方法才有价值。如果不存入是hashCode算法的集合中,那么则不用复写此方法。
2.哈希算法的由来:
若在一个集合中查找是否含有某个对象,通常是一个个的去比较,找到后还要进行equals的比较,对象特别多时,效率很低,通过哈希算法,将集合分为若干个区域,每个对象算出一个哈希值,可将哈希值分组(一般模32为一组),每组对应某个存储区域,依一个对象的哈希码即可确定此对象对应区域,从而减少每个对象的比较,只需在指定区域查找即可,从而提高从集合中查找元素的效率。
3.只有类的实例对象要被采用哈希算法进行存入和检索时,这个类才需要按要求复写hashCode()方法,即使程序可能暂时不会用到当前类的hashCode()方法,但是为提供一个hashCode()方法也不会有什么不好,没准以后什么时候就会用到这个方法,所以通常要求hashCode()和equals()两者一并被覆盖。
4.注意:
A:若同类两对象用equals()方法比较的结果相同时,他们的哈希码也必须是相等的,但反过来就不成立了,如”BB”和”Aa”两字符串用equals()比较式不相等的,但是他们的哈希值是相等的。
B:当一个对象被存储进HashSet集合中,就不能再修改参与计算哈希值的字段,否则对象被修改后的哈希值与最初被存入的HashSet集合中的哈希值就不同了。在这种情况下,即使contains()方法是用对象的当前引用作为参数去HashSet集合中检索对象,也将返回找不到对象的结果,这也导致无法从HashSet集合中单独删除当前对象,从而造成内存泄露。
简单说,之前存入的对象和修改后的对象,是具有不同的哈希值,被认为是不同的两个对象,这样的对象不再使用,又不移除,而越来越多,就会导致内存泄露。
C:对象在调用方法时,对象会先进行一次自身hashCode()方法的调用,再进行操作方法。
内存泄露:某些对象不再使用了,占用着内存空间,并未被释放,就会导致内存泄露;也就是说当程序不断增加对象,修改对象,删除对象,日积月累,内存就会用光了,就导致内存溢出。
反射的作用-> 实现框架的功能
1.框架:通过反射调用位置Java类的一种方式。如房地产商造房子用户住,门窗和空调等等内部都是由用户自己安装,房子就是框架,用户需使用此框架,安好门窗等放入到房地产商提供的框架中。
框架和工具类的区别:工具类被用户类调用,而框架是调用用户提供的类。
2.框架机器要解决的核心问题:
我们在写框架(造房子的过程)的时候,调用的类(安装的门窗等)还未出现,那么,框架无法知道要被调用的类名,所以在程序中无法直接new其某个类的实例对象,而要用反射来做。
3.简单框架程序的步骤:
A:右击项目名-->File-->命名,写入键值对:className=java.util.ArrayList,等号右边的可以自己定义集合的名称,即用户可以对此记事本修改成自己的类名。
B:代码实现,加载此文件:
1:将文件读取到读取流中,一定要用完整的路径,可以使用getRealPath()方法获取路径名,再加上自己定义的文件夹名。
2:用Properties类的load()方法将流加载经内存,即提取文件中的信息。
3:关闭流:关闭的是读取流,因为流中的数据已经加载进内存。
C:通过getProperty()方法获取类名属性,将传入的类名赋值给指定变量。
D:用反射的方式,创建对象newInstance()
E:进行相关的具体操作。
类加载器:
1.类加载器是将.class的文件加载经内存,也可将普通文件中的信息加载进内存。2.文件的加载问题:
A:eclipse会将源程序中的所有.java文件加载成.class文件,以确保编译,然后放到classPath指定的目录中去。并且会将非.java文件原封不动的复制到.class指定的目录中去。在真正编译的时候,使用classPath目录中的文件,即放置.class文件的目录。
B:写完程序是要讲配置文件放到.class文件目录中一同打包,这些都是类加载器加载的,资源文件(配置文件)也同样加载了配置文件。
C:框架中的配置文件都要放到classPath指定的文件夹中,原因是它的内部就是用类加载器加载的文件。
3.资源文件的加载:是使用类加载器。
A:由类加载器ClassLoader的一个对象加载经内存,即用getClassLoader()方法加载。若要加载普通文件,可用getResourseAsStream(String name)在classPath的文件中逐一查找要加载的文件。
B:在.class身上也提供了方法来加载资源文件,其实它内部就是先调用了Loader方法,再加载的资源文件。
如:Reflect.class.getResourseAsStream(String name)
4.配置文件的路径问题:
A:用绝对路径,通过getRealPath()方法运算出来具体的目录,而不是内部编码出来的。
一般先得到用户自定义的总目录,在加上自己内部的路径。可以通过getRealPath()方法获取文件路径。对配置文件修改是需要要储存到配置文件中,那么就要得到它的绝对路径才行,因此,配置文件要放到程序的内部。
B:name的路径问题:
a:如果配置文件和classPath目录没关系,就必须写上绝对路径,
b:如果配置文件和classPath目录有关系,即在classPath目录中或在其子目录中(一般是资源文件夹resource),那么就得写相对路径,因为它自己了解自己属于哪个包,是相对于当前包而言的。
代码演示:
配置文件内容:
className=java.util.ArrayList
public class ReflectTest2 { public static void main(String [] args)throws Exception{ //读取系统文件到读取流中 //方式一: //InputStream ips = new FileInputStream("config.propert"); /*getRealPath()--得到完整的路径//如:金山词霸/内部 * 一定要用完整的路径,但完整的路径不是硬编码出来的,而是运算出来的。*/ //方式二: //InputStream ips = ReflectTest2.class.getClassLoader().getResourceAsStream("cn/itcast/text1/config.propert"); //方式三: //第一种:配置文件(资源文件)在当前包中 InputStream ips = ReflectTest2.class.getResourceAsStream("resourse/config.propert"); //第二种:配置文件(资源文件)不在当前包中,和此包没太大关系 //InputStream ips = ReflectTest2.class.getClassLoader().getResourceAsStream("cn/itcast/test2/resourse/config.properties"); //加载文件中的键值对 Properties props = new Properties(); props.load(ips); //关闭资源,即ips调用的那个系统资源 //注意:关闭的是ips操作的流,加载进内存后,就不再需要流资源了,需要关闭 ips.close(); //定义变量,将文件中的类名赋值给变量 String className = props.getProperty("className"); //通过变量,创建给定类的对象 Collection cons = (Collection)Class.forName(className).newInstance(); //将元素添加到集合中 /*Collection cons = new HashSet();*/ ReflectPoint pt1 = new ReflectPoint(3,3); ReflectPoint pt2 = new ReflectPoint(5,5); ReflectPoint pt3 = new ReflectPoint(3,3); cons.add(pt1); cons.add(pt2); cons.add(pt3); cons.add(pt1); //移除元素 cons.remove(pt1); System.out.println(cons.size()); } }
由内省引出JavaBean
1.内省,是对内部进行检查,了解更多的底层细节。2.内省的作用:主要针对JavaBean进行操作。
3.JavaBean简述:
A:JavaBean是一种特殊的Java类,主要用于传递数据信息,这种Java类中的方法主要用于访问私有的字段,且方法都符合某种特殊的命名规则。
B:它是一种特殊的Java类,其中的方法名称等,都符合特殊的规则。只要一个类中含有get和set打头的方法,就可以将其当做JavaBean使用。
C:字段和属性:
字段就是我们定义的一些成员变量,如private String name;等
属性是具有某些功能,Bean属性,是含有get或set方法的那些属性的字段,即这个变量的get属性,set属性等。
4.JavaBean的作用:
如果要在两个模板之间传递多个信息,可将这些信息封装到一个JavaBean中,这种JavaBean的实例对象通常称之为值对象(Value Object,简称VO),这些信息在类中用私有字段来储存,如果读取或设置这些字段的值,则需要通过一些相应的方法来访问。
5.JavaBean的命名方式
JavaBean的属性是根据其中的setter和getter方法来确定的,而不是依据其中的变量,如方法名为setId,则中文意思是设置Id,getId也是如此;去掉前缀,剩余部分就是属性名称,如果剩余部分的第二个字母小写,则把剩余部分改为小写。如:getAge/setAge-->age;gettime-->time;setTime-->time;getCPU-->CPU。
6.JavaBean的好处:
A:在JavaEE开发中,经常要使用JavaBean。很多环境就要求按JavaBean的方式进行操作,别人都这么用,那么就必须要求这么做。
B:JDK中提供了对JavaBean进行操作的API,这套API称为内省,若要自己通过getX的方式来访问私有x,可用内省这套API,操作JavaBean要比使用普通的方式更方便。
代码演示:
public class IntroSpectorTest { /** * @param args */ /* * public static void main(String[] args) throws Exception { // TODO Auto-generated method stub ReflectPoint pt1 = new ReflectPoint(3,5); String propertyName = "x"; //"x"-->"X"-->"getX"-->MethodGetX--> //内省的方式: //属性描述符:PropertyDescriptor //get属性信息 PropertyDescriptor pd = new PropertyDescriptor(propertyName,pt1.getClass()); Method methodGetX = pd.getReadMethod(); Object retVal = methodGetX.invoke(pt1); System.out.println(retVal); //set属性信息 Object value = 7; PropertyDescriptor pd2 = new PropertyDescriptor(propertyName,pt1.getClass()); Method methodSetX = pd2.getWriteMethod(); methodSetX.invoke(pt1,value); System.out.println(pt1.getX()); } */ //上面的get或set代码分别通过选中要重构的代码,通过右击选重构获得get和set方法: public static void main(String[] args) throws Exception { // TODO Auto-generated method stub ReflectPoint pt1 = new ReflectPoint(3,5); String propertyName = "x"; //一般方式:"x"-->"X"-->"getX"-->MethodGetX--> //内省方式: //通过get和set方法获取属性值 Object retVal = getProperty(pt1, propertyName); System.out.println(retVal); Object value = 7; setProperty(pt1, propertyName, value); System.out.println(pt1.getX()); } //设置属性值的方法 //此处的类型为Object,通用,下同 private static void setProperty(Object rf, String propertyName, Object value) throws IntrospectionException, IllegalAccessException, InvocationTargetException { //创建属性描述符对象,将属性名称和加载文件等信息写入其中 PropertyDescriptor pd = new PropertyDescriptor(propertyName,rf.getClass()); //通过反射的方法类Method,获取属性所对应的set方法 Method methodSetX = pd.getWriteMethod(); methodSetX.invoke(rf, value); } //获取属性值的方法 private static Object getProperty(Object rf, String propertyName) throws IntrospectionException, IllegalAccessException, InvocationTargetException { //创建属性描述符对象,获取属性所对应的名称和加载文件等信息 PropertyDescriptor pd = new PropertyDescriptor(propertyName,rf.getClass()); //通过反射的方法类Method,获取属性所对应的get方法 Method methodGetX = pd.getReadMethod(); Object retVal = methodGetX.invoke(rf); return retVal; } }
7.对JavaBean的复杂内省操作:
A:在IntroSpector类中有getBeanInfo(Class cls)的方法。
B:获取Class对象的Bean信息,返回的是BeanInfo类型。
C:BeanInfo类中有getPropertyDescriptors()的方法,可获取所有的BeanInfo的属性信息,返回一个PropertyDescriptor[]。
D:在通过遍历的形式,找出与自己想要的那个属性信息。
BeanUtils工具包
1.BeanUtils等工具包都是由阿帕奇提供的,为了便于开发。2.BeanUtils可以将8种基本数据类型进行自动的转换,因此对于非基本数据类型,就需要注册转换器Converter,这就需要ConverUtils包,
3.BeanUtils工具包好处:
A:提供的set或get方法中,传入的是字符串,返回的还是字符串,因为在浏览器中,用户输入到文本框的都是以字符串的形式发送至服务器上的,所以操作的都是字符串。也就是说这个工具包的内部有自动将整数转换为字符串的操作。
B:支持属性的级联操作,即支持属性链。如可以设置:人的脑袋上的眼镜的眼珠的颜色。这种级联属性的属性连如果自己用反射,那就很困难了,通过这个工具包就可以轻松调用。
C:可以和Map集合进行相互转换:可将属性信息通过键值对的形式作为Map集合存储(通过staticjava.util.Map describe(java.lang.Object bean)的方法),也可以将Map集合转换为JavaBean中的属性信息(通过static voidpopulate(java.lang.Object bean, java.util.Map properties)的方法)。
代码演示:
1.设置和获取属性值:
public class BeanUtilDemo { /** * BeanUtils使用 */ @Test public void test1() throws Exception{ //创建对象,设置属性值 Person p = new Person(); BeanUtils.setProperty(p, "name", "zzz"); String name = BeanUtils.getProperty(p, "name"); System.out.println(name); } @Test public void test2() throws Exception{ //创建对象,传入属性值 Person p = new Person(); String name = "wangwu"; String age = "23"; String hight = "173.5"; //设置属性值 BeanUtils.setProperty(p, "name", name); BeanUtils.setProperty(p, "age", age); BeanUtils.setProperty(p, "hight", hight); //获取属性值 System.out.println(BeanUtils.getProperty(p, "name")); System.out.println(BeanUtils.getProperty(p, "age")); System.out.println(BeanUtils.getProperty(p, "hight")); }
2.未注册的属性值的获取和设置
//获取未注册的属性,即非八种基本数据类型的引用类型 //private Date birthday @Test public void test3() throws Exception{ Person p = new Person(); String name = "wangwu"; String age = "23"; String hight = "173.5"; String birthday = "1990-09-09"; ConvertUtils.register(new Converter() { //注册器Converter接口中方法的重写 @Override public Object convert(Class type, Object value) { if(value == null) return null; if(!(value instanceof String)) throw new ConversionException("只支持String类型的转换"); String str = (String) value; if(value.equals("")) return null; SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd"); try{ return sdf.parse(str); }catch(ParseException e){ throw new RuntimeException(e);//异常链不能掉,这里必须写上e } }}, Date.class); //测试 BeanUtils.setProperty(p, "name", name); BeanUtils.setProperty(p, "age", age); BeanUtils.setProperty(p, "hight", hight); BeanUtils.setProperty(p, "birthday", birthday); System.out.println(BeanUtils.getProperty(p, "name")); System.out.println(BeanUtils.getProperty(p, "age")); System.out.println(BeanUtils.getProperty(p, "hight")); System.out.println(BeanUtils.getProperty(p, "birthday")); } //使用已经写好的注册器DateLocaleConverter @Test public void test4() throws Exception{ Person p = new Person(); String name = "wangwu"; String age = "23"; String hight = "173.5"; String birthday = "1990-09-09"; //将日期注册到BeanUtils上 ConvertUtils.register(new DateLocaleConverter(), Date.class);//提供的注册器不健壮,因为传入空字符串,就会报错 //所以,当没有提供注册器或需要加强注册器的时候,可以自己写 //测试 BeanUtils.setProperty(p, "name", name); BeanUtils.setProperty(p, "age", age); BeanUtils.setProperty(p, "hight", hight); BeanUtils.setProperty(p, "birthday", birthday); System.out.println(BeanUtils.getProperty(p, "name")); System.out.println(BeanUtils.getProperty(p, "age")); System.out.println(BeanUtils.getProperty(p, "hight")); System.out.println(BeanUtils.getProperty(p, "birthday")); Date date = p.getBirthday(); System.out.println(date.toLocaleString()); }
3.Map集合在BeanUtils中的应用
@Test public void test5() throws Exception { /* * JDK 7.0新特性: * Map map = {"name" : "zs", "age" : 22, "hight" : 176.5}; */ //将数据存入集合 Map map = new TreeMap(); map.put("name", "zhangsan"); map.put("age", "20"); map.put("hight", "172.5"); map.put("birthday", "1999-10-02"); //注册器 ConvertUtils.register(new DateLocaleConverter(), Date.class); //获取属性 Person p = new Person(); BeanUtils.populate(p, map); System.out.println(BeanUtils.getProperty(p, "name")); System.out.println(BeanUtils.getProperty(p, "age")); System.out.println(BeanUtils.getProperty(p, "hight")); System.out.println(BeanUtils.getProperty(p, "birthday")); } //属性链 @Test public void test6() throws Exception { Person p = new Person(); BeanUtils.setProperty(p, "birthday.time", "111212"); System.out.println(BeanUtils.getProperty(p, "birthday.time")); }
补充:
1.BeanUtils是以字符串的形式进行操作的
2.PropertyUtils是以传入值本身的类型进行操作的。
//PropertyUtils可直接解析为指定类型,而BeanUtils只能指定字符串的类型 @Test public void test7() throws Exception { Person p = new Person(); System.out.println("-----BeanUtiles-------"); BeanUtils.setProperty(p, "age", "22");//字符串形式 System.out.println(BeanUtils.getProperty(p, "age")); System.out.println(BeanUtils.getProperty(p, "age").getClass().getName()); System.out.println("-----PropertyUtiles-------"); PropertyUtils.setProperty(p, "age", 22);//Integer形式 System.out.println(PropertyUtils.getProperty(p, "age")); System.out.println(PropertyUtils.getProperty(p, "age").getClass().getName()); }
注解
1.注解相当于一种标记,在程序中加了注解就等于为程序打上了某种标记,没加,则没有某种标记。2.java编译器、开发工具和其他应用程序就可以用反射来了解自己的类及各种元素上有无何种标记,有什么标记,就会做出相应的处理。
3.标记可以加在包、类、字段、方法、方法参数,以及局部变量上等等。
4.在java.lang包中提供了最基本的annotation,即注解。
5.格式:@注解类名()。如果有属性,则在括号中加上属性名(可省略)和属性值。
java中三种最基本的注解:
1.@SuppressWarning(”deprecation”)--->压制警告
SupressWarning是告知编译器或开发工具等提示指定的编译器警告;
”deprecation”是告知具体的信息即方法已过时。
2.@Deprecated--->提示成员等已经过时,不再推荐使用。
源代码标记@Deprecated是在JDK1.5中作为内置的annotation引入的,用于表明类(class)、方法(method)、字段(field)已经不再推荐使用,并且在以后的JDK版本中可能将其删除,编译器在默认情况下检测到有此标记的时候会提示警告信息。
例如:假定之前的某个类升级了,其中的某个方法已经过时了,不能够将过时的方法删除,因为可能会影响到调用此类的这个方法的某些程序,这是就可以通过在方法上加这个注解。
3.@Override--->提示覆盖(父类方法)
加上此注解,,可对自己类中的方法判断是否是要覆盖的父类的方法,典型的例子即在集合中覆盖equals(Object obj)方法,其中的参数类型必须是Object,才能被覆盖,若不是,加上此注解就会提示警告。
注解类
1、定义格式:@interface 名称{statement}
2、元注解(注解的注解)
一个注解有其生命周期(Retetion)和存放的位置(Taget),这就可以通过元注解说明。
A:Retetion:用于说明注解保留在哪个时期,加载定义的注解之上。
①一个注解的声明周期包含:
java源程序--(javac)-->class文件--(类加载器)-->内存中的字节码
第一、当再源程序上加了注解,javac将java源程序编译为class文件,可能会把源程序中的一些注解去掉,进行相应的处理操作,当我们拿到源程序的时候,就看不到这些注解了。
第二、假设javac把这些注解留在了源程序中(或者说留在了class文件中),当运行此class文件的时候,用类加载器将class文件调入内存中,此时有转换的过程,即把class文件中的注解是否保留下来也不一定。
注意:class文件中不是字节码,只有把class文件中的内部加载进内存,用类加载器加载处理后(进行完整的检查等处理),最终得到的二进制内容才是字节码。
②Reteton(枚举类)取值:
Retetion.Policy.SOURSE:java源文件时期,如@Overried和@SuppressWarning
Retetion.Policy.CLASS: class文件时期(默认阶段)
Retetion.Policy.RUNTIME:运行时期,如@Deprecated
B:Taget:用于说明注解存放在哪些成分上,默认值是任何元素
其值可设置为枚举类ElementType类中的任何一个,包括:包、字段、方法、方法参数、构造器、类等值。取值为:
PACKAGE(包声明)
FIELD(字段声明)
ANNOTATION_TYPE(注释类型声明)
CONSIRUCTOR(构造器声明)
METHOD(方法声明)
PARAMETER(参数声明)
TYPE(类、接口(包含注释类型)或枚举声明)
LOCAL_VARIABLE(局部变量声明)
注意:其中代表类的值是TYPE。因为class、enum、interface和@
interface等都是属于Type的。不可用CLASS表示.
3、通过反射查看其它类中的注释:
过程:
第一、注解类:@interfaceA{}
第二、应用了“注释类”的类:@Aclass B{}
第三、对“应用注释类的类”进行反射操作的类:class{...},操作如下:
B.class.isAnnotionPresent(A.class);//判断是否存在此注解类
A a = B.class.getAnnotation(a.class);//存在的话则得到这个注释类的对象
代码演示:
@Retention(RetentionPolicy.RUNTIME) @Target({ElementType.TYPE,ElementType.METHOD}) public @interface ItcastAnnotation {} @ItcastAnnotation() public class AnnotionTest { @SuppressWarnings("deprecation")//表示压制警告的注解 @ItcastAnnotation() public static void main(String[] args) { System.runFinalizersOnExit(true); //反射方式查看注解 //检查类上是否有注解 if(AnnotionTest.class.isAnnotationPresent(ItcastAnnotation.class)){ //通过反射获取到注解 ItcastAnnotation annotation = AnnotionTest.class.getAnnotation(ItcastAnnotation.class); System.out.println(annotation); } }
为注解增加基本属性
1、属性:一个注解相当于一个胸牌,但仅通过胸牌还不足以区别带胸牌的两个人,这时就需要给胸牌增加一个属性来区分,如颜色等。
2、定义格式:同接口中的方法一样:String color();定义缺省格式:Stringvalue() default ”ignal”;
3、应用:直接在注解的括号中添加自身的属性,如:
@ItcastAnnotation(color=”red”)
这个和上面的@SuppressWarnings("deprecation")是一样的,其中的"deprecation"就是属性值
1)当只有一个属性时,可直接传入属性值。如”red”
2)当含有其他属性值的时候,如果那个属性值是缺省的(default),也可以直接传入这个属性值。
为注解增加高级属性
1、可以为注解增加的高级属性的返回值类型有:
1)八种基本数据类型 2)String类型 3)Class类型
4)枚举类型 5)注解类型 6)前五种类型的数组
2、数组类型的属性:
定义:int[]arrayArr() default {1,2,3}; -->可不定义默认值
应用:@MyAnnotation(arrayArr={2,3,4}) --> 可重新赋值
注:若数组属性中只有一个元素(或重新赋值为一个元素),这时属性值部分可省略大括号。
3、枚举类型的属性:
假设定义了一个枚举类TraffLamp,它是EnumTest的内部类,其值是交通灯的三色。
定义:EnumTest.TrafficLamplamp();
应用:@MyAnnotation(lamp=EnumTestTrafficLamp.GREEN)
4、注解类型的属性:
假定有个注解类:MetaAnnotation,其中定义了一个属性:String value()
定义:MetaAnnotationannotation() default @MetaAnnotation(”xxx”);
应用:@MyAnnotation(annotation=@MetaAnnotation(”yyy”)) --> 可重新赋值
可认为上面的@MetaAnnotation是MyAnnotation类的一个实例对象,同样可以认为上面的@MetaAnnotation是MetaAnnotation类的一个实例对象,调用:
MetaAnnotation ma =MyAnnotation.annotation();
System.out.println(ma.value());
5、Class类型的属性:
定义:Class cls();
应用:@MyAnnotation(cls=ItcastAnnotion.class)
注:这里的.class必须是已定义的类,或是已有的字节码对象
6、基本数据类型的属性(以int为例):
定义:int val()default 3; -->可不定义默认值
应用:@MyAnnotation(val=7) --> 可重新赋值
/将定义的注解的生命周期设置在运行时期 @Retention(RetentionPolicy.RUNTIME) //定义注解的放置位置 @Target({ElementType.TYPE,ElementType.METHOD}) //自定义注解 public @interface ItcastAnnotation { //定义属性 String str(); int val() default 1; int[] arr() default {2,3,4}; Class cls() default AnnotionTest.class; EnumText.TrafficLamp lamp() default EnumText.TrafficLamp.YELLOW; MetaAnnotation annotation() default @MetaAnnotation("sss"); } //测试注解类,用反射查看其属性 package cn.itcast.text2; import cn.itcast.text1.EnumText; @ItcastAnnotation(annotation=@MetaAnnotation("anntation"), Lamp=EnumText.TrafficLamp.RED, arr=7,val=5,str="String", cls=ItcastAnnotation.class) public class AnnotionTest { @SuppressWarnings("deprecation")//表示压制警告的注解 @ItcastAnnotation(str = "yyy")//有缺省值可不用写缺省部分 public static void main(String[] args) { //反射方式查看注解 //检查类上是否有注解 if(AnnotionTest.class.isAnnotationPresent(ItcastAnnotation.class)){ //通过反射获取到注解 ItcastAnnotation annotation = AnnotionTest.class.getAnnotation(ItcastAnnotation.class); //打印查看属性值 System.out.println(annotation); System.out.println(annotation.str()); System.out.println(annotation.val()); System.out.println(annotation.arr().length); System.out.println(annotation.cls().getName()); System.out.println(annotation.lamp().nextLamp()); System.out.println(annotation.annotation().value()); } } } //定义枚举类,交通灯 package cn.itcast.text1; public class EnumText { public static void main(String[] args) {} //定义交通灯 public enum TrafficLamp{ //定义3个元素,即此类的子类,覆写抽象方法 RED(30){ @Override public TrafficLamp nextLamp() {return GREEN;}}, GREEN(45){ @Override public TrafficLamp nextLamp() {return YELLOW;}}, YELLOW(5) { @Override public TrafficLamp nextLamp() {return RED;}}; private int time; //构造方法 private TrafficLamp(int time){this.time = time;} //抽象方法,转为下个灯 public abstract TrafficLamp nextLamp(); } }
----------------------
ASP.Net+Android+IOS开发、.Net培训、期待与您交流! ----------------------
相关文章推荐
- 黑马程序员__JAVA基础加强__高新技术(二)
- 黑马程序员_2010年Java高新技术
- 黑马程序员_Java高新技术(静态导入、可变参数、增强for循环、自动拆装箱、枚举、反射)
- 黑马程序员—JAVA高新技术之JavaBean
- 黑马程序员------java学习笔记之高新技术
- 黑马程序员 Java高新技术---反射
- 黑马程序员_Java高新技术(内省、注解、泛型、类加载器、代理)
- 黑马程序员_java高新技术(1)快捷键
- 黑马程序员_Java学习日记23_高新技术2
- 黑马程序员--Java高新技术(2)
- 黑马程序员-java高新技术(反射)
- 黑马程序员—JAVA高新技术之类加载器、动态代理
- 黑马程序员 java高新技术之注解,泛型,类加载器
- 黑马程序员——Java高新技术(3)
- 黑马程序员_Java高新技术之可变参数
- 黑马程序员_Java高新技术之反射 Constructor类
- 黑马程序员--张孝祥Java高新技术-JDK1.5新特性(一)【静态导入、可变参数、增强for循环】
- 黑马程序员——java高新技术学习日记(1)
- 黑马程序员_java高新技术总结【3】(内省、注解、代理)
- 黑马程序员——java高新技术(下)