抽象
概述:
在java中,一个没有方法体的方法应该定义为抽象方法,而类中如果有抽象方法,该类必须定义为抽象类
修饰类:
如果一个类中存在抽象方法,那么该类就必须声明为抽象类。
-
修饰方法:
将共性的行为(方法)抽取到父类之后,发现该方法的实现逻辑无法在父类中给出具体实现,该方法就可以定义为抽象方法。
- 访问修饰符 abstract 返回类型 方法名(参数列表);
- 抽象类价值更多在于设计,设计者设计好后让子类继承并实现抽象类
特点:
- 抽象类和抽象方法必须使用abstract关键字修饰
- 抽象类中不一定有抽象方法,有抽象方法的类一定是抽象类
- 抽象类不能实例化,但可通过子类对象实例化,这叫抽象类多态
- 抽象类的子类要么重写抽象类中所有方法要么是抽象类
抽象类和普通类的区别:(有得有失)
- 抽象类得到定义抽象能力
- 抽象类失去创建对象能力
- 除此之外普通类可以定义的,抽象类都可以
成员特点:
- 成员变量:
- 可以是变量和常量
- 构造方法:
- 有构造方法但不能实例化,用于子类访问父类数据的初始化
成员方法:
接口就是一种公共的规范标准,只要符合标准规范,大家都通用,java中接口更多体现在对行为的抽象
接口特点:
- 接口用关键字interface修饰
- 类实现接口用implements表示
- 接口不能实例化
- 如何实现实例化:通过实现类对象实例化,这叫接口多态
- 多态的形式:具体类多态,抽象类多态,接口多态
- 多态的前提:有继承或者实现关系,有方法重写,有父(类/接口)引用指向(子/实现)类对象
接口实现类
- 要么重写接口中所有抽象方法
- 要么抽象类
接口成员特点:
- 成员变量:
- 只能是常量
- 默认修饰符:public static final
- 构造方法:
- 接口没有构造方法,接口主要是对行为进行抽象的,是没有具体存在
- 一个类如果没有父类,默认继承Object
- 成员方法:
- JDk7及以前, 只能定义抽象方法和常量
- 原因是所有方法都有默认修饰符:public abstract
- JDK8以后, 可以带方法体的方法(减少耦合性)
- 静态方法直接写, 非静态方法要用default修饰
- JDK9以后, 可以私有方法直接写即可(提高复用性)
- JDk7及以前, 只能定义抽象方法和常量
类与接口的关系:
- 类和类的关系:
- 继承关系,只能单继承,但是可以多层继承
- 类和接口的关系:
- 实现关系,可以单实现,也可以多实现,还可以继承一个类的同时实现多个接口
- 接口和接口的关系:
- 继承关系,可以单继承,也可以多继承
抽象类和接口区别:
- 成员区别:
- 抽象类:变量、常量、构造方法、抽象方法、非抽象方法
- 接口:常量、抽象方法
- 关系区别:
- 类与类:继承、单继承
- 类与接口:单实现、多实现
- 接口与接口:单继承、多继承
- 设计理念区别:
- 抽象类:对类抽象,包括属性、行为
- 接口:对行为抽象
对于一个类来讲, 他的父类(继承的关系)中定义的都是:共性内容
对于一个类来讲, 他是父接口(实现的关系)中定义的都是:扩展内容
:::
public interface Usb {
//定义变量public static final为默认修饰可不写
public static final double TYPE = 3.0;
//定义方法public abstract为默认修饰可不写
public abstract void connect();
public abstract void exit();
}
//类实现接口用implements实现
public class Computer implements Usb {
//必须重写接口所有抽象方法
@Override
public void connect() {
System.out.println("USB已安全插入");
}
@Override
public void exit() {
System.out.println("USB已安全断开");
}
}
形参和返回值
类名做为参数返回值
- 方法的形参是类名,其实需要的是该类的对象
-
抽象类名作为形参和返回值
方法的形参是抽象类名,其实需要的是该类的子类对象
-
接口名作为形参和返回值
方法的形参是接口名,其实需要的是该接口的实现类对象
方法的返回值是接口名,其实返回的是该接口的实现类对象 :::
内部类
概述:
一个类的内部又完整嵌套了另一个类结构
- [类的五大成员:属性,方法,构造器,代码块,内部类]
访问特点:
- 内部类可以直接访问外部类成员,包括私有
- 外部类要访问内部类成员,必须创建对象
局部内部类:(定义在方法或者代码块中)
- 可以访问外部类所有成员包括私有
- 不能添加访问修饰符(局部变量),可以使用final修饰
- 局部内部类是在方法中定义的类,所以外界是无法直接使用的,需要在方法内创建对象并使用
- 该类可以直接访问外部类的成员,也可访问方法内的局部变量
- 外部其他类不能访问局部内部类(局部内部类的地位是一个局部变量)
- 外部类和局部内部类的成员重名时,默认遵循就近原则,可以通过(外部类名.this.成员)去访问外部类的成员
#▲匿名内部类:
- 本质还是类 属于内部类 该类没有名字(底层会有) 同时还是一个对象
- 匿名内部类是定义在外部类的局部位置,比如方法中,并且没有名字
- 存在一个类或接口中,可以具体类也可以抽象类
- 本质是一个继承了该类或者实现该接口的子类匿名
基本语法:类/接口 对象名 = new 类/接口(参数列表){}
直接调用:new 类/接口(参数列表).方法名;
匿名内部类比较奇特,既是类的定义,同时本身也是一个对象
成员内部类:
- 成员内部类是定义在外部类的成员位置,并且没有static修饰
- 可以直接访问外部类所有成员,包含私有
- 可以添加任意访问修饰符,因为他就是一个成员
- 作用域和外部类的其他成员一样,为整个类体
- 内部类访问:直接访问
- 外部类访问:创建对象访问
外部其他类访问:
定义在外部类成员位置,并且有static修饰
- 可以访问外部类所有静态成员,但不能访问非静态成员
- 可以添加任意访问修饰符,因为他就是一个成员
- 作用域:同其他的成员为一个整体
- 内部类访问:直接访问
- 外部类访问:创建对象访问
:::
```java //外部其他类 public class AnonymousInnerClass { public static void main(String[] args) {class Outer { { class Inner { } } public void a() { class Inner { } } }
} }Outer outer = new Outer(); outer.method();
//外部类 class Outer { public void method() { //方法 //基于接口的匿名内部类(当有些类只使用一次后不再使用) //编译类型:IA //运行类型:匿名内部类 / 底层:(类名:外部类名 + $1) class Outer$1 implements IA() { @Override public void cry() { System.out.println(“老虎叫唤”); } } / //jdk底层在创建匿名内部类Outer$1,会立即马上创建Outer$1实例并且把地址返回给tiger //匿名内部类在使用一次就不能在使用,但对象可以反复调用 IA tiger = new IA() { @Override public void cry() {} }; tiger.cry(); //打印运行类型类名称 System.out.println(tiger.getClass());//class 包名.Outer$1
//基于方法的匿名内部类
//编译类型:IB
//运行类型:匿名内部类
/*
底层会创建匿名内部类
class Outer$2 extends IB(){}
*/
//同时会返回匿名内部类Outer$2的对象
//参数列表会传递给构造器
IB ib = new IB(){};
ib.test();
System.out.println(ib.getClass());//class 包名.Outer$2
//基于抽象类的匿名内部类
IC ic = new IC(){
@Override
void test() {}
};
ic.test();
System.out.println(ic.getClass());//class 包名.Outer$3
}
}
//接口 interface IA { public void cry(); }
//将只使用一次的类优化为匿名内部类 /class Tiger implements IA { @Override public void cry() { System.out.println(“老虎叫唤”); } }/
//外部其他类 class IB { //构造器 public IB() {} //方法 public void test() {} }
//抽象类 abstract class IC{ abstract void test(); }
```java
public class AnonymousInnerClass01 {
public static void main(String[] args) {
//匿名内部类当做实参进行传递,简洁高效
num(new ID() {
@Override
public void show() {
System.out.println("匿名内部类应用");
}
});
}
//静态方法,形参是接口
public static void num(ID id){
id.show();
}
}
//接口
interface ID{
void show();
}
/*
定义铃声接口Bell,里面有ring方法
定义手机类CellPhone,具有闹钟功能alarmClock
通过匿名内部类(对象)作为参数打印:懒猪起床了
再传入匿名内部类(对象)打印:小伙伴上课了
*/
public class AnonymousInnerClass02 {
public static void main(String[] args) {
//创建手机类对象
CellPhone cP = new CellPhone();
//调用闹钟方法将匿名内部类作为实参传递
cP.alarmClock(new Bell() {
@Override
public void ring() {
System.out.println("懒猪起床了");
}
});
cP.alarmClock(new Bell() {
@Override
public void ring() {
System.out.println("小伙伴上课了");
}
});
}
}
//接口
interface Bell{
//方法
void ring();
}
//手机类
class CellPhone{
//方法闹钟功能
public void alarmClock(Bell bell) {
bell.ring();
}
}
class Outer {
class Inner {
public void a() {}
}
}
枚举
:::tips 概述:
- 枚举类编译后本质是final修饰的java类,并且继承了java.lang.Enum类
- 枚举类的构造方法都是private修饰的,所以枚举类无法在外部创建对象
- 每个枚举值都是该类的对象,并且都是public static final修饰的
- 枚举本质是一个java类,所以枚举中可以有成员变量、成员方法、构造方法等成分
- 枚举类可以实现接口
自定义实现枚举
- 构造器私有化
- 本类内部创建对象
- 对外暴露对象(通过public final static修饰)
- 提供get不提供set方法
enum关键字实现枚举
- 使用关键字enum代替class
- 常量名(实参列表)等同public final static 类名 常量名 = new 类名(实参列表);
- 使用:类名.枚举值
:::
```java
public class Test {
public static void main(String[] args) {
} }Person person = new Person("jack", Gender.MAN); System.out.println(person);
public enum Gender { MAN, WOMEN; }
public class Person { private String name; private Gender sex; //构造方法 //setget //toString } ``` | abstract | /ˈæbstrækt/ | adj. 抽象的 | | —- | —- | —- | | interface | /ˈɪntəfeɪs/ | 接口 | | implements | /‘ɪmplɪm(ə)nts/ | 实现 | | default | /dɪˈfɔːlt/ | 默认 | | enum | /ɪˌnjuːm/ | 枚举 |