Java 抽象类 使用方法【非常详细】 男娘i 2022-06-03 01:43 205阅读 0赞 ### 一、抽象类的基本概念 ### 普通类是一个完善的功能类,可以直接产生实例化对象,并且在普通类中可以包含有构造方法、普通方法、static方法、常量和变量等内容。 而抽象类是指在普通类的结构里面增加抽象方法的组成部分。 **那么什么叫抽象方法呢?**在所有的普通方法上面都会有一个“\{\}”,这个表示方法体,有方法体的方法一定可以被对象直接使用。而抽象方法,是指没有方法体的方法,同时抽象方法还必须使用关键字abstract做修饰。 而拥有抽象方法的类就是抽象类,抽象类要使用abstract关键字声明。 **范例:定义一个抽象类** abstract class A{ //定义一个抽象类 public void fun(){ //普通方法 System.out.println("存在方法体的方法"); } public abstract void print();//抽象方法,没有方法体,有abstract关键字做修饰 } **抽象类的特点:** > 1,抽象方法一定在抽象类中。 > 2,抽象方法和抽象类都必须被abstract关键字修饰。 > 3,抽象类不可以用new创建和实例化对象。因为抽象类本身就是不完整的。 > 4,抽象类中的抽象方法要被使用,必须由子类复写所有的抽象方法后,建立子类对象调用。 > 如果子类只覆盖了部分抽象方法,那么该子类还是一个抽象类。 ### ![Center][] ### ### 二、抽象类的使用 ### **抽象类的注意事项:** > * 抽象类不能实例化 不能造对象(抽象类中一定也有构造器,用于创建子类对象时此构造器可以被调用) > * 抽象类中不一定有抽象方法,但是抽象方法一定存在于抽象类中 > * 若子类重写了父类中所有的抽象方法,则意味着此子类方可进行实例化 > * 若子类没有重写父类中所有的抽象方法,意味着此子类是一个抽象方法,且不能进行实例化 > * 子类重写抽象方法 不光是直接父类的抽象方法 也包括间接父类的抽象方法 **抽象方法的注意事项:** > * 抽象方法一定存在于抽象类中,抽象方法没有方法体 > * 子类如果继承了抽象类,且该子类不是一个抽象类,一定要重写抽象类中的所有方法 **范例:直接实例化抽象类的对象** package com.wz.abstractdemo; abstract class A{ //定义一个抽象类 public void fun(){ //普通方法 System.out.println("存在方法体的方法"); } public abstract void print();//抽象方法,没有方法体,有abstract关键字做修饰 } public class TestDemo { public static void main(String[] args) { A a = new A(); } } 运行: Exception in thread "main" java.lang.Error: Unresolved compilation problem: Cannot instantiate the type A at com.wz.abstractdemo.TestDemo.main(TestDemo.java:15) 从上可知,A是抽象的,无法直接进行实例化操作。为什么不能直接实例化呢?当一个类实例化之后,就意味着这个对象可以调用类中的属性或者放过了,但在抽象类里存在抽象方法,而抽象方法没有方法体,没有方法体就无法进行调用。既然无法进行方法调用的话,又怎么去产生实例化对象呢。 **抽象类的使用原则如下:** > (1)抽象方法必须为public或者protected(因为如果为private,则不能被子类继承,子类便无法实现该方法),缺省情况下默认为public; > (2)抽象类不能直接实例化,需要依靠子类采用向上转型的方式处理; > (3)抽象类必须有子类,使用extends继承,一个子类只能继承一个抽象类; > (4)子类(如果不是抽象类)则必须覆写抽象类之中的全部抽象方法(如果子类没有实现父类的抽象方法,则必须将子类也定义为为abstract类。); 范例: package com.wz.abstractdemo; abstract class A{ //定义一个抽象类 public void fun(){ //普通方法 System.out.println("存在方法体的方法"); } public abstract void print();//抽象方法,没有方法体,有abstract关键字做修饰 } //单继承 class B extends A{ //B类是抽象类的子类,是一个普通类 @Override public void print() { //强制要求覆写 System.out.println("Hello World !"); } } public class TestDemo { public static void main(String[] args) { A a = new B();//向上转型 a.fun();//被子类所覆写的过的方法 } } 运行结果: Hello World ! **现在就可以清楚的发现:** > (1)抽象类继承子类里面有明确的方法覆写要求,而普通类可以有选择性的来决定是否需要覆写; > (2)抽象类实际上就比普通类多了一些抽象方法而已,其他组成部分和普通类完全一样; > (3)普通类对象可以直接实例化,但抽象类的对象必须经过向上转型之后才可以得到。 **虽然一个类的子类可以去继承任意的一个普通类,可是从开发的实际要求来讲,普通类尽量不要去继承另外一个普通类,而是去继承抽象类。** ### 三、抽象类的使用限制 ### **(1)抽象类中有构造方法么?** 由于抽象类里会存在一些属性,那么抽象类中一定存在构造方法,其存在目的是为了属性的初始化。 并且子类对象实例化的时候,依然满足先执行父类构造,再执行子类构造的顺序。 范例如下: package com.wz.abstractdemo; abstract class A{ //定义一个抽象类 public A(){ System.out.println("*****A类构造方法*****"); } public abstract void print();//抽象方法,没有方法体,有abstract关键字做修饰 } //单继承 class B extends A{ //B类是抽象类的子类,是一个普通类 public B(){ System.out.println("*****B类构造方法*****"); } @Override public void print() { //强制要求覆写 System.out.println("Hello World !"); } } public class TestDemo { public static void main(String[] args) { A a = new B();//向上转型 } } 执行结果: *****A类构造方法***** *****B类构造方法***** **(2)抽象类可以用final声明么?** 不能,因为抽象类必须有子类,而final定义的类不能有子类; **(3)抽象类能否使用static声明?** 先看一个关于外部抽象类的范例: package com.wz.abstractdemo; static abstract class A{ //定义一个抽象类 public abstract void print(); } class B extends A{ public void print(){ System.out.println("**********"); } } public class TestDemo { public static void main(String[] args) { A a = new B();//向上转型 a.print(); } } 执行结果 Exception in thread "main" java.lang.Error: Unresolved compilation problem: Illegal modifier for the class A; only public, abstract & final are permitted at com.wz.abstractdemo.A.<init>(TestDemo.java:3) at com.wz.abstractdemo.B.<init>(TestDemo.java:9) at com.wz.abstractdemo.TestDemo.main(TestDemo.java:18) 再看一个关于内部抽象类: package com.wz.abstractdemo; abstract class A{ //定义一个抽象类 static abstract class B{ //static定义的内部类属于外部类 public abstract void print(); } } class C extends A.B{ public void print(){ System.out.println("**********"); } } public class TestDemo { public static void main(String[] args) { A.B ab = new C();//向上转型 ab.print(); } } 执行结果: ********** 由此可见,外部抽象类不允许使用static声明,而内部的抽象类运行使用static声明。使用static声明的内部抽象类相当于一个外部抽象类,继承的时候使用“外部类.内部类”的形式表示类名称。 (4)可以直接调用抽象类中用static声明的方法么? 任何时候,如果要执行类中的static方法的时候,都可以在没有对象的情况下直接调用,对于抽象类也一样。 范例如下: package com.wz.abstractdemo; abstract class A{ //定义一个抽象类 public static void print(){ System.out.println("Hello World !"); } } public class TestDemo { public static void main(String[] args) { A.print(); } } 运行结果: Hello World ! (5)有时候由于抽象类中只需要一个特定的系统子类操作,所以可以忽略掉外部子类。这样的设计在系统类库中会比较常见,目的是对用户隐藏不需要知道的子类。 范例如下: package com.wz.abstractdemo; abstract class A{ //定义一个抽象类 public abstract void print(); private static class B extends A{ //内部抽象类子类 public void print(){ //覆写抽象类的方法 System.out.println("Hello World !"); } } //这个方法不受实例化对象的控制 public static A getInstance(){ return new B(); } } public class TestDemo { public static void main(String[] args) { //此时取得抽象类对象的时候完全不需要知道B类这个子类的存在 A a = A.getInstance(); a.print(); } } 运行结果: Hello World ! ### 四、抽象类的应用——模板设计模式 ### 例如,现在有三类事物: (1)机器人:充电,工作; (2)人:吃饭,工作,睡觉; (3)猪:进食,睡觉。 现要求实现一个程序,可以实现三种不同事物的行为。 先定义一个抽象行为类: package com.wz.abstractdemo; public abstract class Action{ public static final int EAT = 1 ; public static final int SLEEP = 3 ; public static final int WORK = 5 ; public abstract void eat(); public abstract void sleep(); public abstract void work(); public void commond(int flags){ switch(flags){ case EAT: this.eat(); break; case SLEEP: this.sleep(); break; case WORK: this.work(); break; case EAT + SLEEP: this.eat(); this.sleep(); break; case SLEEP + WORK: this.sleep(); this.work(); break; default: break; } } } 定义一个机器人的类: package com.wz.abstractdemo; public class Robot extends Action{ @Override public void eat() { System.out.println("机器人充电"); } @Override public void sleep() { } @Override public void work() { System.out.println("机器人工作"); } } 定义一个人的类: package com.wz.abstractdemo; public class Human extends Action{ @Override public void eat() { System.out.println("人吃饭"); } @Override public void sleep() { System.out.println("人睡觉"); } @Override public void work() { System.out.println("人工作"); } } 定义一个猪的类: package com.wz.abstractdemo; public class Pig extends Action{ @Override public void eat() { System.out.println("猪进食"); } @Override public void sleep() { System.out.println("猪睡觉"); } @Override public void work() { } } 测试主类: package com.wz.abstractdemo; public class AbstractDemo { public static void main(String[] args) { fun(new Robot()); fun(new Human()); fun(new Pig()); } public static void fun(Action act){ act.commond(Action.EAT); act.commond(Action.SLEEP); act.commond(Action.WORK); } } 运行结果: 机器人充电 机器人工作 人吃饭 人睡觉 人工作 猪进食 猪睡觉 所有的子类如果要想正常的完成操作,必须按照指定的方法进行覆写才可以,而这个时候抽象类所起的功能就是一个类定义模板的功能。 ### 四、抽象类相关的设计模式 ### **定义模板** ![这里写图片描述][SouthEast] abstract class Person{ private String name ; // 定义name属性 private int age ; // 定义age属性 public Person(String name,int age){ this.name = name ; this.age = age ; } public String getName(){ return this.name ; } public int getAge(){ return this.age ; } public void say(){ // 人说话是一个具体的功能 System.out.println(this.getContent()) ; // 输出内容 } public abstract String getContent() ; // 说话的内容由子类决定 }; class Student extends Person{ private float score ; public Student(String name,int age,float score){ super(name,age) ; // 调用父类中的构造方法 this.score = score ; } public String getContent(){ return "学生信息 --> 姓名:" + super.getName() + ";年龄:" + super.getAge() + ";成绩:" + this.score ; } }; class Worker extends Person{ private float salary ; public Worker(String name,int age,float salary){ super(name,age) ; // 调用父类中的构造方法 this.salary = salary ; } public String getContent(){ return "工人信息 --> 姓名:" + super.getName() + ";年龄:" + super.getAge() + ";工资:" + this.salary ; } }; public class AbstractCaseDemo02{ public static void main(String args[]){ Person per1 = null ; // 声明Person对象 Person per2 = null ; // 声明Person对象 per1 = new Student("张三",20,99.0f) ; // 学生是一个人 per2 = new Worker("李四",30,3000.0f) ; // 工人是一个人 per1.say() ; // 学生说学生的话 per2.say() ; // 工人说工人的话 } }; **分析:** 1,说话这个功能,正常的是个人都有这个功能,所以可以抽取出来,在Person这个类中,定义一个say()方法,但是说话的内容,不同的类型的人讨论的话题不同,这个话题,不能写成具体的,需要定义成一个抽象的方法,在不同的子类中实现不同的内容。 2,一个人,无论是工人还是学生或者其他什么人,想说话么,想说话,就覆写我的getContent()方法,就是这样规定好了,这就是模板, ### 关注我们,更多技术干货: ### **[2000多G的计算机各行业电子资源分享(持续更新)][2000_G]** **[2020年微信小程序全栈项目之喵喵交友【附课件和源码】][2020]** **[Spring Boot开发小而美的个人博客【附课件和源码】][Spring Boot]** **[Java微服务实战296集大型视频-谷粒商城【附代码和课件】][Java_296_-]** **[Java开发微服务畅购商城实战【全357集大项目】-附代码和课件][Java_357_-]** **[最全最详细数据结构与算法视频-【附课件和源码】][-]** ![在这里插入图片描述][watermark_type_ZmFuZ3poZW5naGVpdGk_shadow_10_text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxXzQwNTg3NTc1_size_16_color_FFFFFF_t_70_pic_center] <table> <tbody> <tr> <td> <p><strong>2021年JAVA 精心整理的常见面试题-附详细答案</strong></p> </td> <td><a href="https://mikejun.blog.csdn.net/article/details/114488339" rel="nofollow">https://mikejun.blog.csdn.net/article/details/114488339</a></td> </tr> <tr> <td> <p><strong>2021年- 精心整理的 SpringMVC 常见面试题-【附详细答案】</strong></p> </td> <td><a href="https://mikejun.blog.csdn.net/article/details/114992529" rel="nofollow">https://mikejun.blog.csdn.net/article/details/114992529</a></td> </tr> <tr> <td> <p><strong>2021年JAVA 面试题之--数据结构篇【附详细答案】</strong></p> </td> <td><a href="https://mikejun.blog.csdn.net/article/details/114647742" rel="nofollow">https://mikejun.blog.csdn.net/article/details/114647742</a></td> </tr> <tr> <td> <p><strong>精心整理的计算机各类别的电子书籍【超全】</strong></p> </td> <td><a href="https://mikejun.blog.csdn.net/article/details/115442555" rel="nofollow">https://mikejun.blog.csdn.net/article/details/115442555</a></td> </tr> <tr> <td> <p><strong>三天刷完《剑指OFFER编程题》--Java版本实现(第一天)</strong></p> </td> <td><a href="https://mikejun.blog.csdn.net/article/details/106996017" rel="nofollow">https://mikejun.blog.csdn.net/article/details/106996017</a></td> </tr> <tr> <td> <p><strong>三天刷完《剑指OFFER编程题》--Java版本实现(第二天)</strong></p> </td> <td><a href="https://mikejun.blog.csdn.net/article/details/108098502" rel="nofollow">https://mikejun.blog.csdn.net/article/details/108098502</a></td> </tr> <tr> <td> <p><strong>三天刷完《剑指OFFER编程题》--Java版本实现(第三天)</strong></p> </td> <td><a href="https://mikejun.blog.csdn.net/article/details/108253489" rel="nofollow">https://mikejun.blog.csdn.net/article/details/108253489</a></td> </tr> </tbody> </table> [Center]: /images/20220603/9ac62a5ba2ea48b3b0e86af9f81bac29.png [SouthEast]: /images/20220603/e3d533ab54164cef926b5a7d92b503a6.png [2000_G]: https://mp.weixin.qq.com/s/sP4JgGWkCzpgwKr9sAV2_Q [2020]: https://mp.weixin.qq.com/s?__biz=MzIyNTI3NDQ4NQ==&mid=2247487704&idx=1&sn=5f4b2127c4d49fd07ae072a0721424a2&chksm=e8036fc2df74e6d489c4aa9b06f917ef7cee6027f13e150fca53cf79d5d188d4ccc1af49e098&scene=21#wechat_redirect [Spring Boot]: https://mp.weixin.qq.com/s?__biz=MzIyNTI3NDQ4NQ==&mid=2247487798&idx=2&sn=ac0293b996521b872a9dba5fbb3e65e6&chksm=e8036e2cdf74e73aba104a9a994a5b2e31483e8dcbe0f1d9936f6d5173b887e1560f59d2819c&scene=21#wechat_redirect [Java_296_-]: https://mp.weixin.qq.com/s?__biz=MzIyNTI3NDQ4NQ==&mid=2247487674&idx=1&sn=7aff0bdf2bb727303f3d3618995aef21&chksm=e8036fa0df74e6b6d872c7e6ece179c524ed463a4a6b74c96875475c9a3d5ddb903427dd993b&scene=21#wechat_redirect [Java_357_-]: https://mp.weixin.qq.com/s?__biz=MzIyNTI3NDQ4NQ==&mid=2247486376&idx=1&sn=d1fef270c463ea8ac663f6fbfedd70a0&chksm=e80374b2df74fda4d3bafba878a106a19e18c5fcda266008f4f37975847a21bc612ffcd5ff39&scene=21#wechat_redirect [-]: https://mp.weixin.qq.com/s?__biz=MzIyNTI3NDQ4NQ==&mid=2247487750&idx=1&sn=747bccbb5f5ea6b58915198de40da777&chksm=e8036e1cdf74e70ae97a5e8e265b49d7236d904d291203309159d07ba1724033062c0e370843&scene=21#wechat_redirect [watermark_type_ZmFuZ3poZW5naGVpdGk_shadow_10_text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxXzQwNTg3NTc1_size_16_color_FFFFFF_t_70_pic_center]: /images/20220603/befb2d41e56e44bf85bc35c5a1c52aa0.png
还没有评论,来说两句吧...