黑马程序员 —— Java基础加强 - 反射

来源:互联网 发布:人工智能 中科院 编辑:程序博客网 时间:2024/06/03 21:34

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

视频17 透彻分析反射的基础 - Class类


1.引入

反射是从JDK1.2就有的新特性,以后学习框架都要用到反射技术。

要了解反射,就要先了解Class这个类。

Class,是一个类,注意首字母是大写的。


2.PPT内容

Java类用于描述一类事物的共性,该类事物有什么属性,没有什么属性,至于这个属性的值是什么,则由这个类的实例对象来确定,不同的实例对象有不同的属性值。Java程序中的各个Java类,它们属于同一类事物,可以用一个类来描述这类事物,这个类的名字就是Class(注意与小写class关键字的区别)。Class类描述了哪些方面的信息呢?类的名字,类的访问属性,类所属于的包名,字段名称的列表、方法名称的列表,等等。学习反射,首先要明白Class这个类。

个人总结:Class类就是Java中各种各样的类,提取构造方法、属性、方法等等共性内容所得的类。

API文档说:Class 类的实例表示正在运行的 Java 应用程序中的类和接口。


再换一个角度思考:

众多的人用一个什么类表示?    人 → Person类

众多的Java类用一个什么类表示?   Java类 → Class

Java程序中的各个Java类属于同一类事物,描述这类事物的Java类就是Class类。


提问:

Person类的实例是张三、李四这样一个个人,Class类的各个实例对象又分别对应什么呢?

  •    对应各个类在内存中的字节码,例如,Person类的字节码,ArrayList的字节码,等等。
  •     一个类被类加载器加载到内存中,占用一片存储空间,这个空间里面的内容就是类的字节码,不同类的字节码是不同的,所以它们在内存中的内容是不同的,这一个个的空间可分别用一个个的对象来表示,这些对象显然具有相同的类型,这个类型是什么呢?答:Class类型。


如何得到各个字节码对应的实例对象,请下面的小程序:

首先,一共有三种方式获取Class类的实例对象,看下面的代码:

public class ReflectTest {public static void main(String[] args) throws ClassNotFoundException {String str = "获取Class类的实例对象";Class cls1 = str.getClass();Class cls2 = String.class;Class cls3 = Class.forName("java.lang.String");System.out.println(cls1 == cls2);  //trueSystem.out.println(cls2 == cls3);  //true}}

从上面可见,有三种方式得到各个字节码对应的实例对象(Class类型):

  1. 类名.class,例如,System.class
  2. 对象.getClass(),例如,new Date().getClass()
  3. Class.forName(),例如,Class.forName("java.util.Date")


另外,有九个预定义Class实例对象:

API文档描述:“有九种预定义的 Class 对象,表示八个基本类型和 void。这些类对象由 Java 虚拟机创建,

与其表示的基本类型同名,即 booleanbytecharshortintlongfloatdouble。”

参见Class.isPrimitive()方法:判定指定的 Class 对象是否表示一个基本类型。

public class ReflectTest {public static void main(String[] args) throws ClassNotFoundException {String str = "获取Class类的实例对象";Class cls1 = str.getClass();System.out.println(cls1.isPrimitive()); // falseSystem.out.println(int.class.isPrimitive()); // trueSystem.out.println(int.class == Integer.class); // falseSystem.out.println(int.class == Integer.TYPE); // trueSystem.out.println(int[].class.isPrimitive()); // false}}


视频18    理解反射的概念


视频17 说了反射的基石 —— Class类,现在才真正讲反射的概念。


反射:就是把Java类中的各种成分映射成相应的Java类。

Java类中有什么啊?

有:它所在那个包的信息,可以通过getPackage()方法得到;

它具有哪些方法,可以通过getMethod()方法得到;它的成员变量,可以通过getFileld()方法得到。

学反射,就是把Java类中各种各样的东西,解析成为一个类。


例如Method这个类,


对于 System.exit(int status) 、System.getProperties() ,它们都是方法,

都是看做是Method方法类的实例对象,

我们可以这样思考,就像下面这样:

Method → methodeObj1 → System.exit(int status)

Method → methodeObj2 → System.getProperties()


它们其实就相当于Methode这个类中的methodobj1,obj2。

public class ReflectTest2 {public static void main(String[] args) throws ClassNotFoundException,SecurityException, NoSuchMethodException {Method methodObj1 = System.class.getMethod("exit", int.class);System.out.println(methodObj1);// public static void java.lang.System.exit(int)Method methodObj2 = System.class.getMethod("getProperties", null);System.out.println(methodObj2);// public static java.util.Properties java.lang.System.getProperties()}}


像上面这样,我们得到了Method这个类的对象,就相当于得到了System这个类的一个方法


PPT上的内容:1.反射就是把Java类中的各种成分映射成对应的Java类。例如,一个Java类中用一个Class类的对象来表示,一个类中组成部分:成员变量,方法,构造方法,包等等信息也用一个个的Java类来标表示,就像汽车是一个类,汽车中的发动机,变速箱等等也是一个个的类。表示Java类的Class类显然要提供一系列的方法,来获得其中的变量,方法,构造方法,修饰符,包等信息,这些信息就是用相应类的实例对象来表示,它们是Field、Method、Contructor、Package等等。2.一个类中的每个成员都可以用相应的反射API类的一个实例对象来表示,通过调用Class类的方法可以得到这些实例对象后,得到这些实例对象后有什么用呢?怎么用呢?这正是学习和应用反射的要点。




视频19    构造方法的反射应用


1.PPT内容

Constructor 类代表某个类中的一个构造方法得到某个类所有的构造方法:例子:Constructor[] constructors = Class.forName("java.lang.String").getConstructors();得到某一个构造方法:例子:Constructor constructor = Class.forName("java.lang.String").getConstructor(StringBuffer.class);//获得方法时要用到类型创建实例对象:通常方式:String str = new String(new StringBuffer("abc"));反射方式:String str = (String)constructor.newInstance(new StringBuffer("abc"));//调用获得的方法时要用到上面相同类型的实例对象Class.newInstance()方法:例子:String obj = (String)Class.forName("java.lang.String").newInstance();该方法内部先得到默认的构造方法,然后用该构造方法创建实例对象。该方法内部的具体代码要怎么写呢? 用了缓存机制来保存默认构造方法的实例对象。


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

API文档描述: Constructor 提供关于类的单个构造方法的信息以及对它的访问权限。


import java.lang.reflect.*;public class ConstructorDemo {public static void main(String[] args) throws SecurityException,NoSuchMethodException, IllegalArgumentException,InstantiationException, IllegalAccessException,InvocationTargetException {Constructor constructor = String.class.getConstructor(StringBuffer.class);String str1 = new String(new StringBuffer("abc")); //通常方式String str2 = (String) constructor.newInstance(new StringBuffer("abc")); //反射方式               //调用获得的方法时,要用到上面相同类型的实例对象System.out.println("str1: " + str1 + " ; str2: " + str2);}}

注意:

(1) 构造方法没有顺序,你不能getConstructors(2)这样去得到,但可以通过参数类型来获取。

(2) JDK1.5后有可变参数的新特性,你可以写多个参数,getConstructor(Class<?>... parameterTypes) ;

      如果是1.5之前,你可以通过传一个数组来传多个参数,getConstructor(Class[] parameterTypes) 。


有了构造方法,能够干嘛呢?

可以得到得到那个类,得到修饰符,最重要的是可以得到实例对象


2.关于得到Constructor实例对象,要主意的两点


注意看下面:

Constructor constructor1 = String.class.getConstructor(StringBuffer.class); String str2 = (String)constructor1.new Instance(new StringBuffer("abc"));

第一句编译时,只检查等号左边的语句是否符合语法规则,

并不会执行等号右边的语句,所以它只知道constructor1是一个构造方法,

而不知道具体是什么类的构造方法。


第二句,根据这个构造方法new Instance创建的实例,得到的是一个Object,要强制转换为String类型才行。

如果第二句传给constructor1的参数是"abc"这样一个String,

编译能够通过,但运行时会有类型不匹配的异常,因为这个constructor1是接收StringBuffer.class的构造方法。

关键:要注意,得到方法的时候要传入类型,调用方法时也需要传入同样类型的对象。



3.Class.newInstance()方法

//请留意:Class和Constructor两个类,都有newInstance()方法的。String obj = (String)Class.forName("java.lang.String").newInstance();

该方法用空参数的构造方法创建实例对象。

API文档:Class的newInstance()方法,如同用一个带有一个空参数列表的 new 表达式实例化该类。

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


Constructor已经有newInstance()了,为什么Class还要有呢?

其实不要上面这个newInstance()方法也没有影响,

但我们平时是通过 class → constructor → obj 这样来得到对象的,

它这里就给我们一个便利,让我们得到空参数构造方法时,可以省去了中间constructor那步。


通过阅览源码可知,反射会导致程序性能下降。



视频20    成员变量的反射


1.PPT内容

Field类Field类代表某个类中的一个成员变量。演示用eclipse自动生成Java类的构造方法问题:得到的Field对象是对应到类上面的成员变量,还是对应到对象上的成员变量呢?类只有一个,而该类的实例对象有多个,如果是与对象关联,那关联的是哪个对象呢?所以字段fieldX代表的是x的定义,而不是具体的x变量。


2.示例代码

import java.lang.reflect.*;public class ReflectTest {public static void main(String[] args) throws SecurityException,NoSuchFieldException, IllegalArgumentException,IllegalAccessException {ReflectPoint pt1 = new ReflectPoint(3, 5);Field fieldY = pt1.getClass().getField("y");// filedY的值是多少?是5? 错!fieldY不是对象身上的变量,而是类上,要用它去取某个对象上对应的值。System.out.println(fieldY.get(pt1)); // 输出5//fieldY只代表类身上的成员变量,不代表某个对象的值。}}
public class ReflectPoint {private int x;public int y;public ReflectPoint(int x, int y) {super();this.x = x;this.y = y;}}

fieldY只代表类身上的成员变量,不代表某个对象的值。


3.关于暴力反射

暴力反射:无视一个类中私有成员变量、构造方法、方法等等访问权限修饰符,用反射技术提供的方法,"抢"到这些私有的资源。

import java.lang.reflect.*;public class ReflectTest {public static void main(String[] args) throws SecurityException,NoSuchFieldException, IllegalArgumentException,IllegalAccessException {ReflectPoint pt1 = new ReflectPoint(3, 5);/***************************************************************///Field fieldX = pt1.getClass().getField("x");//System.out.println(fieldX);//如果ReflectPoint的x是private修饰,那就会抛NoSuchFieldException异常。/***************************************************************///Field fieldX = pt1.getClass().getDeclaredField("x");//System.out.println(fieldX.get(pt1));//会抛IllegalAccessException异常,"让你看见但不让你用"/***************************************************************/Field fieldX = pt1.getClass().getDeclaredField("x");fieldX.setAccessible(true);System.out.println(fieldX.get(pt1)); //3}}


视频21    成员变量反射的综合案例


题目:将任意一个对象中的所有String类型的成员变量所对应的字符串内容中的“b”改为“a”。

import java.lang.reflect.Field;public class ReflectTest {public static void main(String[] args) throws IllegalArgumentException,IllegalAccessException {MyConstructor mc = new MyConstructor();changeStringValue(mc);System.out.println(mc);}private static void changeStringValue(Object obj)throws IllegalArgumentException, IllegalAccessException {Field[] fields = obj.getClass().getFields();for (Field field : fields) {if (field.getType() == String.class) {String oldValue = (String) field.get(obj);String newValue = oldValue.replace('b', 'a');field.set(obj, newValue);}}}}

public class MyConstructor {private int x;private int y;public String a = "bed";public String b = "aaa";public String c = "abc";public String d = "beg";@Overridepublic String toString() {return "MyConstructor [a=" + a + ", b=" + b + ", c=" + c + ", d=" + d+ ", x=" + x + ", y=" + y + "]";}}

field.getType() == String.class这句,是equals好还是==好?

字节码有几份?一份。

所以,只要是比较字节码就用==比。


视频22    成员方法的反射


1.PPT内容

Method类1.Method类代表某个类中的一个成员方法。2.得到类中的某一个方法:例子:Method charAt = Class.forName("java.lang.String").getMethod("charAt",int.class);调用方法:通常方式: System.out.println(str.charAt(1));反射方式: System.out.println(charAt.invoke(str,1));   如果传递给Method对象的invoke()方法的一个参数是null,这有什么意义呢?   说明该Method对象对应的是一个静态方法!3.JDK1.4 和 JDK1.5 的invoke方法的区别: JDK1.5 : public Object invoke(Object obj,Object...args); JDK1.4 :public Object invoke(Object obj,Object[ ] args),即按JDK1.4的语法,需要将一个数组作为参数传递给invoke方法时,数组中每个元素分别对应被……


2.示例代码

import java.lang.reflect.*;public class MethodDemo {public static void main(String[] args) throws SecurityException,NoSuchMethodException, IllegalArgumentException,IllegalAccessException, InvocationTargetException {String str = new String("ABC");Method methodCharAt1 = String.class.getMethod("charAt", int.class);System.out.println(methodCharAt1.invoke(str, 2)); // 输出C,invoke就是调用的意思Method methodCharAt2 = String.class.getMethod("valueOf", char.class);System.out.println(methodCharAt2.invoke(null, 'C')); // 输出C}}

invoke是Method类对象身上的方法,

上面的程序,通过得到String类中的charAt方法,然后调用它。


3.“专家模式”的小例子

例子1:

画圆的方法用到圆心和半径,是圆身上的方法。

只有圆自己知道自己怎么画。


例子2:

列车司机刹车,司机只是给列车发信息,要列车自己才知道自己怎么刹住。


上面两个例子,就是“专家模式”的例子:谁有这个数据,谁就应该拥有操作这个数据的方法。


4.JDK1.4前后invoke方法的区别

  • JDK1.5 :invoke(Object obj, Object... args)   
  • JDK1.4 : invoke(Object obj, Object[] args)


import java.lang.reflect.*;public class MethodDemo {public static void main(String[] args) throws SecurityException,NoSuchMethodException, IllegalArgumentException,IllegalAccessException, InvocationTargetException {String str = new String("ABC");Method methodCharAt1 = String.class.getMethod("charAt", int.class);System.out.println(methodCharAt1.invoke(str, 2)); // JDK1.5做法System.out.println(methodCharAt1.invoke(str, new Object[] { 2 })); // JDK1.4做法}}

按照1.4的做法,多个参数的时候

import java.lang.reflect.*;public class MethodDemo {    public static void main(String[] args) throws SecurityException,            NoSuchMethodException, IllegalArgumentException,            IllegalAccessException, InvocationTargetException {        String str = new String("ABCDEFG");        Method methodIndexOf = String.class.getMethod("indexOf", new Class[] { String.class,                int.class});   //注意new Class[]        System.out.println(methodIndexOf.invoke(str, new Object[] { "C",new Integer(1)}));  //注意这里    }}


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

 

1.PPT内容

目标:写一个程序,这个程序能够根据用户提供的类名,去执行该类中的main方法。用普通方式调完后,要明白为什么要用反射的方式去调?问题:启动Java程序的main方法的参数是一个字符串数组,即public static void main(String[] args),通过反射方式来调用这个main方法时,如何为invoke方法传递参数呢?按JDK1.5的语法,整个数组是一个参数,而按JDK1.4的语法,数组中的每个元素对应一个参数,当把一个字符串数组作为参数传递给invoke方法时,javac会到底按照哪种语法进行处理呢?JDK1.5肯定要兼容JDK1.4的语法,会按JDK1.4的语法进行处理,即把数组打散成为若干个单独参数。所以,给main方法传递参数时,不能使用代码mainMethod.invoke(null,new String[]{"XXX"}),javac只把它当作JDK1.4的语法进行理解,而不把它当作JDK1.5的语法理解,因此会出现参数类型不对的问题。解决方法:mainMethod.invoke(null,new Object[]{new String[]{"XXX"}});mainMethod.invoke(null,(Object)new String[]{"XXX"}); //编译器会作特殊处理,编译时不把参数当作数组看待,也就不会把数组打散成若干个参数了

2.示例代码

import java.lang.reflect.*;public class ReflectMainDemo {public static void main(String[] args) throws SecurityException,NoSuchMethodException, ClassNotFoundException,IllegalArgumentException, IllegalAccessException,InvocationTargetException {String startingClassName = args[0];Method mainMethod = Class.forName(startingClassName).getMethod("main",String[].class);mainMethod.invoke(null, (Object) new String[] { "111", "222", "333" });}}class TestArguments {public static void main(String[] args) {for (String arg : args) {System.out.println(arg);}}}

上面程序,输入的参数是:TestArguments


平时我们这样调:TestArguments.main(new String[]{});


视频24    数组的反射


1.PPT内容

具有相同维数和元素类型的数组属于同一个类型,即具有相同的Class实例对象。代表数组的Class实例对象的getSuperClass()方法返回的父类为Object类对应的Class。基本类型的一维数组可以被当作Object类型使用,不能当作Object[] 类型使用;非基本类型的一位数组,既可以当作Object类型使用,又可以当作Object[]类型使用。Arrays.asList()方法处理int[]和String[]时的差异。Array工具类用于完成对数组的反射操作。思考题:怎么得到数组中的元素类型?

数组也是一种类型,API文档:具有相同的元素类型及维数的每一个数组,反射出来的字节码都是相同的。


2.示例代码

public class ReflectArrayDemo {    public static void main(String[] args) {        int[] a1 = new int[3];        int[] a2 = new int[4];        int[][] a3 = new int[2][3];        String[] a4 = new String[4];        System.out.println(a1.getClass() == a2.getClass());        // System.out.println(a1.getClass() == a3.getClass()); 不能通过编译        // System.out.println(a1.getClass() == a3.getClass()); 不能通过编译        System.out.println(a1.getClass().getName()); // [I        System.out.println(a1.getClass().getSuperclass().getName()); // java.lang.Object        System.out.println(a4.getClass().getSuperclass().getName()); // java.lang.Object                Object obj1 = a1;        Object obj2 = a4;        // Object[] aObj3 = a1; //不能转换,因为a1装的是int,是基本类型,不是Object        Object[] aObj4 = a3;        Object[] aObj5 = a4;    }}


          看上面的代码:

  • .getclass():返回此 Object 的运行时类/得到对象的字节码。
  • System.out.println(a1.getclass().getName());   //输出[I
  • 除了Object,每个类都有父类,System.out.println(a1.getClass().getSuperClass().getName());   //输出java.lang.Object
  • 把a3当成一个数组来看待,然后就可以理解为:一个数组里面装了一个数组(一个Object)


3.Class类的getName()方法

public String getName():以 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"     byte.class.getName()         returns "byte"     (new Object[3]).getClass().getName()         returns "[Ljava.lang.Object;"     (new int[3][4][5][6][7][8][9]).getClass().getName()         returns "[[[[[[[I"   
中括号表示数组,I表示int。


4.Arrays工具类的asList方法


一般来说,我们希望打印这个数组,就直接输出里面的元素内容,

而不是返回它的哈希码:System.out.println(new String[] { "a", "b", "c" });  //[Ljava.lang.String;@1bab50a


这时候可以使用Arrays里面的asList方法,将数组转换为List。

import java.util.Arrays;public class ReflectArrayDemo {public static void main(String[] args) {int[] a1 = new int[] { 1, 2, 3 };String[] a4 = new String[] { "a", "b", "c" };System.out.println(a1); // [I@1e5e2c3System.out.println(a4); // [Ljava.lang.String;@18a992fSystem.out.println(Arrays.asList(a1)); // [[I@18a992f]// 对于int,转换成List后,List后只装了原来那个数组对象,还是输出哈希码System.out.println(Arrays.asList(a4)); // [a, b, c]// 对于字符串,成功了}}

Q:为什么int类型的数组不能用asList方法输出元素呢?

A:首先,String数组符合了JDK1.4的语法,asList(Object[] a),因此String数组的情况就被当作一个数组来处理。

      而int数组不是Object[]数组,只能按JDK1.5的语法处理,asList(T... a),整个数组被当作一个对象,

      就输出了这个 数组对象 的哈希码了。




视频25    数组的反射


1.示例代码

如果我们想通过反射方式,得到数组的length、其中的值,我们应该怎么做?

可以通过 java.lang.reflect.Array; 这个类,看下面的例子程序。

import java.lang.reflect.*;import java.util.Arrays;public class ReflectArrayDemo {public static void main(String[] args) {String[] str = new String[] { "111", "222", "333" };int[] a = new int[] { 1, 2, 3 };printObject(str);printObject(a);}private static void printObject(Object obj) {// 给我是一堆,就一个个地打印;如果是一个,就打印一个。Class clazz = obj.getClass();if (clazz.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);}}}

输出:

111222333123

2.思考:怎么得到数组里面元素的类型?

结论是没有办法得到,只能得到某一个具体元素的类型,不能得到整个数组的类型。
Object[] b = new Object[]{"a",1};System.out.println(b[0].getClass().getName());//java.lang.String


视频26    ArrayList/HashSet的比较 及 HashCode分析


1.示例代码

import java.util.*;public class ReflectTest2 {    public static void main(String[] args) {        Collection collections = new ArrayList();        //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);        System.out.println(collections.size()); // ArrayList的size是4,HashSet的size是3    }}


该例中,如果是 ArrayList则size是4,HashSet则size是3。


2.ArrayList和HashSet的区别

简单概括:

ArrayList类似于数组,它有顺序,不是指大小顺序,而是指排序顺序。

HashSet则是先判断有没有这个对象,有就不放,要么你先把有的那个对象删掉再放。


详细说明:hashCode方法与HashSet类


3.改写示例代码后

现在我们改写ReflectPoint的equals和hashcode方法,只要x/y相等,就是同一个点。

public class ReflectPoint {private int x;public int y;public ReflectPoint(int x, int y) {super();this.x = x;this.y = y;}@Overridepublic int hashCode() {final int prime = 31;int result = 1;result = prime * result + x;result = prime * result + y;return result;}@Overridepublic 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;}}

这时候HashSet的情况就输出2了。


HashSet 是先比较hashCode,相等再进一步比较equals。

ArrayList则是按顺序存放,不会进行什么比较操作。


只有把你的对象存到哈希集合(不仅仅指HashSet)中,

你的hashCode才有价值,才会按照hashCode进行区域分放。

你不存到哈希集合中,你也就不需要修改hashCode了。


面试题:请说一下equals和hashCode的作用。


4.内存泄漏

内存泄漏 就是该回收的内存没有被回收(对象不用了,又不被释放)


比较好的译文:简述Java内存泄漏

落实到HashSet的情况,就是下面这个例子:

package Package1;import java.util.Collection;import java.util.HashSet;public class HashCodeDemo {    public static void main(String[] args) {        Collection collections = new HashSet();        ReflectPoint pt1 = new ReflectPoint(3, 3);        collections.add(pt1);        pt1.setY(7);        collections.remove(pt1);        System.out.println(collections.size()); // 输出1,没有被remove掉,因为改完后hashCode改变了    }}


另外一道面试题:Java中有内存泄露吗?为什么?

就举上面这个例子,ReflectPoint pt1加入到collections中后,

被修改了成员变量Y,导致它的哈希码改变了,

当你要把它从collections中remove的时候,不能remove掉,

pt1这是还持有ReflectPoint(3,7)的引用,而Java虚拟机这种情况下垃圾收集器是不会把ReflectPoint(3,7)从内存中释放的,

ReflectPoint(3,7)不会被回收,并占用着内存空间,它就是该被回收又没有被回收的对象。

这样就产生了内存泄漏了。


视频27    框架的概念及用反射技术开发框架的原理



了这么多反射类,到底有什么用?  用来做框架.

1.PPT内容

1.  框架与框架要解决的核心问题我做房子卖给用户住,用户自己安装门窗和空调等等,我做的房子就是框架,用户需要使用我的框架,把门窗插入进我提供的框架。框架与工具类有区别,工具类被用户的类调用,而框架则是调用用户提供的类。2.   框架要解决的核心问题·我在写框架(房子)时,你这个用户可能还在上小学,还不会写程序呢?我写框架程序怎样能调用到你以后写的类(门窗)呢?·因为在写程序时无法知道要被调用的类名,所以,在程序中无法直接new某个类的实例对象,而要用反射方式来做。3.  综合案例(1)先直接用new语句创建ArrayList和HashSet的实例对象,演示用eclipse自动生成ReflectPoint类的equals和hashCode方法,比较两个集合的运行结果差异。(2)然后改为采用“配置文件+反射”的方式创建ArrayList和HashSet的实例对象,比较观察运行结果差异。(3)引入了eclipse对资源文件的管理方式的讲解。

以后调用别人写的类,有两种方式:
  1. 你调用别人的类 

  2. 别人的类调用你的类(也算是你用别人的)  


工具类与框架的性质,就类似于 你自己在里面装修 和 开发商给你的房子 的区别。


明白了HashSet和ArrayList的区别,又知道了hashCode方法的作用,

接下来就把那个程序改为反射的方式来做,改为从配置文件读取。


2.示例代码

import java.io.*;import java.util.*;import java.lang.reflect.*;public class ReflectTest2 {public static void main(String[] args) throws Exception {InputStream ips = new FileInputStream("config.properties");Properties props = new Properties();props.load(ips);ips.close();String className = props.getProperty("className");Collection collections = (Collection) Class.forName(className).newInstance();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);System.out.println(collections.size());}}


config.properties 文件:

className=java.util.ArrayList
注意是放在 项目的文件夹中,跟src同目录的,不是放src里面。


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

0 0
原创粉丝点击