一、Java进阶
1.注解(Annotation)
最早使用的注解 方法重写 @Override(表明从父类重写过来的)
Java中的注解也称标注,可以用来对类,方法,属性,参数,包等进行标注,然后让编译器或运行时其他类进行解析,完成某个功能。注解也可以编译到字节码文件中。
a.内置注解
Java中已经定义好的注解。
- @Override - 检查该方法是否是重写方法。如果发现其父类,或者是引用的接
口中并没有该方法时,会报编译错误。 - @Deprecated - 标记过时方法。如果使用该方法,会报编译警告。
- @SuppressWarnings - 指示编译器去忽略注解中声明的警告。
- @FunctionalInterface 用于指示被修饰的接口是函数式接口。
b.元注解
由JavaApi提供的,用于修饰注解的注解,通常在注解的定义上。
- @Target 用于描述注解的使用范围(即:被描述的注解可以用在什么地方。)
ElementType.TYPE 可以应用于类的任何元素。
ElementType.CONSTRUCTOR 可以应用于构造函数。
ElementType.FIELD 可以应用于字段或属性。
ElementType.LOCAL_VARIABLE 可以应用于局部变量。
ElementType.METHOD 可以应用于方法级注释。
ElementType.PACKAGE 可以应用于包声明。
ElementType.PARAMETER 可以应用于方法的参数。
- @Retention 注解生效范围
- SOURCE:在源文件中有效(即源文件保留)
- CLASS:在 class 文件中有效(即 class 保留)
- RUNTIME:在运行时有效(即运行时保留)
c.自定义注解
2.对象克隆
对象克隆—对象复制
将一个已经存在的对象以及对象数据克隆到另一个对象中,类实现Cloneable接口 重写Object 类中clone(),在重写的clone方法中,调用父类clone方法返回一个对象
克隆方法:
- 浅克隆:克隆一个对象时,如果对象中有关联的对象,只将关联对象的地址复制过来。
- 深克隆:克隆一个对象时,如果对象中有关联的对象,将关联的对象也一块克隆(创建一个新的)。
如何做到深克隆:
- 在每一层中都重写clone方法,类实现Coneable接口,层级多了就比较麻烦
- 序列化方式:对象输入和输出流
3. Java设计模式(Java design patterns)
a.软件设计模式概念
设计模式概念:在实际开发中,经常出现的问题,进行总结,优化后的解决方案。
本质:面向对象设计的实际运用,是对类的封装性,继承性和多态性以及类与类之间关系的应用。可以提高设计能力;有助于阅读源码;提高程序设计的复用性,可读性,可拓展性(在程序后期添加新功能时,改动成本最低,尽量不影响之前的功能)
b.建模语言(UML)
是一种帮助开发人员进行设计的语言,使用图形符号来表示各模块之间的关系。
Java基本关系:
类
接口
类与类之间的关系:
1. 依赖关系:在一个类的方法中,使用到了另一个类,具有临时性。
2. 关联关系 :把一个类当做另一个类的属性
组合中还可以根据强弱关系程度分为组合,聚合关系
3. 继承关系
4. 实现关系
c.面向对象设计原则
① 单一职责原则:一个类不要负责太多的事情,否则会使内部耦合度太高,不利于拓展
优点:低耦合、高内聚
② 开闭原则:对拓展开放,对修改封闭,不建议修改原有的代码,建议通过扩展一个新的类实现新的功能。
优点:适用性、灵活性、
③里氏替换原则:
继承优势:提高代码复用性,可拓展性
劣势:侵入性,父类修改会影响子类
定义:在使用重写父类方法时,不要在重写后对子类运行产生影响。子类调用的是父类的方法,重写后,0替换成自己的重写的方法,造成结果被影响。
在使用父类时,可以换成子类
④接口隔离:可以根据不同的功能设计接口,不要将所有的功能涉及到一个接口中
⑤依赖倒置:有多个同类型事物时,可以抽取一个共同的抽象层,具体的实现细节依赖于抽象。
⑥迪米特原则:一个对象应该对其他对象有最少的了解(最少知识原则),跟你不相关的对象就不要在你的类里面存在。
⑦组合/聚合复用原则:优先使用组合,使系统更灵活,其次再考虑继承,达到复用的目的。
在某些情况下,B类中只使用A类中的方法,可以不用使用继承关系,可以在B中关联A,调用A中的方法;还可以在B中依赖A。
d.设计模式
设计模式:Java中设计模式共23种。
分为三类:
- 创建型:如何创建对象,特点:将对象的创建与使用分离
单例模式:解决一个类在一个程序中保证只能创建一个对象。如:Windows任务管理器窗口,只需要创建一个
这个对象由单例类自己创建,并向外提供访问方法。实现方式有两种:
1. 饿汉式(急切式):在类加载时就把唯一单例对象就创建好了,不存在线程安全问题
2. 懒汉式单例:在类加载时,并不创建单例对象,在第一次获取单例对象时才创建,存在线程安全问题如果同时有多个线程访问,有可能多个线程同时进入到if条件中,跳过条件,创建多个对象。可以给方法加锁(加synchronized)虽然能解决问题,但是并发访问效率变低,一次只能进一个线程。
解决办法:双层检索加volatile
工厂模式:
- 简单工厂模式
有一个工厂类,负责生产某一类产品,同一类产品,具备同一个抽象父类(抽象类,接口),将创建对象与使用对象分离(spring的设计思想),违背开闭原则,添加一个产品就需要修改工厂代码。 - 工厂方法模式
对工厂进行抽象,一个抽象的产品对应一个抽象的工厂,一个具体的产品对应一个具体的工厂,一个具体的工厂负责生产一个具体的产品,需要扩展新产品,只需要添加新的具体产品类和新的生产该产品的具体工厂类即可,不需要修改原的工厂,符合开闭原则。 - 抽象工厂模式
抽象工厂负责一系列产品(某一个公司产品 某为手机 某为汽车),在抽象工厂中定义生产不同的产品,具体的工厂负责生产一系列公司的一系列产品
原型模式:
在开发过程中,需要创建多个相同的对象,每次使用new创建开销比较大,使用对象克隆,在先创建出来的原型对象为模板,进行对象的克隆复制,提高创建的效率。如:简历,写一份,复制多份;奖状,复制多份,学校信息一致,只需修改名字即可。
- 结构型:
- 代理模式
目标对象的代理者,帮助目标(实际执行者)完成额外的功能,而不用修改目标代码。
如:汽车厂卖汽车,不需要自己卖,可以让4S店代理去卖。
优点:将目标与添加的功能相分离,保护目标对象,耦合度降低,增加新的功能不需要修改目标对象。
代理实现可分为静态代理和动态代理。
- 静态代理:一个代理类可以对某一类的目标提供代理,满足开闭原则(添加一类目标时,可以扩展添加一个新的代理类),但是对于框架场景就不太适合,代码是写死的,不够灵活,因为框架要对任意的类进行代理,静态代理就不能满足需求了,在我们的项目中,如果只对某对象进行代理,可以进行静态代理。
- 动态代理:在运行时可以动态创建代理类,分为jdk代理和cglib代理
- jdk代理:创建一个代理对象生成器,实现InvocatiionHandler,重写invoke方法,此方法会被代理动态调用。代理对象在运行时,被动态的创建,可以代理任意的目标对象,提高灵活度,但是被代理的目标对象,必须实现一个接口, 在生成代理对象时,需要提供接口来获取目标对象信息,底层实现使用的是反射机制。
- cglib代理:实现时不需要目标类实现接口,采用动态字节码生成技术,为我们的目标类生成一个子类对象,当调用方法时,对方法进行拦截,调用目标类的方法。
要求目标类不能是final修饰,方法也不能是final/static修饰的。 - spring框架中俩种代理生成机制都实现了。
可以根据目标是否实现接口,自动选择生成代理对象的方式,默认采用cglib代理方式生成。
- 适配器模式
在两个互不相同的事物之间提供一个转换,使得两者可以互通。比如:读卡器,电脑没有专门的SD卡接口,出现了读卡器,实现了SD卡和电脑之间连接。
- 模板方法模式
在程序开发中,有些实现步骤是固定的,可以抽取父类,在父类中实现各个步骤,再在父类中定义一个流程控制方法,在此方法中按照步骤调用执行,可以将某个容易发生变化的步骤定义为抽象方法,针对不同的情况,可以扩展一个子类实现抽象的方法,最终由子类对象调用父类中流程控制的方法就行。 - 策略模式
可以将同一种功能不同实现细节先抽取一个抽象接口/抽象类然后把不同的实现让子类继承实现,最终选择时,只需要选择不同的子类即可,将不同的实现封装到不同的子类中。 - 观察者模式
定义了一种一对多的依赖关系,让多个观察者对象同时监听某一个主题对象。
例如:微信公众号有新内容更新的话,它就会推送给关注公众号的微信客户端,微信用户就是观察者,微信公众号是被观察者,可以实现广播机制。
总结
面向对象设计原则
- 开闭原则:要求对扩展开放,对修改关闭
- 里氏替换原则:不要破坏继承体系
- 依赖倒置原则:要求面向接口编程
- 单一职责原则:实现类职责要单一
- 接口隔离原则:在设计接口的时候要精简单一
- 迪米特法则:只与直接的朋友的通信
- 合成复用原则:尽量使用聚合和组合的方式,而不是使用继承