Table of Contents
private修饰的方法可以通过反射访问,那么private意义何在?
反射和多态
事实上,反射和多态这两种技术并无直接联系,之所以把它们放在一起说,是因为,在Java技术体系中所提供的能够让我们在运行时识别对象和类的类型信息的方式,一共有两种:即反射和多态关键技术RTTI
RTTI,即run-Time Type Identification运行时类型判定,它的作用是在我们不知道某个对象的确切的类型信息时,即某个对象是哪个类的实例的时候,可以通过RTTI相关的机制帮助我们在编译时获取对象的类型信息,这其实也就是多态的实现基础。
反射机制允许我们在运行时发现和使用类的信息。因此多态和反射两者的最大的共同点在于,他们都是运行时获取程序信息的技术。反射技术对于java世界的众多框架以及特性都发挥着至关重要的作用,博主认为中文的基石一词能够准确形容反射技术的地位,理解反射技术对于学习java相关技术的背后原理非常重要,许多java世界里的特性的实现原理背后都离不开反射。
让我们先来看一下相对简单一点的多态的相关知识以及实现原理RTTI相关的知识。
多态
什么是多态
首先明确一点我们在这里只考虑运行时多态,而不考虑编译时多态(方法重载)。因此下列多态默认都是指运行时多态。
多态是面向对象编程里面的概念,一个接口的多种不同的实现方式,即为多态。注意这里的接口,不应理解得太死板,比如在java里面,继承一个类和实现一个接口本质上都是一种继承行为,因此都应该理解为多态的体现。
在计算机的世界里,尤其是编程的世界里,多态体现在:只有在运行的时候才知道引用变量所指向的具体实例对象。且有三个必要的条件:
- 继承
- 重写/实现
- 父类引用指向子类对象
多态的概念来源于生活,生活中的很多现象都是多态的体现,例如打印机,打印功能可以打印黑白色也可以打印彩色。同一款汽车可以用2.0l排量也可以有1.0l的排量。
多态的技术带来的一个重要影响是:由于一个借口可能有多个实现,而每个实现之间的大小,规模,是不一样的。因此多态对内存的分配是有影响的,不同的实现会有不同的内存分配. 这一点与现实世界的多态例子相比就会非常有意思,第一,我们会发现软件里的多态是动态的多态,而现实世界里的多态大部分是一个预先设定好的多态体现,现实里的多态更多的类似于编译时多态,即方法重载,例如打印机的例子。
java里多态的具体用法
如上面我们提到的一样多态通常有两种实现方法:
- 子类继承父类(extends)
- 类实现接口(implements)
核心之处就在于对父类方法的改写或对接口方法的实现,以取得在运行时不同的执行效果。要使用多态,在声明对象时就应该遵循一条法则:声明的总是父类类型或接口类型,而创建的是实际类型.
以ArrayList为例子,要使用多态的特性,要按照如下方式定义
List list = new ArrayList();
此外,在定义方法参数时也通常总是应该优先使用父类类型或接口类型,例如:
public void test(List list);
这样声明最大的好处在于它的灵活性,假如某一天ArrayList无法满足要求,我们希望用LinkedList来代替它,那么只需要在对象创建的地方把new ArrayList()改为new LinkedList即可,其它代码一概不用改动。
多态的实现原理与RTTI
RTTI,即Run-Time Type Identification运行时类型认定,通过运行时类型信息程序能够使用父类的指针或引用来检查这些指针或引用所指的对象的实际派生类型,是多态实现的技术基础。RTTI的功能主要是通过Class类文件实现的,更精确一点是通过Class类文件的方法表实现的。
Class类是"类的类"(class of classes)。如果说类是对象的抽象的话,那么Class类就是对类的抽象。Class对象就是用来创建一个类的所有的常规对象的。每个类都有一个Class对象,每当编写好并且编译了一个新的类,就会生成一个它对应的Class对象,被保存在一个与类同名的.class文件中。java虚拟机中的被称为类加载器的子系统,就是专门拿来做生成这个类的Class对象的工作的。关于类加载器,请参考这篇博客:[JVM]虚拟机类加载机制
每一个Class类的对象代表一个特定的类。请看如下代码
import java.lang.Class;
public class Test {
public static void main(String[] args) throws ClassNotFoundException {
Cycle unicycle = new Unicycle("Unicycle");
Cycle.ride(unicycle);
Class c1 = unicycle.getClass();//获取clas对象
System.out.println(c1.getName());
Cycle bicycle = new Bicycle("Bicycle");
Cycle.ride(bicycle);
Class c2 = Class.forName("basic.Bicycle");//获取clas对象
System.out.println(c2.getName());
Cycle tricycle = new Tricycle("Tricycle");
Cycle.ride(tricycle);
Class c3 = Tricycle.class;//获取clas对象
System.out.println(c3.getName());
}
}
//父类
class Cycle {
private String name;
public Cycle(String str) {
name = str;
}
public static void ride(Cycle c) {
System.out.println(c.name + "is riding");
}
}
class Unicycle extends Cycle {
private String name;
public Unicycle(String str) {
super(str);
name = str;
}
}
class Bicycle extends Cycle {
private String name;
public Bicycle(String str) {
super(str);
name = str;
}
}
cla