抽象类与接口、final与static

接口与抽象类的区别

  1. 抽象类要被子类继承;接口要被类实现。
  2. 抽象类中可以声明抽象方法和非抽象方法;接口只能声明抽象方法。
  3. 抽象类中的变量是普通变量;接口里定义的变量只能是公共的静态常量
  4. 抽象类使用继承(extends)来使用,无法多继承;接口使用实现(implements),可以多实现
  5. 抽象类中可以包含static方法,但是接口中不允许(静态方法不能被子类重写,因此接口中不能声明静态方法)
  6. 抽象类中可以构造方法;接口不能有。

抽象类

概念

抽象类必须使用abstract class声明
一个抽象类中可以没有抽象方法,但是抽象方法必须写在抽象类或接口中

// 定义一个抽象类
abstract class 类名{   
	// 可以有构造方法
	类名(){}
	// 可以存在非抽象方法
	public void print(){
		System.out.println("这是一个抽象类");
	}
}

抽象方法

抽象方法可以定义在抽象类中,也可以定义在接口中,必须用abstract关键字声明,只定义不实现。抽象方法在子类中实现。

// 定义一个抽象类
abstract class 类名{   
	// 声明抽象方法
	public abstract void 方法名();
}

抽象类与普通类的区别

  1. 抽象类必须用 public protected修饰 ,若用private修饰,那么子类则无法继承,也就无法实现其抽象方法(默认缺省为public)。
  2. 抽象类不能直接进行实例化操作,即抽象类不能使用new关键字创建对象,但是在子类创建对象时,抽象父类也会被JVM实例化。
  3. 如果一个子类继承抽象类,那么必须实现抽象类中所有抽象方法,如果有未实现的抽象方法,那么子类也必须定义为抽象类。

抽象类的常见问题

  1. 抽象类能否使用final声明?(final的解释在下面)

不能。因为final 属性修饰的类不能有子类,而抽象类必须有子类才有意义,所以不能。

  1. 抽象类能否有构造方法

可以有构造方法,而且子类对象实例化的时候的流程与普通类的继承是一样的,都是要先调用父类中的构造方法,之后再调用子类自己的构造方法。

例子

Fruit.java
// 定义一个Fruit抽象类
abstract class Fruit {
    public String name;
    // 构造方法
    Fruit(){}
    // 非抽象方法
    public void print(){
        System.out.println("This is an "+name);
    }
    // 抽象方法
    public abstract void eat();
}

Apple.java
// Apple类实现Fruit抽象类
public class Apple extends Fruit{
    public static void main(String[] args) {
        Apple apple = new Apple();
        apple.name = "apple";
        apple.print();
        apple.eat();
    }
	// 实现抽象方法
    @Override
    public void eat() {
        System.out.println("I am eating an apple");
    }
}

运行结果

This is an apple
I am eating an apple

接口

概念

如果一个类中的全部方法都是抽象方法全部属性都是全局常量(用 static final 修饰),那么此时就可以将这个类定义为一个接口。

// 定义一个接口
interface 接口名{   
	全局常量;
	抽象方法;
}

优点

接口是定义(规范、约束)与实现(名实分离的原则)的分离。

  1. 降低程序的耦合性
  2. 已与程序的扩展
  3. 有利于程序的维护

全局变量与抽象方法的简写

  1. 全局常量编写是,可以省略public static final关键字,例如:
// 全局常量
public static final String INFO = "内容";
// 简写后:
String INFO = "内容";
  1. 抽象方法编写时,可以省略public abstract关键字,例如:
// 接口中的抽象方法
public abstract void print();
// 简写后:
void print();

接口的实现

接口可以多实现
如果一个接口想要使用,必须依靠子类,子类(如果不是抽象类)要实现接口中的所有抽象方法。

class 子类 implements 父接口1,父接口2...{

}

如果一个类既要实现接口,又要继承抽象类,则可按照如下格式编写:

class 子类 extends 父类 implements 父接口1,父接口2...{

}

接口的继承

接口因为都是抽象部分,不存在具体的实现,所以允许多继承,例如:

interface C extends A,B{

}

final

final 的意思为最终的。用final关键字修饰的类、变量和方法都是不能改变的。

final修饰类

表示这个类不能被继承
final 类中的成员方法都会被隐式的指定为final 方法

final 修饰方法

一个类的 private 方法会隐式的被指定为 final 方法
如果父类中有 final 修饰的方法,那么子类不能去重写

final 修饰成员变量

必须初始化值
赋值方式有两种:直接赋值和在构造方法中赋值
修饰的成员变量是基本类型,则表示这个变量的值不能改变
修饰的成员变量是引用类型,则这个引用的地址不能修改,但是这个引用所指向的对象里的内容可以改变

static

静态资源是类初始化时加载的,而非静态资源是类new的时候加载的
static修饰的变量属于类变量,可以通过类名.变量名直接引用,不需要new一个类
static修饰的方法属于类方法,可以通过类名.方法名直接引用,不需要new一个类
类的静态资源是类实例间共享的,一处变,处处变。

// Test.java
public class Test {
    public static int i=1;
    public static void print(){
        System.out.println("此方法属于Test类");
    }
}
public class TestMain {
    public static void main(String[] args) {
    	// 通过类名.变量名直接引用
        System.out.println(Test.i);
        // 通过类名.方法名直接引用
        Test.print();
    }
}

运行结果

1
此方法属于Test类

public class Test {
    private int i=1;
    public static void geti(){
        System.out.println(i);
    }
}
// 定义geti()方法错误,giti()是静态方法,在类初始化时加载,而变量i在Test类new时加载,类初始化早于new,
// 可以将i 也定义为静态变量,或者将geti()定义为非静态方法

由此,我们可以知道:

  1. 静态方法不可以使用非静态资源,因为非静态资源是new的时候才会产生的,静态方法初始化是,非静态资源还没有产生。
  2. 静态方法里可以使用静态资源,因为它们都是在类初始化时产生的。
  3. 非静态方法可以使用静态资源,因为在非静态方法产生时,静态方法已经存在。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值