自学Java过程中,整理了下一些接口和包的知识
interface定义:没有字段的抽象类
interface person{ void hello(); String getName(); } /*接口本质上就是抽象类 abstract class person{ public abstract void fun(); public abstract String getName(); } */
如上代码,方法没有具体化,在需要调用的类里面通过覆写来实现具体功能,多个类之间重新覆写的功能相互不影响。继承接口时,一定要覆写接口里的所有方法
class student implements person{ private String name; public student(String name){ this.name = name; } @override public void hello(){ System.out.print("hello, " + this.name); } @override public String getName(){ return this.name; } } class teacher implements person{ private String name; public student(String name){ this.name = name; } @override public void hello(){ System.out.print("hello, Mr/Mrs." + this.name); } @override public String getName(){ return this.name; } }
普通类继承中,只能继承一个类,而接口可实现多继承
class teacher implements person, parents{/**/}
一个interface可以继承自另一个interface
interface hello{ void hello(); } interface person extends hello{ void fun(); String getName(); //此时,person接口实际上有三个抽象方法前面,其中一个继承自hello }
abstract
- 定义实例字段
- 定义抽象方法
- 定义非抽象方法
- but,只能extends一个class
interface
- 可以implements多个interface
- 定义抽象方法
- 定义default方法
- but,不能定义实例字段
public class aa { public static void main(String[] args) { person p = new student("aaaaa"); p.fun(); } } interface person { String getName(); default void fun() { System.out.println(getName() + " fun()"); }//default修饰具体方法 } class student implements person { private String name; public student(String name) { this.name = name; } public String getName() { return this.name; } //在这个例子中,student类就没有去重新覆写fun()函数 }
当接口新增一个方法时,会涉及到修改全部子类,如果新增的是default方法,子类就不必全部修改,只需要在需要覆写的地方去覆写新增方法
default和抽象类的普通方法是不太一样的,interface没有字段,default无法访问字段,而抽象类的普通方法可以访问实例字段。不过在interface中,default可以修饰具体方法
public class aa { public static void main(String[] args) { person.setNumber(99); System.out.println(person.number); } } class person { public static int number; public static void setNumber(int value) { number = value; } }
静态方法属于class不属于实例,可以直接通过类名来调用
尽管interface是纯抽象类,但它可以有静态字段,静态字段必须是final类型
//person.java public interface person{ public static final int male = 1; public static final int female = 2; }
实际上,因为interface的字段只能是public static final
类型,所以我们可以把int前面的修饰符去掉
//person.java public interface person{ int male = 1; int female = 2; //编译器会自动把该字段变为public static final类型 }
例如,在同一文件夹下,a写了一个person类,b也写了一个person类,c想用a和b的person类,这时候引入包(package)的概念
aa.java
package hello; class person{} public class aa{}
bb.java
package hello; class person{} public class bb{}
包可以是多层结构,用.
隔开,例如java.util
包没有父子关系,
java.util
和java.util.zip
是不同的包,两者没有继承关系
例如,如果想要定义包hello,则需要新建一个文件夹并命名为hello,文件夹下存放有hello包的Java文件
hello\person.java
package hello; public class person{ void hello(){ System.out.println("hello"); } }
hello\main.java
package hello; public class main{ public static void main(String[] args){ person p = new person(); p.hello();//result: hello } }
在一个class中,我们会引用其他的class,例如,Jay的person.jay
类,如果要引用jjlin的hello.jjlin
类,需要引入这个包
hello\jjlin.java
//jjlin.java package hello; public class jjlin{ public void fun(){ System.out.println("hello"); } }
person\jay.java
//jay.java package person; import hello.jjlin;//表示引入hello文件夹下的jjlin文件 public class jay{ public void run(){ jjlin temp = new jjlin(); } }
除了引入包下的具体类,也可以使用*,把包下的所有class都导入进来(不辨认子包的class)
package person; import jay.*;//引入jay文件夹下所有class public class jay{ public void run(){ jjlin temp = new jjlin(); } }
此方法可以导入一个类的静态字段和静态方法,此语法比较少用
//package main; import static java.lang.System.*; //导入System类的所有静态字段和静态方法 public class main{ public static void main(String[] args){ out.println("hello"); //如果不引用System包,则要写成下面形式 //System.out.println("hello"); } }
Java编译器最终编译出的.class
文件只是用完整类名,因此,在代码中,当编译器遇到一个class名称时:
java.lang
包是否含有这个class如果按照上面规则还无法确定类名,则编译报错
下面是一个例子
//main.java package test; import java.text.Format; public class main{ public static void main(String[] args){ java.util.list list;//ok,使用完整类名 Format format = null;//ok,使用import的类 String s = "hi";//ok,使用java.lang的包的String System.out.println(s);//ok,使用java.lang的包的System MessageFormat mf = null;//错误,无法找到MessageFormat } }
因此在编写class时,编译器会自动帮我们做两个import动作
import java.lang.*
自动导入的是
java.lang
的包,但类似java.lang.reflect
这些包还需要手动导入
为避免名字冲突,我们需要确定唯一的包名,推荐使用倒置的域名来确保唯一性
org.apache
,本质上是/org/apache/
路径下的class,下同org.apache.commons.log
com.jayden.sample
子包就可以根据功能自行命名
注意不要和java.lang
的包的类重名
String
System
Runtime
也不要和jdk常用的类重名
java.util.List
java.text.Format
java.math.BigInteger
参考链接-廖雪峰-Java-面向对象编程-接口
参考链接-廖雪峰-Java-面向对象编程-包