6、面向对象
面向机器语言:机器语言、汇编语言
面向过程语言:C 语言,FORTRAN 语言
面向过程:面向过程是一种以过程、事件为中心的编程思想。面向过程语言将代码组织成称为过程或函数的块。每个函数或块的目标是完成某个任务。
Java 面向对象内容:
- Java 类及类成员:属性,方法,构造器,代码块,内部类
- 面向对象的三大特征:封装,继承,多态
- 其他关键字:this,super,static,final,abstract,interface,package,import
1、Java 类和类的成员
面向对象的两个要素:
- 类:对一类事物的描述,是抽象的、概念上的定义
- 对象:是实际存在的该类事物的每个个体,因而也称为实例(instance)
设计类就是设计类的成员,类包含「变量的声明」和「方法的定义」
- 属性 = 成员变量 = 域、字段 = field
- 方法 = 成员方法 = 函数 = method
- 创建类的对象 = 类的实例化 = 实例化类
类和对象的使用
- 创建类、设计类成员
- 创建类的对象
- 调用类的属性或方法
对象的内存解析
- 栈(stack):存储局部变量
- 堆(heap):存放对象实例
1.1、 属性(成员变量)与 局部变量
成员变量又分为 「实例变量」和 「类变量(static)」
「成员变量」与「局部变量」的异同
相同点:
- 定义变量的格式:
数据类型 变量名 = 变量值
- 先声明后使用
- 变量都有其对应作用域
不同点:
- 类中声明的位置不同。
- 成员变量:直接定义在 类 中
- 局部变量:声明在 方法 内,方法形参,代码块内,构造器形参,构造器内部的变量
- 权限修饰符的不同
常用权限修饰符:public、private、protected、缺省
(封装性)- 成员变量:可以 在声明属性时使用权限修饰符
- 局部变量:不可以 使用权限修饰符
- 默认初始化值的情况
- 成员变量:有默认初始化值
- 整形
byte,int,short,long
,默认值:0 - 浮点型
float double
,默认值:0.0 - 字符型
char
,默认值:0或'\u0000' - 布尔型
boolean
,默认值:false - 引用数据类型
类、数组、接口
,默认值:null
- 整形
- 局部变量:没有 默认初始化值,在调用局部变量之前 一定要显式赋值
- 成员变量:有默认初始化值
- 在内存中加载的位置:
- 属性:(非static)加载到堆空间中
- 局部变量:加载到栈空间中
class User{
//属性(或成员变量)
String name;
public void talk(String language){//形参,局部变量
String food = "饼";//局部变量
System.out.println("我们使用"+language+"交流");
}
1.2、 方法声明与使用
方法:描述类应该具有的功能
一般方法的声明:权限修饰符 返回值类型 方法名(形参列表){ 方法体 }
- 权限修饰符:private、public、缺省、protected
- 返回值类型:
- 有返回值
- 无返回值
- 方法名:遵循规范,见名知意
- 形参列表:可以有0个,1个或多个形参
相关信息
方法可以嵌套调用,不能嵌套定义
对象调用方法时,方法中的「局部变量」被分配内存空间。方法执行完毕,局部变量立即释放内存
1.3、方法的重载
Java 中存在两种多态: 重载(Overload)和 重写(Override)
重载的概念:
- 在
同一个类
中,允许存在一个以上的同名方法
- 只要它们的
参数个数
或参数类型不同
即可 - 方法的
返回类型
和参数的名字
不参与比较
1.4、构造器
构造器是一种特殊的方法,它的名字与它所在的类完全相同,且没有类型
构造器的作用:
- 创建对象
- 初始化对象的属性
//创建类的对象:new + 构造器
Person p = new Person()
相关信息
- 构造器 无返回值 (
void A()
不是构造器) - 子类「不能继承」父类的构造器,构造方法只能被显式或隐式的调用
- 若没有显示定义类的构造器,系统默认提供一个 「空参的构造器」
- 定义构造器的格式:
权限修饰符 类名(形参列表){}
- 一个类中定义的多个构造器构成 「重载」
- 显示的定义了类的构造器后,系统就 「不提供」 默认的空参构造器
- 一个类中,至少有一个构造器
1.5、return 关键字
作使用范围:方法体中用:
- 结束方法
- 返回所要的数据
- return关键字后不可以声明执行语句(同break;)
1.6、对象数组
内存解析的说明:
相关信息
引用类型的变量,只可能存储两类值:null 和 地址值(含变量类型)
1.7、匿名对象,抽象类的匿名子类对象
- 匿名对象的意义:一般只使用一次
public class StudentTest{
public static void main(String[] args){
//匿名对象
new Phone.sendEmail();
new Phone.sendEmail();//两个不同的匿名对象
PhoneMall mall = new PhoneMall();
//匿名对象的使用
mall.show(new Phone());
}
抽象类的匿名子类对象
抽象类的匿名字类对象:可以少写一个类,直接重写方法
//一个匿名子类的对象:P
Person p = new Person(){
@oiverride.
public void eat(){
System.out.println("eat");
}
};
1.8、可变个数的形参
jdk5.0 新增内容
可变个数形参的格式:数据类型...变量名
(相当于数组)
相关信息
可变个数的形参的方法与本类中方法名同名,形参类型也相同的数组之间 不构成重载
可变个数形参在方法的形参中必须声明在 末尾,且最多只能有一个
public void show(String ... strs){
//方法体
}
/*public void show(String[] strs){
//方法体
}与上述方法相同*/
//不构成重载,冲突
1.9、方法参数的值传递机制
关于变量的赋值:
如果变量是基本数据类型
,此时赋值的是变量所保存的数据值
。
如果变量是引用数据类型
,此时赋值的是变量所保存的数据的地址值
方法的形参的传递机制:值传递机制
1.10、属性赋值的先后顺序
1、默认初始化
2、显示初始化 5、代码块中赋值
3、构造器赋值
4、通过“对象.方法/属性”赋值
顺序:1→2,5→3→4(由父及子,静态先行)
1.11、代码块
- 代码块用来初始化类、对象
- 代码块如果有修饰的话,只能用
static
修饰 - 分类:静态代码块、非静态代码块
静态代码块
- 内部可以有输出语句
- 随着类的加载而执行且 只执行一次
- 用于初始化类的信息(静态的属性)
- 一个类中定义的多个静态代码块按声明的先后顺序执行
- 静态代码块的执行优先于非静态代码块
- 静态代码块内只能调用静态的属性,静态的方法,不能调用非静态的结构
非静态代码块
- 内部可以有输出语句
- 随着对象的创建而执行,每创建一个对象,就执行一次非静态代码块
- 用于对对象的属性等进行初始化
- 如果一个类中定义了多个非静态代码块,则按照声明的先后顺序执行
- 非静态代码块内能调用静态,非静态的属性,方法都能调用
1.12、内部类
java 中允许将一个类 A 声明在另一个类 B 中,则类 A 就是内部类,类 B 称为外部类(外嵌类)
内部类的分类:
- 成员内部类
- 局部内部类(方法、代码块、构造器内)
成员内部类:
- 作为外部类的成员
- 调用外部类的结构
- 可以被 static 修饰
- 可以被四种不同权限修饰
- 作为一个类:
- 可以定义属性、构造器、方法等
- 可以被 final 修饰,表示此类不能被继承。不使用 final 就可以被继承
- 可以被 abstract 修饰
内部类对应的字节码文件的命名格式是「外嵌类名$内部类名」
关注下列三个问题
- 如何实例化成员内部类的对象
- 如何在成员内部类中区分调用外部类的结构
- 局部内部类的使用
public class InnerClassTest{
public static void main(String[] args){
//创建 Dog 实例(静态的成员内部类):
Person.Dog dog = new Person.Dog();
//创建 Bird 实例(非静态的成员内部类):
Person p = new Person();
Person.Bird bird = p.new Bird();
}
}
class Person{
String name;
int age;
public void eat(){
}
//静态成员内部类
static class Dog{
String name;
int age;
public void show(){
System.out.println("");
}
}
//非静态成员内部类
class Bird{
public void sing(){
System.out.println("");
Person.this.eat(); //调用外部类的结构,Person.this可省略
}
public void display(String name){
System.out.println(name);//方法形参
System.out.println(this.name);//内部类的属性
System.out.println(Person.this.name);//外部类的属性
}
}
public void method(){
//局部内部类
class AA{
}
}
{
//局部内部类
class BB{
}
}
public Person(){
//局部内部类
class cc{
}
}
}
// 开发中局部内部类的使用
public class InnerClassTest1{
// 开发中很少见
public void method(){
//局部内部类
class AA{
}
}
//返回了一个实现了Comparable接口的类的对象
public Comparable getComparable(){
//创建一个实现了Comparable接口的类:局部内部类
//方式一
class MyComparable implements Comparable{
@override
public int compareTo(Object o){
return 0;
}
}
return new MyCompare();
//方式二:
return new Comparable(){
@Override
public int compareTo(Object o){
return 0;
}
};
}
}
局部内部类使用的注意点:
在局部内部类的方法中(show),如果调用局部内部类所在方法(method)中的局部变量的话,要求此局部变量(num)声明为final的
jdk 7之前的版本要求显示声明final的
jdk 8之后的版本,可以省略final
public void method(){
int num = 10;
class AA{
public boid show(){
//num = 20;
System.out,println(num);
}
}
}
1.13、匿名类
Java 允许直接使用一个类的子类的类体创建一个子类对象,例如:
class People{
}
new People(){
// 匿名类的类体
}
- 匿名类一定是内部类
- 匿名类没有类名
- 匿名类是一个子类
- 匿名类不可以创建 static 成员变量和 static 方法
案例:
public class Father {
Animal test(){
return new Animal(){ // 本质是 Animal 子类的一个对象
// static int x = 2; 报错,实例不能含有 static 的变量与方法
public int a = 2; // 无法访问
@Override
void hello() {
System.out.println(123);
}
};
}
public static void main(String[] args) {
Father father = new Father();
Animal test = father.test();
System.out.println(test.a); // 1
test.hello(); // 123
}
}
class Animal{
public int a;
void hello(){
}
}
1.14、Lambda 表达式
Java 中 Lambda 表达式的目的是使用单接口(只含有一个方法的接口)匿名类时,使代码更简洁
Lambda 表达式就是一个匿名方法(函数)
(参数列表) -> {
方法体
}
interface C{
double getC(double x);
}
C c = (double x) -> {
return x*x;
}
2、封装、继承、多态
1、封装
封装:实现了信息的隐藏
Java 提供了 4 中权限修饰符来修饰类及类的内部结构
Java 规定的四种权限(从低到高):private、缺省(default,友好)、protected、public
相关信息
权限修饰符可以修饰类及类的内部结构:属性、方法、构造器、内部类
修饰类只能使用:「缺省」、「public」
2、继承
继承的好处:
- 减少代码冗余
- 便于功能扩展
- 为多态性的使用提供前提
继承性的格式:
class A extends B{}
A:子类、派生类、subclass
B:父类、超类、基类、superclass
- 一旦「子类 A」继承「父类 B」以后,「子类 A」 中就获取了「父类 B」中声明的属性、方法。
- 子类继承父类以后,还可以声明自己特有的属性或方法、实现功能拓展。
相关信息
父类的 private 属性分配了内存空间,但不作为子类对象的变量
子类不能访问父类的私有变量
java 中关于继承的规定(类与父类的关系)
- 一个类可以被多个子类继承
- 一个类只能有一个父类(单继承)
- 子类直接继承的类是直接父类,间接继承的父类为间接父类
- 如果没有显示的声明一个类的父类的话,则默认此类继承与
java.lang.Object
类 - 所有的 java 类(除
java.lang.Object
类之外)都直接或间接继承与java.lang.Object
类 - 所有的 java 类具有
java.lang.Object
类声明的功能
2.1、成员变量的隐藏
在子类中定义以个与父类「同名」的变量即实现了对父类成员变量的隐藏
被隐藏的成员变量任可通过继承父类的方法操作
2.2、方法的重写(override/overwrite)
- 重写:子类继承父类后,可以对父类中
同名同参数
的方法,进行覆盖操作 - 重写后,创建子类对象,通过子类对象调用父类中的同名参数的方法时,实际执行
子类重写父类
的方法 - 重写的规定:
- 方法的声明:
权限修饰符 返回值类型 方法名(形参列表) throws 异常的类型{方法体}
- 子类中的叫重写的方法,父类中的叫被重写的方法
- 子类重写方法的方法名和形参列表和父类中被重写的方法的
方法名和形参列表相同
- 子类重写方法的权限
修饰符不小于父类
被重写的方法的权限修饰符 - 子类不能重写父类中声明为 private 权限的方法
- 返回值类型:
- 父类被重写方法的返回值是
void
,则子类重写的方法的返回值类型只能是void
- 父类被重写的方法的返回值类型是
A类型
,则子类重写的方法的返回值类型可以是A类或A类的子类
- 父类被重写的方法的返回值类型是
基本数据类型
则子类重写的方法的返回值类型必须是相同的基本数据类型
- 父类被重写方法的返回值是
- 子类重写的方法抛出的异常类型
不大于父类
被重写的方法抛出的异常类型
- 方法的声明:
相关信息
static 的方法没有重写,static 的变量和方法随着类的加载而加载
public class Father {
static int x = 10;
static void fun(){
System.out.println(10);
}
public static void main(String[] args) {
Father father = new Son();
father.fun(); // 10
System.out.println(father.x); // 10
Son son = new Son();
son.fun(); // 20
System.out.println(son.x); // 20
}
}
class Son extends Father{
static int x = 20;
static void fun(){
System.out.println(20);
}
}
3、多态性
多态性:可以理解为一个事物的多种形态
对象的多态性(或称上转型对象):父类的引用指向子类的对象(子类的对象赋给父类的引用)
1、多态的使用:虚拟方法调用
上转型对象对「方法」的调用:
- 可以调用子类继承的方法或子类重写的方法
- 在 编译期 ,只能调用 父类中声明的方法
- 在 运行期 ,我们实际执行的是 子类重写父类的方法
- 如果子类重写了父类的静态方法,上转型对象只能调用父类的静态方法
总结:编译看左边,运行看右边
上转型对象对「属性」的调用:
- 不能操作子类 新增 的成员变量与方法
- 可以访问子类 继承 或 隐藏 的成员变量(原本父类就有的)
2、多态性的使用前提:
- 类的继承关系
- 方法的重写
//对象的多态性:父类的引用指向子类的对象
Person p2 = new Man();
//多态的使用:当调用子父类同名同参数的方法时,实际执行的是子类重写父类的方法---虚拟方法调用
p2.eat()
//p2.earnMoney(); 子类中特有的方法,编译错误
相关信息
对象的多态性只适用于方法,不适用于属性
虚拟方法调用的理解
3、其他关键字
3.1、this 关键字
this 关键字的使用:
- this 可以用来修饰、调用:属性、方法、构造器
- this 修饰属性和方法:this 理解为当前对象
- 在类的构造器中可以使用
this(形参列表)
方式调用本类中的其他构造器 - 构造器中不能通过
this(形参列表)
调用自己 - this(形参列表) 必须声明在构造器首行
- 构造器内部最多只能声明一个
this(形参列表)
用来调用其他的构造器
在类的方法或构造器中,我们可以使用 this.属性
或 this.方法
的方式,调用当前对象属性或方法。但是通常情况下我们都省略this.
。
特殊情况下,如果方法或构造器的 形参 和 类的属性重名时,我们必须显示的使用 this.变量
的方式表明此变量是属性,而非形参。
3.2、package 关键字
- 使用 package 声明类或者接口所属的包,声明在源文件的首行
- 包属于标识符,遵循标识符的命名规则(全部小写、见名知意)
- 每
.
一次,就代表一层文件目录 - 同一包下,不可以命名同名的接口或类。不同的包下可以命名同名的接口、类。
- 如果源程序中省略了 package 语句,则该源文件定义的类或接口被认为是无包名的,只要这些类的字节码被存放在相同的目录中,那么它们属于同一个包但没有包名。
包名的目的是有效区分名字相同的类,那么就涉及怎样区分包名,建议使用自己所在公司的Internet域名倒置包作为包名
Java 语言不允许用户程序使用 java 作为包名的第一部分,如 java.bird 是非法的包名(发生运行遗异常)
3.3、import 关键字
如果一个类要使用不同包的类,则需要 import 语句
import:导入
- 在 「package 语句」和「类定义之间」 使用 import 导入指定包下的 「类、接口」
- 可以使用
xxx.
的方式,表示可以导入 xxx 包下的结构 - 如果使用的类或接口是
java.lang
包定义的,则可以省略 import 结构 - 如果使用的类或接口是「本包」下定义的,则可以省略 import 结构
- 如果在源文件中,使用了「不同包」下的「同名」的类,则必须至少有一个类需要以全类名的方式显示(创建对象时,也是用全类名)
- 如果使用「xxx.*」的方式表明可以调用 xxx 包下的所有结构。但是如果使用的是 xxx 子包下的结构,则仍需要显式导入。
import static
:导入指定类或接口中的静态结构:属性,方法。
3.4、super 关键字
- super 理解为父类的,可以用来调用:属性、方法、构造器
- super 的使用
- 在子类的方法或构造器中,通过使用
super.属性
或super.方法
显式的调用父类中声明的属性或方法。但通常情况下都习惯省略 super 关键字。 - 特殊情况,当子类和父类定义了同名的属性,必须显式的使用
super.属性的方式
,表明调用的是父类中声明的属性 - 当子类重写了父类中的方法后,想在子类方法中调用父类被重写的方法,必须显式的使用
super.方法
的方式,表明调用的是父类中声明的方法。 - super 调用构造器:
- 可以在子类的构造器中显式的使用
super(形参列表)
的方式,调用父类中声明的指定的构造器 super(形参列表)
的使用也必须声明在子类构造器的首行
- 在类的构造器中,针对
this(形参列表)
或super(形参列表)
只能二选一,不能同时出现
- 在构造器的首行没有显示的声明
this(形参列表)
或super(形参列表)
,则默认调用
的是父类中空参的构造器,super()
- 在类的多个构造器中,至少有一个类的构造器中使用了
super(形参列表)
,调用父类中的构造器
- 可以在子类的构造器中显式的使用
- 在子类的方法或构造器中,通过使用
相关信息
子类对象实例化全过程
结果上:
子类获取父类中声明的属性和方法
创建子类的对象,在堆空间中,就会加载所有父类中声明的属性
过程上:
通过子类构造器直接或间接的调用父类的构造器,直到调用到 java.lang.Object
类中空参的构造器。
加载过所有父类的结构,所以才能看到内存中有父类的结构,子类对象可以进行调用。
3.5、instanceof 关键字
如何调用子类特有的属性和方法
强制类型转换
Person p1 = new Man();
//使用强制类型转换符(向下转型)
Man m1 = (Man)p1;
使用强转时,可能会出现ClassCastException
的异常
instanceof 的使用
a instanceof A
判断a是否时A的实例,如果是,返回true,若不是,返回false
如果a instanceof A
返回true
,则a instanceof B
也返回true
,那么类B是类A的父类。
if(p2 instanceof Woman){
Woman w1 = (Woman)p2;
wi.goShopping();
}
if(p2 instanceof Man){
Man m1 = (Man)p2;
m1.earnMoney();
}
//常见问题
//编译通过,运行不通过
/*同级之间不可转换
Person p3 = new Woman();
Man m3 = (Man)p3;*/
/*new出来的对象时Person,无法拥有子类的属性,方法
Person p4 = new Person();
Man m4 = (Man)p4;*/
//编译通过,运行也通过
Object obj = new Woman();
Person p = (Person)obj;
Man m = new Man();
Person p = m;
System.out.println(p == m);//true 地址相等
3.6、static 关键字
static
可以修饰:属性,方法,代码块,内部类(无构造器)
1、使用 static 修饰属性:静态变量(类变量)
属性:按是否使用 static
修饰分为:
「静态属性(类变量)」和 「非静态属性(实例变量)」
类变量:创建了多个类的对象,多个对象共享一个静态变量。当通过某一个对象修改静态对象时,会 导致其他对象调用此静态变量时,是修改过了的。
实例变量:创建了多个类的对象,每个类都拥有一套类中的非静态属性。当修改其中一个对象中的非静态属性时,不会导致其他对象中的同样的属性值修改。
public class StaticTest{
public static void main(String[] args){
Chinese.nation = "China";
Chinese.show();
Chinese c1 = new Chinese();
c1.name = "A";
c2.nation = "CHN";//c2的nation也变为CHN
Chinese c2 = new Chinese();
c2.name = "B";
}
}
class Chinese{
String name;
static String nation;
public static void show(){
}
}
static
修饰属性的其他说明:
- 类变量 随着类的加载而加载。可以通过 类.静态变量 的方式进行调用
- 静态变量的加载要 早于对象的创建
- 由于类只会加载一次,则静态变量在内存中也会存在一份:存在方法区的静态域 中
是否可调用 | 类变量 | 实例变量 |
---|---|---|
类 | yes | no |
对象 | yes | yes |
2、类变量和实例变量的内存解析
3、使用 static 修饰方法:静态方法
使用 static 修饰的方法:类方法、静态方法
不使用 static 修饰的方法:实例方法
随着类的加载而加载,可以通过“类.静态方法”的方式进行调用
是否可调用 | 静态方法 | 非静态方法 |
---|---|---|
类 | yes | no |
对象 | yes | yes |
- 静态方法中,只能调用静态的方法或属性
非静态方法中,既可以调用非静态的方法或属性,也可以调用静态方法或属性 - static注意点:在静态的方法内,不能使用this关键字、super关键字(this,super是相对于对象而言的,调用非静态方法,隐含this.),静态方法不能被重写
4、单例设计模式
优点:减少性能的开销
饿汉式:坏处:对象加载时间过长 好处:是线程安全的
懒汉式:好处:延迟对象的创建 目前写法的坏处:线程不安全
3.7、main() 方法的使用说明
- main() 方法作为程序的入口
- main() 方法也是一个普通的静态方法
- main() 也可以作为我们与控制台交互的方式。(形参,Scanner)
3.8、final 关键字
- final 可以用来修饰的结构:类、方法、变量
- final 用来修饰一个「类」:此类不能被其他类所继承
如:String 类,System 类,StringBuffer 类 - final 用来修饰「方法」:表明此方法不可以被重写
如:Object 类中的 getClass() - final 用来修饰「变量(成员变量和实例变量)」:此时的变量就称为一个「常量」,常量不允许改变,常量在声明时没有默认值,所以声明时必须指定值
① final 修饰「属性」,可以写的位置:显示初始化、代码块中初始化、构造器中初始化(没有方法)
② final 修饰「局部变量」:尤其视同 final 修饰形参时,表明此形参是一个常量。当调用此方法时,给常量形参赋一个实参。一旦赋值以后,就只能在方法体内使用此形参,不能再重新赋值
相关信息
static final
用来修饰属性:全局常量
3.9、abstract 抽象类和抽象方法
- abstract 可以用来修饰:类、方法
- abstrasct 类,抽象类
- 此类不能实例化
- 抽象类可以声明对象,该对象可以作为子类的上转型对象
- 抽象类中一定有构造器,便于子类实例化时调用
- 都会提供抽象类的子类,让子类对象实例化,完成相关操作
public abstract class Employee {
private String name;
}
- abstract修饰方法:抽象方法
- 抽象方法只有方法的声明,没有方法体
- 包含抽象方法的类一定是一个抽象类,反之抽象类中可以没有抽象方法
- 若子类重写了父类中的所有的抽象方法后,此子类方可实例化,若子类没有重写父类中的所有抽象方法,子类也是一个抽象类,需使用abstract修饰
public abstract void eat();
abstract不能来修饰:属性、构造器等结构(只能修饰类和方法)
abstract不能用来修饰私有方法、静态方法、final的方法、final的类
模板方法设计模式
abstract class Template{
public void spendTime(){
System.out.println("123");//父类的操作
this.code() //不确定的部分、易变的部分(子类重写的方法)
}
public abstract void code();
}
class SubTempLate extends Template{
public void code(){
//方法体
}
}
public class TemplateTest{
public static void main(String[] args){
SubTemplate t = new SubTemplate(){
t.spendTime();//调用父类的方法
}
}
}
3.10、interface 接口
接口使用 interface 来定义
Java 中,接口和类是并列的两个结构
如何定义接口:定义接口中的成员
JDK8 以前:
- 只能定义「全局常量」和「抽象方法」
- 全局常量:
public static final
的,书写时可以省略 - 抽象方法:
public abstract
的,书写时可以省略
- 全局常量:
- 只能定义「全局常量」和「抽象方法」
JDK8 及以后:
- 除了定义「全局变量」和「抽象方法」之外还可以定义 「静态方法」、「默认方法」
- 静态方法:
public static
,有方法体 - 默认方法:
public default
,有方法体,权限一定是 public 或 省略
不可以用 static 和 abstract 修饰一个方法
相关信息
类实现某接口后,该类继承了接口中的的常量和 default 方法,也可重写 default 方法。
但该类不拥有接口的 static 方法
abstract 类和 接口 的比较
abstract 类 接口 可以有抽象方法 可以有抽象方法 既可以常量也可以有变量 还能有常量,不能有变量 可以有非抽象方法,不能有 default 方法 不可以有非抽象方法,可以有 default 方法
public interface CompareA{
//静态方法
public static void method1(){
System.out.println("");
}
//默认方法
public default void method2(){
System.out.println("");
}
//省略了 public 的默认方法
default void method3(){
System.out.println("");
}
}
class SubClass implements CompareA{
// 重写默认方法
public void method2(){
System.out.println("");
}
}
public class SubClassTest {
public static void main(String[] args){
SubClass s = new SubClass();
//1、接口中定义的静态方法,只能通过接口来调用
CompareA.method1();
//2、通过实现类的对象,可以调用接口中的默认方法或朝重写过的默认方法。
s.method2();
//3、如果子类(实现类)继承的「父类」和「实现的接口」中声明了同名同参数的方法,那么子类在没有重写此方法的情况下,默认调用父类中的同名同参的方法。(类优先原则)
//4、如果实现类实现了多个接口,且这多个接口定义了同名同参数的默认方法,那么在实现类没有重写此方法的情况下,报错(接口冲突)
}
}
相关信息
- 接口中定义的静态方法,只能通过接口来调用
- 通过实现类的对象,可以调用接口中的默认方法。如果实现类重写了接口中的默认方法,调用时,调用的是重写后的方法
- 接口中不能定义构造器,意味着接口不能实例化
Java 中,接口通过类 「实现 implements」的方式来使用
- 如果 实现类覆盖了 接口中的 所有抽象方法,则此 实现类就可以实例化
- 如果 实现类没有覆盖 接口中 所有抽象方法,则此实现类 仍为一个抽象类
Java 类可以实现多个接口,弥补了 Java 单继承性的局限性
格式:class A extends B implements C,D,E
接口与接口之间可以继承,而且可以多继承
public class InterfaceTest{
public static void main(String[] args){
System.out.println(Flyable.MAX_SPEED);
System.out.println(Flyable.MIN_SPEED);
}
}
interface Flyable{
//全局常量
public static final int MAX_SPEED = 7900;//第一宇宙速度
int MIN_SPEED = 1;//同样时常量,省略了public static final
//抽象方法
public abstract void fly();
void stop();//省略了public abstract
}
interface Attackable{
void attack();
}
class Plan implements Flyable{
@override
public void fly(){
//方法体
}
@override
public void stop(){
}
}
class bullet extends Object implements Flyable,Attackable{
@override
public void fly(){
//方法体
}
@override
public void stop(){
}
@override
public void attack(){
}
}
//接口的继承
interface AA{
void method1();
}
interface BB{
void method2();
}
interface CC extends AA,BB{
}
接口的使用、回调、多态性
- 接口使用上也满足多态性
- 接口回调指实现某一接口的对象赋值给接口声明的变量,那么该变量可以调用类重写的接口方法和接口中的 default 方法
- 接口实际上就是定义了一种规范
//接口多态性的体现
public class USBTest{
public static void main(){
Computer com = new Computer();
//1、创建了接口的非匿名实现类的非匿名对象
Flash falsh = new Flash;
com.transforData(flash);
//2、创建了接口的非匿名实现类的匿名对象
com.transforData(new Flash);
//3、创建了接口的匿名实现类的非匿名对象
USB phone = new USB(){
@override
public void start(){
//方法体
}
@override
public void stop(){
//方法体
}
};
com.transforData(phone);
//4、创建了接口的匿名实现类的匿名对象
com.transforData(new USB(){
@override
public void start(){
//方法体
}
@override
public void stop(){
//方法体
}
});
}
}
class Computer{
public void transforData(USB usb){
usb.start();
usb.stop();
}
}
interface USB{
void start();
void end();
}
class flash implements USB{
public void start(){
//方法体
}
public void stop(){
//方法体
}
}
接口的应用:代理模式
public class Network{
public static void main(String[] args){
Server sever = new Server();
ProxyServer proxyServer= new ProxySever(sever);
proxyServer.browse();
}
}
interface Network{
public void browse();
}
//被代理类
class Server implements Network{
@override
public void browse(){
System.out.println("真实的服务器访问");
}
}
//代理类
class ProxySever implements Network{
private Network work;
public ProxySever(Network work){
this.work = work;
}
public void check(){
System.out.println("联网前的一些检查工作");
}
@override
public void browse(){
check();
work.browse;
}
}
接口的应用:工厂模式
接口,父类同名属性的讨论:
interface A{
int x = 0;
}
class B{
int x = 1;
}
class C extends B implements A{
public void s{
//System.out.println(x);//编译不通过,x是不明确的
System.out.println(super.x);//1
System.out.println(A.x);//0
}
}