面向对象
面向对象的三大特征
封装
继承
多态
封装
在OOP中,封装(encapsulation)是指对于某个对象,Java隐藏对象的属性和实现细节,仅对外公开接口,控制在程序中属性的读取和修改的访问级别。
封装可以被认为是一个保护屏障,防止该类的代码和数据被外部类定义的代码随机访问。
要访问该类的代码和数据,必须通过严格的接口控制。
封装最主要的功能在于我们能修改自己的实现代码,而不用修改那些调用我们代码的程序片段。
适当的封装可以让程式码更容易理解与维护,也加强了程式码的安全性。
封装的优点
- 良好的封装能够减少耦合。
- 类内部的结构可以自由修改。
- 可以对成员变量进行更精确的控制。
- 隐藏信息,实现细节。
对于想要实现的操作,一个类已经将其封装好,你只需调用方法即可,这正是OOP中的精髓。 通过封装使一部分成员充当类与外部的接口,而将其他的成员隐藏起来,这样就达到了对成员访问权限的合理控制,使不同类之间的相互影响减少到最低限度,进而增强数据的安全性和简化程序的编写工作。
继承
关键字:extend
继承是java面向对象编程技术的一块基石,因为它允许创建分等级层次的类。
继承就是子类继承父类的特征和行为,使得子类对象(实例)具有父类的实例域和方法,或子类从父类继承方法,使得子类具有父类相同的行为。
多态
多态的作用浓缩成一句话的话,应该就是降低代码耦合度了。
编译看左侧,运行看右侧
多态是通过:
- 接口 和 实现接口并覆盖接口中同一方法的几不同的类体现的 。
- 父类 和 继承父类并覆盖父类中同一方法的几个不同子类实现的。
多态有两种表现形式:方法的重载和类的重写(覆写) 首先说重载(overload),是发生在同一类中。与什么父类子类、继承毫无关系。 标识一个函数除了函数名外,还有函数的参数(个数和类型)。也就是说,一个类中可以有两个或更多的函数,叫同一个名字而他们的参数不同。 他们之间毫无关系,是不同的函数,只是可能他们的功能类似,所以才命名一样,增加可读性,仅此而已! 再说重写/覆盖(override),是发生在子类中!也就是说必须有继承的情况下才有覆盖发生(动态绑定)。 我们知道继承一个类,也就有了父类了全部方法,如果你感到哪个方法不爽,功能要变,那就把那个函数在子类中重新实现一遍。 这样再调用这个方法的时候,就是执行子类中的过程了。父类中的函数就被覆盖了。(当然,覆盖的时候函数名和参数要和父类中完全一样,不然你的方法对父类中的方法就不起任何作用,因为两者是两个函数,毫不关系)
类与对象
人类、鸟类、鱼类… 所谓类,就是对一类事物的描述,是抽象的、概念上的定义,比如鸟类,就泛指所有具有鸟类特征的动物。比如人类,不同的人,有着不同的性格、不同的爱好、不同的样貌等等,但是他们根本上都是人,所以说可以将他们抽象描述为人类。
对象是某一类事物实际存在的每个个体,因而也被称为实例(instance)我们每个人都是人类的一个实际存在的个体。
也可以理解为类是一些东西抽象出来的概念,对象(实例)就是这些东西中的一个实际存在的个体。
类--抽象的,虚拟的。
对象(实例)--现实的,存在的。
类中存在定义好属性
和方法
,根据这个类new
(创建)出来的对象(实例)则会同步拥有这些属性和方法。
类
类的定义
重要成员
- 属性:对应类中的成员变量
- 方法:对应类中的成员方法
Field = 属性 = 成员变量、Method = (成员)方法 = 函数
类中属性可以在对象创建的时候赋值
- 空类,没有方法和属性
public class Person{
//类内部可定义方法和属性
}
- 具有方法和属性的类
public class Person{
//类内部可定义方法和属性
String name;//属性
int age;//属性
String gender;//属性
private String getName(){
//方法
return name;
}
}
构造方法
构造方法能够在创建对象时调用,即使用new关键字创建对象。
Person person = new Person();//Person() 是Person类的无参构造方法
class Person{
String name;
public Person(){
}
public Person(String name){
this.name = name;
}
}
构造方法要求
- 方法名只能是它的类名。
- 构造方法没有返回值。
- 使用public修饰。
- 分为无参和有参两种类型。
this
关键字的保存的当前对象的地址值。
对象
对象的创建
new Person();//创建对象
对象的使用
对象创建后需要使用一个变量(引用类型
)来指代它,不过引用类型的变量存储的对象的引用,而不是对象本身。并且这个变量的类型需和创建的对象类型一直或是其父类。
对象引用创建后未赋值时,默认为null。
public static void main(String[] args) {
Person person = new Person();
}
当对象引用赋值给其他对象引用时,是把对象的地址复制一份,堆中的Person对象还是一个
对象与对象之间不会互相影响
方法
方法定义:
访问修饰符 返回值类型 方法名称(参数类型 参数变量,...) {
方法体...
}
示例:
public int test(int num){
return num * num;//传入一个数,返回该数的平方
}
可变参数
- 声明格式: 方法名(参数类型名...参数名)
- 可变参数:方法参数部分指定类型的参数个数是可变多个:0个、1个或多个。
- 可变个数参数的方法与同名方法之间,彼此构成重载。
- 可变参数方法的使用与方法参数部分使用数组是一致的。
- 方法的参数部分有可变形参,需要放在形参声明的最后。
- 在一个方法的形参位置,最多只能声明一个可变个数形参。
代码示例:
public class Test01 {
public static void main(String[] args) {
String[] strs = {"11","2s","245v"};
String[] strings = string(3,"11","2s","245v");
String[] strings1 = stringTest(3,strs);
System.out.println(Arrays.toString(strings));
System.out.println(Arrays.toString(strings1));
}
private static String[] stringTest(int n,String[] strs) {
return strs;
}
private static String[] string(int n,String...strs) {
return strs;
}
}
执行结果:
参数传递
方法,必须有其所在类或对象调用才有意义。若方法含有参数:
- 形参:方法声明时的参数
- 实参:方法调用时实际传给形参的参数值
Java里方法的参数传递方式只有一种:值传递
。即将实际参数值的副本(复制品)传入方法内,参数本身不受影响。
- 基本数据类型的形参:将实参基本数据类型变量的
数据值
传递给形参 - 引用数据类型的形参:将实参引用数据类型变量的
地址值
传递给形参
本质都是将实参复制一份,然后传给形参
基本数据类型
引用数据类型
内存解析
示例1:
public static void main(String[] args) {
Person person = new Person("小明");
Person person1 = person;
person1.setName("111");
System.out.println(person1 == person);//true
System.out.println(person.getName());
}
//Person对象
public class Person {
private String name;
public Person(String name) {
this.name = name;
}
public void setName(String name) {
this.name = name;
}
public String getName() {
return name;
}
程序执行结果如下:
内存结构:
示例2:
class Phone{
String pName;
double price;
String color;
public void call(String who){
System.out.println("给"+who+"打电话");
}
public void sendMessage(){
System.out.println("发送一条信息");
}
}
public class PhoneTest {
public static void main(String[] args) {
Phone p = new Phone();
System.out.println(p.pName);//null
System.out.println(p.price);//0.0
System.out.println(p.color);//null
p.pName = "Apple";
p.price = 6666;
p.color = "玫瑰金";
System.out.println(p.pName);//Apple
System.out.println(p.price);//6666.0
System.out.println(p.color);//玫瑰金
p.call("老罗");//给老罗打电话
p.sendMessage();//发送一条信息
}
}
程序执行结果如下:
内存结构:
方法进阶:重载
方法重载:方法名相同、参数列表不同。(与返回值无关)
方法重载发生在同一个类中,下文提到的方法重写是在不同类中发生的。
调用重载方法时,会自动适配使用哪一个方法(根据传入的参数)。
方法重载示例:
int test(int num){
System.out.println(num);//返回传入的int类型参数
}
double test(double num){
System.out.println(num);//返回传入的double类型参数
}
JavaBean
符合以下标准的类称为JavaBean
- 类是公共的。
- 有一个无参的公共的构造器。
- 有属性,且有对应的get、set方法。
//Person对象 就是一个JavaBean
public class Person {
private String name;
public Person(String name) {
this.name = name;
}
public void setName(String name) {
this.name = name;
}
public String getName() {
return name;
}
package
package语句作为Java源文件的第一条语句,指明该文件中定义的类所在的包。(若缺省该语句,则指定无无名包),包通常用小写单词标识。通常使用所在公司域名的倒置。com.tyy.xxx
- 包帮助管理大型软件系统:将功能相近的类划分到同一个包中。比如:MVC设计模式。
- 包可以包含类和子包,划分项目层次,便于管理。
- 解决类命名冲突的问题。
- 控制访问权限。
Java中常用的包
- java.lang---包含一些Java语言的核心类,如String、Math、Integer、System和 Thread,提供常用功能。
- java.net---包含执行与网络相关的操作的类和接口。
- java.io---包含提供多种输入/输出功能的类。
- java.util---包含一些使用工具类,如自定义系统特性、接口的集合框架类、使用与日期日历相关的函数。
- java.text---包含了一些java格式化相关的类。
- java.sql---包含java进行JDBC数据库编程的相关类/接口。
- java.awt---图形化相关的(已放弃)。
面向对象进阶
继承
关键字:extend
使用方式:
public class A extend B{//A继承B,A能够拥有B的属性,方法||A可以重写B的方法
//类 A
//属性
//方法
}
public class B{
//类 B
//属性
//方法
}
重写
- 重写是子类对父类的允许访问的
方法
的实现过程
进行重新编写,返回值
和形参
都不能改变。即外壳不变,核心重写! - 重写的好处在于子类可以根据需要,定义特定于自己的行为。 也就是说子类能够根据需要实现父类的方法。
- 重写方法不能抛出新的检查异常或者比被重写方法申明更加宽泛的异常。
代码示例:
public class A{
public void f1(){
System.out.println("A...");
}
}
public class B extends{
@Override
public void f1(){
System.out.println("B...");//重写父类f1()方法的实现过程。
}
}
public class Demo{
public static String main(String[] args){
A a = new B();
a.f1();//输出:B...
}
}
this关键字
this的语法是this.
和this()
this.
:调用当前对象的属性或者方法。this()
:调用当前对象的构造方法。
this
关键字是 Java常用的关键字,可用于任何实例方法
内指向当前对象,也可指向对其调用当前方法的对象,或者在需要当前类型对象引用时使用。
this使用场景:
- 当局部变量和成员变量同名时,可以使用
this
关键字来引用成员变量,以区分局部变量和成员变量。 - 在
构造方法
中,可以使用 this 关键字调用另一个构造方法,用于代码的复用。 - 当需要将当前对象作为参数传递给方法或者构造方法时,可以使用
this
关键字。 - this不能出现在静态方法中。
- this指向的堆中的对象。
super关键字
super的语法是super.
和super()
。
super.
:调用当前对象的属性或者方法。super()
:调用当前对象的构造方法。
super关键字与this关键字很相似
- super能出现在实例方法和构造方法中。
- super不能出现在静态方法中。
this和super区别
super
和this
区别是:this
可以看做一个引用变量,保存了该对象的地址,是当前对象整体,而super
代表的是父类型特征,是子类局部的一些东西,这些继承过来的东西已经在子类里面了,你可以输出整体this
,但不能输出父类型特征super
。因为super
指向的东西不是一个整体,没法打印输出。
访问修饰符
修饰符 | 类内部 | 同一个包 | 不同子包 | 同一个工程 |
private | Y | |||
(缺省) | Y | Y | ||
protected | Y | Y | Y | |
public | Y | Y | Y | Y |
private
:当前类default
:当前包可以访问protected
:子类可以访问
- 在子类中
new Parent().protected变量
不能够访问 - 在子类中
super.protected
变量(方法)能够访问
public
:所有工程能够直接访问
示例
public class Demo{
private int a ;//本类可以访问
int b;//默认为default 本类、同一包可以访问
protected int c;//本类、同一包、子类可以访问
public int d = 20;//同一个工程下都可以访问
//修饰方法时,同上
public Test02() {
}
public Test02(int d) {
this.d = d;
}
private void getA(){
System.out.println("private");
}
void getB(){
System.out.println("default");
}
protected void getC(){
System.out.println("protected");
}
public void getD(){
System.out.println("public");
}
}
多态
- 多态概念解析
- 多态性,是面向对象中最重要的概念,在java中的体现;对象的多态性--父类中的引用指向子类的对象。
- Java引用变量有两个类型:编译类型和运行时类型。编译时类型由声明该变量时使用的类型决定,运行时类型由实际赋给该变量的对象决定。简称:编译时,看
=
左边;运行时,看=
右边。
- 若编译时运行和运行时类型不一致,就出现了对象的多态性(polymorphism)。
- 多态情况下
看左边
:看的是父类的引用(父类中不具备子类特有的方法)、看右边
:看的是子类的对象(实际运行的是子类重写父类的方法)。
- 多态提高代码的通用性,长称作接口重用。
场景设计:
主人操作动物的行为,如让猫进食或叫、让狗进食或叫....
代码:
Animal
类
public class Animal {
public void eat(){
System.out.println("eat...");
}
public void shout(){
System.out.println("shout...");
}
}
Cat
类
public class Cat extends Animal{
@Override
public void eat() {
System.out.println("猫在进食...");
}
@Override
public void shout() {
System.out.println("猫在叫...");
}
}
Dog
类
public class Dog extends Animal {
@Override
public void eat() {
System.out.println("狗在进食...");
}
@Override
public void shout() {
System.out.println("狗在叫...");
}
}
Master
类
public class Master {
public void fc(Animal animal){
animal.eat();
animal.shout();
}
public static void main(String[] args) {
Master master = new Master();
master.fc(new Dog());
master.fc(new Cat());
}
}
instanceof
关键词
instanceof
是 Java 的保留关键字。它的作用是测试它左边的对象是否是它右边的类的实例,返回 boolean 的数据类型。
instanceof
是Java中的二元运算符,左边是对象,右边是类;当对象是右边类或子类所创建对象时,返回true;否则,返回false。
if(A instanceof B){
//执行语句
}else{
//执行语句
}
- 其中左侧对象实例A不能是基础数据类型。
- null用instanceof跟任何类型比较都是false。
public interface A{
//接口A
}
public class B implements A{
//类B实现了接口A
}
public class C extends B{
//类C继承类B
}
A、B、C的继承树如下图
C实例 instanceof A//ture
C实例 instanceof B//ture
B实例 instanceof A//ture
C实例 instanceof C//ture
- 强制类型转换
对Java对象的强制类型转换称为造型
- 从子类到父类的类型转换可以自动进行。
- 从父类到子类的类型转换必须通过
造型
(强制类型转换)。 - 无继承关系的引用类型间的转换是非法的。(无法转换)
- 在
造型
前可以使用instanceof操作符测试一个对象的类型。
基本数据类型:
对象类型:
//父类A强转成子类B
A a = new A();
B b = (B)a;//对象类型强制转换
Object类
==
:比较内存地址。equals()
:比较内容,默比较地址,源码如下:
- String类重写了equals()方法,String对象的equals()方法比较的内容。
//Object类中equals源码
public boolean equals(Object obj) {
return (this == obj);
}
- 重写equals()方法。
@Override
public boolean equals(Object obj) {
//比较Bean类中的age属性;age属性相同返回true,否则返回false
return this.age == ((Bean) obj).age;
}
toString()
:打印时,会打印toString()方法。
- 重写toString()方法,来自定义打印信息。
@Override
public String toString() {
//返回值为打印信息
return "Bean{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}
- getClass:得到堆中的类对象信息对象。
自动装箱和拆箱
- 装箱:
基本数据类型
转换成包装类
。
Integer i1 = 100;//int类型的100 装箱成 Integer类型
int i = 123;
//int类型的123 装箱成 Integer类型
Integer i2 = new Integer(123);//源码中为 Integer i2 = Integer.valueOf(123);将int类型123转换成Integer类型
Integer i3 = new Integer("456");//数值String类型"456" 装箱成 Integer类型
//基本数据类型int->对应的包装类->Integer
//float-> Float
- 拆箱:包类型转换成基本数据类型。
Integer i1 = new Integer(123);
//拆箱
int i2 = i1.intValue();//将包装类型拆箱成对应的基本数据类型
Boolean b2 = new Boolean(false);
boolean b3 = b2.booleanValue(); //拆箱
Byte、Short、Integer、Long类型中调用的valueOf()方法,
判断需要装箱的数值是否在
[-128,127]
中,若在则从缓冲数组
中找到其地址返回,否则创建新的对象。
示例:
Integer i1 = 100;
Integer i2 = 100;
Integer i3 = 128;
Integer i4 = 128;
Integer i5 = new Integer(100);
System.out.println(i1 == i2);//ture
System.out.println(i3 == i4);//false
System.out.println(i1 == i5);//false
new Integer(100)
: 直接调用this.value = value
;不会触发自动装箱。
面向对象高级
static关键字
static
可修饰变量、代码块、方法;它修饰的变量称之为静态变量
,修饰的代码块称之为静态代码块
,修饰的方法称之为静态方法
- 使用范围:在Java类中, 可用static修饰属性、 方法、 代码块、 内部类
- 被修饰后的属性具备以下特点:
- 随着类的加载而加载
- 优先于对象存在
- 修饰的属性,被所有对象所共享
- 访问权限允许时,可不创建对象,直接被类调用
- 类方法,类中使用static修饰的方法
- 没有对象的实例时,可以用类名.方法名()的形式访问由static修饰的类方法。
- 在static方法内部只能访问类的static修饰的属性或方法, 不能访问类的非static的结构
- 因为不需要实例就可以访问static方法,因此static方法内部不能有this。 (也不能有super)
- static修饰的方法不能被重写
final关键词
final使用方式
- 修饰类:被修饰类不能被继承。
- 修饰方法:被修饰方法不能被重写。
- 修饰成员变量:被修饰变量不能被改变(称为常量)。
初始化&初始化顺序
对象初始化顺序:
- 静态初始化
- 初始化
- 构造函数
父类对象先执行
测试:
public class Parent {
private int i = 0;
{
//初始化代码块
System.out.println("Parent 初始化");
}
private static int s = 0;
static
{
//静态初始化代码块
System.out.println("Parent 静态初始化");
}
public Parent() {
System.out.println("Parent 构造函数初始化");
}
}
public class Children extends Parent {
private int i = 0;
{
System.out.println("Children 初始化");
}
private static int s = 0;
static {
System.out.println("Children 静态初始化");
}
public Children() {
System.out.println("Children 构造函数初始化");
}
}
//测试
public class Initialize {
public static void main(String[] args) {
Children children = new Children();
}
}
结果:
Parent 静态初始化
Children 静态初始化
Parent 初始化
Parent 构造函数初始化
Children 初始化
Children 构造函数初始化
抽象类
使用
abstract
修饰的类可以理解为一个使用
abstract
修饰的普通类,但是该类不能被实例化,且其中可以编写abstract
修饰的声明方法。
使用abstract
修饰的方法是抽象方法;抽象方法只是方法的声明,而未实现,以分号;
结尾。
public abstract class A{//抽象类
public abstract void start();//抽象方法
}
含有抽象方法的类是抽象类。
抽象类不能被实例化。抽象是用来继承的,抽象类的子类必须重写父类的所有抽象方法,若子类也是抽象类则可选择重写或不重写。
抽象类中可以拥有普通的实现方法。
代码示例;
抽象类A
public abstract class A {
private int num = 0;
static int s = 0;
public abstract void in();
public void say(){
System.out.println("This is a A abstract class");
}
}
类B继承类A
public class B extends A{
@Override
public void in() {
System.out.println("B 实现了 抽象类A的in()方法");
}
}
测试类Demo
public class Demo {
public static void main(String[] args) {
B b = new B();
b.in();
}
}
输出结果
B 实现了 抽象类A的in()方法
接口
接口的关键词是
interface
接口示例:public interface A{ ..... }
、public interface B{ ..... }
- 接口能够实现多继承的效果
public class C implements A,B{ ..... }
- Java接口是一系列方法的声明,是一些方法特征的集合,一个接口只有方法的特征没有方法的实现,因此这些方法可以在不同的地方被不同的类实现,而这些实现可以具有不同的行为(功能)。
- 猫、狗等动物都具有动物的一些特征,比如嗥叫;动物接口中就可以有一个嗥叫方法,猫实现为“喵喵叫”,狗实现为“汪汪叫”。
- 接口的本质是契约,标准,规范,就像我们的法律一样。制定好后大家都要遵守。
- 抽象方法只能存在于抽象类或者接口中,但抽象类中却能存在非抽象方法,即有方法体的方法。接口是百分之百的抽象类。
- 接口中方法默认的修饰符为
public abstract
(接口中没有普通方法)。 - 接口中存在的变量一定是final,public,static的。
代码示例:
TypeC接口
public interface TypeC {
void tStart();
void tEnd();
}
Usb接口
public interface Usb {
void uStart();
void uEnd();
}
Demo实现TypeC、Usb
public class Demo implements TypeC,Usb {
@Override
public void uStart() {
System.out.println("Demo implements uStart");
}
@Override
public void uEnd() {
System.out.println("Demo implements uEnd");
}
@Override
public void tStart() {
System.out.println("Demo implements tStart");
}
@Override
public void tEnd() {
System.out.println("Demo implements tEnd");
}
}
测试类Test
public class Test {
public static void main(String[] args) {
Demo demo = new Demo();
demo.tStart();
demo.tEnd();
demo.uStart();
demo.uEnd();
}
}
输出结果
Demo implements tStart
Demo implements tEnd
Demo implements uStart
Demo implements uEnd
内部类&匿名内部类
内部类(了解)
类B定义在类A的内部,成类B为内部类。
示例
public class A{
//类A
class B{
//内部类B
}
}
内部类的分类主要看内部类所处的位置:
- 处于成员变量的位置,属于成员内部类。
- static成员内部类
- 非静态的成员内部类
- 位于方法中,局部内部类。
语法
- 修饰
成员变量
的所有的修饰符都可以修饰成员内部类
。 - 内部类可以继承。
示例:
类Example
public class Example {
private String Description;
public static class Dog{//静态内部类
public void eat(){
System.out.println("Dog eating...");
}
}
public class cat{//非静态内部类
public void eat(){
System.out.println("Cat eating...");
}
}
public void f1(){
class Bird{
public void eat(){
System.out.println("Bird eating...");
}
}
new Bird().eat();
}
}
测试类
public class Test {
public static void main(String[] args) {
Example.Dog dog = new Example.Dog();//静态内部类实例化
Example example = new Example();
Example.cat cat = example.new cat();//非静态内部类实例化 类实例.new 非静态内部类构造方法
dog.eat();
cat.eat();
example.f1();//方法内部类使用方法
}
}
执行结果
Dog eating...
Cat eating...
Bird eating...
匿名内部类(掌握)
官方文档的描述:
匿名类使您能够使代码更加简洁。 它们使您能够同时声明和实例化一个类 时间。它们类似于本地类,只是它们没有 名字。如果只需要使用一次本地类,请使用它们。
- 一个匿名内部类一定是在
new
的后面,用其隐含实现一个接口或实现一个类。 - 匿名内部类的特点
- 匿名内部类必须继承父类或实现接口
- 匿名内部类只能有一个对象
- 匿名内部类对象只能使用多态形式引用
- 语法
- new 接口(类){实现};
Usb接口
public interface Usb {
void readFiles();
void writeFiles();
}
类Typec
public class TypeC {
public void readFiles() {
//执行体
System.out.println("Type execute readFiles");
}
public void writeFiles(){
//执行体
System.out.println("Type execute writeFiles");
}
}
测试类Test
public class Test {
public void f1(Usb usb){
usb.readFiles();
usb.writeFiles();
}
public void f2(TypeC typeC){
typeC.readFiles();
typeC.writeFiles();
}
public static void main(String[] args) {
Test test = new Test();
/**
* 建议使用匿名内部类的情况
* 1. 若是某个类只需要使用一次,
* 2. 或是对某个类的方法有需求更改,且使用次数较少
*/
//通过实现接口方法的形式,完成方法的表达
test.f1(new Usb() {
@Override
public void readFiles() {
System.out.println("readFiles...");
}
@Override
public void writeFiles() {
System.out.println("writeFiles...");
}
});
//通过重写父类的方法,完成对方法表达的重写;简洁明了
test.f2(new TypeC(){
@Override
public void readFiles() {
System.out.println("Override readFiles ");
}
@Override
public void writeFiles() {
System.out.println("Override writeFiles ");
}
});
}
}
设计模式
设计模式的六大原则
- 开闭原则(Open Close Principle)
开闭原则就是说对扩展开放,对修改关闭。在程序需要进行拓展的时候,不能去修改原有的代码,实现一个热插拔的效果。所以一句话概括就是:为了使程序的扩展性好,易于维护和升级。想要达到这样的效果,我们需要使用接口和抽象类,后面的具体设计中我们会提到这点。
- 里氏代换原则(Liskov Substitution Principle)
里氏代换原则(Liskov Substitution Principle LSP)面向对象设计的基本原则之一。 里氏代换原则中说,任何基类可以出现的地方,子类一定可以出现。 LSP是继承复用的基石,只有当衍生类可以替换掉基类,软件单位的功能不受到影响时,基类才能真正被复用,而衍生类也能够在基类的基础上增加新的行为。里氏代换原则是对“开-闭”原则的补充。实现“开-闭”原则的关键步骤就是抽象化。而基类与子类的继承关系就是抽象化的具体实现,所以里氏代换原则是对实现抽象化的具体步骤的规范。—— From Baidu 百科
- 依赖倒转原则(Dependence Inversion Principle)
这个是开闭原则的基础,具体内容:真对接口编程,依赖于抽象而不依赖于具体。
- 接口隔离原则(Interface Segregation Principle)
这个原则的意思是:使用多个隔离的接口,比使用单个接口要好。还是一个降低类之间的耦合度的意思,从这儿我们看出,其实设计模式就是一个软件的设计思想,从大型软件架构出发,为了升级和维护方便。所以上文中多次出现:降低依赖,降低耦合。
- 迪米特法则(最少知道原则)(Demeter Principle)
为什么叫最少知道原则,就是说:一个实体应当尽量少的与其他实体之间发生相互作用,使得系统功能模块相对独立。
- 合成复用原则(Composite Reuse Principle)
原则是尽量使用合成/聚合的方式,而不是使用继承。
设计模式
- 单例模式
单例模式是设计模式中最常见也最简单的一种设计模式,保证了在程序中只有一个实例存在并且能全局的访问。
单例模式分为:饿汉式
、懒汉式
单例
- 饿汉式单例模式
饿汉式表示为一次性执行静态变量的初始化,即声明本类的静态变量并指向一个本类的实例对象。
private static HungrySingleton instance = new HungrySingleton();
(由于静态的特性,该实例对象在程序执行过程中只存在一个)
- 加载慢(较懒汉式而言)
- 线程安全
代码实现
public class HungrySingleton {
//饿汉式单例模式
//一次性静态初始化
private HungrySingleton() {
System.out.println("饿汉式实例加载...");
}
private static HungrySingleton instance = new HungrySingleton();//声明本类的静态变量并指向一个本类的实例对象
public static HungrySingleton getInstance(){
return instance;
}
- 懒汉式单例模式
懒汉式表示为懒惰的只声明本类的静态变量,即private static LazySingleton instance = null;
- 加载快(较饿汉式而言)
- 线程不安全
代码实现
public class LazySingleton {
//懒汉式单例模式
//只是声明instance并不实例化
private LazySingleton() {
System.out.println("懒汉式实例化...");
}
private static LazySingleton instance = null;
public static LazySingleton getInstance(){
if (Objects.isNull(instance)){
instance = new LazySingleton();
}
return instance;
}
标签:void,System,面向对象,println,方法,public,out
From: https://blog.51cto.com/u_16230183/7177831