(19)基础加强-反射-类加载器的使用

来源:互联网 发布:计算机维护与网络管理 编辑:程序博客网 时间:2024/06/17 00:50
---------------------- ASP.Net+Android+IOS开发、.Net培训、期待与您交流! ----------------------详细请查看:http://edu.csdn.net

黑马程序员基础加强-反射-类加载器的使用

Java反射

反射基础分析

概述总结:

反射就是把java类中的各个成员分别映射成相应的java类;

例如,

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

   一个类中的每个成员都可以用相应的反射API类的一个实例对象来表示,通过调用Class类的方法可以得到这些实例对象后,得到这些实例对象后有什么用呢?怎么用呢?这正是学习和应用反射的要点。


反射的基石——Class

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

Class类描述了类的名字,类的访问属性,类所属包名,字段名称列表,方法名称列表等等;学习反射,首先要明白Class类。

如:

很多的人用什么类标示?那么很多的Java类用什么标示?

人—Person

Java—Class

Person代表人,他的实例对象就是张三,李四等这样一个个具体的人;Class类代表Java类,他的各个实例对象又分别对应什么呢?

对应各个类在内存中的字节码,例如,Person类的字节码,ArrayList类的字节码等等;

一个类被类加载器加载到内存中,占用一定的存储空间,这个空间里面的内容就是类的字节码,不同的类的字节码是不同的,所以他们在内存中的内容是不同的,这一个个的空间可分别用一个个对象来标示,这些对象具体相同的类型。


什么是字节码?

 当源程序中用到某个类时,首先要从硬盘把这个类的那些二进制代码即:一个类编译成class放在硬盘上以后,就是一些二进制代码,要把这些二进制代码加载到内存中里面来,再用这些字节码去复制出一个一个对象来

如何得到各个字节码对应的实例对象(Class类型),有三种方法:

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

2, 对象.getClass();例如:new Data().getClass();

3, Class.forName(包名.类名);例如:Class.forName(java.util.Data);//  这种方式较为简单,只要知道类的完整名称即可。不需要使用该类,也不需要去调用具体的属性和行为。就可以获取到Class对象了;仅知道类名就可以获取到该类字节码对象的方式,更有利于扩展


九个预定义的Class

1,八种基本类型(byteshortintlongfloatdoublecharboolean)的字节码对象和一种返回值为void类型的void.class。

2Integer.TYPE是Integer类的一个常量,(但是int.classInteger.class是不相等的false,它们是两个不同的字节码)它代表此包装类型包装的基本类型的字节码,所以和int.class是相等的。

基本数据类型的字节码都可以用与之对应的包装类中的TYPE常量表示


数组类型的Class实例对象用的方法是:Class.isArray();

注意:

只要是源程序中出现的类型,都有各自的Class实例对象,例如:int[],void…都是代表一个类型。


Class类中常用方法列举:

1, static Class forName(String className);//返回给定字符串名的类或接口相关类的Class对象;

2, Class getClass();//返回的是Object运行时的类,即返回Class对象即字节码对象;

3, Constructor getConstructor();//返回Constructor对象,反映此Class对象所代表的类指定公共构造方法;

4, Field getField(String name);//返回Filed对象,标示Class对象所代表的的类或接口指定公共成员字段;

5, Field[] getField();//返回Field对象数组,代表类中成员字段;

6, Method getMethod(String name,Class…parameterTypes);//返回一个Method对象,标示次Class对象锁代表的类的指定公共成员方法;

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

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

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

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

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

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


通过Class对象来获取类实例

因为Class类没有构造方法,所以只能通过该类方法来获取类的实例对象

具体步骤:

1, 查找并加载指定名字的字节码文件存储进内存,并封装成Class对象

String className = “包名.Person”;

Class clas = Class.forName(className);

2, 通过Class对象的newInstance()方法创建该Class对应类的实例对象;

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

3,调用构造函数进行初始化

Person p = new Person();

示例:

package 加强Day01.黑马;class Person{private String name;private int age;Person(String name,int age){this.name = name;this.age  = age;}public String toString(){return name+":"+age;}}public class ReflectDemo {public static void main(String[] args) throws Exception{Class cla = Class.forName("加强Day01.黑马.Person");//获取Person类的Class对象Person p = (Person)cla.newInstance();//通过newInstance方法获取对应类对象。System.out.println(p.toString());}}


构造方法的反射应用

Constructor

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

如果指定的类中没有空参数的构造函数,或者要创建的类对象需要通过指定构造函数进行初始化,这是怎么办呢?

首先不能再使用Class类中newInstance方法,因为要通过指定的构造函数进行对象的初始化,那么就要用到Constructor来获取构造函数

获取构造方法例子:

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

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

2, 得到某一个构造方法:

Constructor constrctor = 

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

//获取方法时要用到的类型。

小知识点:

在getConstructor(可变参数)方法中接收的参数没有限制,为什么呢?

因为可以传入1.5新特性可变参数。

再问:那么没有可变参数再来接收多个参数怎么写呢?

我们可以通过数组类获取

得到Constructor对象后干什么呢?

查阅API文档java.lang.reflect.Constructor<T>可参见该类的方法

有了对象就可以创建实例对象(接上面示例):

1,通常方式:String str = new String(new StringBuffer(“abc”));

2,反射方式:String str = (String)constrctor.newInstance(new StringBuffer(“abc”));

Class.newInstance()方法:

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

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

该方法内部具体代码怎么写的呢?

实际上用到了缓存机制类保存默认构造方法的实例对象。

总结:

1, 在创建实例时候,newInstance()方法中的参数列表必须和getConstructor()方法中的参数列表一致。

2, newInstance()方法在构造一个实例对象时,每调用一次就构造一个对象;

3, 利用Constructor类来创建实例的好处是可以指定构造函数,而Class类只能利用无参构造函数创建实例对象。


Fieldjava.lang.reflect.Field

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

常用方法:

1, Field getField(String 变量);//只能获取公有和父类中公有的变量;

2, Field getDeclaredField(String 变量);//获取该类中的任意类型的变量,包括私有的;

3, setAccessible(true);//若是私有的字段,即之前变量是私有的,该方法可以将私有字段进行取消权限获取,也称为暴力访问;

4, set(Object obj,Object value);//将指定对象变量上的Field对象标示的字段设置为指定的新值;

5, Class<?> getType();//返回一个Class对象。

6, Object get(Object obj);//返回指定对象上Field表示的字段的值;

示例:

package 加强Day01.黑马;public class ReflectDemoxy {public int x;private int y;//使用快捷键快速生成构造函数public ReflectDemoxy(int x, int y) {super();//this.x = x;this.y = y;}}public class ReflectDemo {public static void main(String[] args) throws Exception{Reflect();}public static void Reflect()throws Exception{ReflectDemoxy ref = new ReflectDemoxy(3,5);Field fid1 = ref.getClass().getField("x");//通过获取Class对象,得到一个字段,公有的;//fid1它不代表一个值,不是某个变量上的某个值,它代表一个变量。//作用是类上要用它去取是某个对象对应的值。//若要取出这个变量值,我们应该明确是在某个类身上的值:fid1.get(ref)System.out.println(fid1.get(ref));//取出指定类身上的变量。Field fid2 = ref.getClass().getDeclaredField("y");//这时可以看到任何类型的变量,但是对于私有字段不能取出,所以需要Field里的方法setAccessible();暴力访问;fid2.setAccessible(true);System.out.println(fid2.get(ref));}}


练习:

练习:把一个类里所有的String类型的字段里的值b变a;package 加强Day01.黑马;public class ReflectDemoxy {public int x;private int y;public String str1 = "ball";public String str2 = "abstract";public String str3 = "haohaoxuexi";//使用快捷键快速生成构造函数public ReflectDemoxy(int x, int y) {super();//this.x = x;this.y = y;}public String toString(){return str1+":"+str2+":"+str3;}}package 加强Day01.黑马;import java.lang.reflect.Field;public class ReflectTest {public static void main(String[] args) throws Exception{// new一个对象ReflectDemoxy ref = new ReflectDemoxy(3,4);//获取所有字段Field[] fields = ref.getClass().getFields();//对所有字段遍历并判断是否与String类的字节码相等;for(Field field: fields){//if(field.getType().equals(String.class))if(field.getType() == String.class){//获取对应字段的值的字符串;String oldValue = (String)field.get(ref);//将字符串里的b换成aString newValue = oldValue.replace('b', 'a');//改对象的字段field.set(ref,newValue);}}//打印替换后的结果:System.out.println(ref);System.out.println(ref);System.out.println(ref);}}


Methodjava.lang.reflect.Method

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

简单的说:

实际上我们是使用反射的方式拿到指定类的字节码里面的方法,再用这个方法去作用于某个对象。

常用方法:

1, Method[] getMethods();//只获取公共和父类中的方法;

2, Method[] getDeclaredMethods();//获取本类中所有方法包含私有

3, Method getMethod(“方法名”,参数.class);//若是空参数可以写null;因为重载,参数列表和类型可能不一致,参数也可接收可变参数。

4, Object invoke(Object obj,Object…obj(参数));//调用方法,

注意invoke调用方法对象身上的方法:

砖家模式:谁拥有这个数据谁就是调用它的砖家,那么就应该把方法分配给它!

比如停车:

调用者:对象是车,只有车知道该怎么停下来,是车在调用刹车的动作;

指挥者:人在指挥车停车的动作,给车发出信号让车去执行,停车的动作只有车才能做到,车拥有这个停车的动作,它就是这个的砖家,那么就应该把停车方法分配给车,而不是给人;

思考:

当方法对象身上的方法即:invoke(null1)第一个参数是null,不通过对象就调用了,说明这个方法是静态的,因为静态方法是不需要对象的

示例:

package 加强Day01.黑马;import java.lang.reflect.Method;public class MethodTest {public static void main(String[] args)throws Exception {//获取字符串中某一个字符String str = "abc";//通常方式System.out.println(str.charAt(1));//反射方式Class cla = Class.forName("java.lang.String");Method charAtMethod = cla.getMethod("charAt",int.class);System.out.println(charAtMethod.invoke(str, 1));}}


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

Jdk1.5public Object invoke(Object objObject…obj)

Jdk1.4public Object invoke(Object objObject[] args);

安装jdk1,4的语法,需要见那个一个数组作为参数传递给invoke方法时,数组中的每个元素分别对应被调用方法中的一个参数,所以,调用charAt方法的代码页可以用jdk1.4改写为charAt.invoke(“str”,new Object[]{1})的形式。

接上面示例:

System.out.println(charAtMethod.invoke(str, new Object[]{2}));


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

首先明确为什么要使用反射?

因为在写源程序时,或程序写好后,不知道使用者将传入什么类,类名是什么等,但是我们知道这个类中的方法有main这个方法。这时我们可以通过反射的方式把使用者传入的类名(可定义字符串变量作为传入类名的入口,通过这个变量代表类名),在内部通过传入类名来获取main方法,然后执行相应内容。

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

分析:

在启动Java程序的main方法参数是一个字符串数组,即public static void main(String[] args),通过反射方式来调用这个main方法时,如何为invoke方法传递参数呢?

jdk1.5的语法,整个数组是一个参数,而按照jdk1.4的语法,数组中的每个元素对象对应一个参数,当把一个字符串数组作为参数传递给invoke方法时,javac会执行哪种语法来处理呢?

Jdk1.5兼容jdk1.4语法,所以会按照1.4语法去处理,即把数组打散成若干个单独的参数,所以在给main方法传递参数时,不能使用代码mainMethod.invoke(null,new String[]{“…”})javac只有把它当做jdk1.4语法进行理解,而不会当做jdk1.5语法来解释,因此会出现参数类型不对的问题。

解决办法:

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

2, mainMethod.invoke(null,(Object)new String[]{“xxx”});。编译器会做特殊处理,不会吧它当数组看,也就不会数组打散成若干个参数了。

示例:

测试类package 加强Day01.黑马;public class MainTest {public static void main(String[] args) {// 测试类for(String arg:args){System.out.println(arg);}}}package 加强Day01.黑马;import java.lang.reflect.Method;//写一个程序,这个程序能够根据用户提供的类名,去执行该类中的main方法public class ReflectMain{public static void main(String[] args)throws Exception{//普通方式,因为静态所以直接类名.main()MainTest.main(new String[]{"111","222","333"});System.out.println(".............");//反射方式:String strName = args[0];//传进来的参数不确定类型不确定;Class classMain = Class.forName(strName);//获取字节码对象Method method = classMain.getMethod("main",String[].class);//调用方法对象的方法invoked,去执行//方法一:使用Object超类method.invoke(null,(Object)new String[]{"111","222","333"});//方法二:将数组打包,那个编译器拆包后还一个String[]数组。method.invoke(null, new Object[]{new String[]{"111","222","333"}});}}


数组的反射

1,具有相同位数元素类型的数组属于同一个类型,即具有相同的Class示例对象。

示例:

<span style="white-space:pre"></span>int[] a1 = new int[3];int[] a2 = new int[4];int[][] a3 = new int[2][3];String[] a4 = new String[3];System.out.println(a1.getClass()==a2.getClass());System.out.println(a1.getClass()==a3.getClass());System.out.println(a1.getClass()==a4.getClass());System.out.println(a1.getClass().getName());System.out.println(a4.getClass().getName());打印结果是:TrueFalseFalse[I[Ljava.lang.String;

分析结果:

从这里可以看出,当同是一维数组或二维数组,并都是int类型相同,所以为true。由于字节码一定是唯一的并且字节码文件就代表这个类,所以getClass()获取的字节码文件对象是一个,地址值也是一样。

数组类型的父类Object

任何元素类型的数组他们的直接父类就一个java.lang.Object;

我们可以通过Class类里面的方法getSuperclass();返回超类

示例:

package 加强Day01.黑马;import java.lang.reflect.*;import java.util.Arrays;public class ReflectArraysTest {public static void main(String[] args) {int[] a1 = new int[]{1,2,3,};int[] a2 = new int[4];int[][] a3 = new int[2][3];String[] a4 = new String[]{"a","b","c"};System.out.println(a1.getClass()==a2.getClass());//System.out.println(a1.getClass()==a3.getClass());//System.out.println(a1.getClass()==a4.getClass());System.out.println(a1.getClass().getName());System.out.println(a4.getClass().getName());//获取超类类名System.out.println(a1.getClass().getSuperclass());System.out.println(a4.getClass().getSuperclass());//判断是否成立?是否属于对应类型Object obj1 = a1;Object obj2 = a4;//Object[] obj3 = a1;不能从int转Object,类型不匹配,基本数据类型不能转Object[] obj4 = a3;//等效于数组里面装是一个数组,而该数组是属于Object的。Object[] obj5 = a4;//String是属于Object的System.out.println(Arrays.asList(a1));System.out.println(Arrays.asList(a4)); /* Arrays.asList()方法处理int[]和String[]时的差异。           * 打印Arrays.asList(a1);还是跟直接打印a1是一样的              打印Arrays.asList(a4);就会把a4的元素打印出来。              这是因为此方法在JDK1.4版本中,接收的Object类型的数组,              而a4是String类型可以作为Object数组传入。但是a1是基本数据类型不可以作为Object数组传入,所以只能按照JDK1.5版本可变参数来处理。              在JDK1.5版本中,传入的是一个可变参数,所以a1就被当作是一个object,也就是一个参数,              而不是数组传入,所以打印的结果还是跟直接打印a1一样,就无法直接显示数组中的元素。           */ }}打印结果:true[I[Ljava.lang.String;class java.lang.Objectclass java.lang.Object[[I@1bab50a][a, b, c]


数组反射应用

若我们需要获取数组里面的值,或设置值,得到数组的长度,用反射怎么做?

Class类中有Array这个类

演示数组反射的作用:

步骤:

1,先获取Class对象

2,用Class类的isArray()方法判断是否是数组

3,不是数组就直接打印,是数组就用Array类的getLength(obj)静态方法获取长度

4for循环遍历数组并用Array类的静态方法get(objindex)获取数组中的对应角标的元素

示例接上面:

ArrayTest(a4);ArrayTest("abc");}//数组的反射应用:public static void ArrayTest(Object obj){//可以接收一堆(数组)或一个类型Class clazz = obj.getClass();//通过元素获取Class对象//判断是否是数组类型的字节码if(clazz.isArray()){int len = Array.getLength(obj);//通过Array的里的方法获取长度。for(int x=0; x<len;x++){System.out.println(Array.get(obj, x));}}else{System.out.println(obj);}}


ArrayListHashSet的比较及HashCode分析(面试重点)

ArrayList是一个有顺序的集合,相当于一个数组,当我们放一个对象进去的时候,放进去的是对象的引用,然后再次放对象。是先后顺序放进去,不管相同。

HashSet是放之前判断集合里面是否有相同的引用变量,若有就不放,若要放就必须将原来的那个删除掉;

HashCode方法的作用(面试常问)

比如:我们在查找一个集合中是否包含某个即将插入的对象,通常做法是逐一将每个每个元素与要查的对象进行比较,当发现某个元素和要查找的对象进行equals比较相等时,就停止查找并返回信息;但是这样做的效率很低,这样就有了哈希算法!

有人发明的了哈希算法来提高集合中去查找元素的效率,这种方式将集合分成若干个存储区域,每个对象可以计算出一个哈希码值,将哈希码分组,每组分别对应某个区域,再根据要查找的哈希码就可以确定该对象应该存储到哪个区域;如下图:


注意:

1, 要想HashCode方法有价值的话,前提是对象存入的是hash算法这种类型的集合当中才有价值。如果不存入是hashCode算法的集合中,则不用复写此方法。

2, 如果没有复写hashCode方法,对象的hashCode值是按照内存地址进行计算的。这样即使两个对象的内容是想等的,但是存入集合中的内存地址值不同,导致hashCode值也不同,被存入的区域也不同。所以两个内容相等的对象,就可以存入集合中。

3, 当一个对象存储进HashSet集合中以后,就不能修改这个对象中的那些参与计算哈希值的字段了,否则对象修改后的哈希值与最初存储进HashSet集合中的哈希值就不同了。在这种情况下,调用contains方法或者remove方法来寻找或者删除这个对象的引用,就会找不到这个对象。从而导致无法从HashSet集合中单独删除当前对象,从而造成内存泄露。(程序中某一些对象不再被使用,以为被删掉了,但是没有,还一直在占用内存中,当这样的对象慢慢增加时,就会造成内存泄露。)

示例:package 加强Day01.黑马;    import java.util.ArrayList;    import java.util.Collection;    import java.util.HashSet;    public class HashCodeDemo {            public static void main(String[] args) {            //Collection collection =new ArrayList();            Collection collection =new HashSet();            HashCodeTest hct1=new HashCodeTest(1,2);            HashCodeTest hct2=new HashCodeTest(3,4);            HashCodeTest hct3=new HashCodeTest(1,2);                        collection.add(hct1);            collection.add(hct2);            collection.add(hct3);            collection.add(hct1);            //hct1.setX(5);            //collection.remove(hct1);            System.out.println(collection.size());        }    }  //测试类    class HashCodeTest{        private int x;        public int y;        public HashCodeTest(int x,int y){            this.x=x;            this.y=y;        }        public int getX() {            return x;        }        public void setX(int x) {            this.x = x;        }        public int getY() {            return y;        }        public int hashCode() {            final int prime = 31;            int result = 1;            result = prime * result + x;            result = prime * result + y;            return result;        }        public boolean equals(Object obj) {            if (this == obj)                return true;            if (obj == null)                return false;            if (getClass() != obj.getClass())                return false;            HashCodeTest other = (HashCodeTest) obj;            if (x != other.x)                return false;            if (y != other.y)                return false;            return true;        }        public void setY(int y) {            this.y = y;        }        public String toString() {            return "HashCodeTest [x=" + x + ", y=" + y + "]";        }    }


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

框架与框架要解决的核心问题

比如;开发商建设房子给用户,然后由用户自己安装门窗大家电等;

开发商做的房子就是框架,用户使用框架,把门窗插入到框架中。

框架与工具类的区别:

框架是调用用户提供的类,工具是被用户的类调用;

框架要解决的核心问题

比如我在写框架时候,你这个用户可能还在上小学,还不会写程序,那么我写的框架程 序怎么才能调用你以后写的类(门窗)呢?

因为在写程序时无法知道要被调用的类名,所以,在程序中无法直接new某个类的实例对象了,而要用反射的方式来做Class.forName();

简单的框架程序代码实现:

分析步骤:

1, 定义配置文件config.properties;,在配置文件中定义好配置信息如:

className=java.util.ArrayList,等号左边是键,右边是值;

2, 创建文件读取流读取配置文件的信息,写出配置文件的绝对路径;

3, 通过Properties类的load方法将配置信息存储到集合中;

4, 关闭读取流;

5, 通过Properties类中的getProperty()方法获取value即某个类名;

6, 后面步骤就可以通过反射的方式用Class类来获取实例

示例:

在源程序中不出现这个类,而通过配置文件来配,在再通过反射来获取该类的实例对象

package 加强Day01.黑马;import java.io.FileInputStream;import java.io.InputStream;import java.util.Collection;import java.util.Properties;public class ReflectDemo3 public static void main(String[] args)throws Exception{// 创建文件读取流,读取配置文件信息InputStream ins = new FileInputStream("config.Properties");//将流中的数据利用集合Properties类中的load方法存储进集合Properties pro =new Properties();pro.load(ins);//关闭读取流对象;ins.close();//通过集合getProperty(键)方法获取value 即某类名String className = pro.getProperty("className");//获取Class对象,通过反射方式创建实例对象;Class clazz = Class.forName(className);Collection coll = (Collection)clazz.newInstance();}}


类加载器

概述:

类加载器就是将.class文件加载进内存,也可以将普通文件中的信息加载进内存;

具体加载方式:

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

基本上所有的类加载器都是 java.lang.ClassLoader类的一个实例。

Java.lang.ClassLoader类介绍

作用:

1, 就是根据一个指定的类的名称,找到或生成其对应的字节码,然后从这些字节码中定义一个java类,即Class类实例对象。

2, ClassLoader还负责加载java应用所需的资源,比如图像文件和配置文件等,将配置文件放到.class文件目录中一同打包,类加载器就会一同加载。

加载资源文件

方法一:资源文件是由类加载器ClassLoader来加载进内存,具体就是使用getClassLoader()方法获取加载器,然后用类加载器的getResourceAsStream(String name)方法,将配置文件即资源文件加载进内存。

注意:利用类加载器来加载配置文件,需要把配置文件放置的包名一起写上,不然会报异常,这种方法只有读取功能。

方法二:在java.lang.Class类中也提供了getResourceAsStream(String name)方法来加载资源文件,这个时候是配置文件是相对类文件的当前目录,所以不用写包名。其实该方法内部也还是调用了ClassLoader的方法的。

如:Person.class.getResourceAsStream(“配置文件名”);

常用方法:

getParent();// 返回该类加载器的父类加载器。

loadClass(String name);// 加载名称为name的类,返回Class实例对象

findClass(String name);// 查找名为name的类,返回的也是Class实例。

findLoadedClass(String name);// 查找名为name的已被加载过的类。

defineClass(String name,bytr[] b,int off,int len);//把字节数组b中的类容转换成java类。

关于配置文件存放路径的疑问

根据上面示例,和配置文件的加载,我们可以了解到:

1,配置文件如果和classPath目录没有联系,那么要写上绝对路径;

2,配置文件如果和classPath目录有联系,比如是在该目录中或其子目录中,那么可以省略前面路径写文件名即可。

示例:加载资源文件

package 加强Day01.黑马;import java.io.FileInputStream;import java.io.InputStream;import java.util.Collection;import java.util.Properties;public class ReflectClassLoader {public static void main(String[] args) throws Exception{// 首先创建一个Properties对象来存储配置文件Properties pro = new Properties();//简单的相对性路径读取流演示,即当配置文件和.java在同一目录//InputStream ins1 = new FileInputStream("config.properties");//类加载器能加载.class文件,那么在classPath环境变量下附带的配置文件必须也能加载,//注意它也只能在该环境变量下加载,且使用类加载器时候不能以“/”打头;//先将配置文件转为字节码文件对象,使用Class类中的getClassLoader返回该类的类加载器,//再在classPath目录下逐一的查找给定名称的资源配置文件,使用方法getResourceAsStream(Name),返回InputStream//InputStream ins2 = //ReflectClassLoader.class.getClassLoader().getResourceAsStream("加强Day01/黑马/config.Properties");//另外Class类还提供了一个方法,用加载类的加载器去加载相同包目录下的文件;InputStream ins3 = ReflectClassLoader.class.getResourceAsStream("/加强Day01/黑马/propertes/configProperties");//将流里的数据存储到定义好的缓冲区pro.load(ins3);//关闭读取流对象ins3.close();//通过键获取值即文件类型 String className = pro.getProperty("className");         Class clazz = Class.forName(className);             Collection collection = (Collection)clazz.newInstance();         HashCodeTest hct1=new HashCodeTest(1,2);         HashCodeTest hct2=new HashCodeTest(3,4);         HashCodeTest hct3=new HashCodeTest(1,2);                    collection.add(hct1);        collection.add(hct2);        collection.add(hct3);        collection.add(hct1);        System.out.println(collection.size());}}

---------------------- ASP.Net+Android+IOS开发、.Net培训、期待与您交流! ----------------------
0 0
原创粉丝点击
热门问题 老师的惩罚 人脸识别 我在镇武司摸鱼那些年 重生之率土为王 我在大康的咸鱼生活 盘龙之生命进化 天生仙种 凡人之先天五行 春回大明朝 姑娘不必设防,我是瞎子 不小心在qq钱包中充错话费怎么办 衣服质量不好穿了几次就坏了怎么办 手机丢了找到手机店的人怎么办 在手机店买手机买贵了怎么办 王者荣耀好多没对的东西怎么办 用电脑玩游戏键盘不管用怎么办? 王者荣耀跨系统送皮肤领不到怎么办 电脑使用迅雷时提示缓存过高怎么办 扣扣安全中心动态密码忘记了怎么办 pu管两头固定了中间换截怎么办 自己架设的传奇不能注册帐号怎么办 天堂2第八章读取服务端错误怎么办 苹果手机王者荣耀下了不能玩怎么办 苹果手机摔了一下触屏失灵怎么办 华为机回复出厂设置帐号忘了怎么办 华为手机里突然有个pp助手怎么办 华为手机与电脑连接不上怎么办 买房交了首付贷不了款怎么办 手机买贵了实体店不肯退怎么办 在实体店里手机买贵了怎么办 红米手机开启不了安装系统怎么办? 捡个荣耀8双清后要账号怎么办 荣耀7x升级8.0后耗电快怎么办 手机提示当前为耳机播放模式怎么办 华为手机进水了显示耳机模式怎么办 苹果6s突然变成耳机模式怎么办 华为手机出现耳机标志没声音怎么办 苹果手机微信变成耳机模式怎么办 5s不能用4g网络怎么办 华为麦芒四手机系统乱了好卡怎么办 信翼路由器登录密码忘了怎么办 苹果手机电信4g信号变3g怎么办 苹果7手机4g变3g怎么办 朵唯v3逆客手机不支持计步怎么办 移动卡升级4g后网络不好怎么办 电信办宽带送的手机卡不用了怎么办 移动华为悦盒遥控器丢了怎么办 移动签了两年套餐不想用了怎么办 华为手机隐私空间密码忘记了怎么办 华为的隐私空间密码忘记了怎么办 格力新机没密码开不了怎么办