1.
总所周知 Java 有个 Object class,是所有 Java classes 的继承根源,其内声明了数个应该在所有 Java class 中被改写的 methods:hashCode()、equals()、clone()、toString()、getClass() 等。
2.
Class 类十分特殊。它和一般的 classes 一样继承自 Object 类,其实体用以表达 Java 程序运行时的 classes 和 interfaces,也用来表达 enum、array、primitive java types(boolean, byte, char, short, int, long, float, double)以及关键字 void。当一个类被加载,或当加载器(class loader)的 defineClass() 被 JVM 调用,JVM 便自动产生一个该类的 Class 对象。如果你想通过“修改 Java 标准库源码”来观察 Class 对象的实际生成时机(例如在 Class 类的 constructor 内添加一个 println()),答案是否定的!因为 Class 类并没有 public constructor。下面是 Class.java 中的源码:
/*
* 私有构造方法,仅 JVM 能够创建该对象。
*/
private Class(ClassLoader loader, Class<?> arrayComponentType) {
// Initialize final field for classLoader. The initialization value of non-null
// prevents future JIT optimizations from assuming this final field is null.
classLoader = loader;
componentType = arrayComponentType;
}
3.
Class 类是 Reflection 起源。针对任何你使用的类,唯有先为它产生一个 Class 对象,接下来才能使用反射机制(使用 Reflection APIs)。
4.
Java 中为一个类生成对应的 Class 对象的方法:
a. 使用 getclass() 方法。这个方法是 Object 类中的,所以任何类都有这个方法。
eg:
String str = "ym";
Class<?> clazz = str.getClass();
b. 使用 Class.getSuperclass() 方法。(通过它的子类,获取父类 Class 对象)
package com.cfm.test;
public class ClassTest {
public static void main(String[] args) {
// 获取 Child 类的 Class 对象
Class<?> clazz = Child.class;
System.out.println("1: " + clazz);
// 获取 Child 类的父类 Parent 类 Class 对象
clazz = clazz.getSuperclass();
System.out.println("2: " + clazz);
// 获取 Parent 类的父类 Object 类 Class 对象
clazz = clazz.getSuperclass();
System.out.println("3: " + clazz);
// Object 是基类,没有父类,所以打印为 null
clazz = clazz.getSuperclass();
System.out.println("4: " + clazz);
}
}
class Parent{
}
class Child extends Parent{
}
// output
1: class com.cfm.test.Child
2: class com.cfm.test.Parent
3: class java.lang.Object
4: null
c. 使用 Class 类中的静态方法: Class.forName()。
eg:
Class<?> clazz1 = Class.forName("java.lang.String");
Class<?> clazz2 = Class.forName("java.awt.Button");
d. 直接使用 .class 语法。
Class c1 = String.class;
Class c2 = int.class;
Class c3 = java.awt.Button.class;
e. 使用 primitive wrapper classes 的 TYPE 语法。(注意,这里获取的是原生数据类型的 Class 对象,比如 Integer.TYPE 获取的是 int 的Class 对象。如果想获取到 Integer 的 Class 对象,直接使用 Integer.class)
// 8个 primitive java types
Class c1 = Boolean.TYPE;
Class c2 = Byte.TYPE;
Class c3 = Character.TYPE;
Class c4 = Short.TYPE;
Class c5 = Integer.TYPE;
Class c6 = Long.TYPE;
Class c7 = Float.TYPE;
Class c8 = Double.TYPE;
// void 关键字的 Class 对象
Class c9 = Void.TYPE;
5.
为什么获得 Method 对象时不需要指定返回类型?
因为 Method Overloading 机制要求方法声明必须唯一,那么只要指定了 method 的名称和参数列,就一定指定了一个独一无二的 method。
代理模式:
1. 代理模式的作用: 为其它对象提供一种代理以控制对这个对象的访问。(在某些情况下,一个客户不想或者不能直接引用另一个对象时,而代理对象可以在客户端和目标对象之间起到中介的作用。)
2. 代理模式一般涉及到的角色有:
--- 抽象角色:声明真实对象和代理对象的共同接口。
--- 代理角色:a. 代理对象角色内部含有对真实对象的引用,从而可以操作真实对象;b. 代理对象实现与真实对象相同的接口以便在任何时刻都能代替真实对象;c. 代理对象可以在执行真实对象操作时,附加其它的操作,相当于对真实对象进行封装。
--- 真实角色:代理角色所代表的真实对象是我们最终要引用的对象。
eg1:
// 抽象角色
public abstract class Subject {
public abstract void request();
}
// 真实角色
public class RealSubject extends Subject {
@Override
public void request() {
System.out.println("真实对象执行的方法");
}
}
// 代理角色
public class ProxySubject extends Subject {
// 代理角色内部引用的真实角色
private RealSubject realSubject;
@Override
public void request() {
// 代理角色自己想实现的事情
this.preRequest();
if( null == realSubject){
realSubject = new RealSubject();
}
// 真实角色所完成的事情
realSubject.request();
// 代理角色自己想实现的事情
this.postRequest();
}
// 代理角色私有方法
private void preRequest(){
System.out.println("pre request");
}
// 代理角色私有方法
private void postRequest(){
System.out.println("post request");
}
}
// 客户端(通过代理角色调用真实角色中的方法)
public class Client {
public static void main(String[] args) {
Subject subject = new ProxySubject();
subject.request();
}
}
上述代码分析:
客户实际需要调用的 RealSubject 类的 request() 方法,现在用 ProxySubject 来代理 RealSubject 类,同样达到目的,同时还封装了一些其它方法( preRequest() 、 postRequest() ),可以处理一些其它的问题。
引入问题:
如果按照上述的方法使用代理模式,那么真实角色必须是事先已经存在的,并将其作为代理对象的内部属性。但是实际使用时,一个真实角色必须对应一个代理角色,如果大量使用代理模式会导致类的急剧膨胀;此外,如果事先并不知道真实角色,该如何使用代理呢?这个问题可以通过 Java 的动态代理类来解决。下一部分分析 java 的动态代理模式。