抽象
抽象类概述
回想前面我们的猫狗案例,提取出了一个动物类。
并且我们在前面也创建过了动物对象,其实这是不对的。
为什么呢?因为我说动物,你知道我说的是什么动物吗?
只有看到了具体的动物,你才知道,这是什么动物。
所以说,动物本身并不是一个具体的事物,而是一个抽象的事物。只有猫、狗、马才是具体的动物。
同理,我们也可以推想,不同的动物吃的东西应该是不一样的,所以,我们不应该在动物类中给出具体体现,而是应该给出一个声明即可。
抽象类特点
A:抽象类和抽象方法必须用abstract关键字修饰
B:抽象类中不一定有抽象方法,但是有抽象方法的类必须定义为抽象类
C:抽象类不能实例化
因为它不是具体的。
抽象类有构造方法,但是不能实例化?构造方法的作用是什么呢?
用于子类访问父类数据的初始化
D:抽象的子类
a:如果不想重写抽象方法,该子类是一个抽象类。
b:重写所有的抽象方法,这个时候子类是一个具体的类。
抽象类的实例化其实是靠具体的子类实现的。是多态的方式。
Animal a = new Cat();
抽象类不能实例化
抽象类的实例化要按照多态的方式,由具体的子类实例化。
其实这也是多态的一种,抽象类多态。抽象多态是继承多态的一种
抽象类的子类要么是抽象类,要么重写抽象类中的所有抽象方法(具体类)
☆抽象类构造方法作用:父类数据的初始化
用于子类访问父类数据的初始化
//抽象类的声明格式
abstract class Animal {
//抽象方法
public abstract void eat();
public Animal(){}
}
//子类是抽象类
abstract class Dog extends Animal {}
//子类是具体类,重写抽象方法
class Cat extends Animal {
public void eat() {
System.out.println("猫吃鱼");
}
}
class AbstractDemo {
public static void main(String[] args) {
//创建对象
//Animal是抽象的; 无法实例化
//Animal a = new Animal();
//通过多态的方式
Animal a = new Cat();
a.eat();
}
}
抽象类的成员特点
成员变量
可以是变量
也可以是常量
构造方法
有构造方法,但是不能实例化,那么,构造方法的作用是什么呢?
用于子类访问父类数据的初始化
成员方法
抽象类的成员方法特性:
A:抽象方法 强制要求子类做的事情。
B:非抽象方法 供子类继承,提高代码复用性。
abstract class Animal {
public int num = 10;
public final int num2 = 20;
public Animal() {}
public Animal(String name,int age){}
public abstract void show();
public void method() {
System.out.println("method");
}
}
class Dog extends Animal {
public void show() {
System.out.println("show Dog");
}
}
class AbstractDemo2 {
public static void main(String[] args) {
//创建对象
Animal a = new Dog();
//a.num = 10;
System.out.println(a.num);
//a.num2 = 20;
System.out.println(a.num2);
System.out.println("--------------");
a.show();
a.method();
}
}
没有抽象方法定义为抽象类:只能作为父类来被继承
这样做唯一的意义就是该类只能作为父类来被继承,限制该类不能被实例化。
abstract不能和哪些关键字共存
private:冲突
原因是abstract方法要被继承然后必须被子类重写。
但是子类只能继承父类所有非私有的成员(成员方法和成员变量)
final:冲突
原因是abstract方法要被继承然后必须被子类重写。
但是被final修饰的方法无法被子类重写
static:无意义
被static修饰的方法是属于类的方法,不存在重写一说
package netty.bytebuf;
abstract class Fu {
//public abstract void show();
//非法的修饰符组合: abstract和private
//private abstract void show();
//非法的修饰符组合
//final abstract void show();
//非法的修饰符组合
//static abstract void show();
public static void method() {
System.out.println("method");
}
}
class Zi extends Fu {
public void show() {}
}
class AbstractDemo3 {
public static void main(String[] args) {
Fu.method();
}
}
接口:为了体现事物的扩展功能性
继续回到我们的猫狗案例,我们想想狗一般就是看门,猫一般就是作为宠物了。
但是,现在有很多的驯养员或者是驯兽师,可以训练出:猫钻火圈,狗跳高,狗做计算等。
而这些额外的动作,并不是所有猫或者狗一开始就具备的,这应该属于经过特殊的培训训练出来的。
所以,这些额外的动作定义到动物类中就不合适,也不适合直接定义到猫或者狗中,因为只有部分猫狗具备这些功能。
所以,为了体现事物功能的扩展性,Java中就提供了接口来定义这些额外功能,并不给出具体实现,将来哪些猫狗需要被培训,只需要这部分猫狗把这些额外功能实现即可。
接口特点
接口用关键字interface表示
格式:interface 接口名 {}
类实现接口用implements表示
格式:class 类名 implements 接口名 {}
接口不能实例化
那么,接口如何实例化呢?
按照多态的方式,由具体的子类实例化。
其实这也是多态的一种,接口多态。
目前一共学了2种多态:继承多态、接口多态,其中抽象多态是继承多态的一种。
接口的子类
要么是抽象类,要么是接口,要么是接口的具体实现类。
接口的具体实现类必须重写接口中的所有抽象方法
由此可见:
A:具体类多态(几乎没有)
B:抽象类多态(常用)
C:接口多态(最常用)
//定义动物培训接口
interface AnimalTrain {
public abstract void jump();
}
//抽象类实现接口
abstract class Dog implements AnimalTrain {
}
//接口继承接口
public interface DogTrain extends AnimalTrain {
}
//具体类实现接口
class Cat implements AnimalTrain {
public void jump() {
System.out.println("猫可以跳高了");
}
}
class InterfaceDemo {
public static void main(String[] args) {
//AnimalTrain是抽象的; 无法实例化
//AnimalTrain at = new AnimalTrain();
//at.jump();
AnimalTrain at = new Cat();
at.jump();
}
}
接口成员特点
成员变量:默认修饰符public static fina即常量
构造方法:没有
因为接口主要是扩展功能的,而没有具体存在
成员方法默认修饰符 public abstract即抽象
只能是抽象方法
package netty.bytebuf;
/*
接口成员特点
成员变量;只能是常量,并且是静态的。
默认修饰符:public static final
建议:自己手动给出。
构造方法:接口没有构造方法。
成员方法:只能是抽象方法。
默认修饰符:public abstract
建议:自己手动给出。
所有的类都默认继承自一个类:Object。
类 Object 是类层次结构的根类。每个类都使用 Object 作为超类。
接口的父类也是Object
*/
interface Inter {
public int num = 10;
public final int num2 = 20;
public static final int num3 = 30;
//错误:不允许在接口中
//public Inter();
//接口方法不能带有主体
//public void show() {}
//默认public abstract
//abstract void show();
//默认public abstract
//public void show();
//显式声明为 public abstract
//public abstract void show();
}
//接口名+Impl这种格式是接口的实现类格式
/*
class InterImpl implements Inter {
public InterImpl() {
super();
}
}
*/
class InterImpl extends Object implements Inter {
public InterImpl() {
super();
}
public void show() {}
}
//测试类
class InterfaceDemo2 {
public static void main(String[] args) {
//创建对象
Inter i = new InterImpl();
System.out.println(i.num);
System.out.println(i.num2);
//无法为最终变量num分配值
//i.num = 100;
//无法为最终变量num2分配值
//i.num2 = 200;
System.out.println(Inter.num);
System.out.println(Inter.num2);
System.out.println("--------------");
}
}
类与类,类与接口以及接口与接口的关系
类与类
继承关系,只能单继承,但是可以多层继承
类与接口
实现关系,可以单实现,也可以多实现。
可以在继承一个类的同时实现多个接口
接口与接口
继承关系,可以单继承,也可以多继承
interface Father {
public abstract void fatherShow();
}
interface Mother {
public abstract void motherShow();
}
//多继承
interface Sister extends Father,Mother {
}
//class Son implements Father,Mother //多实现
class Son extends Object implements Father,Mother {
public void fatherShow() {
System.out.println("fatherShow");
}
public void motherShow() {
System.out.println("motherShow");
}
}
class InterfaceDemo3 {
public static void main(String[] args) {
//创建对象
//编译看左边
Father f = new Son();
f.fatherShow();
//f.motherShow(); //报错 因为这个是mother的方法
Mother m = new Son();
//m.fatherShow(); //报错 因为这个是father的方法
m.motherShow();
}
}
抽象类和接口的区别
成员变量和成员方法区别
抽象类有变量和常量,有抽象方法和非抽象方法
接口没有变量,只有常量;只有抽象方法
同类型关系之间的区别
类与类 继承,单继承。
类与接口 实现,单实现&多实现。
接口与接口 继承,单继承,多继承
设计理念区别
抽象类被继承,体现的是:is a 的关系,共性功能
接口被实现,体现的是:like a 的关系,扩展功能
★权限修饰符
public | protected | 默认 | private | |
---|---|---|---|---|
同类:同一个类中 | √ | √ | √ | √ |
同包:同一包子类,同一包其它类 | √ | √ | √ | |
子类:同包子类或者不同包子类 | √ | √ | ||
其它类:同包其他类或者不同包其它类 | √ |
所有权限修饰符同类都可以访问
private:同类
default:同包
protected:同包或者子类
public:所有的都可以访问
package A;
/***
*
* 在同一类中 可以发现所有的修饰符修饰的变量都可以访问
* 同时 其他所有的类都可以访问到a
*/
public class A {
public int a = 0;
protected int b = 0;
int c = 0;
private int d = 0;
public static void main(String[] args) {
System.out.println(new A().a);
System.out.println(new A().b);
System.out.println(new A().c);
System.out.println(new A().d);
}
}
package A;
public class 同一包其他类 {
public static void main(String[] args) {
System.out.println(new A().a);
System.out.println(new A().b);
System.out.println(new A().c);
/*
//不能访问
System.out.println(new A().d);
*/
}
}
package A;
public class 同一包子类 extends A {
public static void main(String[] args) {
System.out.println(new A().a);
System.out.println(new A().b);
System.out.println(new A().c);
/*
//不能访问
System.out.println(new A().d);
*/
}
}
package B;
import A.A;
public class 不同包其他类 {
public static void main(String[] args) {
System.out.println(new A().a);
/*
//不能访问
System.out.println(new A().b);
System.out.println(new A().c);
System.out.println(new A().d);
*/
}
}
package B;
import A.A;
public class 不同包子类 extends A {
public 不同包子类() {
System.out.println(new A().a);
System.out.println(super.b);
/*
//不能访问
System.out.println(new A().c);
System.out.println(new A().d);
*/
}
}