Java Reflection And Features Notes

反射——依赖注入框架原理


抽象工厂方法,FactoryBean.getBean(“”)  –>  Class.forName(“”). newInstance()
forName()是静态方法
单例Singleton(饱汉、饿汉)

  • 创建对象
    this.class.getClassLoader.loadClass(""). newInstance();
    此处写XML配置,利用properties对象读入inputStream,读取配置作为className
    三个类: Class/Field/Method  
    clazz.getMethod()  getField();    field.get(Object obj)     method.invoke(Object obj, Object… args)
  • 类装载器,父类加载,委托  
graph TD
A[BootStrap ClassLoader] -->B(ExtClassLoader)
B[ExtClassLoader] -->C(AppClassLoader)
C[AppClassLoader] -->D(Custom Loader)

动态代理 

动态代理是基于什么原理

反射机制是 Java 语言提供的一种基础功能,赋予程序在运行时自省(introspect,官方用语)的能力。通过反射我们可以直接操作类或者对象,比如获取某个对象的类定义,获取类声明的属性和方法,调用方法或者构造对象,甚至可以运行时修改类定义。
动态代理是一种方便运行时动态构建代理、动态处理代理方法调用的机制,很多场景都是利用类似机制做到的,比如用来包装 RPC 调用、面向切面的编程(AOP)。
实现动态代理的方式很多,比如 JDK 自身提供的动态代理,就是主要利用了上面提到的反射机制。还有其他的实现方式,比如利用传说中更高性能的字节码操作机制,类似 ASM、cglib(基于 ASM)、Javassist 等。
@w=300

在静态代理基础上,静态代理没有引入Proxy类,需手动编码把被代理类作为属性引入

java代理,代理有2种,一种是jdk,代理与目标实现同一个接口,一种是CGLIB代理继承目标类
我们先关注jdk动态代理:

  1. 创建一个有相同接口的代理类Proxy—-JDK自动生成字节码。该代理类有一个属性invocationHandler,并有带该入参的构造方法   
Class proxy = Proxy.getProxyClass(  Foo.class.getClassLoader(),     new Class[] { Foo.class }  );
  1. 创建新类 invocationHandler,实现invocationHander接口的invoke(Proxy, method,  args)方法实现
InvocationHandler invocationHandler = new MyInvocationHandler implements InvocationHandler( public Object invoke() ); 
//实现 invoke()方法
  1. 实例化一个Proxy,参数是invocationHandler
//取带参数的构造方法,创建对象时传入参数
proxy.getConstructor( new Class[]{  InvocationHandler.class }  ).newInstance( invocationHandler );     

优化二: 2和3合成一步,匿名内部类
            
优化三:1、2、3合成一步

Proxy.newInstance( ClassLoader, new Class[]{  InvocationHandler.class }, new InvocationHandler({ public Object invoke( Object proxy, Method method, Object[] args ){} }))

spring的aop基础源码(面向切面编程)

框架原理:动态代理   target–advice   日志、安全、事务

Class.for("proxyFactoryBean").newInstance() 
proxyFactoryBean.setAdvice(advice); 
proxyFactoryBean.setTarget(target);
  1.   proxyFactoryBean.getProxy()    
    有2个成员属性advice,target,这2个属性可在xml里配置,也是反射,通过构造方法注入。getProxy()方法里包含动态代理的代码, 
  2.   proxy的invoke方法已经加进了
advice.beforMethod();
method.invoke(target, args);
advice.afterMethod();
  1.   我们的任务是写
MyAdvice implements Advice{
    public beforeMethod(){
        //doSomething();
    }
    public afterMethod(){
        //doSomething();
    }
}

枚举

枚举是抽象abstract类,有一个默认属性name,每个值(public)是类的一个实例对象.
枚举是一种特殊的类,其中的每个元素都是该类的一个实例对象
构造方法是私有的,
枚举类中可包含方法: 1.实现普通的next方法
2.实现抽象的next方法: 每个元素分别是由枚举类的子类来生成的实例对象,这些子类采用类似内部类的方式进行定义。

泛型

jdk1.5引入泛型
泛型提供给javac编译器使用,限定集合中的输入类型,在编译后会擦除。
除了集合使用泛型,反射中Class,Constructor也使用泛型,标记属于什么类,减少类型转换的操作
通配符<? extends Object> 上边界  下边界
1.泛型集合
     Collection collection = new ArrayList();
2.泛型方法:   由C++的模板函数引出,T代表任意类型。
     2.1 
     2.2 调用者,建议大家看看传智播客的巴巴运动网视频中的BaseDao的代码。无需对返回值进行类型转换
3.泛型类

内部类

主要有以下几类:成员内部类(在方法体里创建 有访问说明符)、局部内部类(在方法体里创建,不能有访问说明符)、静态内部类()、匿名内部类(没有类名)

  为什么需要内部类?

  典型的情况是,内部类继承自某个类或实现某个接口,内部类的代码操作创建其的外围类的对象。所以你可以认为内部类提供了某种进入其外围类的窗口。使用内部类最吸引人的原因是:

  每个内部类都能独立地继承自一个(接口的)实现,所以无论外围类是否已经继承了某个(接口的)实现,对于内部类都没有影响。如果没有内部类提供的可以继承多个具体的或抽象的类的能力,一些设计与编程问题就很难解决。从这个角度看,内部类使得多重继承的解决方案变得完整。接口解决了部分问题,而内部类有效地实现了“多重继承”。

内部类主要有以下几类:成员内部类、局部内部类、静态内部类、匿名内部类

super(HystrixCommand.Setter.withGroupKey(HystrixCommandGroupKey.Factory.asKey(BmapRgeoCommand.class.getSimpleName())),        config, client, query);

Java异常与错误

  • Exception
    • checked 编译器检查
    • IOException
    • unchecked 运行时异常
    • NullPointerException
    • ArrayIndexOutOfBoundsException
    • ClassNotFoundException
    • RuntimeException
  • Error
    • OutOfMemoryError 内存溢出错
    • NoClassDefFoundError

Java的checked exception总是被诟病,可我是从C#转到Java开发上来的,中间经历了go,体验过scala。我觉得Java这种机制并没有什么不好,不同的语言体验下来,错误与异常机制真是各有各的好处和槽点,而Java我觉得处在中间,不极端。当然老师提到lambda这确实是个问题…至于响应式编程,我可以泛化为异步编程的概念嘛?一般各种异步编程框架都会对异常的传递和堆栈信息做处理吧?比如promise/future风格的。本质上大致就是把lambda中的异常捕获并封装,再进一步延续异步上下文,或者转同步处理时拿到原始的错误和堆栈信息

谈谈 final、finally、 finalize 有什么不同?

final修饰类,变量,方法,表示不可继承,修改,重载
finally是异常捕捉后执行的语句
finalize是GC内存回收
【final关键字的具体应用】:
【final+变量】:       不能被修改 在实际应用中,这种形式是非常少见的。 比如logger是可以的,但是貌似并不是非常实用,或许用户仍然希望通过setter来改变logger变量。
【static+final+变量】:     1、编译期常量,永远不可改变。2、运行期初始化时,我们希望它不会被改变。常量。经常使用
【final+方法】:      不能被重写,仍然可以继承这个方法,也就是说可以直接使用。JDK中常用,但是开发者并未常用。
【final+类】:         不能被继承, helper类经常使用。
【final用于匿名内部类的参数传递】:
        在多线程测试时,经常使用。{内部类不能访问局部变量,局部变量需加final }
【final用于方法的参数】: 并不常用。

对比Hashtable、HashMap、TreeMap有什么不同?

HashMap 的设计和实现细节,相应的源码解读,
hashMap的,数组加链表,桶,负载因子与容量,哈希碰撞
并发,无限循环,消耗cpu
HashMap 的性能表现非常依赖于哈希码的有效性,请务必掌握 hashCode 和 equals 的一些基本约定

谈谈接口和抽象类有什么区别?

abstract
interface

定义出语法基本正确的接口、抽象类或者相关继承实现,涉及重载(Overload)、重写(Override)
我们一定要清楚面向对象的基本要素:封装、继承、多态。

  • Single Responsibility
  • Open-Close
  • Liskov Substitution
  • Interface Segregation
  • Dependency Injection
    S.O.L.I.D 原则。单一职责(Single Responsibility),类或者对象最好是只有单一职责,在程序设计中如果发现某个类承担着多种义务,可以考虑进行拆分。
    开关原则(Open-Close, Open for extension, close for modification),设计要对扩展开放,对修改关闭。换句话说,程序设计应保证平滑的扩展性,尽量避免因为新增同类功能而修改已有实现,这样可以少产出些回归(regression)问题。
    里氏替换(Liskov Substitution),这是面向对象的基本要素之一,进行继承关系抽象时,凡是可以用父类或者基类的地方,都可以用子类替换。
    接口分离(Interface Segregation),我们在进行类和接口设计时,如果在一个接口里定义了太多方法,其子类很可能面临两难,就是只有部分方法对它是有意义的,这就破坏了程序的内聚性。对于这种情况,可以通过拆分成功能单一的多个接口,将行为进行解耦。在未来维护中,如果某个接口设计有变,不会对使用其他接口的子类构成影响。
    依赖反转(Dependency Inversion),实体应该依赖于抽象而不是实现。也就是说高层次模块,不应该依赖于低层次模块,而是应该基于抽象。实践这一原则是保证产品代码之间适当耦合度的法宝。

数据库事务

  • 原子性 所有操作要么全成功,要么回滚全失败
  • 一致性 数据库的多表数据的完整性和一致性
  • 隔离性 并发过程,各线程相互隔离互不影响 > 并发问题:脏读;幻读;不可重复读
    • 隔离级别:读未提交
    • 读已提交
    • 可重复读
    • 串行化
  • 持久性 数据的改变就是永久性,不会丢失

访问符号

访问权限 子类其他包
public  ∨  ∨ ∨   ∨
protect  ∨  ∨ ∨ ×
default ∨  ∨ ×  ×
private ∨ × ×  ×

Http协议与Tcp/IP协议

TCP 建连与断连:TCP 的滑动窗口时,能讲到流量和拥塞控制:三次握手

参考

黄宇辰:我当时做的几个思维导图,多指导
java虚拟机
算法

多线程
集合框架
类加载


Posted

in

by

Tags:

Comments

3 responses to “Java Reflection And Features Notes”

  1. 七色彩虹 Avatar
    七色彩虹

    七色彩虹来过,点赞

Leave a Reply

Your email address will not be published. Required fields are marked *