Java-Day12 面向对象的三大特征之封装、继承,单例模式(饿汉式、懒汉式)、方法重写 (覆盖)、注解 (annotation)、super关键字、对象的创建流程超详细

目录

1. 面向对象的三大特征之封装

1.1 封装的含义

1.2 封装的目的

1.3 封装的优点

1.4 封装的实现过程

1.5 拓展知识:JavaBean

2. 面向对象的三大特征之继承

2.1 继承的概念

2.2 如何实现继承

2.3 继承的作用

2.4 继承的类型

2.5 继承的特点

3. 私有化构造函数和单例模式

3.1 私有化构造函数的常景

3.2 单例模式

3.2.1 单例模式 (饿汉式)

3.2.2 单例模式 (懒汉式)

4. 方法重写 (覆盖)

5. 注解 (annotation)

6. super关键字

7. 对象的创建流程


面向对象的三大特征:封装、继承、多态

1. 面向对象的三大特征之封装

1.1 封装的含义

面向对象的封装有两层含义

  1. 类:属性、方法这些定义在类内部,其实就是一种封装,但并不是这里的三大特征之一

  2. 面向对象的封装是使用访问修饰符private将属性私有化的设计思想。

封装(英语:Encapsulation),是指为了安全考虑,在开发的过程中,会讲属性私有化 (private关键字修饰) ,需要提供对应接口完成设置和访问 (公开的setter和getter方法) 的过程。

1.2 封装的目的

  • 隐藏一个类中不需要对外提供的实现细节;

  • 使用者只能通过事先定制好的方法来访问数据,可以方便地加入控制逻辑, 限制对属性的不合理操作;

  • 便于修改,增强代码的可维护性

1.3 封装的优点

  1. 良好的封装能够减少耦合。

  2. 类内部的结构可以自由修改。

  3. 可以对成员变量进行更精确的控制。

  4. 隐藏信息,实现细节。

1.4 封装的实现过程

1. 修改属性的可见性来限制对属性的访问(一般限制为private),例如:

public class Person {
    private String name;
    private int age;
}

这段代码中,将 name 和 age 属性设置为私有的,只能本类才能访问,其他类都访问不了,如此就对信息进行了隐藏。

2. 对每个值属性提供对外的公共方法访问,也就是创建一对赋取值方法(公开的setter和getter方法) ,用于对私有属性的访问,例如:

public class Person{
    private String name;
    private int age;
​
    public int getAge(){
      return age;
    }
​
    public String getName(){
      return name;
    }
​
    public void setAge(int age){
      this.age = age;
    }
​
    public void setName(String name){
      this.name = name;
    }
}

采用 this 关键字是为了解决实例变量(private String name)和局部变量(setName(String name)中的name变量)之间发生的同名的冲突。

访问上面这个封装后的属性,通过创建对象,调用对应的get/set方法进行属性的操作

public class PersonTest {
	public static void main(String[] args) {
		Person person = new Person();
		person.setAge(2);

		System.out.println(person.getAge());  // 2
	}
}

1.5 拓展知识:JavaBean

POJO对象:(Plain Ordinary Java Object) 标准的Java bean 对象

根据封装来写,私有化属性,提供公开的setter和getter方法,至少两个或者以上的构造方法

JavaBean是一种Java语言写成的可重用组件。符合如下标准的Java类:

  • 类是公共的

  • 有一个无参的公共的构造器

  • 有属性,且有对应的get、set方法

       用户可以使用JavaBean将功能、处理、值、数据库访问和其他任何可以 用Java代码创造的对象进行打包,并且其他的开发者可以通过内部的JSP 页面、Servlet、其他JavaBean、applet程序或者应用来使用这些对象。用 户可以认为JavaBean提供了一种随时随地的复制和粘贴的功能,而不用关 心任何改变。

案例:博客系统设计

        板块:Board、文章:Article、作者:Author、回复:Comment/Reply等类

Board类

//import java.util.Arrays;

public class Board {
	private int id; // 板块id
	private String name; // 板块名称
	private String intro; // 简介或描述
//	开发中尽量使用单项关联
//	private Article[] articles;

	@Override
	public String toString() {
		return "Board [id=" + id + ", name=" + name + ", intro=" + intro + "]";
	}

	public Board() {
		super();
	}

	public Board(int id, String name, String intro) {
		super();
		this.id = id;
		this.name = name;
		this.intro = intro;
	}

	public int getId() {
		return id;
	}

	public void setId(int id) {
		this.id = id;
	}

	public String getName() {
		return name;
	}

	public void setName(String name) {
		this.name = name;
	}

//	public Article[] getArticles() {
//		return articles;
//	}
//
//	public void setArticles(Article[] articles) {
//		this.articles = articles;
//	}

}

Article类

import java.util.Date;

//import java.util.Arrays;

public class Article {
	private int id; // 文章id
	private String tittle; // 标题
	private String content; // 内容
	private Author blogAuthor; // 作者
	private Board board; // 所属板块
	private Date publishTime; // 发布时间
	private Date modifyTime; // 修改时间
	@Override
	public String toString() {
		return "Article [id=" + id + ", tittle=" + tittle + ", content=" + content + ", blogAuthor=" + blogAuthor
				+ ", board=" + board + ", publishTime=" + publishTime + ", modifyTime=" + modifyTime + "]";
	}
	
	public Article(int id, String tittle, String content, Author blogAuthor, Board board, Date publishTime,
			Date modifyTime) {
		super();
		this.id = id;
		this.tittle = tittle;
		this.content = content;
		this.blogAuthor = blogAuthor;
		this.board = board;
		this.publishTime = publishTime;
		this.modifyTime = modifyTime;
	}
	
	public Article() {
		super();
	}

	public int getId() {
		return id;
	}

	public void setId(int id) {
		this.id = id;
	}

	public String getTittle() {
		return tittle;
	}

	public void setTittle(String tittle) {
		this.tittle = tittle;
	}

	public String getContent() {
		return content;
	}

	public void setContent(String content) {
		this.content = content;
	}

	public Author getBlogAuthor() {
		return blogAuthor;
	}

	public void setBlogAuthor(Author blogAuthor) {
		this.blogAuthor = blogAuthor;
	}

	public Board getBoard() {
		return board;
	}

	public void setBoard(Board board) {
		this.board = board;
	}

	public Date getPublishTime() {
		return publishTime;
	}

	public void setPublishTime(Date publishTime) {
		this.publishTime = publishTime;
	}

	public Date getModifyTime() {
		return modifyTime;
	}

	public void setModifyTime(Date modifyTime) {
		this.modifyTime = modifyTime;
	}
}

Author类

//import java.util.Arrays;

public class Author {
	private int id; // 作者id
	private String name; // 姓名
	private boolean gender; // 性别
	private int age; // 年龄
	private String intro; // 简介或描述
//	private Article[] articles;

	@Override
	public String toString() {
		return "Author [id=" + id + ", name=" + name + ", gender=" + gender + ", age=" + age + ", intro=" + intro + "]";
	}

	public Author(int id, String name, boolean gender, int age, String intro) {
		super();
		this.id = id;
		this.name = name;
		this.gender = gender;
		this.age = age;
		this.intro = intro;
	}

	public Author() {
		super();
	}

	public int getId() {
		return id;
	}

	public void setId(int id) {
		this.id = id;
	}

	public String getName() {
		return name;
	}

	public void setName(String name) {
		this.name = name;
	}

	public boolean isGender() {
		return gender;
	}

	public void setGender(boolean gender) {
		this.gender = gender;
	}

	public int getAge() {
		return age;
	}

	public void setAge(int age) {
		this.age = age;
	}

	public String getIntro() {
		return intro;
	}

	public void setIntro(String intro) {
		this.intro = intro;
	}
}

Comment类

package com.openlab.day12.blog;

import java.util.Date;

public class Comment {
	private int id; // 回复id
	private String content; // 内容
	private Author blogAuthor; // 作者
	private Date publishTime; // 发布时间
	private Date modifyTime; // 修改时间
	private Article article; // 文章

	@Override
	public String toString() {
		return "Comment [id=" + id + ", content=" + content + ", blogAuthor=" + blogAuthor + ", publishTime="
				+ publishTime + ", modifyTime=" + modifyTime + ", article=" + article + "]";
	}

	public Comment(int id, String content, Author blogAuthor, Date publishTime, Date modifyTime, Article article) {
		super();
		this.id = id;
		this.content = content;
		this.blogAuthor = blogAuthor;
		this.publishTime = publishTime;
		this.modifyTime = modifyTime;
		this.article = article;
	}

	public Comment() {
		super();
	}

	public int getId() {
		return id;
	}

	public void setId(int id) {
		this.id = id;
	}

	public String getContent() {
		return content;
	}

	public void setContent(String content) {
		this.content = content;
	}

	public Author getBlogAuthor() {
		return blogAuthor;
	}

	public void setBlogAuthor(Author blogAuthor) {
		this.blogAuthor = blogAuthor;
	}

	public Date getPublishTime() {
		return publishTime;
	}

	public void setPublishTime(Date publishTime) {
		this.publishTime = publishTime;
	}

	public Date getModifyTime() {
		return modifyTime;
	}

	public void setModifyTime(Date modifyTime) {
		this.modifyTime = modifyTime;
	}

	public Article getArticle() {
		return article;
	}

	public void setArticle(Article article) {
		this.article = article;
	}
}

2. 面向对象的三大特征之继承

2.1 继承的概念

在面向对象中,类与类之间可以存在继承关系,继承就是子类继承父类的特征和行为,使得子类对象(实例)具有父类的实例域和方法,或子类从父类继承方法,使得子类具有父类相同的行为。

继承是java面向对象编程技术的一块基石,因为它允许创建分等级层次的类。

生活中的继承:

兔子和羊属于食草动物类,狮子和豹属于食肉动物类。

食草动物和食肉动物又是属于动物类。

所以继承需要符合的关系是:is-a,父类更通用,子类更具体。

虽然食草动物和食肉动物都是属于动物,但是两者的属性和行为上有差别,所以子类会具有父类的一般特性也会具有自身的特性。

生活中继承的例子还有很多,如财产继承、人的特征等等

2.2 如何实现继承

在 Java 中通过 extends 关键字可以申明一个类是从另外一个类继承而来的,一般形式如下:

类的继承格式

class 父类 {
}
 
class 子类 extends 父类 {
}

父类 (超类、基类);子类

案例:RichMan类和他的子类Son类

RichMan类

package com.openlab.day12.inherit;

public class RichMan {
	public String surname = "张";
	public double money = 1000000;
	private String honor = "Java";
	
	// 仅提供有参的构造方法 不提供无参的
	public RichMan(String surname, double money, String honor) {
		super();
		this.surname = surname;
		this.money = money;
		this.honor = honor;
	}

//	public RichMan() {
//		// TODO Auto-generated constructor stub
//	}

	@Override
	public String toString() {
		return "RichMan [surname=" + surname + ", money=" + money + ", honor=" + honor + "]";
	}

	public void say() {
		System.out.println("我的钱留给我的儿子!");
	}

	void test1() {
		System.out.println(this.money);
	}

	protected void test2() {
		System.out.println(this.honor);
	}
}

Son(与父类不同包下)

package com.openlab.day12;

import com.openlab.day12.inherit.RichMan;

public class Son extends RichMan {
	/*
	 * 	发现当父类只存在有参构造方法的时候 ,子类去继承会报错
	 * 	原因是每一个构造方法都会存在一个隐藏的super()去调用父类的无参构造器
	 * 	而这里父类只是显示的声明了有参构造器 并没有声明无参构造器
	 * 	在子类的构造方法中,一定会调用父类的某个构造方法
	 * 	处理方法:通过super关键字指定调用父类的哪个构造方法	如果未指定就会自动调用父类无参构造
	 * 
	 * 	简单的说:在子类的构造方法里调用了父类有参的构造方法就行了
	 */
	
	public Son() {
		super("张", 1, "1");
	}

	public static void main(String[] args) {
		Son son = new Son();
		System.out.println(son.money);
		System.out.println(son.surname);
//		System.out.println(son.honor); // 错误:honor is not visible

//		son.test1(); // 错误:The method test1() from the type RichMan is not visible
		son.test2();
		son.say();
	}

	// 在子类中,重写方法,
	@Override
	public void say() {
		// TODO Auto-generated method stub
		super.say();
		System.out.println("111111");
	}

//	@Override
	public void sayHello() {
		// TODO Auto-generated method stub
		System.out.println("Hello!");
	}
}

注意:private关键字修饰的属性和方法都是无法被子类继承的

protected关键字修饰的方法,就是用来给子类继承的!!!

2.3 继承的作用

  • 继承的出现减少了代码冗余,提高了代码的复用性。

  • 继承的出现,更有利于功能的扩展。

  • 继承的出现让类与类之间产生了关系,提供了多态的前提。

2.4 继承的类型

        在Java中,也存在继承,Java是一种典型的单继承编程语言。需要注意的是 Java 不支持多继承,但支持多重继承。

img

2.5 继承的特点

  • 子类拥有父类非 private 的属性、方法。

  • 子类可以拥有自己的属性和方法,即子类可以对父类进行扩展。

  • 子类可以用自己的方式实现父类的方法。

  • Java 的继承是单继承,但是可以多重继承,单继承就是一个子类只能继承一个父类,多重继承就是,例如 B 类继承 A 类,C 类继承 B 类,所以按照关系就是 B 类是 C 类的父类,A 类是 B 类的父类,这是 Java 继承区别于 C++ 继承的一个特性。

  • 提高了类之间的耦合性(继承的缺点,耦合度高就会造成代码之间的联系越紧密,代码独立性越差)。

3. 私有化构造函数和单例模式

3.1 私有化构造函数的常景

1. 工具类 (静态方法或者静态属性)

一般在一些工具类中,把全都是一些静态属性和方法,不需要修改,只需要调用即可,会把他的构造函数私有化,以不让其他的类创建该类的实例。之间通过类名称访问,不需要创建对象,如Math、Arrays等。

2. 单例模式

将构造函数私有化,使得该类不能以new的方式创建对象,而让该类使用自己创建好的那一个对象,这个类提供了一种访问其唯一的对象的方式,可以直接访问,不需要实例化该类的对象。

3.2 单例模式

       单例模式(Singleton Pattern)是 Java 中最简单的设计模式之一。这种类型的设计模式属于创建型模式,它提供了一种创建对象的最佳方式。这种模式涉及到一个单一的类,该类负责创建自己的对象,同时确保只有单个对象被创建。这个类提供了一种访问其唯一的对象的方式,可以直接访问,不需要实例化该类的对象。

注意:

  • 1、单例类只能有一个实例。
  • 2、单例类必须自己创建自己的唯一实例。
  • 3、单例类必须给所有其他对象提供这一实例。

意图:保证一个类仅有一个实例,并提供一个访问它的全局访问点。

主要解决:一个全局使用的类频繁地创建与销毁。

何时使用:当您想控制实例数目,节省系统资源的时候。

如何解决:判断系统是否已经有这个单例,如果有则返回,如果没有则创建。

关键代码:构造函数是私有的。

应用实例:

  • 1、一个班级只有一个班主任。
  • 2、Windows 是多进程多线程的,在操作一个文件的时候,就不可避免地出现多个进程或线程同时操作一个文件的现象,所以所有文件的处理必须通过唯一的实例来进行。
  • 3、一些设备管理器常常设计为单例模式,比如一个电脑有两台打印机,在输出的时候就要处理不能两台打印机打印同一个文件。

优点:

  • 1、在内存里只有一个实例,减少了内存的开销,尤其是频繁的创建和销毁实例(比如管理学院首页页面缓存)。
  • 2、避免对资源的多重占用(比如写文件操作)。

缺点:没有接口,不能继承,与单一职责原则冲突,一个类应该只关心内部逻辑,而不关心外面怎么样来实例化。

使用场景:

  • 1、要求生产唯一序列号。
  • 2、WEB 中的计数器,不用每次刷新都在数据库里加一次,用单例先缓存起来。
  • 3、创建的一个对象需要消耗的资源过多,比如 I/O 与数据库的连接等。

注意事项:getInstance() 方法中需要使用同步锁 synchronized (Singleton.class) 防止多线程同时进入造成 instance 被多次实例化。

3.2.1 单例模式 (饿汉式)

       饿汉式,是多线程安全的,实现容易,这种方式比较常用,但容易产生垃圾对象。

public class Singleton {
	// 饿汉式:单例模式
	private static Singleton singleton = new Singleton();
	
	// 1.私有化构造函数
	private Singleton() {
		
	}
	// 2.给室友者提供提供创建好的对象
	public static Singleton newInstance() {
		return singleton;
	}
	
	public static void main(String[] args) {
		Singleton s1 = Singleton.newInstance();
		Singleton s2 = Singleton.newInstance();
		System.out.println(s1 == s2);  // true
	}
}

3.2.2 单例模式 (懒汉式)

       懒汉式,是线程不安全的,实现容易,这种方式是最基本的实现方式,这种实现最大的问题就是不支持多线程。因为没有加锁 synchronized,所以严格意义上它并不算单例模式。这种方式不要求线程安全,在多线程不能正常工作。

public class Singleton2 {
	// 懒汉式:单例模式
	private static Singleton2 singleton2 = null;
	
	private Singleton2() {
		
	}
	
	private static Singleton2 newInstance() {
		if (singleton2 == null) {
			singleton2 = new Singleton2();
		}
		return singleton2;
	}
	
	public static void main(String[] args) {
		Singleton2 s3 = Singleton2.newInstance();
		Singleton2 s4 = Singleton2.newInstance();
		System.out.println(s3 == s4);  // true
	}
}

4. 方法重写 (覆盖)

重写 (OverWrite)

覆盖 (OverRide)

发生在继承中,指的是,子类继承了父类的方法后,该方法不能满足子类,重写该方法,以达到满足子类使用。

访问修饰符 返回值类型 方法名() {}

注意重写的方法中不可缩小访问权限,尽量不要更改,返回值类型不可改变

方法重载 (OverLoad):

5. 注解 (annotation)

JDK5.0提供的新特性,利用反射技术,可以很轻松使用标准方法、属性、类等,从而扩展功能。

@ 加在属性、方法的上方

@Override :覆盖

@Deprecate :过时警告

6. super关键字

super 在Java中,是一个指针,类似于this关键字

this关键字代表当前对象的引用,用在当前类中。主要有三个用法

  • this(),代表在当前类中调用其他的构造方法,并且只能在构造方法中写,只能调用一次,只能写在第一行。
  • this.date,代表访问当前类中的成员属性。
  • this.func(),代表调用当前类中的其他成员方法。

注意:this并不代表当前对象,而是代表当前对象的引用,因为在当前类的构造方法中就已经可以使用this关键字了,而只有当构造方法完成之后该类的对象才算是被实例化出来。

super关键字代表父类对象的引用,主要有以下三个用法

  • super(),代表在当前类中调用其父类的构造方法,默认是不写的,是调用父类的无参构造。
  • super.data,代表访问父类的成员属性。
  • super.func(),代表访问父类的成员方法。

7. 对象的创建流程

  1. 使用java命令将源码(.java)进行编译,生成字节码文件(.class)

  2. javac命令执行字节码文件

  3. 将字节码文件加载进虚拟机(JVM),静态方法区开始加载静态资源

  4. JVM从静态方法区读取主函数,并加载进栈(执行栈被创建)

  5. main函数开始执行,创建对象的代码,如:Son son = new Son();

  6. 在堆内存中开辟对象的内存空间,并分配地址

  7. 创建成员变量并进行默认初始化

  8. 子类构造函数从非静态方法区加载进栈开始执行

  9. 第一句先执行父类的构造函数

  10. 父类构造函数执行,为子类继承到的成员变量进行初始化(对象内存空间里的父类空间)

  11. 父类构造函数弹栈执行完张

  12. 子类构造函数继续执行,此时先对成员变量进行显式初始化

  13. 再执行子类构造函数的内容,进行针对性初始化

  14. 执行完张,子类构造函数弹栈,将对象的内存空间地址赋予相应的引用变量

文章的结尾给大家普及几个面向对象的专业术语:

  • OO (Oriented Object) :面向对象

  • OOP (Oriented Object Programming):面向对象的编程

  • OOD (Oriented Object Design):面向对象的设计

  • OOA (Oriented Object Analysis):面向对象的分析

  • OOT (Oriented Object Test):面向对象的测试

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Golang_HZ

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值