享元模式Flyweight Pattern
枚举enumeratin
为什么要有枚举
问题:要定义星期几或性别的变量,该怎么定义?
假设用1-7分别表示星期一到星期日,但有人可能会写成int weekday = 0;
枚举就是要让某个类型的变量的取值只能为若干个固定值中的一个,否则编译器就会报错.
枚举可在编译时就发现源程序中填写的非法值,普通变量无法实现.
[生活中的例子,开发程序时用几表示Sunday呢,有的用1(在国外是一周的第一天),用0(计算机中第一用0表示)或者用7(在中国是第七天)。都有道理,那么公司规定我的公司Sunday就用0表示,Saturday用6表示。但是这样的小细节要对每个新来的程序员都告诉一遍吗?麻烦!要定义一个Weekday,里面设定好值,以后程序员要用Weekday型变量时,它的值只能是应经提前定义好的值.这个值不是基本类型的,而是引用类型的,是对象]
定义一个Weekday的类来模拟普通类实现枚举功能。 。
定义抽象方法nextDay,将大量的if.else语句转移成了一个个独立的内部类。
枚举就相当于一个类,可定义成员变量,构造方法,普通方法和抽象方法。
枚举元素必须位于枚举体中的最开始部分。
总结:枚举是一种特殊的类,其中的每个元素都是该类的一个实例对象
例如可以调用WeekDay.SUN.getClass().getName和WeekDay.class.getName()。
反射的基石àClass类
Java程序中的各个Java类属于同一事物,为Class类
众多的人用Person类表示
众多的Java类用Class类表示
Person类有人的姓名年龄等属性,学习吃饭等方法
Class类
Person p1 = new Persion(); //先把java文件,编译成二进制的字节码,即class文件
Person p2 = new Persion(); //当程序用到Person类时,先把Person的字节码加载到内存后,创建对象 即:先把字节码加载到内存,通过字节码创建类的对象
如果用了Person类,Date类,Math类,内存中就有3分字节码文件,即3个Class类的实例对象
Class c1 = Date.class //Class类不能new对象,但可以指向。内存中若有Date类,就有Date对应的字节码,这个字节码就是对象,这个对象的类型就是Class
p1 就是Person类字节码创建出的一个对象
p1.getClass(); p1有相应的方法得到是哪个字节码创建的自己
得到字节码的三种方式:
1.字节码已经加载到内存 直接类名.class,例如,System.class
2.字节码已经加载到内存 对象.getClass(),例如,new Date().getClass()
3.字节码没加载到JVM Class类的静态方法forName
Class.forName("类名"),例如,Class.forName("java.util.Date");
若没加载就先用类加载器把指定的类加载到内存,同时forName方法返回加载的字节码
Class<T> API:
The primitive Java types (boolean, byte, char, short, int, long, float, and double), and the keyword void are also represented as Class objects.
基本的 Java 类型(boolean、byte、char、short、int、long、float 和 double)和关键字 void 也表示为Class 对象。
总之,只要是在源程序中出现的类型,都有各自的Class实例对象,例如,int[],void…
反射:
学员冯伟立(大二辍学,现广州电信)听完后反射后的一句总结:“反射就是把Java类中的各种成分映射成相应的java类”。这句话比许多书上讲解得都透彻,都精辟!
就像汽车是一个类,汽车中的发动机,变速箱,轮胎等也是一个个的类。
表示java类的Class类要提供一系列的方法,来获得其中的变量,方法,构造方法等信息。这些信息就是用相应类的实例对象来表示,它们是Field、Contructor、Package等等。
一个类中的每个成员都可以用相应的反射API类的一个实例对象来表示
通过调用Class类的方法可得到这些实例对象
得到这些实例对象后有什么用呢?怎么用呢?这正是学习和应用反射的要点。
Constructor类
Field类
暴力反射
成员变量的反射与成员方法的反射
作业:将任意一个对象中的所有String类型的成员变量所对应的字符串内容中的"n"改成"*"。
s1.charAt, s2.charAt
s1与s2都能调用同一方法,方法是属于类的,不是属于对象的
invoke
[?n'vok] vt. 调用;招灵
方法调用
method invocation
Method类代表某个类中的一个成员方法
得到类中的某一个方法:
例子: Method m = Class.forName("java.lang.String").getMethod("charAt", int.class);
获得String类的Method类中charAt方法,该charAt方法有多种重载方式,这里我们选参数时int型的,就要写出int.class
这要就得到了Method类中的对象m,m具体是String类中的charAt方法,且参数是int型。如何使用对象m中的方法,方法需要被对象调用,故m.invoke(str,1)把对象和参数通过Method类中的invoke方法传给m
Invoke要理解:关门,不是人关门,人给一个力量,一个信号,门自己关的自己知道回到哪儿位置,
Circle。Draw.是你发命令,circle自己画圆
(面向对象:把变量私有,谁操作变量,变量在谁身上,方法就在谁身上,关门 门与门槛角度为0,这个角度是门的,角度变小的方法在门身上)
调用方法:
通常方式:System.out.println(str.charAt(1));
反射方式: System.out.println(charAt.invoke(str, 1));
如果传递给Method对象的invoke()方法的第一个参数为null,这有着什么样的意义呢?说明该Method对象对应的是一个静态方法!
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方法时,数组中的每个元素分别对应被调用方法中的一个参数,所以,调用charAt方法的代码也可以用Jdk1.4改写为 charAt.invoke(“str”, new Object[]{1})形式。
Class.getMethod方法用于得到一个方法,该方法要接受什么参数呢?显然要一个方法名,而一个同名的方法有多个重载形式,用什么方式可以区分清楚想得到重载方法系列中的哪个方法呢?根据参数的个数和类型,例如,Class.getMethod(name,Class... args)中的args参数就代表所要获取的那个方法的各个参数的类型的列表。
再强调一遍参数类型用什么来表示啊?用Class对象!
—稍后总结(就像看书如果卡在第五页了,就跳过去看第10页,不要反复看前五页)
m.invoke(null,1);
当传入的对象为null,是就是该方法不需要对象调用,即静态方法
用反射方式执行某个类中的main方法
大家要明白为什么要用反射方式去调啊?
问题:按jdk1.5的语法,整个数组是一个参数,而按jdk1.4的语法,数组中的每个元素对应一个参数
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"}); ,编译器会作特殊处理,编译时不把参数当作数组看待,也就不会数组打散成若干个参数了
数组的反射
Arrays.asList()方法处理int[]和String[]时的差异。
Array工具类用于完成对数组的反射操作。
Object[] 与String[]没有父子关系,Object与String有父子关系
故:new Object[]{“aaa”,”bb”}不能强制转换成new String[]{“aaa”,”bb”};
Object x = “abc”能强制转换成String x = “abc”。
main.invoke(null, (Object)(new Object[]{“aaa”,“xxx”}));
不能调用public static void main(String [] args)
反射到底干什么:实现框架
框架与工具类的区别:
我作为开发商建房子卖给住户,由住户自己安装门窗,我建的房子就是框架
住户需使用我的框架,把门窗插入进我提供的框架中.
住户自己做的门,然后到商店买一个锁安装上,锁就是工具类
工具类被用户的类调用,而框架则是调用用户提供的类。
框架要解决的核心问题
我在写框架(房子)时,调用你未来的那个门,就是我建房子时,你还没做门
这时不能直接new某个门,因为门还没有,怎样能调用到后写的类(门窗)呢?
要用反射方式来做,通过Class向回找
综合案例
先直接用new语句创建ArrayList和HashSet的实例对象
通过eclipse可自动生成 ReflectPoint类的equals和hashcode方法
Class类也提供getResourceAsStream方法
好比:你每次都找我给你商店买可乐,那我还不如直接向你买可乐,即直接提供一个买可乐的方法给你