黑马程序员----基础加强3反射和内省

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




 

>>JAVA1.2时就存在反射,并不是1.5的新特性

 

 

 

 

>>类Class(平时定义时是小写的class,这个是一个类,名字叫Class)

 

Class代表一类什么样的事物?

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

         Class描述了类的名字、类的访问属性、类所属于的包名、字段名的列表、方法名称的列表、等等。

         理解:比如Person代表人,具体的实例对象就是如“小强”、“志明”这样的人。所以,Class代表类,具体的实例就是各个类在内存中的字节码。

         一个类被类加载器加载到内存中,占用一片存储空间,这个空间里面的内容就是类的字节码,不同类的字节码是不同的,所以它们在内存中的内容是不同的,这一个个的空间可分别用一个个的对象来表示。

 

Eg:理解

//两个人

Person p1 = new Person();

Person p2 = new Person();

 

//Class

Class class1 = new Class(); //编译报错,不可以new的

Class cla1 = 字节码1;

Class cla2 = 字节码2;

Class class1 = Date.class;

Class class2 = Math.class;

 

 

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

1)  类名.class,例如System.class

2)  对象.getClass(),例如newDate().getClass()

3)  Class.forName(“类名”),例如Class.forName(“java.util.Date”);

 

基本数据类型也有对应的Class的,称为9个预定义类型:(来自API)

基本的 Java 类型(boolean、byte、char、short、int、long、float 和 double)和关键字 void 也表示为 Class 对象。

 

Eg:void也是预定义Class实例对象

……………………

Class cla = void.class; //允许

……………………

 

 

Eg:内存中的字节码,它们相等吗?

package cn.com.cty;

 

import java.util.Date;

 

public class ClassTest {

 

         //为演示方便不处理异常

         publicstatic void main(String[] args) throws ClassNotFoundException {

                  

                   Stringstr = "durex";

                   Classcla1 = str.getClass();

                   Classcla2 = String.class;

                   Classcla3 = Class.forName("java.lang.String");

                  

                   System.out.println(cla1== cla2);  //true

                   System.out.println(cla2== cla3);  //true

                  

                   Stringstr2 = "jissbon";             

                   Classcla4 = str2.getClass();

                  

                   //是预定义类型吗?

                   System.out.println(cla4.isPrimitive());  //false

                   System.out.println(int.class.isPrimitive());  //true

                  

                   //相等吗(Integer是int的一个包装类)

                   System.out.println(int.class== Integer.class);  //false

                  

                   //Integer中提供了一个TYPE常量来代表包装类型包装的那个基本类型的字节码

                   System.out.println(int.class== Integer.TYPE);  //true

 

                   /*其它包装类型中也提供了TYPE(来自API对isPrimitive的解释)

                   Boolean.TYPE,Character.TYPE, Byte.TYPE, Short.TYPE,

                   Integer.TYPE,Long.TYPE, Float.TYPE, Double.TYPE, Void.TYPE*/

                  

                   //基本类型的数组呢?

                   System.out.println(int[].class.isPrimitive());  //false

                   System.out.println(int[].class.isArray());  //true

 

         }

}

 

 

>>反射

         反射就是把Java类中的各种成分映射成相应的java类。--某人总结

例如,一个java类中用一个Class类的对象来表示,一个类中的组成部分:成员变量、方法、构造方法、包等等信息也用一个个java类来表示,就像汽车是一个类,汽车中的发动机、变速箱等等也是一个个类。表示java类的Class类显然要提供一系列方法来获取其中的变量、构造方法、方法等等的信息,这些信息就是用相应类的实例对象来表示,它们是Field、Method、Contructor、Package等等。

 

反射会导致程序性能下降。

 

 

 

>>构造方法的反射应用

 

java.lang.reflect

类 Constructor<T>

java.lang.Object

 java.lang.reflect.AccessibleObject

     java.lang.reflect.Constructor<T>

类型参数:T - 在其中声明构造方法的类。

 

Eg:入门例子

……………………

//所有的

Constructor[] constructor = Class.forName(“java.lang.String”).getConstructor();

 

//指定的,我要有参还是无参的?

Constructor constructor1

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

 

//用反射实现new String(newStringBuffer(“durex”));

String str

= (String)constructor1.newInstance(newStringBuffer(“durex”));

sop(str.charAt(2));  //输出第三个字符验证

……………………

 

注意:以上例子中

String str

= (String)constructor1.newinstance(newStringBuffer(“durex”));

如果写成

String str

= (String)constructor1.newinstance(“abc”);

则编译时正常,运行时报错。因为反射的不是带String参数的构造函数,特别注意。

 

 

以上例子中,其实可以省略从Class->constructor->new的过程,Class中有newInstence()方法。

 

 

 

 

>>成员变量反射应用

 

java.lang.reflect

类 Field

java.lang.Object

  java.lang.reflect.AccessibleObject

     java.lang.reflect.Field

 

Field代表某个类中的一个成员变量。那么,得到的Field对象是对应到类上的成员变量,还是对应到该类创建的对象上的成员变量呢?

 

Eg:说明例子,包括反射和暴力反射

package cn.com.cty;

 

import java.lang.reflect.Field;

import java.util.Date;

 

public class ReflectFieldDemo {

 

         /**

          * @param args

          * @throws NoSuchFieldException

          * @throws SecurityException

          * @throws IllegalAccessException

          * @throws IllegalArgumentException

          */

         publicstatic void main(String[] args) throws SecurityException, NoSuchFieldException,IllegalArgumentException, IllegalAccessException {

                  

                   /*Person类

                   publicString name;  //注意这个是公有的

                   privateint age;

                   privateString address;

                   privateDate birthday;*/

                  

                   Personp = new Person("durex", 20, "what", new Date());

                  

                   //反射成员变量,这里只能反射public定义的变量

                   Fieldf1 = p.getClass().getField("name");

                   //现在,f1上的值是durex吗?错!现在f1只代表一个变量,是类上的变量

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

                   Stringname = (String) f1.get(p);

                   System.out.println(name);

                  

                   //想取出private定义的变量怎么办?

                   //使用getField报NoSuchFieldException

                   Fieldf2 = p.getClass().getDeclaredField("age");

                   f2.setAccessible(true);//暴力反射

                   intage = f2.getInt(p);

                   System.out.println(age);

                   /*如果没有设定暴力反射,则虽然可以找到变量(不会报NoSuchFieldException),

                   但不能使用(报IllegalArgumentException,IllegalAccessException)

                  

                   这里张老师有一个形象的比喻:好比一个鸟人,拿钱在你面前晃(可以找到变量),

                   但是不让你用他的钱(不合法的access),我们一气之下暴力抢夺(暴力反射)。

                   */

         }

}

 

 

 

 

>>综合应用:将任意一个对象中的所有String类型的成员变量所对应的字符串内容中的“b”换成“a”。

 

Eg:self

 

package cn.com.cty;

 

import java.lang.reflect.Field;

import java.util.Date;

 

public class ReflectFieldApp {

 

         publicstatic void main(String[] args) {

                  

                   Personp = new Person();

                   Personnewp = new Person();

                  

                   p.setName("bbbbx");

                   p.setAge(20);

                   p.setAddress("bbboooxxxbbb");

                   p.setBirthday(newDate());

                  

                   newp= (Person) replace(p);

                  

                   System.out.println(p.getName()+

                                     "|||"+ p.getAge() +

                                     "|||"+ p.getAddress() +

                                     "|||"+ p.getBirthday());

         }

        

         publicstatic Object replace(Object obj)

         {

                   Field[]fields = obj.getClass().getDeclaredFields();

                  

                   for(Fieldfield : fields)

                   {

                            //暴力反射

                            field.setAccessible(true);

                           

                            //因为每个类字节码在内存只有一份,所以用等号比equals好

                            if((field.getType())== (String.class))

                            {

                                     try{

                                               StringoldValue = (String)field.get(obj);

                                               StringnewValue = oldValue.replace('b', 'a');

                                              

                                               field.set(obj,newValue);

                                     }catch (IllegalArgumentException e) {

                                               //TODO Auto-generated catch block

                                               e.printStackTrace();

                                     }catch (IllegalAccessException e) {

                                               //TODO Auto-generated catch block

                                               e.printStackTrace();

                                     }

                            }

                   }

                  

                   returnobj;

         }

}

输出:aaaax|||20|||aaaoooxxxaaa|||Tue Apr 02 11:09:37 CST 2013

和老师打的差不多,就这么着吧。

 

 

 

 

>>成员方法反射应用

 

java.lang.reflect

类 Method

java.lang.Object

 java.lang.reflect.AccessibleObject

     java.lang.reflect.Method

 

 

getMethod

public Method getMethod(String name,  Class<?>... parameterTypes)

                 throws NoSuchMethodException,SecurityException

 

 

Eg:入门例子

 

//获取

Method rCharAt

= Class.forName(“java.lang.String”).getMethod(“chatAt”,int.class);

//调用

//通常方式

sop(str.charAt);

//反射方式

sop(rCharAt.invoke(str,2));

 

说明:invoke是调用方法对象上的方法。可以这么理解,列车司机停住了列车,其实是列车自己刹住的,司机只是发了命令。

 

         如果传递给invoke()方法的第一个参数为null,说明该Method对象对应的是一个静态方法,调用其不需要对象。

 

         当然,1.4和1.5的区别在于是否有可变参数:

public Object invoke(Object obj, Object...args)

throwsIllegalAccessException, IllegalArgumentException, InvocationTargetException

如果使用1.4的方式调用也是可以的:

System.out.println(rCharAt.invoke( str, newObject[]{ 2 } ) );

 

 

 

 

>>调用任意类的main方法

 

eg:一般调用main方法

/*试验用的带main方法的类*/

package cn.com.cty;

public class TempTest {

 

         /**

          * @param args

          */

         publicstatic void main(String[] args) {

                  

                   //输出传入的参数

                   for(Stringstr : args)

                   {

                            System.out.println(str);

                   }

         }

}

 

/*调用TempTest类的main方法*/

package cn.com.cty;

public class ReflectMethodDemo {

 

         publicstatic void main(String[] args) {

                  

                   TempTest.main(newString[]{"durex","jissbon","what"});

         }

}

输出:

durex

jissbon

what

 

 

eg:反射方式调用

 

package cn.com.cty;

 

import java.lang.reflect.Method;

 

public class ReflectMethodDemo {

 

         publicstatic void main(String[] args) throws Exception{

                  

                   //TempTest.main(newString[]{"durex","jissbon","what"});

                  

                   //演示方便,简单处理异常

                   MethodmainMethod =

                            Class.forName("cn.com.cty.TempTest").getMethod("main",String[].class);

                  

                   /*

                   mainMethod.invoke(null,new String[]{"durex","jissbon","what"});

                   //运行时异常,java.lang.IllegalArgumentException:wrong number of arguments

                   //因为为了兼容1.4,这样传入的参数会被拆开,等于传入了3个参数,而main只

接收一个数组参数

                   */

                  

//解决方法1

                   //再打一个包来解决这个问题,将数组放到数组中去,拆开后还是一个数组

                   Object[]obj = {new String[]{"durex","jissbon","what"}};

                   mainMethod.invoke(null,obj);

                  

                   //解决方法2

//将String数组当成Object,具体原因待考究

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

 

         }

}

 

 

 

 

>>数组的反射

 

         API中解释:每个数组属于被映射为 Class 对象的一个类,所有具有相同元素类型和维数的数组都共享该 Class 对象。即具有相同元素类型和相同维度的数组都属于同一个Class对象。

 

eg:一系列试验

package cn.com.cty;

 

import java.util.Arrays;

 

public class ReflectArrayDemo {

 

 

         publicstatic void main(String[] args) {

                  

                   int[]a1 = new int[3];

                   int[]a2 = new int[3];

                   int[]a3 = new int[5];//不同个数

                   int[][]a4 = new int[5][5];//不同维度

                   String[]a5 = new String[3];//不同类型

                  

                   System.out.println(a1== a2);  //false

                   System.out.println(a1.getClass()== a2.getClass());  //true

                   System.out.println(a1.getClass()== a3.getClass());  //true

                   System.out.println(a1.getClass()== a4.getClass());  //false

                   //System.out.println(a1== a5);  //编译即报错

                   System.out.println(a1.getClass()== a5.getClass());  //false

                  

                   //查看名字

                   System.out.println(a1.getClass().getName());//输出[I,什么意思呢?

                  

                   /*查看API的getName()方法解释

                   如果此类对象表示一个数组类,则名字的内部形式为:表示该数组嵌套深度的一个或多个 '[' 字符加元素类型名。元素类型名的编码如下:

 

                   ElementType       Encoding 

                   boolean       Z 

                   byte       B 

                   char       C 

                   classor interface       Lclassname; 

                   double       D 

                   float       F 

                   int       I 

                   long       J 

                   short       S */

                  

                   //查看父类,输出java.lang.Object

                   System.out.println(a1.getClass().getSuperclass().getName());

                  

                   //父类都是Object,做个试验,都改成Object

                   Objectobj1 = a1;

                   Objectobj2 = a4;//a4是二维数组

                   Objectobj3 = a5;//a5是String类型

                   Object[]obj4 = a5;

                   //Object[]obj5 = a1;//a1是int型,基本数据类型,不能放入Object数组

                  Object[] obj6 = a4;//a4是二维数组

                  

                   //由上面的试验引申出的一些问题

                   //重新定义一些数组来做试验,注意格式,赋值了就不用规定大小了

                   //int[]arr1 = new int[3]{1,2,3};

                   int[]arr1 = new int[]{1,2,3};

                   String[]arr2 = new String[]{"durex","jissbon","what"};

                   int[][]arr3 = new int[][]{{11,22,33},{44,55,66}};

                   String[][]arr4 = newString[][]{{"11","22","33"},{"44","55","66"}};

                   //用工具类输出

                   System.out.println(Arrays.asList(arr1));

                   System.out.println(Arrays.asList(arr2));

                   System.out.println(Arrays.asList(arr3));

                   System.out.println(Arrays.asList(arr4));

                   /*输出:

                   [[I@c17164]

                   [durex,jissbon, what]//只有字符串类型的输出了

                   [[I@1fb8ee3,[I@61de33]

                   [[Ljava.lang.String;@14318bb,[Ljava.lang.String;@ca0b6]

                  

                   为什么呢?

                   在1.5中,asList()是这样定义的

                   publicstatic <T> List<T> asList(T... a)

                   在1.4中,asList()是这样定义的

                   publicstatic List asList(Object[] obj)

                   结合上面的Object试验,String是在1.4处理的,等效于多个参数,而int在1.5处

                   理,当做一个参数

                   */

                  

         }

}

 

 

eg:打印数组或任意对象

package cn.com.cty;

 

import java.lang.reflect.Array;

import java.util.Arrays;

 

public class ReflectArrayDemo {

 

 

         publicstatic void main(String[] args) {

         int[]arr1 = new int[]{1,2,3};

 

         Objectobj = arr1;

                   printObject(obj);

                   printObject("durex");

                  

}

 

private static void printObject(Object obj){

                  

                   Classclazz = obj.getClass();

                  

                   //判断是不是数组

                   if(clazz.isArray())

                   {

                            intlen = Array.getLength(obj);

                            for(intx=0 ; x<len ; x++)

                            {

                                     System.out.println(Array.get(obj,x));

                            }

                   }

                   else

                   {

                            System.out.println(obj);

                   }

         }

 

 

 

 

>>hashCode分析,面试题目,hashCode的功能

 

一个集合是否包含某个对象,怎么查找呢?通常逐一取出每个元素和要查找的对象对比,当某个元素和要查找的对象的equal是方法比较结果相同时,返回肯定信息。但是如果当集合中有非常多的元素且不包含要查找的信息,显然,很没有效率。

         于是有人发明了一种哈希算法来提高效率,这种方法将集合分成若干个存储区域,每个对象可以计算出一个哈希码,可以将哈希码分组,每组分别对应某个存储区域,根据一个对象的哈希码就可以确定该对象应该存储在那个区域。

         HashSet集合就是采用哈希算法存取对象的集合,它内部采用对某个数字n进行取余的方式对哈希码进行分组和划分存储区域。

         Object类中定义了一个hashCode方法来返回每个java对象的哈希码。当从HashSet集合中查找对象时,java系统首先调用对象的hashCode方法获取该对象的哈希码,然后根据哈希码找到相应的存储区域,最后取出该区域内的每个元素与该对象进行equals方法比较。

 

 

eg:说明例子

……………………

//复写了Person类中的hashCode()和equals()方法

         publicint hashCode() {

                   finalint prime = 47;

                   intresult = 1;

                   result= prime * result + age;

                   result= prime * result + ((name == null) ? 0 : name.hashCode());

                   returnresult;

         }

 

         publicboolean equals(Object obj) {

                   if(this == obj)

                            returntrue;

                   if(obj == null)

                            returnfalse;

                   if(getClass() != obj.getClass())

                            returnfalse;

                  final Person other = (Person) obj;

                   if(age != other.age)

                            returnfalse;

                   if(name == null) {

                            if(other.name != null)

                                     returnfalse;

                   }else if (!name.equals(other.name))

                            returnfalse;

                   returntrue;

         }

……………………

package cn.com.cty;

 

import java.util.ArrayList;

import java.util.Collection;

import java.util.Date;

import java.util.HashSet;

 

public class ReflectHashCodeAnalyse {

 

         publicstatic void main(String[] args) {

 

                   //Collectioncoll = new ArrayList();

                   Collectioncoll = new HashSet();//不能重复

                  

                   //Person中,名字和年龄相同认为是“一个人”

                   Personp1 = new Person("durex",20,"1",new Date());

                   Personp2 = new Person("jissbon",18,"2",new Date());

                   Personp3 = new Person("what",25,"3",new Date());

                   Personp4 = new Person("durex",20,"4",new Date());//和p1同

                  

                   coll.add(p1);

                   coll.add(p2);

                   coll.add(p3);

                   coll.add(p4);//试验1

                   coll.add(p1);//试验2

                  

                   //复写equals方法

                   System.out.println(p1.equals(p4));  //true

                   //没有复写hashCode前为4(试验2排除),之后为3(实验1排除)

                   System.out.println(coll.size());

         }

}

 

说明:没有复写hashCode前size为4。因为虽然p4和p1的equals结果为true。但是p1和p4被存放到了不同的区域,所以p4可以被add进HashSet集合。

         所以有说法,equals相等的,应让其hashCode也相等。所以复写了hashCode方法后,size为3。

         但是反过来可以不成立,即hashCode相同的两个对象equals可以不等。

 

 

         当一个对象呗存储进HashSet集合中以后,就不能修改这个对象中的那些参与计算哈希码的属性了,否则,对象修改后的哈希值与最初存储进HashSet集合中的哈希值就不同了,在这种情况下,即使在contains方法使用该对象的当前引用作为的参数去Hashset集合中检索对象,也将返回找不到对象的结果,这也会导致无法从HashSet集合中单独删除该对象,造成“内存泄露”。

 

eg:修改导致内存泄露

//在上一个例子的基础上,修改已经加入HashSet集合的对象属性值

package cn.com.cty;

 

import java.util.ArrayList;

import java.util.Collection;

import java.util.Date;

import java.util.HashSet;

 

public class ReflectHashCodeAnalyse {

 

         publicstatic void main(String[] args) {

 

                   //Collectioncoll = new ArrayList();

                   Collectioncoll = new HashSet();//不能重复

                  

                   //Person中,名字和年龄相同认为是“一个人”

                   Personp1 = new Person("durex",20,"1",new Date());

                   Personp2 = new Person("jissbon",18,"2",new Date());

                   Personp3 = new Person("what",25,"3",new Date());

                   Personp4 = new Person("durex",20,"4",new Date());//和p1同

                  

                   coll.add(p1);

                   coll.add(p2);

                   coll.add(p3);

                   coll.add(p4);//试验1

                   coll.add(p1);//试验2

                  

                   System.out.println("修改之前size:"+coll.size());//3

                  

                   p1.setAge(40);

                   coll.remove(p1);  //内部调用了equals

                  

                   System.out.println("修改之后size:"+coll.size());//3,没删除

         }

}

 

 

 

 

>>反射实现框架功能

 

         框架与工具类的区别:工具类是被用户的类调用,而框架则是调用用户提供的类。

         好比我提供房子(框架),用户自己安装门窗,把门窗插入我提供的房子(框架)。

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

 

eg:使用反射和配置文件来模拟框架,配置文件暂时放在根目录下

//————————配置文件config.properties————————

className=java.util.ArrayList

 

 

//————————main————————

package cn.com.cty;

 

import java.io.BufferedInputStream;

import java.io.FileInputStream;

import java.io.FileNotFoundException;

import java.io.IOException;

import java.io.InputStream;

import java.util.Collection;

import java.util.Date;

import java.util.Properties;

 

public class ReflectFromProp {

 

         publicstatic void main(String[] args) throws Exception {

                  

                   BufferedInputStreambis =

                            newBufferedInputStream(

                                               newFileInputStream("config.properties"));

                  

                   Propertiesprop = new Properties();

                   prop.load(bis);

                  

                   StringclassName = prop.getProperty("className");

                  

                   Collectioncoll =

                            (Collection)Class.forName(className).newInstance();

                  

                   Personp1 = new Person("durex",20,"1",new Date());

                   Personp2 = new Person("jissbon",18,"2",new Date());

                   Personp3 = new Person("what",25,"3",new Date());

                  

                   coll.add(p1);

                   coll.add(p2);

                   coll.add(p3);

                  

                   System.out.println(coll.size());

         }

}

 

 

 

 

>>类加载器

上一个例子的配置文件放在根目录下,那么配置文件放在其他地方怎么办?上一个例子用的是相对路径且是相对于当前工作目录。

 

eg:改变config.properties的位置,同时使用类加载器改造上一个例子

 

package cn.com.cty;

 

import java.io.InputStream;

import java.util.Collection;

import java.util.Date;

import java.util.Properties;

 

public class ReflectFromProp {

 

         publicstatic void main(String[] args) throws Exception {

 

                   /*

                    * BufferedInputStream bis = newBufferedInputStream( new

                    *FileInputStream("config.properties"));

                    */

                  

                   //使用类加载器

                   /*InputStreambis = (InputStream) ReflectFromProp.class

                                     .getClassLoader().getResourceAsStream(

                                                        "cn/com/cty/config.properties");*/

                  

                   //偷懒方式

                   InputStreambis = ReflectFromProp.class.getResourceAsStream("config.properties");

 

                   Propertiesprop = new Properties();

                   prop.load(bis);

 

                   StringclassName = prop.getProperty("className");

 

                   Collectioncoll = (Collection) Class.forName(className).newInstance();

 

                   Personp1 = new Person("durex", 20, "1", new Date());

                   Personp2 = new Person("jissbon", 18, "2", new Date());

                   Personp3 = new Person("what", 25, "3", new Date());

 

                   coll.add(p1);

                   coll.add(p2);

                   coll.add(p3);

 

                   System.out.println(coll.size());

         }

}

说明:但是这种方法只能读,还不能向config.properties中写入。

 

 

 

 

>>内省(introspector),且引出JavaBean

 

         JavaBean是一种特殊的Java类,主要用于传递数据信息,这种Java类中的方法主要用于访问私有的字段,且方法名符合某种命名规则。

         如果要在两个模块之间传递信息,那么可以将信息封装到JavaBean中,这种JavaBean的实例对象通常称之为值对象(Value Object,VO)。这些信息在类中使用私有字段来存储,而读取和设置则通过set和get方法来进行。

         JavaBean有什么属性是根据set和get方法的方法名来决定的。

 

eg:属性名字,命名规则

 

//方法名去掉set或get后作为属性名

//如果第二个字母是小的,则把第一个字母变成小的

setAge()àage

setage()àage

//如果第二个字母是大的,则保持不变

getCPUàCPU

 

 

eg:对JavaBean的内省,使用属性描述符

 

package cn.com.cty;

 

import java.beans.IntrospectionException;

import java.beans.PropertyDescriptor;

importjava.lang.reflect.InvocationTargetException;

import java.lang.reflect.Method;

 

public class IntrospectorBeanDemo {

 

         publicstatic void main(String[] args) throws Exception {

 

                   //Person为JavaBean,有name属性

                   Personp = new Person();

 

                   Stringname = "";

 

                   //set属性name的值

                   propertiesSet(p,"name", "durex");

 

                   //get属性name的值

                   name= (String) propertiesGet(p, "name");

 

                   System.out.println(name);

 

         }

 

         /**

          * 内省set方法

          * @param bean

          * @param propertyName

          * @param setValue

          * @throws Exception

          */

         privatestatic void propertiesSet(Object bean, String propertyName,

                            ObjectsetValue) throws Exception {

                  

                   //调用属性描述符类

                   PropertyDescriptorpd = new PropertyDescriptor(propertyName, bean

                                     .getClass());

 

                   //得到set方法

                   MethodsetMethod = pd.getWriteMethod();

                  

                   //调用set方法

                   setMethod.invoke(bean,setValue);

         }

 

         /**

          * 内省get方法

          * @param bean

          * @param propertyName

          * @return

          * @throws Exception

          */

         privatestatic Object propertiesGet(Object bean, String propertyName)

                            throwsException {

 

                   //调用属性描述符类

                   PropertyDescriptorpd = new PropertyDescriptor(propertyName, bean

                                     .getClass());

 

                   //得到get方法

                   MethodgetMethod = pd.getReadMethod();

 

                   //调用get方法

                   ObjectretValue = getMethod.invoke(bean, null);

                   returnretValue;

         }

}

 

 

 

 

>>对Bean更多的内省操作

 

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

 

eg:为说明而采用一种复杂的方式内省get方法

 

private static Object propertiesGet(Objectbean, String propertyName)

                            throwsException {

                   /*

                   //调用属性描述符类

                   PropertyDescriptorpd = new PropertyDescriptor(propertyName, bean

                                     .getClass());

 

                   //得到get方法

                   MethodgetMethod = pd.getReadMethod();

 

                   //调用get方法

                  Object retValue =getMethod.invoke(bean, null);

                   returnretValue;

                   */

                  

                   //使用BeanInfo来获取get方法

                   BeanInfobeanInfo = Introspector.getBeanInfo(bean.getClass());

                   PropertyDescriptor[]props = beanInfo.getPropertyDescriptors();

                  

                   ObjectretValue = null;

                  

                   for(PropertyDescriptorprop : props)

                   {

                            if(prop.getName().equals(propertyName))

                            {

                                     //得到get方法

                                     MethodgetMethod = prop.getReadMethod();

 

                                     //调用get方法

                                     retValue= getMethod.invoke(bean, null);

                                     break;

                            }

                   }

                   returnretValue;

         }

比上一个例子麻烦,这里只是器说明作用。

 

 

 

 

>>BeanUtils工具包

 

commons-beanutils.jar

commons-logging.jar

 

eg:入门演示

 

package cn.com.cty;

 

import java.util.Date;

import java.util.Iterator;

import java.util.Map;

import java.util.Set;

import java.util.TreeMap;

import java.util.Map.Entry;

 

importorg.apache.commons.beanutils.BeanUtils;

 

public class BeanUtilsDemo {

 

         publicstatic void main(String[] args) throws Exception{

                  

                   Personp = new Person();

                   p.setName("durex");

                   p.setAge(20);

                   p.setAddress("what");

                   p.setBirthday(newDate());

                  

                   //报错,.NoClassDefFoundError:org/apache/commons/logging/LogFactory

                   //没有引入logging包

                   System.out.println(BeanUtils.getProperty(p,"name"));

                  

                   //设置

                   BeanUtils.setProperty(p,"age",30);

                   System.out.println(p.getAge());

                  

                   //Date类中有方法setTime,所以time是一个属性

                   //setProperty支持级联操作

                   BeanUtils.setProperty(p,"birthday.time", 99999);

                   System.out.println(BeanUtils.getProperty(p,"birthday"));

                   //这里是上面已经初始化”p.setBirthday(newDate());“,否则因为级联操作找不到实例而报异常

                   //java.lang.IllegalArgumentException:No bean specified

                  

                  

                   /*以上输出:

                   durex

                   30

                   ThuJan 01 08:01:39 CST 1970*/

                  

                   //拷贝所有属性到另一个bean中

                   Personp2 = new Person();

                   BeanUtils.copyProperties(p2,p);

                   System.out.println(p2.getName());

                  

                   //bean转换Map,describe方法

                   MapbeanMap = BeanUtils.describe(p);

                   SetentrySet = beanMap.entrySet();

                   Iteratorit = entrySet.iterator();

                   while(it.hasNext())

                   {

                            Map.Entryme = (Entry) it.next();

                           

                            System.out.println(me.getKey()+":"+me.getValue());

                   }

                  

                   //可以这样搞看到没有,可以操作Map

                   MapbeanMap2 = new TreeMap();

                   beanMap2.put("name","jissbon");

                   BeanUtils.setProperty(beanMap2,"name", "xxxxxx");

                  

                   //Map灌装到bean中,populate方法

                   BeanUtils.populate(p2,beanMap2);

                   System.out.println(p2.getName());

         }

}

 

 

 

 

>>PropertyUtils工具

         也有和BeanUtils一样的setProperty方法,这里不再赘述。


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: INTP-A的男生和INFJ、INTJ、ENTP、ENFP等MBTI最配。这是因为INTP-A的男生倾向于思考型、内向、直觉型、开放性,与这些MBTI的人也都有相似的倾向。不过,最终的匹配还是取决于两个人的个人特点和感情关系。 ### 回答2: INTP-A的男生最适合与ENFJ女生结合。INTP-A的男生通常是理性和冷静的思考者,非常擅长逻辑分析和抽象思维。而ENFJ女生则是情感丰富和热情的社交者,注重与他人的联系和合作。他们俩的性格特点互补了彼此的不足。 INTP-A的男生在思考问题时非常客观和理性,喜欢追求真理。而ENFJ女生则更注重情感和人际关系,擅长理解他人的需要。所以,在决策过程中,ENFJ女生可以帮助INTP-A男生考虑到更多的人际因素和社会影响,避免过于片面的决策。 此外,ENFJ女生非常擅长与他人沟通和交流,可以帮助INTP-A男生更好地将他的抽象思维转化为言语和行动,更好地与他人分享和交流。ENFJ女生的社交技巧和鼓励也能激发INTP-A男生的潜能,使他更多地参与到社交活动和团队合作中。 总的来说,INTP-A的男生和ENFJ女生的配对可以相互补充,形成一个强大的团队。他们的不同性格特点相得益彰,能够共同实现他们的目标。通过互相倾听、沟通和理解,他们可以相互促进和支持,建立一个稳定和融洽的关系。 ### 回答3: 根据人格类型理论,INTP-A型的男生通常被认为是理性、深思熟虑和富有创造力的人。他们喜欢追求知识,探索理论,并对解决复杂问题充满热情。对于INTP-A男生来说,以下几个MBTI类型可能是与他们高度相配的: 1. ENTJ-A(统帅型):ENTJ-A型的人具有明确的目标和领导能力,他们是创新思维者和决策者,善于将理论付诸实践。这与INTP-A型男生的理性和创造力相得益彰,两者在问题解决和决策制定上形成良好的合作。 2. ENTP-A(辩证型):ENTP-A型的人天生好奇,并具有挑战传统观念的倾向。他们富有创造力,乐于进行思维实验,与INTP-A型男生一起,他们可以激发彼此的思维,共同探索新领域。 3. INFJ-A(博爱型):INFJ-A型的人重视内省和情感,他们对人们的需求和感受非常敏感。与INTP-A型男生相配,INFJ-A型的人可以提供情感上的支持和理解,帮助INTP-A男生更好地处理人际关系。 4. ENFP-A(倡导者型):ENFP-A型的人富有想象力,热情洋溢,能够激励和鼓舞他人。与INTP-A型男生相处,ENFP-A型的人可以为他们提供情感上的支持,并促使他们更多地关注他人的情感需求。 以上只是一些可能的配对,人际关系和配对并不仅仅依赖于MBTI类型,更多取决于个人价值观、互相尊重和良好沟通的能力。最佳的配对通常是建立在互补和相互理解的基础上。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值