abstractClass 抽象类的概念
        1.抽象类的基本定义
        2.抽象类的使用原则
        
        不会抽象类与接口,java = 没学
        
        如果说现在在一个类之中需要定义一个没有方法体的方法,那么可以利用adstract关键字来进行抽象方法的定义
        而包含有抽象方法的类就可以使用abstract来定义成为抽象类
        类的核心组成:属性,方法。但是在学习完继承操作之后,会发现子类存在有一种覆写父类方法的机制,而且这一机制直接与对象的多态性有关
        于是这样就会出现一个问题:假设现在使用的是普通类,并且在这个类里面有一个println()方法

class A{
public void print(){
System.ot.println("**************");
}
}
public class abstractClass{
public static void main(String args[]){ }
}

但是这个A类在设计之初有一个要求,希望继承它的子类一定要覆写这个 print()方法。但是事实上这个时候的子类完全可以灵活的选择是否需要覆写方法

class A{
public void print(){
System.ot.println("**************");
}
}
class B extends A{}
public class abstractClass{
public static void main(String args[]){ }
}

但是由于只是一个普通方法,所以对于子类是否覆写没有任何的要求,于是这样就会出现一个漏洞,父类无法强制要求子类覆写方法
        如果只依靠普通类的继承,那么根本就不能够对子类产生限制,所以就可以利用抽象类和抽象方法来解决此类问题
        范例:定义抽象类

abstract class A{
public void fun(){
System.ot.println("**************");
}
public abstract void print();//没有方法体,使用 abstract 声明
}
class B extends A{}
public class abstractClass{
public static void main(String args[]){ }
}

抽象方法的特点: 一个是使用了 abstract 关键字定义,另外一个是方法的后面没有“{}”,表示没有方法体
        范例:错误的使用抽象类

abstract class A{
public void fun(){
System.ot.println("**************");
}
public abstract void print();//没有方法体,使用 abstract 声明
}
// class B extends A{}
public class abstractClass{
public static void main(String args[]){
A a = new A();
}
}           

本处直接采用了关键字new实例化了抽象类对象,但是在程序编译的时候就会出现的错误信息“A是抽象的:无法实例化”
        抽象类是不能够直接进行对象实例化操作的,因为一旦类的对象实例化了,就意味着可以调用类中的所有方法了,但是抽象方法只是一个声明,并没有具体的方法体
        所以在实际的开发之中,抽象类的使用原则如下:
            抽象类必须有子类,子类利用 extends关键字来继承抽象类,一个子类只能够继承一个父类
            抽象类的子类(如果不是抽象类)那么必须要覆写抽象类中的全部抽象方法
            抽象类可以利用对象的向上转型机制,通过子类对象进行实例化操作
            
不能直接产生实例化对象的分析:
        当一个类对象实例化之后就意味着,需要进行属性的堆内存分配,同时该对象可以调用类中的全部方法
        而抽象类中有抽象方法,抽象方法没有方法体,你如何调用呢?

abstract class A{
public void fun(){
System.ot.println("**************");
}
public abstract void print();//没有方法体,使用 abstract 声明
}
class B extends A{
public void print(){
System.out.println("这个方法是强制子类要覆写的方法");
}
}
public class abstractClass{
public static void main(String args[]){
A a = new B(); // 向上转型
a.print(); // 被子类所覆写过的方法
}
}
/*
结果:
这个方法是强制子类要覆写的方法
*/

抽象类与普通类相比最大的好处是强制定义了子类的实现要求
        本质上讲抽象类就是比普通类多了一些抽象方法的定义而已
        在实际的设计之中,父类的设计是最重要的,普通类与抽象相比,明显抽象类的约束更加的严格
        所以在实际的开发之中,几乎不会出现普通类定义子类的情况,大多数都是继承抽象类

*/

/*     抽象类的相关说明
        整个的设计结构里面多了抽象类的定义,那么多;了一个定义之后,就需要与原始的结构有一些对比
        0.抽象类允许提供构造方法,如果抽象类父类提供的是有参构造,则子类必须使用 super() 明确的去调用父类的指定构造方法
1.抽象类不能使用final关键字来定义,因为抽象类必须有子类,而final不能有子类
        2.抽象类就是比普通类多了抽象方法而已,但是普通类中的所有结构抽象类都可以定义,包括普通方法,构造方法,属性,常量等内容:
            而且子类对象也符合于对象实例化流程,默认先调用父类中的无参构造,而后再执行子类自己的构造操作

abstract class A{
public static final String INFO = "HELLO";
public A(){
this.fun();
}
public void fun(){
System.out.println("**************");
}
public abstract void print();//没有方法体,使用 abstract 声明
}
class B extends A{
public void print(){
System.out.println("这个方法是强制子类要覆写的方法");
}
}
public class abstractClass{
public static void main(String args[]){
A a = new B(); // 向上转型
a.print(); // 被子类所覆写过的方法
}
}
/*
结果:
*******************
这个方法是强制子类要覆写的方法
*/

思考题:

abstract class A{

    public A(){
this.fun();
}
public abstract void print();//没有方法体,使用 abstract 声明
}
class B extends A{
private int num = 50;
public B(int num){
this.num = num;
}
public void print(){
System.out.println("num ="+this.num);
}
}
public class abstractClass{
public static void main(String args[]){
new B(100); }
}
/*
结果:
num = 0
*/

本程序的解决关键思路:子类对象实例化前一定要先实例化父类对象,也就是说此时,子类对象的属性都没有内容
            分析:

abstract class A{
public A(){ // 2.默认调用父类构造
this.fun();// 3.调用println()方法
}
public abstract void print();//没有方法体,使用 abstract 声明
}
class B extends A{
private int num = 50;
public B(int num){ // 1.传递内容过来,在子类对象实例化前先实例化父类对象
this.num = num;
}
public void print(){ // 4.调用此方法执行,此时子类对象还未实例化,内容没有赋值
System.out.println("num ="+this.num);// 5.只能够输出对应数据的类型默认值
}
}
public class abstractClass{
public static void main(String args[]){
new B(100); }
}

3. 抽象类中可以没有抽象方法,但是依然不可能使用关键字new进行对象的实例化操作

abstract class A{

}
public class abstractClass{
public static void main(String args[]){
A a = new A(); }
}
//结果:出错

因为类A上存在有 abstract 关键字,所以此处无法进行对象的直接实例化
        
        4.外部抽象类上不允许使用static声明,但是内部抽象中可以使用 static声明,这样表示的是一个外部抽象类
        范例:定义普通的内部抽象类

abstract class A{
public abstract void printA();
abstract class B{
public
abstract void printB();
}
}
class X extends A{
public void printA(){}
class Y extends B{
public void printB(){ }
}
}
public class abstractClass{
public static void main(String args[]){
A a = new A(); }
}
//结果:

范例:在内部抽象类中使用 staic 关键字

abstract class A{
public abstract void printA();
static abstract class B{
public abstract void printB();
}
}
class X extends A.B{
public abstract void printB(){}
}
public class abstractClass{
public static void main(String args[]){
A a = new A(); }
}

5.抽象类中可以存在有 static方法,而且 static 方法不受实例化对象的控制
        范例:直接通过抽象类产生实例化对象

abstract class A{// 设计之初考虑到N年后的发展,需要有子类,但是N年前不需要子类
public abstract void printA();
private static class B extends A { // 在A类里面直接定义实现的子类
public void printA(){
System.out.println("**************");
}
}
public static A getlnnstance(){ // 取得
return new B();
}
}
public class abstractClass{
public static void main(String args[]){
A a = A.getlnnstance();
a.printA();
}
}

日后如果发现在系统类库中有某个抽象类可以直接利用一个 static 方法取得实例化对象的时候不要觉得陌生

abstract class A{
public abstract void printA();
private static class B extends A { // 在A类里面直接定义实现的子类
public void printA(){
System.out.println("**************");
}
}
public static A getlnnstance(){ // 取得
return new B();
}
}
class C extends A{ // N年以后
public void printA(){
System.out.println("***************");
}
}
public class abstractClass{
public static void main(String args[]){
A a = A.getlnnstance();
a.printA();
A a1 = new C(); // 留给用户做的
a1.printA();
}
}

以上出现的几种形式有些是在后面讲解系统类库中会出现的问题,现阶段看看就完了

*/

/*    抽象类实际应用--模版设计模式
        清楚了抽象类产生动机以及使用之后,下面就必须搞清楚一个问题,抽象类与普通类到底有那些区别?
        现在假设有三个物种;
            机器人:补充能量+工作
            人:吃饭+工作+睡觉
            猪:吃+睡
        现在要求实现一种命令的模式,不管是何物种,只要传递指定的指令就可以进行操作
        范例:实现程序操作

abstract class Action{// 定义的是行为,行为一定不是具体的
public static final int EAT = 1;
public static final int SLEEP = 2;
public static final int WPRK = 5;
public void command(int flag){// 执行命令
switch(flag){// 数值用 switch 判断最好
case EAT:{
this.eat();
break;
}
case SLEEP:{
this.sleep();
break;
}
case WORK:{
this.work();
break;
}
}
}
public abstract void eat();// 因为这些具体的行为如何执行不知道 交由子类根据自己的实际情况完成
public abstract void sleep();
public abstract void work();
}
class Robot extends Action{
public void eat(){
System.out.println("机器人补充能量");
}
public void sleep(){}
public void work(){
System.out.println("机器人正在工作");
}
}
class Person extends Action{
public void eat(){
System.out.println("人在吃饭");
}
public void sleep(){
System.out.println("人在休息");
}
public void work(){
System.out.println("人在工作");
}
}
class Pig extends Action{
public void eat(){
System.out.println("猪在吃");
}
public void sleep(){
System.out.println("猪在睡");
}
public void work(){}
}
// 不同的子类有着自己不同的操作支持
public class abstractClass{
public static void main(String args[]){ }
}

范例:程序测试

abstract class Action{// 定义的是行为,行为一定不是具体的
public static final int EAT = 1;
public static final int SLEEP = 2;
public static final int WORK = 5;
public void command(int flag){// 执行命令
switch(flag){// 数值用 switch 判断最好
case EAT:{
this.eat();
break;
}
case SLEEP:{
this.sleep();
break;
}
case WORK:{
this.work();
break;
}
}
}
public abstract void eat();// 因为这些具体的行为如何执行不知道 交由子类根据自己的实际情况完成
public abstract void sleep();
public abstract void work();
}
class Robot extends Action{
public void eat(){
System.out.println("机器人补充能量");
}
public void sleep(){}
public void work(){
System.out.println("机器人正在工作");
}
}
class Person extends Action{
public void eat(){
System.out.println("人在吃饭");
}
public void sleep(){
System.out.println("人在休息");
}
public void work(){
System.out.println("人在工作");
}
}
class Pig extends Action{
public void eat(){
System.out.println("猪在吃");
}
public void sleep(){
System.out.println("猪在睡");
}
public void work(){}
}
// 不同的子类有着自己不同的操作支持
public class abstractClass{
public static void main(String args[]){
fun(new Pig());
System.out.println("*********************");
fun(new Robot());
System.out.println("*********************");
fun(new Person());
}
public static void fun(Action act){ // 接收的是行为
act.eat();
act.sleep();
act.work();
}
}

这样的设计就是将抽象类设计为了一个模版,如果要想实现这个模版的功能,子类就必须按照要求进行指定方法的覆写
        而关于这一设计的应用,在以后学习到的 Servlet 程序设计上就要采用到        

现在在整个程序之中,如果某一类事物需要实现特定的功能,那么就必须按照Action所定义的方法进行覆写
        这个时候类必须按照父类提供的模版编写代码

        总结
            1.抽象类的设计是在普通类之上的抽象类
            2.抽象类关键的问题就是约定了子类必须要覆写的抽象方法
            3.抽象类的使用原则:
                抽象类必须有子类,子类利用 extends关键字来继承抽象类,一个子类只能够继承一个父类
                抽象类的子类(如果不是抽象类)那么必须要覆写抽象类中的全部抽象方法
                抽象类可以利用对象的向上转型机制,通过子类对象进行实例化操作

*/

菜鸡的Java笔记 第二十三 - java 抽象类的概念的更多相关文章

  1. 菜鸡的Java笔记 第二十七 - java 链表基本概念

    链表基本概念        1.链表的基本形式        2.单向链表的完整实现            认识链表        链表= 可变长的对象数组,属于动态对象数组的范畴        链表 ...

  2. 菜鸡的Java笔记 第二十 - java 方法的覆写

    1.方法的覆写    当子类定义了与父类中的完全一样的方法时(方法名称,参数类型以及个数,返回值类型)这样的操作就称为方法的覆写    范例:观察方法的覆写 class A{ public void ...

  3. “全栈2019”Java多线程第二十三章:活锁(Livelock)详解

    难度 初级 学习时间 10分钟 适合人群 零基础 开发语言 Java 开发环境 JDK v11 IntelliJ IDEA v2018.3 文章原文链接 "全栈2019"Java多 ...

  4. 菜鸡的Java笔记 第二十八 - java 包的定义

    包的主要作用以及定义    包的导入操作    系统常见的开发包    jar 程序命令        包的定义        在任何的操作系统之中都有一个统一的共识:同一个目录下不能够存在有相同的文 ...

  5. <<深入Java虚拟机>>-第二章-Java内存区域-学习笔记

    Java运行时内存区域 Java虚拟机在运行Java程序的时候会将它所管理的内存区域划分为多个不同的区域.每个区域都有自己的用途,创建以及销毁的时间.有的随着虚拟机的启动而存在,有的则是依赖用户线程来 ...

  6. Java基础学习笔记二十三 Java核心语法之反射

    类加载器 类的加载 当程序要使用某个类时,如果该类还未被加载到内存中,则系统会通过加载,链接,初始化三步来实现对这个类进行初始化. 加载就是指将class文件读入内存,并为之创建一个Class对象.任 ...

  7. 【Java笔记】配置文件java.util.Properties类的使用

    配置文件的路径:项目名/src/main/resources/mmall.properties mmall.properties的内容是键值对.例如假设写了ftp服务器的一些信息. ftp.serve ...

  8. Java笔记12:Java对象排序

    代码: import java.util.Arrays; import java.util.Comparator; class Person { private String name; privat ...

  9. 菜鸡的Java笔记第二 - java 数据类型

    1.程序的本质实际上就是在于数据的处理上. JAVA中的数据类型有两类 基本数据类型:是进行内容的操作而不是内存的操作 数值型: 整型:byte(-128 ~ 127),short(-32768 ~ ...

随机推荐

  1. NVIDIA驱动安装

    在一次重启之后,NVIDIA显卡突然驱动坏了.实验室同学推测可能是有人安装了caffe,导致驱动被升级了.不论如何,需要重装驱动. 我的开发环境:Ubuntu 16.04 + GeForce GTX ...

  2. MR 01 - MapReduce 计算框架入门

    目录 1 - 什么是 MapReduce 2 - MapReduce 的设计思想 2.1 如何海量数据:分而治之 2.2 方便开发使用:隐藏系统层细节 2.3 构建抽象模型:Map 和 Reduce ...

  3. 原生JS实现简单留言板功能

    原生JS实现简单留言板功能,实现技术:css flex,原生JS. 因为主要是为了练手js,所以其中布局上的一些细节并未做处理. <!DOCTYPE html> <html lang ...

  4. Azure Devops实践(5)- 构建springboot项目打包docker镜像及容器化部署

    使用Azure Devops构建java springboot项目,创建镜像并容器化部署 1.创建一个springboot项目,我用现有的项目 目录结构如下,使用provider项目 在根目录下添加D ...

  5. 洛谷3320 SDOI2015寻宝游戏(set+dfs序)(反向迭代器的注意事项!)

    被\(STL\)坑害了一个晚上,真的菜的没救了啊. 准确的说是一个叫\(reverse\ iterator\)的东西,就是我们经常用的\(rbegin()\) 有一个非常重要的性质 在反向迭代器中,+ ...

  6. Dapr-简介及环境搭建

    一.Dapr是什么? Dapr 是一个可移植的.事件驱动的运行时,它使任何开发人员能够轻松构建出弹性的.无状态和有状态的应用程序,并可运行在云平台或边缘计算中,它同时也支持多种编程语言和开发框架. 在 ...

  7. vps实现私人代码托管并用nginx部署hexo

    个人博客 原本我的博客是通过github pages搭建的,但由于一些众所周知的原因,即使套上了CDN依旧是访问状态令人堪忧,经常会造成各种各样的问题,并且由于不存在服务器也不好进行进一步的管理,更不 ...

  8. 《看漫画学Pyhton》中计算水仙花数

    利用while循环实现 i = 100 r = 0 s = 0 t = 0 while i < 1000: r = i // 100 s = (i - r * 100) // 10 t = i ...

  9. 6月2日 Scrum Meeting

    日期:2021年6月2日 会议主要内容概述: 取消账单类别自定义 图表属性分析取消函数输入 增加新的主题模板 一.进度情况 组员 负责 两日内已完成的工作 后两日计划完成的工作 工作中遇到的困难 徐宇 ...

  10. 6月8日 Scrum Meeting

    日期:2021年6月8日 会议主要内容概述: 确定6.9日下午两点到五点集中对接 初步确定主题配色和echarts默认图表颜色 一.进度情况 组员 负责 两日内已完成的工作 后两日计划完成的工作 工作 ...