黑马程序员__枚举__反射__内省

来源:互联网 发布:大数据服务器硬件配置 编辑:程序博客网 时间:2024/04/28 11:38

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

MyEclipseEclipse的插件

透视图是视图的组合

Window-- >Show View -- >other里找相应视图

导入工程:先把工程COPY到工作间,导入Existing Projects intoWorkspace

再配JDKBuild Path - - >configure Build Path,把Libraries里原来的删除掉,添加新的add Lib

alt+/内容助理

import static java.lang.Math.*;//静态导入

可变参数的特点:

       只能出现在参数列表的最后,位于变量类型和变量名之间,前后有无空格都可以

       调用可变参数的方法时,编译器为该可变参数隐含创建一个数组,在方法体中

       以数组的形式访问可变参数

享元模式:flyweight很多个小的对象,它们有很多属性相同,把它们变成一个对象,那些不同的属性把它们变成方法的参数,称之为外部状态,那些相同的属性称之为这些对象的内部状态

枚举:

把字符串变成枚举中对应的对象: WeekDay.valueOf("SUN");

WeekDay.values();得到枚举中所有元素的数组

枚举类定义的东西都要位于元素列表之后,这时元素列表后面要用个分号;

枚举类的构造方法都要私有

public enum TrafficLamp{RED(30){public TrafficLamp nextLamp(){return GREEN;}},GREEN(30){public TrafficLamp nextLamp(){return YELLOW;}},YELLOW(5){public TrafficLamp nextLamp(){return RED;}};public abstract TrafficLamp nextLamp();private int time;private TrafficLamp(int time){this.time = time;}}

反射的基石:Class

Java程序中的各个Java类属于同一类事物,描述这类事物的Java类名就是Class

Class类描述了哪些方面的信息呢?

类的名字,类的访问属性,类所属于的包名,字段名称的列表,方法名称的列表,等等

如何得到各个字节码对应的实例对象(Class类型)

类名.class,例如System.class

对象.getClass(),例如new Date().getClass()

Class.forName("类名"),例如Class.forName("java.util.Date");//反射常用

九个预定义Class实例对象

void.class和八个基本数据类型int.class

int.class == Integer.class;结果为false

int.class == Integer.TYPE;结果为true,TYPE为对象包装的基本类型的字节码

数组类型的Class实例对象

       Class.isArray()

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

表示Java类的Class类显然要提供一系列的方法,来获得其中的变量,方法,构造方法

,修饰符,包等信息,这些信息就是用相应类的实例对象来表示,

它们是FieldMethodContructorPackage等等

Constructor

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

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

       Constructor[] constructors = Class.forName("java.lang.String").getConstructors();

得到某一个构造方法

       Constructor constructor =

       Class.forName("java.lang.String").getConstructor(StringBuffer.class);

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

因为JDK1.5的可变参数新特性,使getConstructor里可以传多个参数

constructor.newInstance(new StringBuffer("abc"))创建对象时要对其进行强转(String)

创建实例对象

       通常方式String str=new String(new StringBuffer("abc"));

       反射方式String str=(String)constructor.newInstance(new StringBuffer("abc"));

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

Class.newInstance()方法

       例子:String obj=String)Class.forName("java.lang.String").newInstance();

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

       该方法内部的具体代码是怎样写的呢?用到了缓存机制来保存默认构造方法的实例对象

ReflectPoint pt1=new ReflectPoint(3,5);

Field fieldY=pt1.getClass().getField("y");//只能取得public上的

//fieldY的值是多少?是5,错!fieldY不是对象身上的变量,而是类上,

//要用它去取某个对象上对应的值

fieldY.get(pt1);//取得pt1对象上y的值

Field fieldX=pt1.getClass().getDeclaredField("x");//只要是声明过的就可以取得

fieldX.setAccessible(true);//暴力反射,设置为可访问

fieldX.get(pt1);

Method

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

得到类中的某一个方法

       例子Method charAt =

       Class.forName("java.lang.String").getMethod("charAt",int.class);

调用方法:

       通常方式:System.out.println(str.charAt(1));

       反射方式:System.out.println(charAt.invoke(str,1));

       如果传递给Method对象的invoke()方法的第一个参数为null,

       说明该Method对象对应的是一个静态方法!

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

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

问题:

启动Java程序的mian方法的参数是一个字符串数组,即String[] args,通过反射

方式来调用这个main方法时,如何为invoke方法传递参数呢?按JDK1.5的语法,整个

数组是一个参数,而按JDK1.4的语法,数组中的每个元素对应一个参数,当把一个字

符串数组作为参数传递给invoke方法时,javac会到底按照哪种清洁进行处理呢?

JDK1.5肯定要兼容JDK1.4的语法,会按JDK1.4的语法进行处理,即把数组打散成为

若干个单独的参数,所以在给main方法传递参数时,不能使用代码

mainMethod.invoke(null,new String[]{"xx"}),javac只把它当作JDK1.4的语法进行理解

而不把它当作JDK1.5的语法解释,因此会出现参数类型不对的问题

解决办法:

       mainMethod.invoke(null,new Object[]{new String[]{"xxx"}});

       mainMethod.invoke(null,(Object)new String[]{"xxx"});编译器会作特殊处理,编译

时不把参数当作数组看待,也就不会数组打散成若干个参数了

每一个具有相同元素类型和相同维度的数组反射的Class都是同一个

框架要解决的核心问题:若干年前的框架调用若干年后写的程序      

一定要记住用完整的路径存放properties文件,但完整的路径不是硬编码,而是运算出来的

示例代码

package cn.itcast.day1;import java.io.FileInputStream;import java.io.InputStream;import java.util.ArrayList;import java.util.Collection;import java.util.HashSet;import java.util.Properties;public class ReflectTest2 {public static void main(String[] args) throws Exception{//InputStream ips = new FileInputStream("config.properties");//读取properties配置文件//InputStream ips = ReflectTest2.class.getClassLoader().getResourceAsStream("cn/itcast/day1/config.properties");//类加载器加载根目录下相应位置的配置文件InputStream ips = ReflectTest2.class.getResourceAsStream("config.properties");Properties props = new Properties();props.load(ips);ips.close();String className = props.getProperty("className");Collection collections = (Collection)Class.forName(className).newInstance();//Collection collections = new HashSet();ReflectPoint pt1 = new ReflectPoint(3,3);ReflectPoint pt2 = new ReflectPoint(5,5);ReflectPoint pt3 = new ReflectPoint(3,3);collections.add(pt1);collections.add(pt2);collections.add(pt3);collections.add(pt1);System.out.println(collections);}}


 

内省(Introspector

JavaBean是一种特殊的Java类,主要用于传递数据信息,这种Java类中的方法主要用于访问私有的字段,且方法名符合某种命名规则如果要在两个模块之间传递多个信息,可以将这些信息封装到一个JavaBean中,这种JavaBean的实例对象通常称之为值对象(ValueObject,简称VO)这些信息在类中用私有字段来存储,如果读取或设置这些字段的值,则需要通过一些相应的方法来访问,大家觉得这些方法的名称叫什么好呢?JavaBean的属性是根据其中的settergetter方法来确定的,而不是根据其中的成员变量,如果方法名为setId,中文意思即为设置id,至于你把它夏至哪个变量上,用管吗?如果方法名为getId,中文意思即为获取id至于你从哪个变量上取,用管吗?去掉set前缀,剩余部分就是属性名,如果剩余部分的第二个字母是小写的,则把剩余部分的首字母改成小的

setId()的属性名idisLast()的属性名lastsetCPU的属性名是CPU

总之,一个类被当作JavaBean使用时,JavaBean的属性是根据方法名推断出来的,它根本看不到Java类内部的成员变量

一个符合JavaBean特点的类可以当作普通类一样进行使用,但把它当JavaBean用肯定需要带来一些额外的好处,我们才会去了解和应用JavaBean,好处如下

1.       Java EE开发中,经常要使用到JavaBean,很多环境就要求按JavaBean方式进行操作,别人都这么么用和要求这么做,那你就没什么挑选的余地

2.       JDK中提供了对JavaBean进行操作的一些API,这套API就称为内省,如果要你自己去通过getX方法来访问私有的x怎么做,有一定难度,用内省这套API操作JavaBean比用普通类的方式更方便

采用遍历BeanInfo的所有属性方式来查找和设置某个ReflectPoint对象的x属性,在程序中把一个类当作JavaBean来看,就是调用IntroSpector.getBeanInfo方法,得到的BeanInfo对象封装了把这个类当作JavaBean看的结果信息

内省示例

package cn.itcast.day1;import java.beans.BeanInfo;import java.beans.IntrospectionException;import java.beans.Introspector;import java.beans.PropertyDescriptor;import java.lang.reflect.InvocationTargetException;import java.lang.reflect.Method;import org.apache.commons.beanutils.BeanUtils;import org.apache.commons.beanutils.PropertyUtils;import cn.itcast.day1.ReflectPoint;public class IntroSpectorTest {/** * @param args */public static void main(String[] args) throws Exception{// TODO Auto-generated method stubReflectPoint pt1 = new ReflectPoint(3,5);String propertyName = "x";Object retVal = getProperty(pt1, propertyName);System.out.println(retVal);Object value = 7;setProperty(pt1, propertyName, value);System.out.println(BeanUtils.getProperty(pt1, "x"));BeanUtils.setProperty(pt1, "x", 8);System.out.println(pt1.getX());BeanUtils.setProperty(pt1, "birthday.time", "111");System.out.println(BeanUtils.getProperty(pt1, "birthday.time"));PropertyUtils.setProperty(pt1, "x", 7);System.out.println(PropertyUtils.getProperty(pt1, propertyName).getClass());}private static void setProperty(Object pt1, String propertyName,Object value) throws IntrospectionException,IllegalAccessException, InvocationTargetException {PropertyDescriptor pd2 = new PropertyDescriptor(propertyName,pt1.getClass());Method methodSetX = pd2.getWriteMethod();//通过getWriteMethod方法获取属性名pd的set方法methodSetX.invoke(pt1, value);}private static Object getProperty(Object pt1, String propertyName)throws IntrospectionException, IllegalAccessException,InvocationTargetException {/*PropertyDescriptor pd = new PropertyDescriptor(propertyName, pt1.getClass());Method methodGetX = pd.getReadMethod();//通过getReadMethod方法获取属性名pd的get方法Object retVal = methodGetX.invoke(pt1);*/ BeanInfo beanInfo = Introspector.getBeanInfo(pt1.getClass());PropertyDescriptor[] pds = beanInfo.getPropertyDescriptors();Object retVal = null;//遍历pds查找propertyName属性名并保存到retVal中for(PropertyDescriptor pd : pds){if(pd.getName().equals(propertyName)){Method methodGetX = pd.getReadMethod();retVal = methodGetX.invoke(pt1);break;}} return retVal;}}

用到的ReflectPoint

package cn.itcast.day1;import java.util.Date;public class ReflectPoint {private Date birthday = new Date();private int x;public int y;public int getX() {return x;}public void setX(int x) {this.x = x;}public int getY() {return y;}public void setY(int y) {this.y = y;}public String str1 = "ball";public String str2 = "basketball";public String str3 = "itcast";public ReflectPoint(int x, int y) {super();this.x = x;this.y = y;}@Overridepublic String toString(){return x+":"+y;}@Overridepublic int hashCode() {final int prime = 31;int result = 1;result = prime * result + x;result = prime * result + y;return result;}@Overridepublic boolean equals(Object obj) {if (this == obj)return true;if (obj == null)return false;if (getClass() != obj.getClass())return false;ReflectPoint other = (ReflectPoint) obj;if (x != other.x)return false;if (y != other.y)return false;return true;}public Date getBirthday() {return birthday;}public void setBirthday(Date birthday) {this.birthday = birthday;}}


 

导入外部的Jar包,在工程上建一个lib目录用于存放jar

jar包上右键-- >build path -- >add to build path

apacheBeanUtils.jar包的时候还要导入logging



 

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

原创粉丝点击