高新技术——反射


 

1.   反射

透彻分析反射的基础_Class

1)  概述

class

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

 

Person类的实例对象

Person p1 = new Person();

Person p2 = new Person();

 

Data

 

Math

Java(Class)的实例对象,对应各个类在内存中的字节码。

 

概念:

所有的类文件都有共同属性,所以可以向上抽取,把这些共性内容封装成一个类,这个类就叫Class(描述字节码文件的对象)。

获取类的字节码:

1.类名.class

Class cls1 = Data.class//字节码1

Class cls2 = Person.class//字节码2

 

2.对象.getClass()

p1.getClass();

 

3.Class.forName("java.name.String"),主要用于反射

分两种情况:

类的字节码已经加载到内存,直接找到字节码,返回;

虚拟机还没有字节码,类加载器去加载,缓存起来,然后返回字节码;

 

九个预定义Class实例对象

表示八个基本类型和 void。这些类对象由 Java虚拟机创建,与其表示的基本类型同名,

booleanbytecharshortintlongfloat double。对应获取Class对象的方法为:

Boolean.TYPE, Byte.TYPE,Character.TYPE,  Short.TYPE, Integer.TYPE, Long.TYPE, Float.TYPE, Double.TYPE, Void.TYPE

 

int.class == Integer.TYPE

boolean isPrimitive() :判定指定的 Class对象是否表示一个基本类型。

 

数组类型的Class实例对象

boolean isArray():判定此 Class对象是否表示一个数组类。

Class.isArray();

 

总之,只要是在源程序中出现的类型,都有各自的Class实例对象,例如:int[],void

 

2)  使用

class  ReflectTest 

{

    publicstaticvoid main(String[] args) throws Exception

    {

       String str = "fff";

       Class c1 = String.class;

       Class c2 = str.getClass();

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

       System.out.println(c1==c2);//true

       System.out.println(c1==c3);//true

 

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

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

       

       //static Class<Integer> TYPE 表示基本类型 int 的 Class 实例。

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

       

       //boolean isArray():判定此 Class 对象是否表示一个数组类。

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

    }

} 

理解反射的概念

反射的概念

 

就是把java类中的各种成分映射成相应的java类。例如,一个java类是用一个class类的对象来表示,一个类的组成部分:成员变量,方法,构造方法,包等等信息也用一个个的java类来表示,就像汽车是一个类,汽车中的发动机,变速箱等等也是一个个的类。表示java类的class类显然要提供一系列的方法,来获得其中的变量,方法,构造方法,修饰符,包、数组等信息。这些信息就是用相应的类的实例对象来表示,他们是FieldMethodContructorPackage等等。

 

一个类中的每个成员都可以用相应的反射API类的一个实例对象来表示,通过调用Class类的方法可以得到这些实例对象,

 Package getPackage():获取此类的包。返回的是Package类的实例对象;

 Method getMethod(String name, Class<?>... parameterTypes):返回一个 Method对象,代表某个类中的一个方法,它反映此 Class对象所表示的类或接口的指定公共成员方法。

Constructor<T> getConstructor(Class<?>... parameterTypes) :返回一个 Constructor对象,代表某个类中的一个构造方法,它反映此 Class对象所表示的类的指定公共构造方法。

.............

 

问题:

得到这些实例对象后有什么用?怎么用?

构造方法的反射应用

1)  概述

 

构造方法的反射应用

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

 

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

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

 

得到某个类的一个构造方法:

//获得String类的构造方法,只获得参数为一个,且为StringBuffer类型的构造方法

Constructor ct1 = Class.forName(java.lang.String).getConstructor(StringBuffer.class);//获得方法时要用StringBuffer.class类型

 

创建实例对象(三步:classàConstructorànew Object)

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

反射方式:String str1 = (String)ct1.newInstance(new StringBuffer("abc"));

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

 

Class.newInstance()方法创建实例对象(两步:classà new Object)

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

 

该方法内部先得到默认构造方法(空参数的构造方法),然后用该构造方法创建实例对象。

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

 

反射会导致程序性能严重下降

 

 

2)  使用

class  ReflectTest 

{

    publicstaticvoid main(String[] args) throws Exception

    {

       

       //用反射实现类似功能:new String(new StringBuffer("asd"));

       Constructor con1 = String.class.getConstructor(StringBuffer.class);//编译器只看变量的定义(=左边),不看代码的执行(=右边),只是将右边编程二进制

       //用构造方法new一个实例,此时创建的实例为Object类型,需要强转

       String str1 = (String)con1.newInstance(new StringBuffer("asdf"));

       System.out.println("str1="+str1);

       

       String str2 = (String)Class.forName("java.lang.String").newInstance();

       str2="123";

       System.out.println("str2="+str2);

    }

} 

成员变量的反射

1)  概述

Field类:代表某个类中的一个成员变量

问题:得到的Field对象是对应到类上面的成员变量,还是对应到对象上的成员变量?

      类只有一个,而该类的实例对象有多个,如果是与对象关联,那关联的是哪个对象呢?

 所以字段FieldX代表的是x的定义,而不是具体的x变量

 

2)  使用(获取指定成员变量)

请看如下案例:

//参考类:

publicclass ReflectPoint {

    privateintx;

    publicinty;

    

    public ReflectPoint(int x, int y) {

       super();

       this.x = x;

       this.y = y;

    }

    publicstaticvoid main(String[] args) 

    {

       System.out.println("我是一个参考类");

    }

}

 

//应用类

class  ReflectTest 

{

    publicstaticvoid main(String[] args) throws Exception

    {

       ReflectPoint r1 = new ReflectPoint(8,9);

       Field fieldy = r1.getClass().getField("y");//获得其他类的成员变量,先从其他类中得到字节码,字节码中有成员变量

       /*fieldy的值?

       fieldy只代表这个类字节码上的变量,没有对应到对象身上;每一个对象身上都有fieldy,要用它去取某个对象上的值

       */

       

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

       System.out.println("fieldy在r1对象上的值 = "+fieldy.get(r1));

       

       //Field fieldx = r1.getClass().getField("x");//x是私有的,fieldx变量看不见。

       Field fieldx = r1.getClass().getDeclaredField("x");//x是私有的,只要是声明过的,fieldx都看得见,但是不能访问私有的。

       fieldx.setAccessible(true);//设置允许访问,暴力反射

       System.out.println("fieldx在r1对象上的值 = "+fieldx.get(r1));

    }

} 

成员变量反射的综合案例(获取部分成员变量)

Class<?> getType() :返回一个 Class对象,它标识了此 Field对象所表示字段的声明类型。

Object get(Object obj) :返回指定对象上此 Field表示的字段的值。

void set(Object obj, Object value) :将指定对象变量上此 Field对象表示的字段设置为指定的新值

请看如下示例:

//参考类

class ReflectPoint1 {

    

    public String str1;

    public String str2;

    public String str3;

    

 

    public ReflectPoint1(String str1, String str2, String str3) {

       super();

       this.str1 = str1;

       this.str2 = str2;

       this.str3 = str3;

    }

 

    //要打印对象的属性值,需覆盖toString()方法

    public String toString()

    {

       returnstr1+";"+str2+";"+str3;

    }

}

//应用类

class  ReflectTest 

{

    publicstaticvoid main(String[] args) throws Exception

    {

       ReflectPoint1 rp = new ReflectPoint1("bababa","abdgfbbaaabbbb","string");

       strchange(rp);

       System.out.println(rp);

    }

    publicstaticvoid strchange(Object obj)throws Exception

    {

       Field[] fi = obj.getClass().getFields();

       for(Field field:fi)

       {

           if(field.getType() == String.class);//字节码的比较用==,比较的都是一份字节码;

           {

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

              String strnews = strolds.replace('b','a');

              field.set(obj,strnews);

              

           }

       }

    }

}

成员方法的反射

1)  概述

成员方法的反射

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

得到类中的某一个方法:

Method method = String.class.getMethod("charAt", int.class);

 

调用方法:

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

反射方式:method.invoke(str,1);

               如果invoke(null,1),表示该Method对象对应的是一个静态的方法

 

JDK1.4JDK1.5invoke方法的区别

1.4public Object invoke(Object obj,Object[] args)

        将数组作为参数传递给invoke方法,

                  数组中的每个元素分别对应被调用方法中的一个参数,

                  所以可写成method.invoke("str",new object[]{1})形式

 

1.5public Object invoke(Object obj,Object... args)传入的参数为可变参数

 

2)  使用

 

class  ReflectTest 

{

    publicstaticvoid main(String[] args) throws Exception

    {

       //Object invoke(Object obj, Object... args):对带有指定参数的指定对象调用由此 Method 对象表示的底层方法。

       

       String str = "abcd";

       

       //用反射实现str.charAt(1)功能

       Method m = String.class.getMethod("charAt", int.class);

       System.out.println(m.invoke(str,1));//jdk1.5  传入可变参数

       System.out.println(m.invoke(str,new Object[]{2}));//jdk1.4  传入数组参数

       //m.invoke(null,1),表示不用对象就能调用的方法,静态方法

    }

} 

对接收数组参数的成员方法进行反射

 

1)  概述

对接收数组参数的成员方法进行反射

 

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

调用方法

通常方式:类名.main(new String[]{"ttt","www","qq"});

 

反射方式:

String classstartname = args[0];

Method mainmethod =  Class.forName(classstartname).getMethod("main", String[].class);

mainmethod.invoke(null, new Object[]{new String[]{"11","22"}});

 

为什么要用反射去调用?

程序中已知要调用main方法,但是不知道哪个类的main方法,要通过传进来的参数,确定类名,

然后调用传进来的类的main方法。

 

为什么会出现参数个数异常呢?

通过反射的方法调用main方法时,为invoke方法传递参数的方式是:

JDK1.5:整个数组是一个参数,JDK1.4:数组中每一个元素对应一个参数,

当把字符串数组作为参数传递给invoke方法时,JDK1.5肯定要兼容JDK1.4语法,

会按JDK1.4的去处理,即把数组打散成若干单独参数。所以在给main方法传递参数时,

不能使用mainmethod.invoke(null, new String[]{"11","22"});,会出现参数类型不对问题;

 

解决办法:

1.mainmethod.invoke(null, new Object[]{new String[]{"11","22"}});

 

2.mainmethod.invoke(null, (Object)new String[]{"11","22"});

 

2)  使用

 

class  ReflectTest 

{

    publicstaticvoid main(String[] args) throws Exception

    {

       

       //实现在此程序中调用testArguments类的main方法

       

       //通常方式

       testArguments.main(new String[]{"11","22"});

       

       //反射方式

       //假设传进main方法的参数中args[0]就是一个类名,且有main方法

       String classstartname = args[0];

       Method mainmethod =  Class.forName(classstartname).getMethod("main", String[].class);

       /*mainmethod.invoke(null, new String[]{"11","22"});

       参数个数异常,本来是接收一个数组参数,JDK1.5为了兼容JDK1.4,会将数组拆一次,拆成一个个(多个)参数*/

       

       //解决办法:1.将数组参数再次封装成数组; 2.将数组参数强转成Object对象,就不拆包了;

       mainmethod.invoke(null, new Object[]{new String[]{"11","22"}});

       mainmethod.invoke(null, (Object)new String[]{"11","22"});

    }

}

class testArguments//按f2出现完整的类名,将完整的类名复制到run configurations界面

                 //中的Arguments界面的program arguments中,用来配置运行类的main方法参数

{

    publicstaticvoid main(String args[])

    {

       for(String str:args)

       {

           System.out.println(str);

       }

    }

} 

数组与Object的关系及其反射类型

1)  概述

数组的反射

 

数组元素类型相同,维度相同,得到的字节码就是同一份,属于同一个类型,即具有相同的Class实例对象;

 

基本数据类型的一维数组可以被当做Object类型使用,不能当做Object[]类型使用,

非基本数据类型的一维数组既可以当做Object类型使用,也可当做Object[]类型使用

 

ClassgetName()方法:

String 的形式返回此 Class 对象所表示的实体(类、接口、数组类、基本类型或 void)名称

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

元素类型名的编码如下:

Element Type       Encoding 

boolean                                Z 

byte                                      B 

char                                      C 

class or interface       Lclassname; 

double                                  D 

float                                      F 

int                                          I 

long                                       J 

short                                     S 

类或接口名 classname是上面指定类的二进制名称。

String.class.getName():returns "java.lang.String"

(new int[3][4][5][6][7][8][9]).getClass().getName():returns "[[[[[[[I"

 

ClassgetSuperclass()方法:

Class<? super T> getSuperclass() :返回表示此 Class所表示的实体(类、接口、基本类型或 void)的超()类的 Class

 

2)  使用

 

class  ReflectTest 

{

    publicstaticvoid main(String[] args) throws Exception

    {

       int a0 = 3;

       int[] a1 = newint[]{1,2};

       int[] a2 = newint[]{3,4,5};

       int[][] a3 = newint[][]{{4,4},{3,3},{2,2,2}};

       String[] a4 = new String[]{"a","b","c"};

       sop(a1.getClass() == a2.getClass());

       sop(a1.getClass().getName());//[I

       sop(a1.getClass().getSuperclass().getName());//java.lang.Object

       sop(a4.getClass().getSuperclass().getName());//java.lang.Object

       sop(a2.getClass().getSuperclass().getName());//java.lang.Object

       sop(a3.getClass().getSuperclass().getName());//java.lang.Object

       sop(String.class.getSuperclass().getName());

       

       Object o0 = a0;

       Object o1 = a1;

       Object o2 = a2;

       Object o3 = a3;

       Object o4 = a4;

       sop(o0);

       sop(o1);

       sop(o2);

       sop(o3);

       sop(o4);

       

       //Object[] b0 = a0;编译不通过,因为a0是个基本数据类型,是个对象

       //Object[] b1 = a1;编译不通过,因为a1,a2是基本数据类型的一维数组,是个对象,不是对象数组

        //Object[] b2 = a2;

       Object[] b3 = a3;//编译通过,因为a3是基本数据类型的二维数组(数组的数组),表示有一个数组,数组里面装的是int[](Objet),是个对象数组    

       Object[] b4 = a4;//编译通过,因为String是Object,String[]等于对象数组

       //可得出:int(基本数据类型)不是对象,String是对象,所以前者不能转成Object数组,后者可以

    

       /*结果没有意义

        *sop(a1);

       sop(a4);*/

       

       //用Arrays工具类对数组进行操作

       //JDK1.5:public static <T> List<T> asList(T... a)

       //JDK1.4:public static List asList(Object[] a)

       sop(Arrays.asList(a1));//JDK1.5处理

       sop(Arrays.asList(a3));//JDK1.4处理+JDK1.5处理

       sop(Arrays.asList(a4));//JDK1.4处理

    }

    public  staticvoid sop(Object obj)

    {

       System.out.println(obj);

    }

}<span style="font-family:Calibri;font-size:14px;"> </span>

数组的反射应用

1)  概述

数组的反射应用

 

获取,设置,数组的值,获取数组的长度,怎么做?

通过java.lang.reflect.Array类中的方法:

static Object get(Object array, int index)

          返回指定数组对象中索引组件的值。

static int getLength(Object array)

           int形式返回指定数组对象的长度。

static void set(Object array, int index, Object value)

          将指定数组对象中索引组件的值设置为指定的新值。

 

怎么得到数组中的元素类型?没有办法

int [] a = new int[3]

怎么知道a的数组类型?没有办法

因为

Object[] a =new Object[]{"a",1}

a[0].getClass.getName();

a[0].getClass.getName();

只能得到每一个具体元素的类型,不能得到整个数组的元素类型

 

2)  使用

class  ReflectTest 

{

    publicstaticvoid main(String[] args) throws Exception

    {

       int a0 = 3;

       int[] a1 = newint[]{1,2};

       int[] a2 = newint[]{3,4,5};

       int[][] a3 = newint[][]{{4,4},{3,3},{2,2,2}};

       String[] a4 = new String[]{"a","b","c"};

       

       

       sop(a2);

       sop(a3);

       sop(a4);

       sop("asd");       

       

    }

    public  staticvoid sop(Object obj)//打印数组或基本数据类型

    {

       Class c = obj.getClass();

       if(c.isArray())

       {

           int len = Array.getLength(obj);//通过Array类访问数组,获取数组长度

           for(int i=0;i<len;i++)

           {

              System.out.println(Array.get(obj, i));//返回指定数组对象中索引组件的值。

           }

       }

       else

       System.out.println(obj);

    }

}
 

ArrayList_HashSet的比较及Hashcode分析

1)  概述

反射的综合应用--ArrayList_HashSet的比较及Hashcode分析

 

哈希算法

哈希算法提高从集合中查找元素的效率,这种方式将集合分成若干区域,每个要存入哈希集合的对象可以计算出一个哈希码,

可以将哈希码分组,每组分别对应某个存储区域,根据一个对象的哈希码就可以确定该对象应该存储在哪个区域。

 

面试题1--HashCode()方法的作用?

返回该对象的哈希码值。支持此方法是为了提高哈希表(例如 java.util.Hashtable提供的哈希表)的性能。

当从hashset集合中查找某个对象时,java系统首先调用对象的hashcode()方法获得该对象的哈希码,然后根据哈希码,

找到相应的存储区域,最后取出该存储区域内的每个元素与该对象进行equals方法比较,不用遍历集合中的所有元素,就可以得到结论。

 

面试题2--内存溢出,内存泄露的例子?

当一个对象被存储进HsahSet集合中后,就不能修改这个对象中的那些参与计算哈希值得字段了,否则,对象修改后的哈希值就不同了,

在这种情况下,去哈希集合中检索对象时,就找不到原来的对象了。这也会导致无法从hashset集合中单独删除当前对象,

从而导致内存泄露。

 

提示:

一个类的两个实例对象用equals()方法比较的结果相等时,他们的哈希码也必须相等,但是,

 equals(java.lang.Object) 方法比较结果不相等的对象可以有相同的哈希码,

 或者哈希码相同的两个对象,调用equals()方法比较结果可以不等。

 

2)  使用

1
publicclass ReflectPoint {

    

    privateintx;

    publicinty;

    public String str1="aa";

    public String str2="ss";

    public String str3="dd";

 

    public ReflectPoint(int x, int y) {

       super();

       this.x = x;

       this.y = y;

    }

 

    @Override

    publicint hashCode() {

       finalint prime = 31;

       int result = 1;

       result = prime * result + x;

       result = prime * result + y;

       return result;

    }

 

    @Override

    publicboolean equals(Object obj) {

       if (this == obj)

           returntrue;

       if (obj == null)

           returnfalse;

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

           returnfalse;

       ReflectPoint other = (ReflectPoint) obj;

       if (x != other.x)

           returnfalse;

       if (y != other.y)

           returnfalse;

       returntrue;

    }

 

    //要打印对象的属性值,需覆盖toString()方法

    public String toString()

    {

       returnstr1+";"+str2+";"+str3;

    }

} 
2

 

class  ReflectTest 

{

    publicstaticvoid main(String[] args) throws Exception

    {

       Collection c = new HashSet();//new ArrayList();//

       ReflectPoint r1 = new ReflectPoint(2,2);

       ReflectPoint r2 = new ReflectPoint(3,3);

       ReflectPoint r3 = new ReflectPoint(2,2);

       

       c.add(r1);

       c.add(r2);

       c.add(r3);

       c.add(r1);

       

       r1.y = 8;

       c.remove(r1);//将r1的y值更改后,哈希值改变,存储区域改变,remove()方法在原本区域里找不到r1的y值了

       //这样原本该删除的对象没有删掉,又新增对象的话,日积夜累,就会导致内存溢出。

       sop(c.size());

       /*list集合是有序可重复的,存的是对象的引用;

       set集合是无序不可重复的,默认equals()比较的是哈希值,hashcode值是根据内存地址值算出来的,

       要让r1与r3完全相等,必须同时复写equals(),hashcode()方法(用eclipse自带生成)*/

       

    }

    public  staticvoid sop(Object obj)//打印数组或基本数据类型

    {

       Class c = obj.getClass();

       if(c.isArray())

       {

           int len = Array.getLength(obj);//通过Array类访问数组,获取数组长度

           for(int i=0;i<len;i++)

           {

              System.out.println(Array.get(obj, i));//返回指定数组对象中索引组件的值。

           }

       }

       else

       System.out.println(obj);

    }

} 

 

 

反射的作用--实现框架功能

1)  概述

框架与工具类

自己做房子给用户住,用户自己安装门,我做的房子就是框架,用户需要使用我的框架,把门插进我提供的框架中。

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

 

框架要解决的核心问题

我在写框架时,我的框架程序怎样能调用到你以后写的程序呢?

因为在写框架程序时,无法知道要被调用的类名,所以,

在程序中无法直接new某个类的实例对象了,而要用反射的方式(Class.forName(classname).new Instance)来做。

 

使用步骤:

先在程序中直接用new语句创建ArrayListHashSet的实例对象,

然后创建一个properties文件,配置内容。

在程序中加载进配置文件,用配置文件加反射的方式创建ArrayListHashSet的实例对象

 

提示

IO.close();的底层含义是:先把widowswidow(系统资源,物理资源)关掉,然后由java VM回收本IO流对象

 

2)  使用

配置文件的获取方式
1.通过Properties得到资源文件

可以读写配置文件,因为有InputStreamOutputStream

/*资源文件放在project文件夹中,

* 要用完整的路径,但完整的路径不是硬编码,而是运算出来的。

* javawebgetRealPath()方法动态的得到eclipse的安装目录,再拼上配置文件的路径

*/

    InputStream ips = new FileInputStream("config.properties");//此处用的是相对路径,不符合开发。

实际开发中不这样放置配置文件,javaweb中通过getRealpath()方法得到eclipse的真实安装完整路径,在拼接上配置文件的内置路径

 

 

2.通过类加载器得到资源文件的方式(不能替代上面的方式,此方式常用)

 

类加载器:

类加载器负责读取 Java 字节代码,并转换成java.lang.Class类的一个实例。每个这样的实例用来表示一个 Java类。通过此实例的newInstance()方法就可以创建出该类的一个对象。

 

加载类的方式有以下几种:

1)从本地系统直接加载

2)通过网络下载.class文件

3)从zipjar等归档文件中加载.class文件

4)从专有数据库中提取.class文件

5)将Java源文件动态编译为.class文件(服务器)

 

开发中一般将配置文件放到classpath路径下(用户目录下,即全部存放的是.class文件的文件夹)

配置文件放到当前包里,保存的时候会直接保存在classpath路径下,即用户目录(.class目录)中生成该配置文件。

通过类加载器获取资源文件,只读。

格式:

/*1.资源文件放在同个包里,保存的时候eclipse会自动将配置文件放到classpath目录下

* 通过类加载器加载,在classpath路径指定目录下,逐一查找要加载的文件.

* 该方式获得资源文件首先要获得class文件,然后获得类加载器,然后才获得资源

* */

InputStream ips = ReflectTest.class.getClassLoader().getResourceAsStream("com/config.properties");

      

//2.资源文件放在另一个子包里,通过类文件,直接获得资源文件,用相对路径

InputStream ips = ReflectTest.class.getResourceAsStream("resources/config.properties");

      

//3.资源文件放在另一个子包里,通过类文件,直接获得资源文件,用绝对路径

InputStream ips = ReflectTest.class.getResourceAsStream("/com/resources/config.properties");

 

动态代理:在程序运行时,运用反射机制动态创建代理类

参考:http://www.cnblogs.com/jqyp/archive/2010/08/20/1805041.html

 类1

publicclass ReflectPoint {

    

    privateintx;

    publicinty;

    public String str1="aa";

    public String str2="ss";

    public String str3="dd";

 

    public ReflectPoint(int x, int y) {

       super();

       this.x = x;

       this.y = y;

    }

 

    @Override

    publicint hashCode() {

       finalint prime = 31;

       int result = 1;

       result = prime * result + x;

       result = prime * result + y;

       return result;

    }

 

    @Override

    publicboolean equals(Object obj) {

       if (this == obj)

           returntrue;

       if (obj == null)

           returnfalse;

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

           returnfalse;

       ReflectPoint other = (ReflectPoint) obj;

       if (x != other.x)

           returnfalse;

       if (y != other.y)

           returnfalse;

       returntrue;

    }

 

    //要打印对象的属性值,需覆盖toString()方法

    public String toString()

    {

       returnstr1+";"+str2+";"+str3;

    }

}
<span style="font-family:Calibri;font-size:14px;"> </span>

 类2

 

class  ReflectTest 
{
	public static void main(String[] args) throws Exception
	{
		
		//类名.class.getResourceAsStream(String name) :在classpath路径下查找具有给定名称的资源。
		//类名.class.getClassLoader().getResourceAsStream(String name)在classpath路径下查找,返回读取指定资源的输入流。
		
		/*资源文件放在同个包里,保存的时候eclipse会自动将配置文件放到classpath目录下
		 * 通过类加载器加载,在classpath路径指定目录下,逐一查找要加载的文件.
		 * 该方式获得资源文件首先要获得class文件,然后获得类加载器,然后才获得资源
		 * */
		InputStream ips = ReflectTest.class.getClassLoader().getResourceAsStream("com/config.properties");
		
		//资源文件放在另一个子包里,通过类文件,直接获得资源文件,用相对路径
		//InputStream ips = ReflectTest.class.getResourceAsStream("resources/config.properties");
		
		//资源文件放在另一个子包里,通过类文件,直接获得资源文件,用绝对路径
		//InputStream ips = ReflectTest.class.getResourceAsStream("/com/resources/config.properties");
		
		/*资源文件放在project文件夹中,
		 * 要用完整的路径,但完整的路径不是硬编码,而是运算出来的。
		 * javaweb中getRealPath()方法动态的得到eclipse的安装目录,再拼上配置文件的路径
		 * */
		//InputStream ips = new FileInputStream("config.properties");//此处用的是相对路径,不符合开发。
		
		Properties pp = new Properties();
		pp.load(ips);
		ips.close();//先把widows的widow(系统资源,物理资源)关掉,然后java VM回收本对象
		String className = pp.getProperty("className");
		
		//通过反射,传进一个类名,得到一个默认构造方法生成的对象
		Collection c = (Collection)Class.forName(className).newInstance();
		
		//Collection c = new HashSet();//new ArrayList();//
		ReflectPoint r1 = new ReflectPoint(2,2);
		ReflectPoint r2 = new ReflectPoint(3,3);
		ReflectPoint r3 = new ReflectPoint(2,2);
		
		c.add(r1);
		c.add(r2);
		c.add(r3);
		c.add(r1);
		
		//r1.y = 8;
		//c.remove(r1);
		
		sop(c.size());
		
	}
	public  static void sop(Object obj)//打印数组或基本数据类型
	{
		Class c = obj.getClass();
		if(c.isArray())
		{
			int len = Array.getLength(obj);//通过Array类访问数组,获取数组长度
			for(int i=0;i<len;i++)
			{
				System.out.println(Array.get(obj, i));//返回指定数组对象中索引组件的值。
			}
		}
		else
		System.out.println(obj);
	}
}


 

 

 

 




评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值