1. 反射
反射:通过对象求出类的名称,加载完类之后,堆内存方法区中产生了Class对象,通过这个对象看到类的结构就被称为反射
java通过反射机制获得动态性,变为准动态语言
Reflection API使程序执行期间可以取得任何类的内部信息,并能直接操作对象的内部属性和方法
1.1 反射的相关概念
new和反射的区别:
- 反射的特征是动态性,编译时不确定怎么new,就选择反射
反射与封装性:
- 反射使程序员具备这些能力,但是public、private表明了程序建议怎么使用
类的加载过程:
- 程序经过javac.exe命令生成一个或多个字节码文件.class
- 使用java.exe命令对某个字节码文件解释运行,相当于把该文件加载到内存中
- 加载到内存中的类被称为运行时类,作为Class的一个实例,即Class的实例对应着一个运行时类
- 运行时类会缓存一定时间,在此过程中通过不同方式获取的Class实例是同一个运行时类
主要使用反射的方式:
- 调用Class的静态方法forName(String classPath)获取运行实例
Class实例的说明:
类加载器分类:
- 引导类加载器:C++编写,JVM自带,装载核心类库,无法获取 – String
- 扩展类加载器:负责jre/lib/ext目录下的jar包装载
- 系统类加载器:负责java-classpath目录下的类与jar包装载,最常用
1.2 动态代理
代理设计模式:
使用一个代理将对象包装起来, 然后用该代理对象取代原始对象。任何对原始对象的调用都要通过代理。代理对象决定是否以及何时将方法调用转到原始对象上。
实现动态代理需要解决的问题:
- 如何根据加载到内存中的被代理类动态创建一个代理类及其对象?
- 代理类对象调用方法时如何动态的调用被代理类的同名方法?
- AOP:面向切面编程,利用动态代理实现:
动态代理示例代码:
interface Human{
String getBelief();
void eat(String food);
}
class SuperMan implements Human{
@Override
public String getBelief() {
return "I can fly";
}
@Override
public void eat(String food) {
System.out.println("我喜欢吃" + food);
}
}
class MyInvocationHandler implements InvocationHandler{
private Object obj;
public void bind(Object obj){
this.obj = obj;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("通用方法1");
Object invoke = method.invoke(obj, args);
System.out.println("通用方法2");
return invoke;
}
}
class ProxyFactory{
public static Object getProxyInstance(Object obj){
MyInvocationHandler handler = new MyInvocationHandler();
handler.bind(obj);
return Proxy.newProxyInstance(obj.getClass().getClassLoader(), obj.getClass().getInterfaces(), handler);
}
}
public class ProxyTest {
public static void main(String[] args) {
SuperMan jack = new SuperMan();
Human human = (Human) ProxyFactory.getProxyInstance(jack);
human.eat("氪石");
System.out.println(human.getBelief());
}
}
2. 其它新特性
lambda表达式、Stream API等新特性目前可以看懂即可,需要时再学习。
|