@(简书)
引言
工作中,有时感觉对Java的理解不够深,想补补。以后,不定期更新《重新看编程思想》。《Java编程思想》这本书从大一开始伴随着我,再看这本书感觉全是回忆。
RTTI(Run-Time Type Identification))
- 理解泛型,首先得知道RTTI是什么?
运行时类型信息可以在程序运行时发现和使用类型信息。
下面看一个例子,来看看RTTI的作用。
定义一个抽象类,声明
abstract
方法。
public abstract class Shape {
void draw() {
System.out.println(this + ".draw()");
}
abstract public String printStr();
}
- 继承抽象类,重写基类方法。
public class Square extends Shape {
@Override
public String printStr() {
return "Square";
}
}
public class Triangle extends Shape {
@Override
public String printStr() {
return "Triangle";
}
}
public class Circle extends Shape {
@Override
public String printStr() {
return "Circle";
}
}
- 测试运行类
public class Shapes {
public static void main(String[] args) {
List<Shape> shapes = new ArrayList<Shape>() {{
add(new Circle());
add(new Triangle());
add(new Square());
}};
for (Shape shape : shapes) {
System.out.println(shape.printStr());
shape.draw();
}
}
}
- 运行结果
Circle
fanxing.Circle@54bedef2.draw()
Triangle
fanxing.Triangle@5caf905d.draw()
Square
fanxing.Square@27716f4.draw()
分析
对于
Shape
列表来说,把Circle
、Triangle
、Square
放入时,都会被向上转型,即对列表而言,都是Shape
对象。当遍历元素时,容器会将所有事物当做
Object
持有,并自动转型回Shape
,这就是RTTI的基本使用形式,在运行时,识别一个对象的类型。可以看出,RTTI的转型并不彻底,只是从
Object
转型为Shape
,没有转型为具体的Circle
:
Object -> Shape ? -> Circle
- 那么,为什么执行了
Circle
的代码呢?
多态使得
Shape
对象执行引用所指向的具体对象的代码。
Class对象
理解RTTI的工作原理,首先要知道类型信息在运行时是如何表示的,即Class
对象。
每个类都有一个
Class
对象(每当编写并且编译一个类),对象被载入内存,就会被用来创建这个类的对象。
Class
对象还可以使用另外一种方法生成,即Gum.class
,即类字面常量。
try {
// forName方式
Class<?> gum = Class.forName("fanxing.studyclass.Gum");
System.out.println(gum.getCanonicalName());
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
// 类字面常量
System.out.println(Gum.class.getCanonicalName());
- 为
.class
创建Class
对象引用的“三步准备”。
加载:类加载器执行,查找字节码,并从字节码中创建一个Class对象。
链接:验证类的字节码,为静态域分配存储空间,解析这个类创建的对其他类的引用。
初始化:如果该类具有超类,对其初始化,执行静态初始化器和静态初始化块。
public class Initable {
static final int a = 47;
static final int b = new Random().nextInt(1000);
static {
System.out.println("初始化 Initable");
}
}
public class Initable2 {
static int a = 147;
static {
System.out.println("初始化 Initable2");
}
}
public class Initable3 {
public static int a = 74;
static {
System.out.println("初始化 Initable3");
}
}
public static void main(String[] args) throws ClassNotFoundException {
// 没有引发Initable初始化
Class initable = Initable.class;
System.out.println("创建Initable class对象引用");
// 没有引发Initable初始化
System.out.println(Initable.a);
// 引发初始化
System.out.println(Initable.b);
// Initable2 初始化
System.out.println(Initable2.a);
Class initable3 = Class.forName("fanxing.leizimianchangliang.Initable3");
System.out.println("创建Initable3 class对象引用");
System.out.println(Initable3.a);
}
分析
初始化为“惰性”,static final值如果为编译期常量,不会引发初始化。
.class获得对类的引用,不会引发初始化,但是forname产生class引用,立即引发初始化。
反射:运行时的类信息
- 使用反射,进行类方法提取
try {
Class<?> c = Class.forName(args[0]);
Method[] methods = c.getMethods();
Constructor[] constructors = c.getConstructors();
if (args.length == 1) {
for (Method method : methods) {
System.out.println(p.matcher(method.toString()).replaceAll(""));
}
for (Constructor constructor: constructors) {
System.out.println(p.matcher(constructor.toString()).replaceAll(""));
}
lines = methods.length + constructors.length;
} else {
for (Method method: methods) {
if (method.toString().contains(args[1])) {
System.out.println(p.matcher(method.toString()).replaceAll(""));
lines++;
}
for (Constructor constructor:constructors) {
if (constructor.toString().contains(args[1])) {
System.out.println(p.matcher(constructor.toString()).replaceAll(""));
lines ++;
}
}
}
}
} catch (Exception e) {
e.printStackTrace();
}
动态代理
public class DynamicProxyHandler implements InvocationHandler {
private Object proxied;
public DynamicProxyHandler(Object proxied) {
this.proxied = proxied;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("proxy: " + proxy.getClass() + " method: " + method + " args: " + args);
if (args != null) {
for (Object s : args) {
System.out.println(" arg");
}
}
return method.invoke(proxied, args);
}
}
public class SimpleDynamicProxy {
public static void consumer(Interface in) {
in.doSomething();
in.somethingElse("bo");
}
public static void main(String[] args) {
RealObject object = new RealObject();
consumer(object);
// 动态创建代理
Interface proxy = (Interface) Proxy.newProxyInstance(
Interface.class.getClassLoader(),
new Class[]{Interface.class},
new DynamicProxyHandler(object));
consumer(proxy);
}
结语
- 理解上述概念有助于后续对一些框架源码的阅读,例如反射、动态代理会在很多框架源码中看到。
- 后续自己对一些业务功能,进行封装也可以考虑动态代理。
参考文献
- Java编程思想