每天二十分钟,成就Java大神,点点关注不迷路!
今天是第十九天,给坚持到这里的小伙伴点个赞!
梦想不曾坠落悬崖千钧一发,又怎会晓得执着的人拥有隐形翅膀,共勉!
目录
Java接口(Interface)
接口(Interface),在 Java 编程语言中是一个抽象类型,是抽象方法的集合,接口通常以interface 来声明。一个类通过继承接口的方式,从而来继承接口的抽象方法。
接口并不是类,编写接口的方式和类很相似,但是它们属于不同的概念。类描述对象的属性和方法。接口则包含类要实现的方法。
除非实现接口的类是抽象类,否则该类要定义接口中的所有方法。
接口无法被实例化,但是可以被实现。一个实现接口的类,必须实现接口内所描述的所有方法,否则就必须声明为抽象类。另外,在 Java 中,接口类型可用来声明一个变量,他们可以成为一个空指针,或是被绑定在一个以此接口实现的对象。
接口的特性
- 接口中每一个方法也是隐式抽象的,接口中的方法会被隐式的指定为 public abstract(只能是 public abstract,其他修饰符都会报错)。
- 接口中可以含有变量,但是接口中的变量会被隐式的指定为 public static final 变量(并且只能是 public,用 private 修饰会报编译错误)。
- 接口中的方法是不能在接口中实现的,只能由实现接口的类来实现接口中的方法。
接口与类的相似点和区别
相似点:
- 一个接口可以有多个方法。
- 接口文件保存在 .java 结尾的文件中,文件名使用接口名。
- 接口的字节码文件保存在 .class 结尾的文件中。
- 接口相应的字节码文件必须在与包名称相匹配的目录结构中。
区别:
- 接口不能用于实例化对象。
- 接口没有构造方法。
- 接口中所有的方法必须是抽象方法,Java 8 之后 接口中可以使用 default 关键字修饰的非抽象方法。
- 接口不能包含成员变量,除了 static 和 final 变量。
- 接口不是被类继承了,而是要被类实现。
- 接口支持多继承。
抽象类和接口的区别:
- 抽象类中的方法可以有方法体,就是能实现方法的具体功能,但是接口中的方法不行。
- 抽象类中的成员变量可以是各种类型的,而接口中的成员变量只能是 public static final 类型的。
- 接口中不能含有静态代码块以及静态方法(用 static 修饰的方法),而抽象类是可以有静态代码块和静态方法。
- 一个类只能继承一个抽象类,而一个类却可以实现多个接口。
接口的声明
接口的声明方式如下:
[访问控制运算符] interface 接口名称 [extends 其他的接口名] {
// 声明静态变量
// 抽象方法
}
上面提到,接口是隐式抽象的,当声明一个接口的时候,不必使用abstract关键字;接口中每一个方法也是隐式抽象的,声明时同样不需要abstract关键字。
interface Animal {
public void eat();
public void travel();
}
接口的实现
上面提到,当类实现接口的时候,类要实现接口中所有的方法。否则,类必须声明为抽象的类。
类使用 implements 关键字实现接口。在类声明中,Implements 关键字放在 class 声明后面。
public class MammalInt implements Animal{
public void eat(){
System.out.println("Mammal eats");
}
public void travel(){
System.out.println("Mammal travels");
}
public int noOfLegs(){
return 0;
}
public static void main(String args[]){
MammalInt m = new MammalInt();
m.eat();
m.travel();
}
}
重写接口中声明的方法时,需要注意以下规则:
- 类在实现接口的方法时,不能抛出强制性异常,只能在接口中,或者继承接口的抽象类中抛出该强制性异常。
- 类在重写方法时要保持一致的方法名,并且应该保持相同或者相兼容的返回值类型。
- 如果实现接口的类是抽象类,那么就没必要实现该接口的方法。
在实现接口的时候,也要注意一些规则:
- 一个类可以同时实现多个接口。
- 一个类只能继承一个类,但是能实现多个接口。
- 一个接口能继承另一个接口,这和类之间的继承比较相似。
接口的继承
一个接口能继承另一个接口,和类之间的继承方式比较相似。接口的继承使用 extends 关键字,子接口继承父接口的方法。
非抽象类在实现接口时,应该将接口和其继承的接口的方法一起实现。
接口允许多继承,extends 关键字只需要使用一次,在其后可以跟着一个或多个继承接口。
标记接口
标记接口是没有任何方法和属性的接口.它仅仅表明它的类属于一个特定的类型,供其他代码来测试允许做一些事情。最常用的标记接口是没有包含任何方法的接口。
标记接口作用:简单形象的说就是给某个对象打个标(盖个戳),使对象拥有某个或某些特权。
- 建立一个公共的父接口:你可以使用一个标记接口来建立一组接口的父接口。
- 向一个类添加数据类型:这种情况是标记接口最初的目的,实现标记接口的类不需要定义任何接口方法(因为标记接口根本就没有方法),但是该类通过多态性变成一个接口类型。
Java包(package)
为了更好地组织类,Java 提供了包机制,用于区别类名的命名空间。这种机制是为了防止命名冲突,访问控制,提供搜索和定位类(class)、接口、枚举(enumerations)和注释(annotation)等。
包的作用
把功能相似或相关的类或接口组织在同一个包中,方便类的查找和使用。
如同文件夹一样,包也采用了树形目录的存储方式。同一个包中的类名字是不同的,不同的包中的类的名字是可以相同的,当同时调用两个不同包中相同类名的类时,应该加上包名加以区别。因此,包可以避免名字冲突。
包也限定了访问权限,拥有包访问权限的类才能访问某个包中的类。
创建包
创建包的时候,你需要为这个包取一个合适的名字。之后,如果其他的一个源文件包含了这个包提供的类、接口、枚举或者注释类型的时候,都必须将这个包的声明放在这个源文件的开头。
包声明应该在源文件的第一行,每个源文件只能有一个包声明,这个文件中的每个类型都应用于它。
如果一个源文件中没有使用包声明,那么其中的类,函数,枚举,注释等将被放在一个无名的包(unnamed package)中。
- 编译的时候,编译器为包中定义的每个类、接口等类型各创建一个不同的输出文件(即使两个类在同一个文件中),输出文件的名字就是这个类型的名字,并加上 .class 作为扩展后缀。
- 并不要求 .class 文件的路径跟相应的 .java 的路径一样。你可以分开来安排源码和类的目录。这样,你可以将你的类目录分享给其他的编程人员,而不用透露自己的源码。用这种方法管理源码和类文件可以让编译器和java 虚拟机(JVM)可以找到你程序中使用的所有类型。
例子-
这个例子创建了一个叫做animals的包。通常使用小写的字母来命名避免与类、接口名字的冲突:
首先创建一个文件夹,命名为animals,将这两份代码copy进去,编译运行:
package animals;
interface Animal {
public void eat();
public void travel();
}
package animals;
public class MammalInt implements Animal{
public void eat(){
System.out.println("Mammal eats");
}
public void travel(){
System.out.println("Mammal travels");
}
public int noOfLegs(){
return 0;
}
public static void main(String args[]){
MammalInt m = new MammalInt();
m.eat();
m.travel();
}
}
这时候你会发现报错了:
因为当你使用 vscode 中的 runcode 插件运行程序时,他会默认进入到程序所在的目录,然后编译ManmmalInt.java 文件,这个文件有接口的实现,但是系统没有找到Animal(因为用户只让他运行ManmmalInt.java)。现在有两种解决方法:
方法一 java
在终端使用以下命令:
java MammalInt.java
隐式编译:当使用 java MammalInt.java 时,Java 会:
-
自动编译 MammalInt.java。
-
发现它依赖 Animal 接口,于是自动编译同目录下的文件 Animal.java 。
-
将所有编译后的类文件放在内存中临时目录,不污染源文件目录。
这种方法适用于单个文件的临时调试时。
方法二 javac + java(严格方法)
必须在项目根目录中:
D:\Code\JAVA_learning\proj15
然后输入下面两个命令:
# 编译指定包中的类
javac animals/MammalInt.java
# 运行
java animals.MammalInt
正式项目开发多使用这种方法。
导入包(import关键字)
为了能够使用某一个包的成员,我们需要在 Java 程序中明确导入该包。
import 关键字用于引入其他包中的类、接口或静态成员,它允许你在代码中直接使用其他包中的类,而不需要完整地指定类的包名。
在 java 源文件中 import 语句必须在包声明之后(位于package 语句之后),类声明之前,其语法格式为:
import package1[.package2…].(classname|*);
可以使用 import语句来引入一个特定的类:
import animals.fish.Shark;// 引入 animals.fish 包中的 Shark 类
也可以使用通配符 * 来引入整个包或包的子包:
import animals.fish.*// 引入 animals.fish 包中的所有类
下节预告
下节开始,笔者将详细展开介绍 Java 中的枚举和反射,有疑惑可私信或评论区提出,and不妨动动发财的手点个赞吧,明天见!