随着继承层次中一个个新子类的定义,类变得越来越具体,而父类则更为一般,更通用。类的设计应该保证父类和子类能够共享特征,有时将一个父类设计得非常抽象,以至于它没有具体的实例,这样的类叫做抽象类。
例如:
上面动物移动方式没法在动物类中去写,所有动物类和其方法都是抽象化处理,即不写具体的实现
抽象类的特点:
抽象方法的特点:
package com.zhukun;
abstract class Animal{//定义一个抽象类
public void action(){//普通方法,存在方法体
System.out.println("动物的动作");
}
public abstract void move();//抽象方法,没有方法体,有abstract关键字做修饰
}
//单继承
class Dog extends Animal{//B类是抽象类的子类,是一个普通类
@Override
public void move() {//强制要求覆写
System.out.println("狗的移动方式是跑 !");
}
}
public class test {
public static void main(String[] args)
{
Dog d = new Dog();
d.move();
d.action();//从父类继承的方法
Animal a = new Dog();//向上转型
a.move();//被子类重写过的方法
}
}
狗的移动方式是跑 !
动物的动作
狗的移动方式是跑 !
可以知道:抽象类不能直接实例化,需要依靠子类采用向上转型的方式处理;抽象类必须有子类,使用extends继承,一个子类只能继承一个抽象类;子类(如果不是抽象类)则必须覆写抽象类之中的全部抽象方法(如果子类没有实现父类的抽象方法,则必须将子类也定义为为abstract类);
(1)抽象类中有构造方法吗?
抽象类里会存在一些属性,那么抽象类中一定存在构造方法,其存在目的是为了属性的初始化。并且子类对象实例化的时候,依然满足先执行父类构造,再执行子类构造的顺序。
package com.zhukun;
abstract class Animal{//定义一个抽象类
public Animal()
{
System.out.println("动物类的构造方法");
}
public void action(){//普通方法,存在方法体
System.out.println("动物的动作");
}
public abstract void move();//抽象方法,没有方法体,有abstract关键字做修饰
}
//单继承
class Dog extends Animal{//B类是抽象类的子类,是一个普通类
public Dog() {
System.out.println("狗类的构造方法");
}
@Override
public void move() {//强制要求覆写
System.out.println("狗的移动方式是跑 !");
}
}
public class test {
public static void main(String[] args)
{
Dog d = new Dog();//向上转型
}
}
动物类的构造方法
狗类的构造方法
(2)抽象类可以用final声明吗?
不能,因为抽象类必须有子类,而final定义的类不能有子类;
(3)抽象类能否使用static声明?
外部抽象类不允许使用static声明,而内部的抽象类运行使用static声明。使用static声明的内部抽象类相当于一个外部抽象类,继承时使用“外部类.内部类”的形式表示类名称
package com.zhukun;
abstract class Animal{//定义一个抽象类
static abstract class Action{
public abstract void move();//抽象方法,没有方法体,有abstract关键字做修饰
}
}
//单继承
class Dog extends Animal.Action{//B类是抽象类的子类,是一个普通类
public void move() {//强制要求覆写
System.out.println("狗的移动方式是跑 !");
}
}
public class test {
public static void main(String[] args)
{
Animal.Action ab = new Dog();//向上转型
ab.move();
}
}
狗的移动方式是跑 !
(4)可以直接调用抽象类中用static声明的方法吗?
任何时候,如果要执行类中的static方法的时候,都可以在没有对象的情况下直接调用,对于抽象类也一样。
(5)有时候由于抽象类中只需要一个特定的系统子类操作,所以可以忽略掉外部子类。这样的设计在系统类库中会比较常见,目的是对用户隐藏不需要知道的子类。
package com.zhukun;
abstract class A{//定义一个抽象类
public abstract void print();
private static class B extends A{//内部抽象类子类
public void print(){//覆写抽象类的方法
System.out.println("Hello World !");
}
}
//这个方法不受实例化对象的控制
public static A getInstance(){
return new B();
}
}
public class test
{
public static void main(String[] args) {
//此时取得抽象类对象的时候完全不需要知道B类这个子类的存在
A a = A.getInstance();
a.print();
}
}
声明一个接口,我们使用interface关键字。在接口中的所有方法都必须只声明方法标识,而不要去声明具体的方法体,因为具体的方法体的实现是由继承该接口的类来去实现的,因此,接口并不用管具体的实现。接口中的属性默认为Public Static Final.接口中的所有方法都默认是由public abstruct修饰。
实现接口的类中必须提供接口中所有方法的具体实现内容,方可实例化。否则,仍为抽象类。接口的主要用途就是被实现类实现。与继承关系类似,接口与现实类之间存在多态性
(接口采用多层继承机制:接口可以继承接口)
interface in1
{
final int a = 10;
void display();
}
为了实现这个接口,我们使用implements关键词去实现接口:
class Outtest implements in1
{
public void display()
{
System.out.println("我是:"+a);
}
}
测试
public class test
{
public static void main(String[] args) {
Outtest o = new Outtest();
o.display();
}
}
我是:10
如果一个类既继承父类,又实现接口。那么先继承后实现。
package com.zhukun;
interface in1
{
final int a = 10;
void display();
}
class A{
private int a = 20;
public A()
{
System.out.println("A类构造器");
}
public void display()
{
System.out.println("我是:"+a);
}
}
class Outtest extends A implements in1
{
public void display()
{
System.out.println("我是:"+a);//可以用接口中的a,父类中的a为private,没有继承
}
}
public class test
{
public static void main(String[] args) {
Outtest o = new Outtest();
o.display();
A a = new A();
a.display();
}
}
A类构造器
我是:10
A类构造器
我是:20
问题:接口和抽象类很相似,好像接口能做的事用抽象类也能做,干嘛还要用接口呢?
我们发现:一个父类为抽象类,当父类增加新的抽象方法时。子类必须实现父类新增加的抽象的方法,否则就得把子类改为抽象类,这样不可行。
实际解决:如果父类要新增一个抽象方法,新建一个接口,把父类需要新增的抽象方法放到接口里面,如果子类需要实现这个新增的方法直接实现这个接口就好了
(父类需要的是稳定的抽象,有时我们又确实需要给父类增加一些方法,那么就不能直接在父类上下手,只能新建一个接口,在接口上扩展方法,其他需要的子类自行去实现接口)
(如图:需要用Java描述会唱歌的厨子是个老师,因为Java语言不支持多继承所以只能一个个继承过去,像图中上半部分的结构一样,可以发现这样会污染cook类,cook和singer实际中没什么关系,cook却继承了singer。所以正确的做法时teacher类直接继承person类,同时实现cooking接口和sing接口)