Java 基础加强 - 反射Reflect

来源:互联网 发布:sql join 编辑:程序博客网 时间:2024/05/23 10:21

反射Reflect

一.什么叫做反射?

在程序的运行时期,可以通过一种动态的方式去知道任意一个类中具备了哪些属性和方法,并且还可以获取到这些方法和属性,对于属性还具备值的设置;那么也可用通过这种动态的方式去知道任何一个对象的属性和方法,并对这个对象进行操作,这种动态的获取类中的信息,动态的调用类的属性或方法,叫做反射机制。

简单的概括就是,在运行时期,将一个java类中各个成分,映射成相应类的对象。例如一个Java类用一个Class类的对象来表示,一个类中的组成部分:成员变量,方法,构造方法,包等等信息也用一个个的Java类来表示,就像汽车是一个类,汽车中的发动机,变速箱等等也是一个个的类。表示java类的Class类显然要提供一系列的方法,来获得其中的变量,方法,构造方法,修饰符,包等信息,这些信息就是用相应类的实例对象来表示,它们是Field、Method、Contructor、Package等等。

二.反射的基石(Class)

1.     定义

Class是Java中的一个类,是用来描述所有Java类这一类事物的。

例子:众多的人,用Person来表示,那么Java中有这么多的类,也可以用Class来进行描述。

2.      那么每一个Class类的实例对象又分别对应着什么呢?

对应着各个类在内存中的字节码,例如Person类的字节码,Animal类的字节码等,当一个类被类加载器加载到内存中之后,占用一片存储空间,这块空间就是字节码,不同类的字节码是不同的,所以他们在内存中的字节码是不同的,这些空间可以分别用一个个的对象来表示,那么这些对象显然是同一个类型,那么这个类型就是Class类型。
Java类用于描述一类事物的共性,该类事物有什么属性,没有什么属性,至于这个属性的值是什么,则是由这个类的实例对象来确定的,不同的实例对象有不同的属性值。Java程序中的各个Java类,他们都属于同一类事物,都属于Class类型,每个java类都是Class的一个实例对象,它们的内容不同,但是,它们的特征相同,譬如,都有方法,有字段,有父类,有包等,可以用不同的Class对象来表示。

/* Person p1 = new Person("zhangsan");Person p2 = new Person("lisi");*//*Class x1 = Vector类在内存里的字节码Class x2 = Date类在内存里的字节码*/Class x1 = Vector.class;Class x2 = Date.class;

3.     一个类不管有多少个对象,这些对象只对应一个Class对象,也就是说只对应唯一一份字节码

  Date d1 = new Date();  Date d2 = new Date();  Date d3 = new Date();  Class type1 = d1.getClass();  Class type2 = d2.getClass();  Class type3 = d3.getClass();  Class type4 = Date.class;  Class type5 = Class.forName("java.util.Date");  System.out.println( type1 == type2); ture  System.out.println( type2 == type3); ture  System.out.println( type3 == type4); ture  System.out.println( type4 == type5); ture
<span style="font-size:18px">以上打印的结果都为true,表示一个类不管有多少个对象,这些对象只对应一个Class对象</span>

4.      如何获得每个类或对象对应的字节码Class实例对象
Class 没有公共构造方法,只有一个私有的构造方法,Class 对象是在加载类时由 Java 虚拟机以及通过调用类加载器中的 defineClass 方法自动构造的。

A.     

Class type = 某个类实例对象.getClass();
Date d= new Date();

Class type = d.getClass();

B.     

Class type = 类名.class

Class type = Date.class;

C.     

Class type = Class.forName(“完整类名”);
完整类名就是包名.类名

forName(String name)是Class类的静态方法。

Class type = Class.forName("java.util.Date");

5.     Class对象的产生过程

在运行期间,如果我们要产生某个类的对应的Class类的实例对象,Java虚拟机会先在内存中检查该Class对象是否已经存在,如果存在,就直接将地址返回,如果不存在则使用Class类中的forName(String name)方法根据给定的类名,找到该类的.class文件,并加载它到内存中缓存起来,将地址返回。

6.      能否用new Class()方式创建对象?
不可用new Class()的方式,因为Class没有这样的构造方法,Class没有公共构造方法,只有一个私有的构造方法,Class 对象是在加载类时由 Java 虚拟机以及通过调用类加载器中的 defineClass 方法自动构造的。

7.     9个基本类型的Class对象
可以使用Class类中的实例方法boolean isPrimitive()判断某个Class对象是否为基本数据类型。

 Class type1 = int.class;//等效于Integer.TYPE

                 Class type2 = double.class; //等效于Double.TYPE

                 Class type3 = void.class;

                 Class type4 = String.class;

                 Class type5 = Date.class;

                 Class type6 = int[].class;

                 Class type7 = int[][].class;

                 System.out.println(type1.isPrimitive());-->ture

                 System.out.println(type2.isPrimitive());-->ture

                 System.out.println(type3.isPrimitive());-->ture

                 System.out.println(type4.isPrimitive());-->false

                 System.out.println(type5.isPrimitive());-->false

                 System.out.println(type6.isPrimitive());-->false

         System.out.println(type7.isPrimitive());-->false

8. 判断某个Class实例对象是否为数组类型

 判断某个Class实例对象是否为数组类型可以使用Class中的实例方法 boolean isArray()来判断。

Classtype1 = new int[]{2,5,8,9}.getClass();

                 Class type2 = int[].class;

                 Class type3 = newint[][]{{1,2,3},{7,8,9}}.getClass();

                 Class type4 = int[][].class;

                 Class type5 =  new String[]{"A","B"}.getClass();

                 Class type6 =  new String[2].getClass();

                 System.out.println(type1.isArray());-->true

                 System.out.println(type2.isArray());-->true

                 System.out.println(type3.isArray());-->true

                 System.out.println(type4.isArray());-->true

                 System.out.println(type5.isArray());-->true

                 System.out.println(type6.isArray());-->true

9.      利用Class对象创建一个类的对象

调用Class中的newInstance()方法默认使用类中的无参构造方法创建对象。

Class classtype  = Person.class;

Person p = (Person)classtype.newInstance();

10.      常用方法

A.    staticClass forName(String className) à返回与给定字符串名的类或接口的相关联的Class对象。

B.     Class getClass()à返回的是Object运行时的类,即返回Class对象即字节码对象

C.     Constructor getConstructor()à返回Constructor对象,它反映此Class对象所表示的类的指定公共构造方法。

D.     Field getField(String name) à返回一个Field对象,它表示此Class对象所代表的类或接口的指定公共成员字段。

E.     Field[] getFields(à返回包含某些Field对象的数组,表示所代表类中的成员字段。

F.    Method getMethod(Stringname,Class… parameterTypes) à返回一个Method对象,它表示的是此Class对象所代表的类的指定公共成员方法。

G.     Method[] getMehtods()à返回一个包含某些Method对象的数组,是所代表的的类中的公共成员方法。

H.      String getName()à以String形式返回此Class对象所表示的实体名称

I.    String  getSuperclass()à返回此Class所表示的类的超类的名称

J.    boolean isArray()à判定此Class对象是否表示一个数组

K.       boolean isPrimitive()à判断指定的Class对象是否是一个基本类型。

L.       T newInstance()à创建此Class对象所表示的类的一个新实例。

11.     总之,每个源程序中出现的数据类型,都有各自的Class实例对象。

三.Constructor类

1.     定义

Constructor用来描述一个类中的构造方法,也就是说一个Constructor对象就代表类中的一个构造方法。

2.     作用

A.      获得到某个类的一个Constructor对象之后,就可以使用这个Constructor对象的newInstance(Object... initargs)创建这个类的实例对象。

B.     获得到某个类的一个Constructor对象之后,就可以通过这个Constructor对象获得这个类的这个构造方法的信息,如参数信息、修饰符信息等。

3.     反射时构造方法的区分

一个类有多个构造方法,用什么方式可以区分清楚想得到其中的哪个方法呢?根据参数的个数和类型,例如, getMethod(name,Class... args)中的args参数就代表所要获取的那个方法的各个参数的类型的列表。
重点: 参数类型用什么方式表示?用参数所对应的Class实例对象。

例如:

classtype.getConstructor(String.class, int.class);

Constructorcons = classtype.getConstructor(String.class,int.class);

4.     使用Constructor实例创建一个对象

A.     

Class classtype  = Person.class;classtype.getConstructor(String.class , int.class);Constructor cons = classtype.getConstructor(String.class , int.class);Person p = (Person)cons.newInstance(new Object[]{"Alvin",28});
B.

当类中显示的声明了无参的构造方法,就可以使用如下这种方式来创建对象。

public class ConstructorDemo{public static void main(String[] args) throws Exception{       Class classtype = Animal.class;//say()方法没有参数,可以省略       Method m = classtype.getMethod("say");//获得无参Constructor对象classtype.getConstructor()可省参数传递。       Constructor con = classtype.getConstructor();//用无参Constructor对象创建对象,可以省略参数传递。       Animal a =(Animal) con.newInstance();//调用无参的方法,可以省略参数传递。       m.invoke(a); }}class Animal{  private String name ;//显示给定无参构造方法。  public Animal()  {    }  public void say()  {System.out.println("我是一只小动物,主人还没给我取名字");  }}

C.     要使用无参数的构造方法创建对象,还可以使用Class对象的newInstance()方法,这个默认使用类中无参数的构造方法创建一个类的对象。

Class classtype  = Person.class;Person p = (Person) classtype.newInstance();

四. Field类

1.      定义:

一个类中有很多成员变量,也可以用一个类来描述,那么一个Field类的对象,表示某个类中的一个成员变量。

2.      Field对象的关联关系

得到的Field对象是对应到类上面的成员变量,还是对应到对象上的成员变量?类只有一个,而该类的实例对象有多个,如果是与对象关联,哪关联的是哪个对象呢?

严格来说利用发射获取到的Field对象要进行设置和获取,都要在某个对象上去完成,但是这样并不代表这些属性就属于某个对象,所以通过反射的方法获取到的属性并不属于某个对象。

3.      Filed对象的获取

要获取某个类的某个或多个Field对象就必须要先获得某个类的字节码Class对象,再调用Class中的方法获得,方法摘要如下:

A.     获取一个指定字段名的Field对象

Field getField(String name);à 返回一个 Field 对象,只能获取public的成员变量。

Field getDeclaredField(String name); à返回一个 Field 对象,只能获取public的成员变量,可以是private的,也可以是public,只要是类中声明的就可以获取。

B.     获取多个字段的Field数组对象

Field[] getFields();à返回一个包含某些 Field 对象的数组,只能获取public的成员变量。

Fied[] getDeclaredFields();返回一个包含某些 Field 对象的数组,只能获取public的成员变量,可以是private的,也可以是public,只要是类中声明的就可以获取。

        注意: 要获取单个Field对象时候,就必须传递一个字符串类型的属性名字进去,告诉方法到底要获取哪个属性。

4.      Field中的常用方法

A.      获取Field对象所表示字段的值

Objectget(Object obj);à作用在某个对象上进行的获取操作。

longgetLong(Object obj) à作用在某个对象上进行的获取操作,获取一个long类型的值

chargetChar(Object obj) à作用在某个对象上进行的获取操作,获取一个char类型的值

intgetInt(Object obj) à作用在某个对象上进行的获取操作,获取一个int类型的值

doublegetDouble(Object obj) à作用在某个对象上进行的获取操作,获取一个double类型的值

bytegetByte(Object obj) à作用在某个对象上进行的获取操作,获取一个byte类型的值

等等…(还有一些其他就不列出)

B.      获取Field对象所表示的字段的Class类型

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

C.      修改 Field对象所表示字段的值

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

void setBoolean(Objectobj, boolean newValue);à 将字段的值设置为指定对象上的一个 boolean 值。

void setLong(Object obj,long newValue);à 将字段的值设置为指定对象上的一个 long 值。

void setChar(Object obj,char newValue);à 将字段的值设置为指定对象上的一个 char 值。

void setInt(Object obj,int newValue);à 将字段的值设置为指定对象上的一个 int 值。

等等…(还有一些其他就不列出)

5.      暴力反射作用在Field之上

当我们使用Field getDeclaredField(String name)获取到一个类中私有成员变量对应的Field对象时候,是不能直接对其进行重新赋值或获取值的,那么只能利用暴力发射的方法来操作,所以要用到setAccessible(true)这个方法来进行设置,当某个私有成员变量对应的Field对想调用这个方法之后,就能进行赋值和获取值的操作了。

import java.lang.reflect.Field;public class FieldDemo2{public static void main(String[] args) {    Book book = new Book("Java", 48.0);    Class type = book.getClass();//使用getDeclaredFields()才能获取到私有的成员变量    Field[] fields = type.getDeclaredFields();    for(Field field : fields)    {   if(field.getType() == String.class)   {//因为要对变量的值进行修改,必须强制暴力的进行设置可访问   field.setAccessible(true);   String name = null;   try   {name= (String)field.get(book);    field.set(book,name.replaceAll("a","b"));   }   catch(IllegalAccessException e)   {   e.printStackTrace();   }   }    }  System.out.println(book);}}class Book{//将成员变量都声明为private    private String name ;   private double price ;   public Book(String name , double price)   {   this.name = name ;  this.price = price;   }   public String toString()   {    return "书名:"+this.name+", 价格:"+this.price;    }}

五.Method类

1.     定义: 一个类中有很多的成员方法,它是描述一个类中方法的类,一个Method对象代表一个方法,它所反映的方法可能是类方法或实例方法。

2.      如何获得一个类的Method对象

A.     通过Class对象的getDeclaredMethod(String name, Class... parameterTypes) 返回一个 Method 对象,该对象反映此 Class 对象所表示的类或接口的指定已声明方法。

B.      通过Class对象的getDeclaredMethods() 返回 Method 对象的一个数组,这些对象反映此 Class 对象表示的类或接口声明的所有方法,包括公共、保护、默认(包)访问和私有方法,但不包括继承的方法。

C.      通过Class对象的getMethod(String name, Class... parameterTypes)
返回一个 Method 对象,它反映此 Class 对象所表示的类或接口的指定公共成员方法。à只能获取public修饰的方法。

D.     通过Class对象的getMethods() 返回一个包含某些 Method 对象的数组,这些对象反映此 Class 对象所表示的类或接口(包括那些由该类或接口声明的以及从超类和超接口继承的那些的类或接口)的公共 member 方法。à只能获取public修饰的方法。

3.      使用Class类对象获取Method方法时的注意点

A.     一个类中有很多方法,假如要获取这个类中某一个方法,即一个Method对象,那么该怎么去获取,所以要知道方法名,传递一个方法名的参数,可是,一个类中同名的重载方法很多,又要如何去区分呢?所以只能看参数,参数的个数和类型,所以一般是这样的:

Class类的对象.getMethod(String name,Class...args)

4.      方法的执行调用

A.     一般情况下,我们执行某个方法,是通过类名.方法或者对象.方法的方法执行某个方法,不然,在反射中,也需要在某个方法上去执行,虽然是这样,但是并不说明这个方法属于某个对象上的的功能。

B.     执行一个Mehtod对象对应方法的方式如下:

Object invoke(Objectobj, Object...args) 对带有指定参数的指定对象调用由此Method 对象表示的基础方法。

Object objà在哪个对象上去执行这个方法

Object args[]或Object… argsà参数列表

C.     获取某个类中的某个方法:(如String str = ”abc”)
通常方式:str.charAt(1)
反射方式:
Method charAtMethod =
Class.forName(“java.lang.String”).getMethod(“charAt”,int.class);
charAtMethod.invoke(str,1);

5.      如果传递给Method对象的invoke()方法的第一个参数为null,说明Method对象对应的是一个静态方法

6.      用发射的方式执行某个类的main()方法
首先要明确为何要用反射:在写源程序时,并不知道使用者传入的类名是什么,但是虽然传入的类名不知道,而知道的是这个类中的方法有main这个方法,所以可以通过反射的方式,通过使用者传入的类名(可定义字符串型变量作为传入类名的入口,通过这个变量代表类名),内部通过传入的类名获取其main方法,然后执行相应的内容。

//Method类演示  private static void methodTest(String [] args) throws Exception {      String str1 = "abc";      //一般方法:      System.out.println(str1.charAt(1));      //反射方法 :      Method methodCharAt =          Class.forName("java.lang.String").getMethod("charAt",int.class);      System.out.println(methodCharAt.invoke(str1,1));            //用反射方式执行某个main方法      //一般方式:      Test.main(new String[]{"111","222","333"});      System.out.println("-------");            //反射方式:      String startingClassName = args[0];      Method methodMain =          Class.forName(startingClassName).getMethod("main",String[].class);          //方案一:强制转换为超类Object,不用拆包          methodMain.invoke(null,(Object)new String[]{"111","222","333"});          //方案二:将数组打包,编译器拆包后就是一个String[]类型的整体          methodMain.invoke(null,new Object[]{new String[]{"111","222","333"}});      }  //定义一个测试类  class Test{      public static void main(String [] args){          for(String arg : args){              System.out.println(arg);          }      }  }  

六.  数组的反射

1.      特点:

A.     具有相同维数和元素类型的数组属于同一个类型,即具有相同的Class实例对象。

B.     代表数组的Class实例对象的getSuperClass()方法返回的父类为Object类对应的Class。

C.     基本类型的一维数组可以被当作Object类型使用,不能当作Object[]类型使用;非基本类型的一维数组,既可以当做Object类型使用,又可以当做Object[]类型使用。

D.    Array工具类用于完成对数组的反射操作。

E.     基本数据类型的一维数组不能转换为Object数组,如:
int[] a = new int[3];Object[] obj= a;这样是不成立的。

F.      如何得到某个数组中的某个元素的类型:
例:int a = newint[3];Object[] obj= new Object[]{”ABC”,1};
无法得到某个数组的具体类型,只能得到其中某个元素的类型,如Obj[0].getClass().getName()得到的是java.lang.String
若通过b.getClass().getName(),结果是:[Ljava.lang.Object;

2.      如何判断一个Object 类型的对象是否为数组类型?

private static void printObject(Object obj)   {  //判断一个Object类型对象是否为数组使用Class对象的isArray(Object obj)  //方法     if(obj.getClass().isArray())      {        int len = Array.getLength(obj);        for(int i=0;i<len;i++)        {           System.out.println(Array.get(obj, i));  }  }  else   {  System.out.println(obj);  }  }

3.      Array类中的常用方法(方法几乎全是静态的)

A.     Static Object get(Objectarray,int index) 返回指定数组对象中索引组件的值。

B.     staticgetLength(Objectarray) 以 int 形式返回指定数组对象的长度。

C.     static setInt(Objectarray,int index, int i) 将指定数组对象中索引组件的值设置为指定的 int 值。

D.    static setDouble(Objectarray,int index, double d) 将指定数组对象中索引组件的值设置为指定的 double 值。

4.     练习

public static void arrayTest()throws Exception {      int[] a1 = new int[]{1,2,3};      int[] a2 = new int[4];      int[][] a3 = new int[2][3];      Integer[] ai = new Integer[3];      String[] a4 = new String[]{"a","b","c"};            System.out.println(a1.getClass() == a2.getClass());      System.out.println((Object)a1.getClass() == (Object)a3.getClass());                System.out.println(a3[0].getClass() == a1.getClass());      System.out.println(a3[0].getClass().getSuperclass().getName());      System.out.println(a1.getClass().equals(a3.getClass()));      System.out.println(a1.getClass().equals(a4.getClass()));      System.out.println(a1.getClass().getName());      System.out.println("----:" + a1.getClass());      System.out.println(a1.getClass().getSuperclass().getName());      System.out.println(a2.getClass().getSuperclass().getName());                Object obj1 = a1;      Object obj2 = a2;      //int基本数据类型不是Object的      //Object[] obj3 = a1;      Object[] obj4 = a3;      Object[] obj5 = a4;                System.out.println(a1);      System.out.println(a4);            System.out.println(Arrays.asList(a1));      System.out.println(Arrays.asList(a4));      System.out.println("-------");      int[] a = new int[3];      Object[] obj = new Object[]{"abc",new Integer(1)};      System.out.println(a.getClass().getName());      System.out.println(obj.getClass().getName());      System.out.println(obj[0].getClass().getName());  }  

七.  Hashcode 和HastSet的分析

import java.util.ArrayList;  import java.util.Collection;  import java.util.HashSet;    public class ReflectTest2 {      public static void main(String [] args){          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());      }  }    public class ReflectPoint {      private int x;      public int 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;      }            public int hashCode() {          final int prime = 31;          int result = 1;          result = prime * result + x;          result = prime * result + y;          //System.out.println("demo...");//测试          return result;      }        public 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 String toString(){          return str1+";" + str2 + ";" + str3;      }  }  

1.     覆写hashCode()方法的意义:只有存入的是具有hashCode算法的集合的,覆写hashCode()方法才有价值。

2.    哈希算法的由来:


若在一个集合中查找是否含有某个对象,通常是一个个的去比较,找到后还要进行equals的比较,对象特别多时,效率很低,通过哈希算法,将集合分为若干个区域,每个对象算出一个哈希值,可将哈希值分组(一般模32为一组),每组对应某个存储区域,依一个对象的哈希码即可确定此对象对应区域,从而减少每个对象的比较,只需在指定区域查找即可,从而提高从集合中查找元素的效率。

3.     如果不存入是hashCode算法的集合中,那么则不用复写此方法。

4.     只有类的实例对象要被采用哈希算法进行存入和检索时,这个类才需要按要求复写hashCode()方法,即使程序可能暂时不会用到当前类的hashCode()方法,但是为提供一个hashCode()方法也不会有什么不好,没准以后什么时候就会用到这个方法,所以通常要求hashCode()equals()两者一并被覆盖。

5.     若同类两对象用equals()方法比较的结果相同时,他们的哈希码也必须是相等的,但反过来就不成立了,如”BB””Aa”两字符串用equals()比较式不相等的,但是他们的哈希值是相等的。

6.     当一个对象被存储进HashSet集合中,就不能再修改参与计算哈希值的字段,否则对象被修改后的哈希值与最初被存入的HashSet集合中的哈希值就不同了。在这种情况下,即使contains()方法是用对象的当前引用作为参数去HashSet集合中检索对象,也将返回找不到对象的结果,这也导致无法从HashSet集合中单独删除当前对象,从而造成内存泄露。简单说,之前存入的对象和修改后的对象,是具有不同的哈希值,被认为是不同的两个对象,这样的对象不再使用,又不移除,而越来越多,就会导致内存泄露。

7.     内存泄漏

内存泄露:某些对象不再使用了,占用着内存空间,并未被释放,就会导致内存泄露;也就是说当程序不断增加对象,修改对象,删除对象,日积月累,内存就会用光了,就导致内存溢出。对象在调用方法时,对象会先进行一次自身hashCode()方法的调用,再进行操作方法。

                       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); pt1.y = 7;//pt1属性发生变法,hash值也发生变法,重新存入了集合,而此时集合中还有另//外一个原来的元素pt1,不过这两个元素的hash值不一样了,所以原来哪个已经//不指向了,就产生了内存泄漏collections.remove(pt1);System.out.println(collections.size());

八. 反射实现小框架

其实前面利用反射低调用某个类的main方法实例,有点涉及到了小框架,不确定调用哪个类的main,使用动态获取传递。

1.      框架、工具的概念


框架存在的时候,而要调用的类还不知道存在不存在,或者还没写出来,那么以后要调用到我们的类,怎么办?因为框架不知道调用的类名,在程序中无法使用new的方式来创建对象使用,那么只能用反射。

2.      配置文件的路径问题:

A.     用绝对路径,通过getRealPath()方法运算出来具体的目录,而不是内部编码出来的。一般先得到用户自定义的总目录,在加上自己内部的路径。可以通过getRealPath()方法获取文件路径。对配置文件修改是需要要储存到配置文件中,那么就要得到它的绝对路径才行,因此,配置文件要放到程序的内部。

2.     name的路径问题:
如果配置文件和classPath目录没关系,就必须写上绝对路径,
如果配置文件和classPath目录有关系,即在classPath目录中或在其子目录中(一般是资源文件夹resource),那么就得写相对路径,因为它自己了解自己属于哪个包,是相对于当前包而言的。

import java.io.InputStream;import java.util.Collection;import java.util.Properties;public class PropertiesAndReflectDemo{public static void main(String[] args) throws Exception{//方式1使用IO流的方式加载properties文件//InputStream in = new FileInputStream(new File("Config.properties"));//使用类加载器的getResourceAsStream("Config.properties")方法获取输入流InputStream  in = PropertiesAndReflectDemo.class. getClassLoader().getResourceAsStream("Config.properties");Properties pro = new Properties();pro.load(in);String classname = pro.getProperty("className");Collection collection = (Collection)Class.forName(classname).newInstance();Person p1 = new Person("Ansen",24);Person p2 = new Person("Hahn",25);Person p3 = new Person("Ansen",24);Person p4 = new Person("Peak",22);collection.add(p1);collection.add(p2);collection.add(p3);collection.add(p4);System.out.println(collection.size());}

























原创粉丝点击