目录
PS:这部分不知道怎么整😂 ,要不贴代码吧,没有啥是代码不能说明的,如果有,那就多贴点😂
一、单接口
基础概念
- 接口定义了某一批类所需要遵守的规范
- 接口可以实现多继承,即一个子接口可以同时继承多个父接口
- 一个类可以继承字一个父类,同时实现多个接口
- 当类实现接口时,需要实现接口中的所有的抽象方法,否则需要将该类设置为抽象类
- 可以用在接口的修饰符public 和 默认,例如 public interface INet
- 接口中抽象方法可以不写abstract关键字,方法的修饰符默认是public,而方法重写时重写方法的访问权限应该大于等于接口的访问权限
- 接口不能直接实例化对象,只能设置接口的引用指向具体的接口实现类。当使用接口引用指向实现类时,不能直接调用实用类独有的方法,需要进行强制类型转换才可以调用。
细节
- 接口中可以包含常量,默认是public static final,例如int TEMP=20 => public static final int TEMP=20
- 只有default方法及static方法可以添加方法体。
- 当一个类同时实现多个接口时,且其中同时具有相同方法时,实现类需要重写该方法否则会报错
- 接口中定义的常量在定义时必须初始化
- default:默认方法,可以带方法体,JDK1.8新增,可以在实现类中重写,并可以在类外通过接口的引用调用,若实现类中没有重名的(包括继承),则在实现类中,可通过方法名直接调用,若有同名的,需要用接口名.super.方法名调用
- static: 静态方法,可以带方法体,JDK1.8新增,不可以在实现类中重写,即使实现类中没有同名方法也只可以通过接口名调用(就是interface后面的那个名字)
二、多接口
- 多接口含有重名的方法,这时候实现类需要实现自己的方法(从父类继承的也算),否则会报错,就算不使用重名的方法也报错。
- 多接口含有重名的常量,只要不在实现类内使用,或者在类外不通过实现类对象.常量就不会有错,当然了要调用在实现类的内部需要指明调用的哪个接口的常量,在类外接口指向实现类对象,各自引用调用的是自己接口的属性,当然了与方法相同也可以直接在实现类内部重新定义该变量,此时实现类调用的是自己重新定义的变量,在类外接口指向实现类对象,各自引用调用的依旧是自己接口的属性。
- 与方法不同的是,若父类与接口有同名的成员属性,子类(实现类)依旧没法解析,解决方法同上
三、接口的继承
- 接口也可以继承,且可以多继承
- 多继承的时候,有同名方法,子接口必须创建自己的方法。
- 多继承的时候,有同名变量,要么不用则会出错,要么在方法中指明访问的是谁的,但是实现类要么不用(在类外其对象也不能用,接口的引用可以调用不过都是自己接口的),要么自己定义。
- 子接口无法继承静态方法。
四、类中的内部类
- 在Java中,可以将一个类定义在另一个类里面或者一个方法里面,这样的类称为内部类
- 与之对应,包含内部类的类被称为外部类
- 内部类可以通过private修饰
- 通过内部类可以更好的体现封装以及代码编写的灵活性。
- 当我们将内部类声明为private时,只有外部类可以访问,很好地隐藏了内部类信息。
- 内部类可以继承(extends)或实现(implements)其他的类或接口,而不受外部类的影响。
- 内部类可以直接访问外部类的字段和方法,即使是用private修饰的;而外部类则不能直接访问内部类的成员。
成员内部类
- 内部类在外部使用时,无法直接实例化、需要借由外部信息才能完成实例化
- 内部类相当于外部类的一个成员变量,内部类的访问修饰符可以任意,但是访问范围会受到影响,不管咋样,都需要Person.Heart类型,该Person.Heart类型可见范围受访问限制符控制
- 内部类可以直接访问外部类的成员,而不受访问控制符的影响,如果出现同名属性,优先访问内部类中的
- 可以使用外部类.this.成员的方式,访问外部类中的同名信息
- 外部类访问内部类信息,需要通过内部类实例,无法直接访问
- 内部类编译后.class文件命名:外部类$内部类.class
- 在成员内部类中无法声明静态属性/方法
// 外部类
public class Person {
public int age;
public Heart getHeart(){
Heart heart = new Heart(); //外部类访问内部类信息,需要通过内部类实例,无法直接访问
heart.temp = 12; // 内部类自己的对象自然可访问其成员
System.out.print("getHeart方法 ");
heart.speak();
return heart;
}
public void eat(){ System.out.println("外部类eat 人会吃东西"); }
// 成员内部类
/**
* 1、内部类在外部使用时,无法直接实例化、需要借由外部信息才能完成实例化
* 2、内部类的访问修饰符可以任意,但是访问范围会受到影响,
* 不管咋样,都需要Person.Heart类型,该Person.Heart类型可见范围受访问限制符控制
* 3、内部类可以直接访问外部类的成员,如果出现同名属性,优先访问内部类中的
* 4、可以使用外部类.this.成员的方式,访问外部类中的同名信息
* 5、外部类访问内部类信息,需要通过内部类实例,无法直接访问
* 6、内部类编译后.class文件命名:外部类$内部类.class
*
* */
// 内部类的访问修饰符可以任意,但是访问范围会受到影响,
//不管咋样,都需要Person.Heart类型,该Person.Heart类型可见范围受访问限制符控制
public class Heart{
//在成员内部类中无法声明静态属性/方法
// static int age = 13; //Inner classes cannot have static declarations
int age = 13;
int temp = 22;
public String beat(){
Person.this.eat(); // 可以使用外部类.this.成员的方式,访问外部类中的同名信息
eat(); //内部类可以直接访问外部类的成员,如果出现同名属性,优先访问内部类中的
return Person.this.age + "岁的心脏在跳动";
}
public void eat(){
System.out.println("内部类自己的eat");
}
public void speak(){
System.out.println("内部类自己的speak");
}
}
}
public class ClassTest {
public static void main(String[] args){
Person lily = new Person();
lily.age = 12;
// Heart heart = new Heart(); // 报错, 内部类在外部使用时,无法直接实例化、需要借由外部信息才能完成实例化
// Person.Heart heart = new Person.Heart(); // 报错,其实成员内部类也是内部类的一种,可以理解为属于对象,需要借助对象实例化
// 获取内部类对象实例,方式1,new外部类.new内部类
Person.Heart heart1 = new Person().new Heart();
System.out.println(heart1.beat()); // 拿到了内部类对象,自然可访问内部类自己的成员
System.out.println("===============");
// 获取内部类对象实例,方式2,外部类对象.new内部类
Person.Heart heart2 = lily.new Heart();
System.out.println(heart2.beat());
System.out.println("===============");
// 获取内部类对象实例,方式3,外部类对象.获取方法
Person.Heart heart3 = lily.getHeart();
System.out.println(heart3.beat());
System.out.println("===============");
System.out.println(lily); // com.imooc.people.Person@6e0be858
System.out.println(heart1); // com.imooc.people.Person@6e0be858
}
}
输出
外部类eat 人会吃东西
内部类自己的eat
0岁的心脏在跳动
===============
外部类eat 人会吃东西
内部类自己的eat
12岁的心脏在跳动
===============
getHeart方法 内部类自己的speak
外部类eat 人会吃东西
内部类自己的eat
12岁的心脏在跳动
===============
com.imooc.people.Person@6e0be858
com.imooc.people.Person$Heart@61bbe9ba
静态内部类
- 静态内部类中,只能直接访问外部类的静态成员,如果需要调用外部类的非静态成员,可以通过对象实例
- 静态内部类对象实例时,可以不依赖于外部类对象
- 可以通过外部类.内部类.静态成员的方式,访问内部类中的静态成员,当然也可以通过内部类对象.静态成员的方式
- 当内部类属性与外部类属性同名时,默认直接调用内部类中的成员
若需要访问外部类中的静态属性,则可以通过外部类.属性的方式
若需要访问外部类中的非静态属性,则可以通过new 外部类().属性的方式
public class StaticPerson{
public int age;
public Heart getHeart(){
Heart heart = new Heart();
heart.temp = 12;
return heart;
}
public void eat(){ System.out.println("外部类普通方法eat 人会吃东西"); }
public static void speak(){ System.out.println("外部类静态方法 speak"); }
// 静态内部类
/**
* 1、静态内部类中,只能直接访问外部类的静态成员,如果需要调用外部类的非静态成员,可以通过对象实例
* 2、静态内部类对象实例时,可以不依赖于外部类对象
* 3、可以通过外部类.内部类.静态成员的方式,访问内部类中的静态成员,当然也可以通过内部类对象.静态成员的方式
* 4、当内部类属性与外部类属性同名时,默认直接调用内部类中的成员
* 若需要访问外部类中的静态属性,则可以通过外部类.属性的方式
* 若需要访问外部类中的非静态属性,则可以通过new 外部类().属性的方式
*/
public static class Heart{
public static int age = 13;
int temp = 22;
public static void say(){System.out.println("内部类静态方法say hello");}
public void info(){System.out.println("内部类 普通方法 info");}
public String beat(){
// StaticPerson.this.eat(); //报错 同静态方法不能与this共存的道理一样
new StaticPerson().eat();// 静态内部类没办法直接调用外部非静态方法
StaticPerson.speak(); // 静态方法可以直接调用,例如speak()亦可
// info(); // 普通方法里调用普通方法自然是可以的
return new StaticPerson().age + "岁的心脏在跳动";
}
}
}
public class StaticPersonTest {
public static void main(String[] args){
// 获取静态内部类对象实例,方式1,new外部类.new内部类
// 静态内部类,可以看成静态成员,通过类名调用自然没问题
StaticPerson.Heart heart1 = new StaticPerson.Heart(); //静态内部类对象实例时,可以不依赖于外部类对象
System.out.println(heart1.beat());
heart1.say();// 静态方法自然也能通过对象滴哦啊用
System.out.println("===============");
StaticPerson lily = new StaticPerson();
lily.age = 12;
// 获取静态内部类对象实例,方式2,外部类对象.获取方法
StaticPerson.Heart heart2 = lily.getHeart();
System.out.println(heart2.beat());
StaticPerson.Heart.say(); // 静态方法,通过类名调用也没毛病
System.out.println("===============");
}
}
输出:
外部类普通方法eat 人会吃东西
外部类静态方法 speak
0岁的心脏在跳动
内部类静态方法say hello
===============
外部类普通方法eat 人会吃东西
外部类静态方法 speak
0岁的心脏在跳动
内部类静态方法say hello
===============
方法内部类
- 定义在方法内,作用范围也在方法内
- 和方法内部成员使用规则一样,class前面不可以添加public、private、protected、static
- 类中不能包含静态成员
- 类中可以包含final、abstract(通常不推荐)修饰的成员
- 类中普通方法如需访问外部方法中的局部变量,则该变量也需定义为final(jdk1.8之后底层默认会给该变量加上final)
- 编译后产生:外部类$数字内部类.class
public class MethodPerson {
public static int age;
public void eat(){ System.out.println("外部类普通方法eat"); }
public String getHeart(){
// 方法内部类
/**
* 1、定义在方法内,作用范围也在方法内
* 2、和方法内部成员使用规则一样,class前面不可以添加public、private、protected、static
* 3、类中不能包含静态成员
* 4、类中可以包含final、abstract(通常不推荐)修饰的成员
*/
String str = "getHeart方法的局部变量";
class Heart{//和方法内部成员使用规则一样,class前面不可以添加public、private、protected、static
public int age = 13;
int temp = 12;
public final void say(){ //类中可以包含final、abstract(通常不推荐)修饰的成员
System.out.println("方法内部类final修饰的方法 say");
}
public void eat(){ }
public String beat(){
new MethodPerson().eat();
// str = "方法内部类重新赋值"; //类中普通方法如需访问外部方法中的局部变量,则该变量也需定义为final(jdk1.8之后底层默认会给该变量加上final)
return MethodPerson.age + "岁的心脏在跳动";
}
}
// return new Heart(); // 直接返回实例化的对象,在主方法中也无法通过该对象访问到里面的方法
return new Heart().beat();// 通常返回内部类的方法
}
}
public class MethodPersonTest {
public static void main(String[] args) {
//方法内部类,定义在方法内,作用范围也在方法内
MethodPerson methodPerson = new MethodPerson();
methodPerson.age = 12;
//我们直接通过外部类对象调用外部类方法,这个方法中包含了内部类
System.out.println(methodPerson.getHeart());
}
}
输出
外部类普通方法eat
12岁的心脏在跳动
匿名内部类
- 使用场景:
- 只用到类的一个实例
- 类在定义后马上用到
- 给类命名并不会导致代码更容易理解
- 匿名内部类没有类型名称、实例对象名称
- 编译后的文件命名:外部类$数字.class
- 因其没有类型名称、实例对象名称,故无法使用private、public、protected、abstract、static修饰
- 无法编写构造方法,可以通过构造代码块
- 不能出现静态成员
- 匿名内部类可以实现借口也可以继承父类,但是不可兼得
- 匿名内部类没有类名,没有class关键字,也无法产生具体类实例对象名
- 必须继承或实现一个接口,指定给new的类型为匿名类的父类或父接口,但不能有显示的extends或implements子句。
- 编译后产生:外部类$数字.class
- 使用原则
- 一般来说,匿名内部类用于继承其他类或是实现借口,并不需要增加额外方法,只是对继承方法的实现或重写
- 通过匿名内部类返回的是一个对象的引用,所以可以直接使用或将其复制给一个对象变量。
public abstract class Person {
private String name;
public Person(){}
public String getName(){return name;}
public void setName(String name){this.name = name;}
public abstract void read();
}
public class AnonymousTest {
//根据传入的不同的人的类型,调用对应的read方法
//方案1
// public void getRead(Man man){man.read();}
// public void getRead(Woman woman){woman.read();}
// 方案2
public void getRead(Person person){ person.read(); }
public static void main(String[] args){
AnonymousTest test = new AnonymousTest();
// test.getRead(new Man());
// Woman woman = new Woman();
// test.getRead(woman);
// 方案3:匿名内部类
/**
* 使用场景:
* 只用到类的一个实例
* 类在定义后马上用到
* 给类命名并不会导致代码更容易理解
* 匿名内部类没有类型名称、实例对象名称
* 编译后的文件命名:外部类$数字.class
* 因其没有类型名称、实例对象名称,故无法使用private、public、protected、abstract、static修饰
* 无法编写构造方法,可以通过构造代码块
* 不能出现静态成员
* 匿名内部类可以实现借口也可以继承父类,但是不可兼得
*/
// 这边的Person是父类,整个的一起可以看作没有类型名称、实例对象名称的子类
//因其没有类型名称、实例对象名称,故无法使用private、public、protected、abstract、static修饰
test.getRead(new Person() {
@Override
public void read() {
System.out.println("男生喜欢看科幻书籍");
}
});
test.getRead(new Person() {
@Override
public void read() {
System.out.println("女生喜欢看言情小说");
}
});
}
}
输出
男生喜欢看科幻书籍
女生喜欢看言情小说
说其是匿名的,主要是整个的一块构成一个子类,注意哈这边的Person是父类。可以理解为我们是创建了一个没有名字的Person类的子类对象。我们对比一下哈,其实可以定义两个子类实现同样的效果。这边的Person的read方法也不一定要是抽象方法哈。
public class Man extends Person{
@Override
public void read() {System.out.println("男生喜欢读科幻书籍");}
}
public class Woman extends Person{
@Override
public void read() {System.out.println("女生喜欢读言情小说");}
}
五、接口中的内部类
如果想要创建某些公共代码,使得它们可以被某个接口的所有不同实现所共用,那么接口内部的嵌套类会显得很方便。也就是说,在接口中可以含有内部 类,实现类可以根据各自的需求进行有针对性的复用和调整。 下面结合代码说明。
若一个类实现接口,若需设置为非抽象类,则只需要实现抽象方法abMethod,与继不继承抽象类重写抽象类中的方法无关。
获取方法和类中的成员内部类类似,但需要注意无法实例化接口。
这是一个包罗万象的接口
常量-TEMP
抽象方法-abMethod
默认方法-deMethod
静态方法-stMethod
普通内部类- InnerClass
抽象内部类-AbInnerClass
public interface IOuterInterface {
int TEMP = 100; // public static final
void abMethod();
public default void deMethod(){
System.out.println("接口中的默认方法");
}
public static void stMethod(){
System.out.println("接口中的静态方法");
}
// 普通内部类
public class InnerClass{
String innerTemp = "普通内部类InnerClass 成员属性";
public void show(){
innerTemp += ",普通内部类InnerClass show 重新赋值";
System.out.println(innerTemp);
}
}
// 抽象内部类
public abstract class AbInnerClass{
public abstract void abInfo();
String innerTemp = "普通内部类InnerClass 成员属性";
public void info(){
innerTemp += ",抽象内部类AbInnerClass abInfo 重新赋值";
System.out.println(innerTemp);
}
}
}
创建非抽象类(此时需要实现接口的抽象方法)来获取接口的普通成员内部类。在该方法中定义获取接口普通内部类成员的方法。
/**
* 创建非抽象类ClassDemo实现IOuterInterface。
* 此时,类中需实现接口中的抽象方法abMethod,
* 但并不需刻意继承接口内的普通成员内部类及抽象成员内部类。
* 为方便后面实例获取,在ClassDemo中设置获取普通成员内部的方法getInner,
*/
public class ClassDemo implements IOuterInterface{
//当实现该接口时,如需设置为非抽象类,则只需实现接口中抽象方法abMethod即可
@Override
public void abMethod() { System.out.println("实现类ClassDemo 重写abMethod"); }
public InnerClass getInner(){
InnerClass innerClass = new InnerClass();
innerClass.innerTemp = "实现类ClassDemo 调用重新赋值";
return innerClass;
}
}
import com.imooc.interfaceInner.IOuterInterface.InnerClass;
public class ClassDemoTest {
public static void main(String[] args){
// 方式1,接口名.类名,感觉和类中的成员内部类相似,不过接口不能实例化
IOuterInterface.InnerClass inner = new IOuterInterface.InnerClass();
inner.show();
// 方式2,通过在实现类中创建接口中内部类获取方式,用实现类对象调用获取方法
ClassDemo classDemo = new ClassDemo();
classDemo.getInner().show();
// 方式3,将内部类导入后直接实例化
InnerClass innerTwo = new InnerClass();
innerTwo.show();
}
}
输出
普通内部类InnerClass 成员属性,普通内部类InnerClass show 重新赋值
实现类ClassDemo 调用重新赋值,普通内部类InnerClass show 重新赋值
普通内部类InnerClass 成员属性,普通内部类InnerClass show 重新赋值
创建非抽象类(此时需要实现接口的抽象方法),在类中创建成员内部类,该成员内部类继承自接口中的抽象内部类,此时该成员内部类若要设置成非抽象类则需要重写接口抽象内部类中的抽象方法
public class ImplementAbClassDemo implements IOuterInterface{
@Override
public void abMethod() {
}
public class AbDemo extends AbInnerClass{
@Override
public void abInfo() { System.out.println("重写接口中抽象类的抽象方法"); }
}
}
public class ImplementAbClassDemoTest {
public static void main(String[] args){
// 方式3,通过接口名.类名进行实例化,但是抽象类不能直接实例化,所以只用匿名内部类
IOuterInterface.AbInnerClass abInner = new IOuterInterface.AbInnerClass() {
@Override
public void abInfo() { System.out.println("主方法重写抽象类的抽象方法"); }
};
abInner.abInfo();
System.out.println(abInner.innerTemp);
System.out.println("================================");
// 方式2,在实现类中定义内部类结成接口中的抽象内部类
IOuterInterface.AbInnerClass abInnerTwo = new ImplementAbClassDemo().new AbDemo();
abInnerTwo.abInfo();
System.out.println(abInnerTwo.innerTemp);
}
}
输出:
主方法重写抽象类的抽象方法
普通内部类InnerClass 成员属性
================================
重写接口中抽象类的抽象方法
普通内部类InnerClass 成员属性
若外部类没有实现接口,内部类依旧可以实现接口,不受外部类影响。此处注意匿名内部类实现接口的写法。
//接口Ball
public interface Ball {
//创建抽象方法play():void
void play();
}
//创建类BallTest
public class BallTest {
// 创建成员内部类Inner_m
class Inner_m implements Ball{
@Override
public void play() {
System.out.println("成员部类");
System.out.println("打篮球");
}
}
public Inner_m getInner_m(){ return new Inner_m(); }
// 创建方法内部类
void info(){
class Inner_f implements Ball{
@Override
public void play() {
System.out.println("**********");
System.out.println("方法部类");
System.out.println("打乒乓球");
}
}
new Inner_f().play();
}
// 定义一个方法void playBall(Ball ball),调用play()方法
public void playBall(Ball ball){ ball.play(); }
}
//测试类
public class Test {
public static void main(String[] args) {
BallTest ballTest = new BallTest();
//完成成员内部类内部测试
BallTest.Inner_m inner_m = ballTest.getInner_m();
inner_m.play();
//完成方法内部类测试
ballTest.info();
//完成匿名内部类测试
//在匿名内部类中这样写相当于该类实现了这个接口,所以通过new Ball()就是实现了接口Ball的实现类对象
ballTest.playBall(new Ball(){
@Override
public void play(){
System.out.println("**********");
System.out.println("匿名内部类");
System.out.println("打排球");
}
});
}
}
输出
成员部类
打篮球
**********
方法部类
打乒乓球
**********
匿名内部类
打排球
参考:慕课网,Java工程师课程
附
============================================================================
什么是方法签名?
在Java中,方法签名着重指代:方法名和参数列表(包括:参数的类型、个数以及顺序)
通过代码来看一下接口的多态
public interface IDemographic {
void run();
default void age(){System.out.println("IDemographic age");}
static void speak(){System.out.println("IDemographic speak");}
default void swim(){System.out.println("IDemographic swim");}
}
public interface IAction {
final String name = "IAction";
void run();
default void age(){System.out.println("IAction age");}
default void swim(){System.out.println("IAction swim");}
}
public interface ISon extends IAction, IDemographic{
default void age(){
System.out.println("========");
IAction.super.age();
System.out.println("ISon age");
System.out.println("========");
}
default void swim(){System.out.println("ISon swim");}
}
public class Behavior implements ISon{
public void run() { System.out.println("Behavior run"); }
// public static void swim(){System.out.println("Behavior swim"); } // 报错
public void swim(){System.out.println("Behavior swim"); }
public static void print(){
// name = "reassign"; // 报错:Cannot assign a value to final variable 'name'
System.out.println("Behavior中打印出的来自接口的name" + name);
}
}
public class MyTest {
public static void main(String[] args){
System.out.println("--------Behavior - Behavior-------");
Behavior behavior = new Behavior();
System.out.println("来自接口的变量name也可直接实现类对象.变量名: " + behavior.name);
behavior.age();
behavior.print();
behavior.swim();
System.out.println("------IAction--Behavior-------");
IAction iAction = new Behavior();
System.out.println("来自接口的变量name也可直接接口引用.变量名: " + iAction.name);
iAction.age(); // 接口的多态
iAction.swim();
System.out.println("---------iDemographic-Behavior-----");
IDemographic iDemographic = new Behavior();
// System.out.println(iDemographic.name); //该接口中并没有定义,故报错
iDemographic.age();
iDemographic.run();
IDemographic.speak();
// iDemographic.speak(); // 报错,与属性不一样,静态方法只能通过接口名调用
System.out.println("--------iSon---Behavior----");
ISon iSon = new Behavior();
System.out.println("来自接口的变量name也可直接接口引用.变量名: " + iSon.name);
System.out.println("来自接口的变量name也可接口名.变量名: " + ISon.name);
iSon.age();
}
}
输出:
- 接口的静态方法没法被继承,且类外只能接口名.静态方法
- 接口中定义的变量,默认public final static,不能修改,在类外可以通过接口引用.变量,或者接口名.变量。
--------Behavior - Behavior-------
来自接口的变量name也可直接实现类对象.变量名: IAction
========
IAction age
ISon age
========
Behavior中打印出的来自接口的nameIAction
Behavior swim
------IAction--Behavior-------
来自接口的变量name也可直接接口引用.变量名: IAction
========
IAction age
ISon age
========
Behavior swim
---------iDemographic-Behavior-----
========
IAction age
ISon age
========
Behavior run
IDemographic speak
--------iSon---Behavior----
来自接口的变量name也可直接接口引用.变量名: IAction
来自接口的变量name也可接口名.变量名: IAction
========
IAction age
ISon age
========
接口应用常见问题2
在一个java文件中可以存在多个类,多个接口,但是只能存在一个public修饰的类或接口,且此时文件名与需要与public修饰的类或者接口同名。
接口及其中成员默认修饰符是什么?什么情况下可以访问?
接口中默认访问修饰符是:包内可见。?待确认
接口中常量:默认访问修饰符是:public static final 这三个任意缺省都不影响应用,可以通过接口名.常量名进行调用。
接口中默认抽象方法:
默认访问修饰符是:public abstract 这两个任意缺省都不影响应用。
接口中的静态方法和默认方法的相同点和不同点
共性:作为jdk1.8版本口新增功能,都在接口中提供了带方法体的实现,这些方法在接口的实现类中可以直接调用,已保障再扩展系统功能的同时,不对现有的继承关系及类库产生很大影响,提高代码的可重用性。
区别:
语法
默认方法:public default 返回值类型 方法名(参数列表){方法体}
其中,public可以省略,为默认访问修饰符
静态方法:public static 返回值类型 方法名(参数列表){方法体}
其中,public 可以省略,为默认访问修饰符。
应用:
默认方法:
1,在实现类中需要通过接口进行访问
2,可以在实现类中重写与重载,重写时需去掉default关键字,重载的方法无法通过接口引用访问
3.重写方法中,可以通过:接口.super.默认方法 的方式调用接口中原有的默认方法。
静态方法:
1,在实现类中需要通过接口名进行访问
2.实现类无法继承(即直接应用)接口中的静态方法
3.实现类无法重写静态方法,恶意存在相同格式静态方法,但两者独立存在。
如果希望更多的接口扩展方法是支持在无实例对象的情况下调用,那么静态方法更佳;如果希望实现类能更多的直接应用接口中的方法,则默认方法更适合。
接口和抽象类的比较
抽象类
访问修饰符 abstract class 类名{
//可以包含下列成员
成员属性、类属性;
成员方法、类方法;
抽象方法;
构造方法;
}
特点:
抽象类不能实例化,只能引用指向子类实例
含有抽象方法的类一i当时抽象类,但是抽象类中可以没有抽象方法
如果一个子类实现了父类的所有抽象方法,那么该子类可以不鄙视抽象类,否则也需要设置为抽象类
子类只能通过extends继承一个父类
抽象类中静态成员和方法可以被子类继承应用
类中抽象方法必须加关键字abstract
抽象方法支持public、protced和默认访问权限
接口:
访问修饰符 interface 接口名{
//可以包含下列成员
抽象方法;
默认方法;
静态方法;
常量;
}
特点:
1.接口不能实例化,只能通过引用指向实现类实例
2.如果一个类未实现接口的所有抽象方法,则该类必须设置为抽象类,反之则不必
3.子接口可以通过extends继承多个接口,接口之间用逗号隔开
4.实现类可以通过implements实现多个接口,用逗号隔开,当实现类同时继承父类并实现接口时,需要先继承后实现
5.默认方法和静态方法字jdk1.8后可以在接口中应用,默认方法可以在实现类应用,静态方法只属于接口
6.接口的抽象方法可以不写public abstract修饰符,且只能是public
7.接口中常量可以不写public static final修饰符
应用:
实际应用中,抽象类通常用来捕捉子类的通用特性,更加侧重于重用。接口则多是为了把握程序模块进行固化的契约,即侧重降低耦合。简单的来说,接口可以理解为:"更加抽象的抽象类",但也请注意,这并不代表,接口和抽象类有继承关系,他门也不能完全相互替代,都有各自适用的场景。譬如,当我门更希望描述多种毫无关系的类型直接的共同行为能力时候,更推荐用接口。而当多累间可以形成可追溯的产生轨迹时。通过抽象类继承则是更推荐的选择