目录
引序
说不通1:注解
说不通2:匿名内部类
说不通3:动态代理
反射:
反射定义
强调:类对象
又强调:static 类静态成员
再三强调:synchronized 修饰符
类对象:知晓类结构
类结构之:内部成员
内部成员--构造函数
内部成员--数据成员
内部成员--方法成员
静态代理:
动态代理:
反射 + 注解
反射 + 泛型 + 注解
getGenericSuperclass()用法
引序:开始反射概念学习之前,先来段引序。
请牢记:计算机的三大程序结构;顺序执行结构、条件分支结构、循环处理结构。
有时我们写的程序会自我感觉这里写了代码,它是怎么被调度执行的呢,按照程序的顺序执行来考究,有点说不通。我举几个例子说明看起来说不通的现象:
import java.lang.reflect.*;
import java.lang.annotation.*;
@Retention(RetentionPolicy.RUNTIME)
@interface MyAnno{ // 注解定义
String name() default "12345";
int value();
}
@MyAnno(name="haha",value=123) // 注解钉点
class B {
public static void main(String[] args){
if( B.class.isAnnotationPresent(MyAnno.class) ){
Annotation annos[] = B.class.getAnnotations(); // 消费注解
for(Annotation anno : annos){
System.out.println(anno);
System.out.println( ((MyAnno)anno).name() );
System.out.println( ((MyAnno)anno).value() );
System.out.println( anno.annotationType().getName() );
}}}}
上面注解的小示例:如果看《注解定义》《注解钉点》 这两个地方,能搞懂我们写这两处的意思嘛?完全是懵圈的,这是什么代码,又什么时候被调度执行,咋执行的呢?正是因为有 《注解消费》 这个梗,我们才恍然大悟,注解是啥时用起来的。(这也是很多框架利用大量注解的底层技术手段,第三方框架有其自己的《注解定义》以及《注解消费》底层,开放给我们开发时用的就是“注解钉点”,我们利用好《注解钉点》这一点就OK)
匿名内部类:作为方法的入参来使用,例如:
1:事件监听处理器类:处理事件时作为监听处理器方法的形参的Handler类
event.addEventListener( new Handler() { //这里的Handler就是匿名内部类
public void xxxMethed(Event event){ //这是匿名类中的方法xxxMethod();
}
}); //这个xxxMtd()是由事件调度线程来执行的。
以上代码我们只是调用了addEventListener(Handler hd); 传进来一个hd对象而已,那么Handler类中的xxxMethod()方法怎么会被调用的呢?答:是被事件调度线程来执行的。事件调度线程是JVM管理的,不受我们的代码控制。
2:多线程编程时的任务类:往线程池当中提交一个实现了Runnable接口的类
threadPoolExecutor.execute( new Runnable() { // Runnable是匿名内部类
public void run(){ } // 匿名类中的方法run();
}); // 这个run()是由线程池调度工作线程来执行的。
以上代码只是调用了execute(Runnable task); 传进来一个task任务而已,那么Runnable类中的run()方法怎么会被调用的呢?答:是被线程池调度工作线程来执行的。线程池是一个框架,它怎么调度和管理工作线程,不受我们的代码控制。我们“写好匿名内部类中的方法业务逻辑”这一点就OK。理解匿名内部类很重要,它是静态代理模式的一种体现。之所以匿名内部类很重要,是因为它是理解lambda函数式编程思想的基础。
import java.lang.reflect.*;
//接口
interface InterfaceHello {
void sayHello();
void read();
}
//业务类:实现接口
class HelloImpl implements InterfaceHello {
public void sayHello() {
System.out.println("hello world");
}
public void read() {
System.out.println("I am reading...");
}
}
//我是代理:业务类真正业务逻辑的前后,我搞点事(比如:打个广告)
class ProxyHello implements InvocationHandler{
private Object target;
public ProxyHello(Object target) {
this.target=target;
}
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("我是代理,看视频之前我打个广告,haha!");
Object obj = method.invoke(target,args); // 真正的业务逻辑
System.out.println("我是代理,视频看完给评价下呗,多谢!\r\n");
return obj;
}
}
//测试
public class HelloTest {
public static void main(String[]args) {
try{
InterfaceHello h = (InterfaceHello)Proxy.newProxyInstance(
HelloTest.class.getClassLoader(),
new Class>[]{InterfaceHello.class},
new ProxyHello(new HelloImpl())
);
h.sayHello(); // 调用InterfaceHello接口中的sayHello()方法
h.read(); // 调用InterfaceHello接口中的read()方法
}
catch(Exception e){}
}
}
程序输出:
我是代理,看视频之前我打个广告,haha!
hello world
我是代理,视频看完给评价下呗,多谢!
我是代理,看视频之前我打个广告,haha!
I am reading...
我是代理,视频看完给评价下呗,多谢!
如果单看以上的测试类:h.sayHello(); 这句代码,是蒙圈的,因为按照我们以往的程序经验,这不就是实现了InterfaceHello接口的HelloImpl干的事嘛,但是程序的输出却不是这样,前有广告,中间是正事,后有评论。为什么这样呢?是因为:h是Proxy.newProxyInstance()出来的,下面简要分析下:
Proxy.newProxyInst