ASP.Net+Android+IO开发S、.Net培训、期待与您交流! (2)java反射中Constructor的描述 constructor是代表类的构造函数的一个类,它可以获得类的构造函数的名字,参数,创建一个新的对象以及Annotation等, 1》、根据字节码文件可以获得相应的构造函数例如String.class.getConstructor(StringBuffer.class)或者可以通过对象的str.getclass.getConstructor()方法获得对象对应的类 的构造函数;在java.lang包下的Class类提供两个可以获得类的构造函数的方法为getConstructor(Class<?>... parameterTypes)和getConstructors(),前者是获得一个特定的 构造函数,后者的到字节码的所有的构造函数 2》、得到类的某一个构造函数需要知道该构造函数对应的参数列表如: class People{ public People(String name){} public People(String name,int age){} } class Test{ public static void main(String[] args){ Constructor con = People.class.getConstructor(String.class);//获得People类中带有一个String类型参数的构造函数 Constructor con = People.class.getConstructor(String.class,int.class);//获得People类中带有两个参数的构造函数并且参数分别为String类型和int类型 } } 3》、我们可以通过反射方式来创建类的对象,此时我们用到Constructor类中的newInstance(Object... initargs)方法来实例化对象,(注,在Class类中也有一个newInstance()) 创建对象时我们应该明确创建该对象时所需要的参数 如上例中的People类我们创建一个name=“zhou”的对象时只需 People p1 = con.newInstance(new String("zhou")); (3)java反射中Field类:该类用于描述类的属性,描述类属性是否有Annotation,属性名,得到该属性的值,设置属性是否可以Accessable等等 1》、我们可以根据字节码获得类中定义的属性例如String.class.getField()和String.class.getDeclaredField(String name)获得属性名为name的属性 其中getField和getFields是获得类中定义的公共属性,而getDeclaredField和getDeclaredFields是获得类中定义的所有属性 对于类People定义如下public class People { private String name; private int age; private char sex; } 可以通过一下格式来获得类中的属性 Field fields[] = People.class.getDeclaredFields(); for(Field field : fields){System.out.println(field);} 2》、我们可以通过Field类的相关方法获得类属性的值,但是在取属性对应值时应先将属行的访问权限设为true 实例代码:People p1 = People.class.getConstructor(String.class,int.class,char.class).newInstance(new String("zhangsan"),18,'F'); Field name = People.class.getDeclaredField("name"); name.setAccessible(true);//设置属性的访问权限 String name1 = (String) name.get(p1);//得到对象p1的对应的name属性值也可以用getString(Object obj)方法 System.out.println(name1); Field age = People.class.getDeclaredField("age"); age.setAccessible(true); int ages = age.getInt(p1); System.out.println(ages); 同时我们可以使用set方法为某一对象设置值例如:age.setInt(p1, 28);//第一个参数为类对象,第二个参数为索要设置的值 3》、判断两个对象是否是一个对象,即一个类的属性是否与另一个类的属性相同使用Field类的equal方法:name.equals(p1.getClass().getDeclaredField("name")) (4)java反射中Method类,用于描述类的成员方法的类 1》、Method的对象的获得,我们可以通过字节码的getMethods(),getMethod(String name, Class<?>... parameterTypes)和getDeclaredMethods()、getDeclaredMethod(String name, Class<?>... parameterTypes) 其中前两个是获得字节码中定义的公共方法,后两个是获得字节码中定义的所有方法,针对People类我们可以通过一下方式获得它中所定义的方法 Method[] methods = People.class.getMethods();或者得到类中定义的所有方法Method[] methods = People.class.getDeclaredMethods(); 获得类中某一特定的方法可以通过: Method method1 = People.class.getMethod("setName",String.class); 2》、如何调用反射中产生的方法 在Method类中提供了invoke(Object obj,object ... parmas)方法,方便我们使用利用反射得到的method,如Method getNameMethod = p1.getClass().getMethod("getName"); String name2 = (String)getNameMethod.invoke(p1, new Object(){}); System.out.println(name2); 注意:在jdk1.4及以前Method的invoke方法接受的对象是一个数组,当执行时,编译器先将数组拆成多个对象作为多个参数进行传递,而当某一个方法需要一个数组类型的参数时 传入的数组参数时,编译器会将其认为多个对象,而产生一个参数数目不符的异常,我们可以通过以下两个方式来解决这个问题 <1>、将数组封装为一个新的Object数组,这样在编译器第一次拆箱后,还是一个数组new Object[]{new String[]{"abd","abc","123"}} <2>、将数组通过强制类型转化为Object类型对象,这样告诉编译器这是一个对象(基本数据类型不是Object类型) (5)java数组的反射是用Array类,我们可以通过Class类的isArray方法判断一个类是否为数组类型,我们可以通过Array的getLength(Object obj)方法获得数组的长度,也可以通过get(Object obj,int index) 获得数组中某一索引的值 (6)java反射的应用:配置文件的使用,减少对源文件的修改,实现开闭原则 实现方法有 代码//ResourceBundle rbs = ResourceBundle.getBundle("it");//在源文件目录下,编译时,虚拟机将其拷贝到class所在目录只能使用后缀为properties的文件 // String className = rbs.getString("className"); InputStream isp = new FileInputStream("it.properties");//在工程目录下 //InputStream isp = ReflectSet.class.getClassLoader().getResourceAsStream("it.properties");//在源文件目录下,编译时,虚拟机将其拷贝到class所在目录,这是使用类加载器的方式 // Properties proper = new Properties(); proper.load(isp); String className = proper.getProperty("className"); Collection<Student> collection = (Collection<Student>)Class.forName(className).newInstance(); (7)javabean的使用:javabean是符合一定规则的特殊的类,其中类的属性都是私有的并且提供公共的get和set方法,为外部使用,javabean的构造函数只有一个并且不带有任何参数 例子public class People { private String name; private int age; private char sex; 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;} public char getSex() {return sex;} public void setSex(char sex) {this.sex = sex;} } javabean的作用:使用与传递信息(值)的用处,在javaEE中应用主要是在页面之间传递信息。我们可以通过java的内省和java反射机制来实现对javabean的操作 People p1 = new People("zhangsan"); //使用java的内省实现对javabean的操作 PropertyDescriptor pd = new PropertyDescriptor(propertyName, People.class); //利用反射机制实现对javabean中类的调用 Method methodGetName = pd.getReadMethod(); 对于javabean的操作我们可以使用BeanInfo的操作方法BeanInfo bi = Introspector.getBeanInfo(People.class); PropertyDescriptor[] pds = bi.getPropertyDescriptors(); People p1 = new People(); for(PropertyDescriptor pd:pds) { if(pd.getName() == "name") { Method methodSetName = pd.getWriteMethod(); methodSetName.invoke(p1,new String("zhangsan")); break;}} 对JavaBean的第三种操作方法:使用BeanUtils来操作javabean People p1 = new People("zhangsan",18,'F'); System.out.println(BeanUtils.getProperty(p1, "name")); BeanUtils.setProperty(p1, "age", 20);//义字符串的方式对属性进行的操作 System.out.println(BeanUtils.getProperty(p1, "age")); PropertyUtils.setProperty(p1, "age", 22);//以属性对应的类型对属性进行操作 System.out.println(PropertyUtils.getProperty(p1, "age")); 7、hashcode与hashSet的关系 hashSet集合根据hashcode值被分为若干个区域,在每个区域内其hashcode值满足一定的规律,每一个要存入的对象,根据hashcode算法算出该对象的hashcode值,再根据hashcode值将其存放到特定区域 当要蒋某一个对象放到该集合中时,先算出其hashcode值,确定该将该对象放入到那个区域,并在该区域中查找是否有与该对象的hashcode值相等的对象,这样就提高了操作效率。但是对于hashSet集合 就是采用hashcode算法来存取对象的,当对象中实现了hashcode方法,它会根据对象的hashcode算法来存取对象,当对象未实现hashcode时,他会根据系统默认的hashcode来存取对象,相同的对象被放在 不同的区域内,就会造成对象重复 8、java注解:annotation在java的lang包中有三个基本的annotation,分别为Overrider(子类重写父类的方法)、Deprecated(过时标记)、SuppressWarnings(取消一些警告) 1》、自定义Annotation:我们也可以开发出特定功能的Annotation格式为 @ interface className{},源注解包含Retention、Target 在定义Annotation时应该标记该Annotation应保留到啥时间才能去掉标记用Retention其中value值有三个CLASS,RUNTIME和SOURCE,其中RUNTIME表示标记保留到java文件运行时,在字节码中可以查看到标记 信息,CLASS表示标记保留到编译时,运行时标记已经没有啦,在字节码中找不到此标记;SOURCE则是在编译器编译时就将标记丢失的标记,我们定义的标记一般是为了运行时使用,所以应该将value设置为 RUNTIME使之在vm执行时有意义 Target指示注释类型所适用的程序元素的种类,是属性,方法还是类等等,它对应的value值为ElementType类型的值 Target对应的value值有ANNOTATION_TYPE(注释类型声明)、CONSTRUCTOR(构造方法声明)、FIELD(字段声明)、LOCAL_VARIABLE(局部变量声明)、METHOD(方法声明)、PACKAGE(包声明)、PARAMETER (参数声明)、TYPE(类、接口(包括注释类型)或枚举声明) 实例@Retention(RetentionPolicy.RUNTIME) @Target(value = ElementType.FIELD) public @interface Cloumn { String color() default "red" ;//给Annotation添加属性 String value(); }//这是定义了一个作用在Field上的Annotation 2》、获得相应的Annotation,利用java的反射机制我们可以的到在类,成员,变量....上的注解,javalang包下的Method,Field,Constructor类都也提供了相应的方法来获得定义在本身上的Annotation 获得方法如下 Field[] fields = clazz.getDeclaredFields(); for(Field field : fields) { if(field.getAnnotations()!= null) { Cloumn clo = field.getAnnotation(Cloumn.class);//获得定义在Field上的Annotation String value = clo.value(); String color = clo.color(); System.out.println(value + "\t"+color); } } 定义在类上的Annotation的获得 TypeAnnotation annot = (TypeAnnotation)clazz.getAnnotation(TypeAnnotation.class);//此时TypeAnnotation是定义在类,接口或者枚举类型上的Annotation System.out.println(annot.value()); 3》、可以定义特殊的属性:如 int[]类型 也可以有默认值用default{1,2,3}获得后可以通过反射得到数组中的值 4》、可以定义一个枚举类型的属性,如WeekDay也可设置默认值 5》、也可以定义一个注解类型的属性 9、java泛型是java提供给集合类来约束集合类中元素类型的一种技术,在执行javaC以后,编译器会将泛型去掉,同样泛型也可以方法定义是作为形参来使用 例如List<String> list = new ArrayList<String>();方法的定义中作形参public void update(T t)throws SQLException;这是在数据库操作是使用的,这里主要是通过java的反射机制,来拼接一个sql 语句使用到的 注意1、参数化类型与原始类型具有兼容性 1>、参数化类型可以引用一个原始类型的对象,如List<String> list = new ArrayList();2>、原始类型也可以引用一个参数化类型对象,如List list = new ArrayList<String>() 此时list对象中只能存放String类型的数据 2、参数化类型不考虑类型参数的继承关系 对于以下两种格式都是错误的 Vector<String> vector = new Vector<Object>();和Vector<Object> vector = new Vector<String>(); 3、在创建数组实例时,数组的原素不能使用参数化类型,例如List<String> list[] = new ArrayList<String>[10] 1》、?泛型中的通配符,根据注意中第2条可以知道在泛型中参数不能进行类型的转化,所以引入了通配符? private static void printList(List<?> list) {//其中list的参数可以是任何类型,?代表任意类型 for(int i = 0 ; i<list.size();i++) { System.out.println(list.get(i)); } }在使用?通配符可以引用其他的各种参数化的类型,?通配符定义的变量主要用作引用,可以调用与参数化无关的方法,不能调用与参数化有关的方法 2》、通配符的扩展 java中对通配符的定界,有限定通配符的上边界用extends,限定?的下边界用super,这样就指定了?所代表的类型必须是super后类型的父类或者是super后类型 Vector<? extends Number> x = new Vector<Double>();这是限定集合的上边界,如果?代表的类型不是Number的子类,则会报错,因为x中只能存放Number子类型的对象。 Vector<? super Number> x = new Vector<Number>();Vector<? super Number> x1 = new Vector<Double>();前面一个方法是正确的,后者因为Double是Number的子类,错误 注意:我们不能将带有通配符的集合赋值给一个固定类型的集合 ASP.Net+Android+IO开发S、.Net培训、期待与您交流!