java进阶
- 注解
- 内置注解
- 元注解
- 自定义注解
- 对象克隆
- 浅克隆
- 深克隆
- java设计模式
- 建模语言
- 类之间的关系
- 依赖关系
- 关联关系
- 单向关联
- 双向关联
- 自关联
- 聚合关系
- 组合关系
- 继承关系
- 实现关系
- 面向对象设计原则
- 单一职责
- 开闭原则
- 里氏替换原则
- 依赖倒置
- 接口隔离
- 迪米特原则
- 组合/聚合复用原则
注解
java注解又叫java标注,Java 语言中的类、方法、变量、参数和包等都可以被标注。
java注解,可以通过反射来获取注解内容,可以在编译期间使用,也可以被编译到字节码文件中,运行时生效.支持自定义注解
内置注解
java已经定义好的注解,比如
@Override:重写方法注解
@Deprecated:标记过时注解
@SuppressWarnings - 指示编译器去忽略注解中声明的警告。
@FunctionalInterface 用于指示被修饰的接口是函数式接口
元注解
元注解是由java API提供的,用于修饰注解,比如:
@Retention - 标识这个注解怎么保存,是只在代码中,还是编入 class 文件中,或者是在运行时可以通过反射访问。
@Documented - 标记这些注解是否包含在用户文档中。
@Target - 标记这个注解应该是哪种 Java 成员。
@Inherited - 标记这个注解是继承于哪个注解类(默认注解并没有继承于任何子类)
@Repeatable - 标识某注解可以在同一个声明上使用多次。
重点:@Target - 标记这个注解应该是哪种 Java 成员。
ElementType.TYPE 可以应用于类的任何元素。
ElementType.CONSTRUCTOR 可以应用于构造函数。
ElementType.FIELD 可以应用于字段或属性。
ElementType.LOCAL_VARIABLE 可以应用于局部变量。
ElementType.METHOD 可以应用于方法级注释。
ElementType.PACKAGE 可以应用于包声明。
ElementType.PARAMETER 可以应用于方法的参数
@Retention:@Retention 定义了该注解被保留的时间长短,用于注解的生命周期
1.SOURCE:在源文件中有效(即源文件保留)
2.CLASS:在 class 文件中有效(即 class 保留)
3.RUNTIME:在运行时有效(即运行时保留)
自定义注解
1.自定义注解
@Target(ElementType.FIELD)//作用在类的属性上
@Retention(RetentionPolicy.RUNTIME)//运行时生效
public @interface NotNull {
//定义注解属性
String message() default "";
int length() default 0;
String lengthmessage() default "";
}
2.使用自定义注释
@NotNull(message="姓名不能为空",length=3,lengthmessage="长度不能小于3")
private String name;
3.解析注释
User user = new User();
user.setName("jiim");
//反射解析注解
Field[] fields = user.getClass().getDeclaredFields();//获取所有的属性
for (Field field : fields) {
//获取属性的注解
NotNull notNull = field.getAnnotation(NotNull.class);
if (notNull != null) {
Method m = user.getClass().getMethod("get" + getMethodName(field.getName()));
Object value=m.invoke(user);//调用get方法 获取属性值
//name值为空,抛出异常
if (value==null) {
System.err.println(field.getName() +notNull.message());
throw new NullPointerException(notNull.message());
}else{
//判断name值的长度
if(String.valueOf(value).length()<(notNull.length())){
System.err.println(field.getName() +notNull.lengthmessage());
}
}
}
}
对象克隆
对象克隆是指创建一个新的对象,新的对象拥有之前对象内容。
如何是实现克隆
实现Cloneable接口,重写Object类中的clone方法就可以实现克隆,克隆分为浅克隆和深克隆,浅克隆和深克隆的主要区别在于是否支持引用类型的成员变量的复值
浅克隆
浅克隆克隆值类型的成员变量克隆的是值,克隆引用类型的成员变量克隆的是对象地址。
//重写clone方法
@Override
protected Person clone() throws CloneNotSupportedException {
Person person = (Person)super.clone();
return person;
}
Person p1 = new Person(100,"jim");
Person p2 =p1.clone();//克隆的新对象
实现方式:
1.在 Java 语言中,通过覆盖 Object 类的 clone()方法可以实现浅克隆。
2.在 spring 框架中提供 BeanUtils.copyProperties(source,target);
深克隆
深克隆中,无论原型对象的成员变量是值类型还是引用类型,都将复制一份给克隆对象,深克隆将原型对象的所有引用对象也复制一份给克隆对象。简单来说,在深克隆中,除了对象本身被复制外,对象所包含的所有成员变量也将复制。
实现方式:
- 类 实现Cloneable接口, 重写Object中的clone方法.(在多级关联时,处理起来比较麻烦)
//Address对象中重写clone方法
@Override
protected Address clone() throws CloneNotSupportedException {
return (Address)super.clone();
}
//重写Person对象的clone方法
@Override
protected Person clone() throws CloneNotSupportedException {
Person person = (Person)super.clone();
person.address = (Address)address.clone(); //深度复制 联同person中关联的对象也一同克隆.
return person;
}
2.使用序列化方式,可以重写创建对象,包含关联的对象。
/**
* 自定义克隆方法
* @return
*/
public Person myclone() {
Person person = null;
try { // 将该对象序列化成流,因为写在流里的是对象的一个拷贝,而原对象仍然存在于JVM里面。所以利用这个特性可以实现对象的深拷贝
ByteArrayOutputStream baos = new ByteArrayOutputStream();
ObjectOutputStream oos = new ObjectOutputStream(baos);
oos.writeObject(this);
// 将流序列化成对象
ByteArrayInputStream bais = new ByteArrayInputStream(baos.toByteArray());
ObjectInputStream ois = new ObjectInputStream(bais);
person = (Person) ois.readObject();
} catch (IOException e) {
e.printStackTrace();
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
return person;
}
解决多层克隆问题:我们可以用序列化的方式来实现对象的深克隆,来解决多层克隆的问题
java设计模式
软件设计模式,又称设计模式,它是被反复使用、代码设计经验的总结。它描述了在软件过程中重复发生的问题,以及该问题的解决方案。
设计模式的本质是面向对象设计原则的实际运用,是对类的封装性、继承性和多态性以及类的关联关系和组合关系的充分理解。
优点:提高程序员的思维能力、编程能力和设计能力
使程序设计更加标准化、提高软件开发效率
设计的代码重用性高、可读性强、可维护性强
建模语言
统一建模语言(UML)是一种用于软件系统分析和设计的语言工具。
UML图:通过不同的图形和符号,来描述软件模型以及各个元素之间的关系
类图(Class diagram)是一种静态的结构图,描述了系统的类的集合,类的属性和类之间的关系。类图是系统分析和设计阶段的重要产物。
类之间的关系
在软件系统中,类不是孤立存在的,类与类之间存在各种关系。根据类与类之间的耦合度从弱到强排列,UML 中的类图有以下几种关系:依赖关系、关联关系、聚合关系、组合关系、泛化关系和实现关系。其中泛化和实现的耦合度相等,它们是最强的。
依赖关系
依赖关系是一种使用关系,它是对象之间耦合度最弱的一种关联方式,是临时性的关联。在代码中,某个类的方法通过局部变量、方法的参数或者对静态方法的调用来访问另一个类(被依赖类)中的某些方法来完成一些职责。
在 UML 类图中,依赖关系使用带箭头的虚线来表示,箭头从使用类指向被依赖的类。下图所示是人与手机的关系图,人通过手机的语音传送方法打电话。
关联关系
关联关系是对象之间的一种引用关系,用于表示一类对象与另一类对象之间的联系,如老师和学生、师傅和徒弟等。关联关系是类与类之间最常用的一种关系,分为一般关联关系、聚合关系和组合关系。
关联又可以分为单向关联,双向关联,自关联
单向关联
在 UML 类图中单向关联用一个带箭头的实线表示。上图表示每个顾客都有一个地址,这通过让 Customer 类持有一个类型为 Address
双向关联
从上图中我们很容易看出,所谓的双向关联就是双方各自持有对方类型的成员变量。上图中在 Customer 类
中维护一个 List,表示一个顾客可以购买多个商品;在 Product 类中维护一个 Customer 类型的成员变量表示这个产品被哪个顾客所购买
自关联
自关联在 UML 类图中用一个带有箭头且指向自身的线表示。上图的意思就是Node 类包含类型为 Node 的成员变量,也就是“自己包含自己”。
聚合关系
聚合关系是关联关系的一种,是强关联关系,是整体和部分之间的关系。聚合关系也是通过成员对象来实现的,其中成员对象是整体对象的一部分,但是成员对象可以脱离整体对象而独立存在。例如,学校与老师的关系,学校包含老师,但如果学校停办了,老师依然存在。
组合关系
组合表示类之间的整体与部分的关系,但它是一种更强烈的聚合关系。在组合关系中,整体对象可以控制部分对象的生命周期,一旦整体对象不存在,部分对象也将不存在,部分对象不能脱离整体对象而存在。例如,头和嘴的关系,没有了头,嘴也就不存在了
继承关系
继承关系是对象之间耦合度最大的一种关系,表示一般与特殊的关系,是父类与子类之间的关系,是一种继承关系,是 is-a 的关系
实现关系
实现关系是接口与实现类之间的关系。在这种关系中,类实现了接口,类中的操作实现了接口中所声明的所有的抽象操作。
面向对象设计原则
单一职责
单一职责原则是最简单的面向对象设计原则,它用于控制类的粒度大小。简单来说,就是一个类只负责一个功能领域中的职责。
优点:低耦合、高内聚。
开闭原则
开闭原则即扩展开发,对修改封闭,简单来说就是在项目种增加新的业务功能时,不会修改原来的代码,而是通过增加类的方式来是实现新的业务功能。抽象化是开闭原则的关键。
优点:提高了可复用性可维护性
里氏替换原则
定义:所有使用父类的地方必须能透明地使用其子类对象,简单来说就是使用父类地地方子类也能使用。
所以遵循里氏替换原则时,子类继承父类时,不能重写父类的方法。
作用:是实现开闭原则的重要方式之一,克服了继承种重写父类方法造成的可复用性变差的缺点,降低需求变更时引入的风险。
依赖倒置
依赖倒置原则定义:上层模块不应该依赖底层模块,它们都应该依赖于抽象。简单来说就是要求对抽象进行编程,不要对实现进行编程。
接口隔离
使用多个接口,而不使用单一的总接口,不强迫新功能实现不需要的方法。
迪米特原则
迪米特原则又叫做最小知识原则,它要求一个对象应该对其他对象有最少的了解。只和你的直接朋友交谈。
直接朋友:
1.类中的成员属性
2.在类中的方法作为参数使用
3.在类中的方法作为返回值类型。
注意事项:
-
迪米特法则的核心是降低类之间的耦合
-
从被依赖者的角度来说,尽量将逻辑封装在类的内部,对外除了提供的public 方法,不泄露任何信息
-
从依赖者的角度来说,只依赖应该依赖的对象
-
切忌不要为了用而用
组合/聚合复用原则
优先使用组合,使系统更灵话,其次才考虑继承,达到复用的目的
使用继承,为了复用父类中的方法,但是类与类的耦合性高.可以使用关联/依赖,在一个类中达到复用别的类中的方法.
总结
- 开闭原则:要求对扩展开放,对修改关闭
- 里氏替换原则:不要破坏继承体系
- 依赖倒置原则:要求面向接口编程
- 单一职责原则:实现类职责要单一
- 接口隔离原则:在设计接口的时候要精简单一
- 迪米特法则:只与直接的朋友的通信
- 组合/聚合原则:尽量使用聚合和组合的方式,而不是使用继承
设计原则的核心思想就是为了让程序高内聚,低耦合。