抽象类 abstract class
场景
public abstract class MockBusiness {
public void fun1(){
public abstract void fun2();// 依赖于第三方实现
public void fun3(){
}
}
1.抽象类的使用场景:
在业务实现中,有一个或多个功能需要依赖于第三方实现,则把该些功能设计为抽象方法,则该类就为抽象类。
2.定义:
含有抽象方法的类,就是抽象类
方法只有声明,没有实现(没有方法体)。
abstract void grow();
abstract void grow(){} // 有实现,空实现 error
3. 抽象类的定义以及使用规则:
抽象类不一定含有抽象方法。
包含一个抽象方法的类必须是抽象类;
抽象类和抽象方法都要使用 abstract 关键字声明;
抽象方法只需声明不要实现;
抽象类必须被子类继承,子类(如果不是抽象类)必须覆写抽象类中的全部抽象方法;
抽象类不能被实例化,只能引用子类的对象。 向上转换
抽象类作为参数,传的是子类的对象
抽象类作为返回值,返回的是子类的对象。
-
示例:
public abstract class MockBusiness {
public MockBusiness(){} public void fun1(){ } public void fun2(){ } public abstract void fun3() ;//fun3() 依赖于其他类【子类】实现 public void fun4(){ }
}
-
子类
/**
*
alt + enter implements 父类的抽象方法
*/
public class A extends MockBusiness {@Override public void fun3() { //子类实现父类方法(语法上是重写) }
}
public abstract class B extends MockBusiness {
//abstract fun3();
abstract void fun7();
}//实现子类C 要实现 所有父类 的所有抽象方法
public class C extends B {@Override void fun7() { } @Override public void fun3() { }
}
4. 注意:final abstract 不能结合使用
final类不能有子类;
抽象类必须有子类;
抽象类中能定义构造方法么?
答:能的;因为抽象类依然使用的是类的继承关系,且抽象类中
也存在各个属性,所以子类在实例化之前肯定是对父类进行的实例化的。
-
补充:
1.什么时候覆盖toString()方法?
Person p = new Person();
System.out.println§;
java会自动调用toString()方法;
但是结果不是我们想要的,因为Object类的toString()方法总是返回对象的
实现类类名 + @ + hashCode值。
我们希望的是能够打印出p的全名来,这时就希望能覆盖toString()方法,
因为重写toString方法之后,会优先调用自己的toString()方法。
应用中的抽象类:
若子类的方法实现都不一样,父类就没必要具体实现这些方法,父类把这些方法定义为抽象方法,子类根据自己的需求各自实现
**
* 银行账户
* 业务中:new Account() 错误
* new SavingAccount()
* new CreditAccount()
*
*/
public abstract class Account {
//取款 储蓄账户、信用账户 取款方式都不一样,
public abstract double withdrwa(double money);
}
public class SavingAccount extends Account {
@Override
public double withdrwa(double money) {
return 0;
}
}
public class CreditAccount extends Account {
@Override
public double withdrwa(double money) {
return 0;
}
}
接口存在的意义:
1、安全、严密性(封装):接口是实现软件松耦合的重要手段,它描叙了系统对外的所有服务,而不涉及任何具体的实现细节。这样就比较安全、严密一些(一般软件服务商考虑的比较多)。
2、维护、拓展性:比如你要做一个画板程序,其中里面有一个面板类,主要负责绘画功能,
然后你就这样定义了这个类,可是在不久将来,你突然发现这个类满足不了你了,然后你又要重新设计这个类,更糟糕是你可能要放弃这个类,那么其他地方可能有引用他,这样修改起来很麻烦,如果你一开始定义一个接口,把绘制功能放在接口里,然后定义类时实现这个接口,然后你只要用这个接口去引用实现它的类就行了,以后要换的话只不过是引用另一个类而已,这样就达到维护、拓展的方便性。
3、简单、规范性:如果一个项目比较庞大,
那么就需要一个能理清所有业务的架构师来定义一些主要的接口,
这些接口不仅告诉开发人员你需要实现那些业务,
而且也将命名规范限制住了(防止一些开发人员随便命名导致别的程序员无法看明白)。
4、重要性:在Java语言中, abstract class 和interface 是支持抽象类定义的两种机制。正是由于这两种机制的存在,才赋予了Java强大的 面向对象能力。
接口定义:就是两个对象相互通信的约束或规则
接口:
纯抽象类,是类能够做什么的合约,方法只有声明,没有实现。
是一种特殊类,里面全部是由全局常量和公共的抽象方法组成。
如何定义接口?
interface 接口名称{
// 全局常量;
// 抽象方法;
}
Ps:接口中定义的成员变量 ,成员方法
public interface A{
public static final int AGE= 18;
public abstract void fly();
}
等价于:(完全一样)
public interface A{
int i= 1;
void fly();
}
// 注意:
final、private、static、protected void fly();//非法定义接口的方法
- 示例:
接口:
public interface Cpu {
//全局常量
public static final int PRODUCT_YEAR = 2019;
//抽象方法
public abstract void cpuRun();
public abstract void cpuStop();
}
实现子类 HpCpu
public class HpCpu implements Cpu {
@Override
public void cpuRun() {
}
@Override
public void cpuStop() {
}
}
实现子类 HuaWeiCpu
//实现CPU 必须具备的功能
public class HuaWeiCpu implements Cpu{
@Override
public void cpuRun() {
}
@Override
public void cpuStop() {
}
}
接口使用注意:
1. 接口的使用也必须有子类,子类必须覆盖全部抽象方法,implements关键字实现, 一个子类可以实现多个接口,则子类如果不是抽象类的话,
一定要覆写接口中的全部方法。
2. 继承抽象类实现接口:
一个子类可以同时继承抽象类和实现接口
语法:
class 子类 extends 抽象类 implements 接口A,接口B...{}
3.接口的继承:
一个接口不能继承抽象类,但是能通过extends关键字同时继承多个接口,实现
接口的多继承。
语法:
interface 子接口 extends 父接口A,父接口B,...{}
接口中的抽象方法可以不加入abstract,而抽象类中的抽象方法必须有abstract关键字声明;
4.一个类只能继承一个父类,但是可以同时实现多个接口;
一个接口可以同时继承多个接口,以实现接口的多继承;
接口和抽象类一样,都必须依靠子类;
一个抽象类可以实现多个接口,但是一个接口不能继承一个抽象类。
5、如果某个类实现了某个接口,那么我们就说,这个类具备这个接口所定义的功能。从语法角度来说,和继承类似
6、接口不能被实例化,只能引用子类的对象(接口作为参数或者返回值类型)
7、什么时候使用抽象类和接口?
什么时候使用抽象类和接口?
应用:
一个类中一部分功能需要依赖于其他类实现,则把这些方法定义为抽象方法,该类 为 抽象类
组件与组件之间(模块与模块之间)的通讯,使用接口 (保证业务内部实现不被暴露,降低模块之间的耦合性)
语法:
public abstract class A{
public void fun1(){}
public abstract void fun2();
}
public interface B{
//全局常量
public static final int X = 10;
//抽象方法
public abstract void fun3();
}
public interface A {
public void fun1();
}
interface B{
public void fun2();
}
//接口 可以多继承
interface C extends A,B{
public void fun3();
}
class D{
}
// 继承 + 实现多接口
class E extends D implements A,B,C{
@Override
public void fun1() {
}
@Override
public void fun2() {
}
@Override
public void fun3() {
}
}
枚举 enum
JDK5.0新特性之枚举:
1、枚举分析
是一种数据类型,是一个类,是一个final类,
其对象是现成的固定的,其父类是java.lang.Enum。
2.在JDK5.0之前,用此方式实现枚举
例子:自己完成一个枚举类;
class Season1{
public static final Season1 SPRING = new Season1();
public static final Season1 SUMMER = new Season1();
public static final Season1 AUTUMN = new Season1();
public static final Season1 WINTER = new Season1();
private Season1(){} //构造方法私有
}
或者
class Season1{
public static final Season1 SPRING = new Season1(“春天”);
public static final Season1 SUMMER = new Season1(“夏天”);
public static final Season1 AUTUMN = new Season1(“秋天”);
public static final Season1 WINTER = new Season1(“冬天”);
private String name;
private Season1(){ this.name=name} //构造方法私有
public String getName(){
return name;
}
}
3. JDK5.0支持枚举
语法格式:
修饰符 enum Season2{
//枚举值
//属性
//构造器(私有)
//方法
}
-
示例
enum Season2{ SPRING, SUMMER, AUTUMN,WINTER }
或者
enum Season{
//枚举值
SPRING(“春天”),
SUMMER(“夏天”),
AUTUMN(“秋天”),
WINTER(“冬天”);
//属性
String name;
//构造器
Season(String name){
this.name=name;
}
//方法
public String getName(){
return this.name;
}
}
-
注意:
1)枚举可以很好的控制参数的种类和数量,保证必须按照程序员安排来选择; 2)类不能继承枚举,枚举也不能继承类,但可以实现接口; 3)枚举是一个final类,但是enum中却可以有抽象方法,抽象方法是由枚举值实现的;即这些 抽象方法只能通过定义好的几个对象来实现,而且只能通过匿名的内部类的方法来实现。 4)枚举写在最前面,否则编译错误 5)实现带有构造器的枚举: a. 通过括号赋值,而且必须带有一个参构造器和一个属性跟方法,否则编译出; b. 赋值必须都赋值或都不赋值,不能一部分赋值一部分不赋值;如果不赋值则不能写构造器,赋值编译也出错. 6)构造器默认也只能是private, 从而保证构造函数只能在内部使用 7)枚举是一种类型,用于定义变量,以限制变量的赋值;赋值时通过“枚举名.值”取得枚举中的值(例如:ColorEnum colorEnum = ColorEnum.black;(switch case)) 8)for-each遍历枚举 9)获取枚举的个数 10)获取枚举的索引位置,默认从0开始 11)枚举默认实现了java.lang.Comparable接口