一,抽象类
概念
抽象类和具体类是相对的概念。“抽象”是一种存在思想逻辑中的概念,而“具体”是一种可见可触摸的现实对象。简单说,比如“人”比“男人”抽象一点,“动物”又比“人”更抽象一点,而“生物”又比“动物”更抽象。
抽象的概念是由具体概念依其“共性”而产生的,把具体概念的诸多个性排出,集中描述其共性,就会产生一个抽象性的概念。抽象思维,是人类思维达到高级阶段产生的一种能力,例如,当小孩子思维尚未成熟时,他们只能掌握具体概念,他们在学习代词“你、我、他”时往往遇到困难,因为代词具有较高的抽象性。
总之,抽象概念的外延大,内涵小;具体概念的外延小,内涵大。
抽象类与普通类
-
普通类可以去实例化调用;抽象类不能被实例化,因为它是存在于一种概念而不非具体。
-
普通类和抽象类都可以被继承,但是抽象类被继承后子类必须重写继承的方法,除非自类也是抽象类。
-
实例演示:
public class Pet {
public void play(){ //这是宠物类,普通父类,方法里是空的
}
}
--------------------------
public class Cat extends Pet { //这是子类,是一个猫类,重写了父类方法
public void play(){
System.out.println("1、猫爬树");
}
}
------------------------
public class Dog extends Pet { //这是子类,是一个狗类,重写了父类方法
public void play(){
System.out.println("2、狗啃骨头");
}
}
-------------------------
public class Test {
public static void main(String[] args) { //这是测试类,分别调用了子类的不同方法
Pet p1=new Cat(); //多典型的多态表现啊,相当的给力
Pet p2=new Dog();
p1.play();
p2.play();
}
}
抽象类与抽象方法的使用
- 抽象类中可以没有抽象方法,但包含了抽象方法的类必须被定义为抽象类。
- 如果子类没有实现父类的所有抽象方法,子类必须被定义为抽象类。
- 没有抽象构造方法,也没有抽象静态方法
- 抽象类中可以有非抽象的构造方法,创建子类的实例时可能调用
总结
public class Test {
/*
* 抽象类的学习
*
* 抽象类:把子类中那些具有共同属性以及共同行为的特性,归纳,总结出一个父类,我们把这个父类,称为抽象类
* 虽然我们口头上称这种类为抽象类,但是java语法结构上并没有体现出这种抽象的概念
* 那么怎么让一个类变为抽象类?
*
* 1:给类加关键字:abstract
* 语法格式
* public abstract class 类名{
*
* }
* 2:如果一个类中有抽象方法,那么这个类一定是抽象类
* 抽象方法 语法格式:抽象方法只有方法声明,没有方法体。
* 修饰符 abstract 返回值 方法名();
*
* 3:如果一个类继承了抽象类
* 那么这个类
* 1:要么重写父类中所有抽象方法
* 2:要么自己变成抽象类
*
* 抽象类的作用?
* 1:减少了抽象类中方法体的写法,提高了部分效率
* 2:规定了一个类必须做什么,约束了子类的行为,大大的增强了类的范围性,使得一个类在设计的时候,不是那么的随意
* 但是正因为类的规范性,使得类与类之间的耦合关系大大增加,无形之中给子类增加了负担
*
* 抽象类的细节处理
* 1:抽象类是否有变量:有
* 2:抽象类是否有常量:有
* 3:抽象类是否有抽象方法
* 3.1 抽象类中可以没有抽象方法,也可以有
* 3.2 有抽象方法的类,必须是抽象类
* 4:抽象类是否有成员方法:有
* 5:抽象类是否有构造方法:有
* 6:抽象类是否可以创建对象:不可以创建对象
* 7:每个类至少会提供一个构造方法
* 7.1:向上引用,调用父类的构造方法
* 7.2:初始化属性值
* 8:抽象类就是为了被继承的,如果没有子类继承,抽象类没有任何作用
* 9:所以多态的特性,在抽象类最能体现出来,因为多态的前提是继承
*
*
*
*/
public static void main(String[] args) {
//People p = new People();
//People p = new Student(); //多态 向上转型
}
}
二,接口
接口的概念
接口,严格的来讲属于一个特殊的类,而这个类里面只有抽象方法和全局常量,就连构造方法也没有。
Java是只支持单继承的,但现实之中存在多重继承这种现象。eg.如“金丝猴是一种动物”,金丝猴从“动物”这个类继承,同时“金丝猴是一种值钱的东西”,金丝猴从“值钱的东西”这个类继承,再同时“金丝猴是一种应该受到保护的东西”,金丝猴从“应该受到保护的东西”这个类继承。这样金丝猴可以同时从 “动物类”、“值钱的东西类”、“应该受到保护的东西” 这三个类继承,但由于Java只支持单继承,因此金丝猴只能从这三个类中的一个来继承,不能同时继承这三个类。因此为了封装现实生活中存在的多重继承现象,为了实现多继承,可以把其中的两个类封装成接口。使用接口可以帮助我们实现多重继承。
抽象类所具有的一些东西接口可以具有,假如一个抽象类里面所有的方法全都是抽象的,没有任何一个方法需要这个抽象类去实现,并且这个抽象类里面所有的变量都是静态(static)变量,且都是不能改变(final)的变量,即为静态常量(static final)。这时可以把这样的抽象类定义为一个接口(interface)。把符合这样条件的一个类定义成一个接口的格式是把声明类的关键字class用声明接口的关键字interface替换掉即可。
定义一个接口:
interface A{ //定义一个接口
public static final String MSG = "hello"; //全局常量,用static final 定义
public abstract void print(); //抽象方法,没有方法体
}
接口的特征
- 接口(interface)是一种特殊的抽象类,在这种抽象类里面,所有的方法都是抽象方法,并且这个抽象类的属性(即成员变量)都是声明成“public static final 类型 属性名”这样的,默认也是声明成“public static final”即里面的成员变量都是公共的、静态的,不能改变的。因此在接口里面声明常量的时候,可以写成“public static final 类型 常量名=value(值)”这样的形式,也可以直接写成“类型 常量名=value(值)”如:“public static final int id=10”可以直接写成“int id=10”这样的形式,因为在接口里面默认的属性声明全部都是“public static final”的,因此“public static final”可以省略不写。在接口里面声明的抽象方法可以不写abstract关键字来标识,因为接口里面所有的方法都是抽象的,因此这个“abstract”关键字默认都是省略掉的,如在一个接口里面声明这样的三个方法:“public void start()”、“public void run()”、“public void stop()”这三个方法前面都没有使用abstract关键字来标识,但它们全是抽象方法,因为在接口里面的声明的方法都是抽象方法,因此在接口里面的抽象方法都会把abstract关键字省略掉,因为默认声明的方法都是抽象的,所以就没有必要再写“abstract”字了,这一点与在抽象类里面声明抽象方法时有所区别,在抽象类里面声明抽象方法是一定要使用“abstract”关键字的,而在接口里面声明抽象方法可以省略掉“abstract”。注意:在接口里面声明的抽象方法默认是“public(公共的)”的,也只能是“public(公共的)”之所以要这样声明是为了修正C++里面多重继承的时候容易出现问题的地方,C++的多继承容易出现问题,问题在于多继承的多个父类之间如果他们有相同的成员变量的时候,这个引用起来会相当地麻烦,并且运行的时候会产生各种各样的问题。Java为了修正这个问题,把接口里面所有的成员变量全都改成static final,成员变量是static类型,那么这个成员变量就是属于整个类里面的,而不是专属于某个对象。对于多重继承来说,在一个子类对象里面实际上包含有多个父类对象,而对于单继承来说,子类对象里面就只有一个父类对象。多继承子类对象就有多个父类对象,而这些父类对象之间可能又会存在有重复的成员变量,这就非常容易出现问题,因此在JAVA里面避免了这种问题的出现,采用了接口这种方式来实现多继承。作为接口来说,一个类可以从接口继承(或者叫实现接口),这也是多继承,接口里面的成员变量不专属于某个对象,都是静态的成员变量,是属于整个类的,因此一个类去实现多个接口也是无所谓的,不会存在对象之间互相冲突的问题。实现多个接口,也就实现了多重继承,而且又避免了多重继承容易出现问题的地方,这就是用接口实现多重继承的好处。
示例
如下:
package javastudy.summary;
/**
* 这里定义了第一个接口:Painter,在Painter接口里面定义了paint()和eat()这两个抽象方法。
*
* @author gacl
*
*/
interface Painter {
public void eat();
public void paint();
}
/**
* 这里定义了第二个接口:Singer,在Singer接口里面定义了sing()和sleep()这两个抽象方法。
*
* @author gacl
*
*/
interface Singer {
public void sing();
public void sleep();
}
/**
* 类Student实现了Singer这个接口
*
* @author gacl
*
*/
class Student implements Singer {
private String name;
public Student(String name) {
this.name = name;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
/**
* 实现接口中定义的sing方法
*/
@Override
public void sing() {
System.out.println("student is singing");
}
/**
* 实现接口中定义的sleep方法
*/
@Override
public void sleep() {
System.out.println("student is sleeping");
}
public void study() {
System.out.println("Studying...");
}
}
/**
* Teacher这个类实现了两个接口:Singer和Painter。 这里Teacher这个类通过实现两个不相关的接口而实现了多重继承。
*
* @author gacl
*
*/
class Teacher implements Singer, Painter {
private String name;
public Teacher(String name) {
this.name = name;
}
/**
* 在Teacher类里面重写了这两个接口里面的抽象方法,
* 通过重写抽象方法实现了这两个接口里面的抽象方法。
*/
@Override
public void eat() {
System.out.println("teacher is eating");
}
public String getName() {
return name;
}
@Override
public void paint() {
System.out.println("teacher is painting");
}
public void setName(String name) {
this.name = name;
}
@Override
public void sing() {
System.out.println("teacher is singing");
}
@Override
public void sleep() {
System.out.println("teacher is sleeping");
}
public void teach() {
System.out.println("teaching...");
}
}
public class TestInterfaces {
public static void main(String[] args) {
/**
* 这里定义了一个接口类型的变量s1
*/
Singer s1 = new Student("le"); //相当于一个父类对象s1 的引用指向子类对象Student
s1.sing();
s1.sleep();
Singer s2 = new Teacher("steven");
s2.sing();
s2.sleep();
Painter p1 = (Painter)s2; //强制类型转换
p1.paint();
p1.eat();
}
}
总结
public class Test {
/*
* 接口和实现类起名规则
*
* 例如: 接口名称:StudentDao,StudentService
* 实现类:StudentDaoImpl,StudentServiceImpl
*
*/
}
public interface TestInter {
/*
* 接口的内部结构
*
* 1:接口是否有变量:没有
* 2:接口是否有常量:有
* 默认修饰符 public static final
* 3:接口是否有实现方法:没有
* 注意 jdk1.8之前没有
* 1.8之后有了,静态实现方法,默认方法
* 4:接口是否有抽象方法:有
* 默认修饰符 public abstract 返回值 方法名();
* 5:接口是否有构造方法:没有
* 接口不是类,所以也就没有必要写构造器
*
* 抽象类是为了被继承的
* 接口是为了被实现的
*/
int a = 10;
final int b = 20;
/*
default void ss(){
}
*/
void s();
}
3.抽象类与接口
public interface A extends D,E {
}
public abstract class B extends C implements A,D{
}
public class C{
}
public interface D {
public void show();
public void main(String[] args) ;
}
public interface E {
//public abstract void show();
}
public class Test {
/*
* 接口的用法
* A:接口
* B实现类,C实现类
*
* A a = new B();
* 等号左边是接口类型,右边是实现类的对象
* 多态的重要体现形式:向上转型
*
* 实际开发中,方法的形参是接口类型,实际上需要我们传入一个实现类对象
* 实际开发中,方法的形参是抽象类,实际上需要我们传入一个子类对象
*
* 面向接口编程:有利于大型项目的的可扩展和可维护性
*
* 类与类的关系
* 继承,单继承,但是有继承链
* 类与接口的关系
* 实现关系,多实现
* 接口和接口的关系
* 继承关系,多继承
* java的的最基本的2大组织结构:类与接口
* 接口把方法定义好,等着实现类来实现
* 实际开发,先定义接口,在写具体的实现类
* 注意:一个类既能继承父类,还能实现接口,但是必须先继承,后实现
*
*
* 面试题:接口和抽象类的区别?
* 1:方法实现
* 抽象类可以有实现方法
* 接口没有,1.8之后有了,可以有静态方法,默认方法
* 2:实现方式
* 抽象类是extends继承的
* 接口是implements实现的
* 3 构造器
* 抽象类可以有构造器
* 接口不能有构造器
* 4:方法修饰符
* 抽象类的抽象方法可以有public、protected和default这些修饰符
* 接口方法默认修饰符是public。你不可以使用其它修饰符。
* 5:继承
* 抽象类的抽象方法可以继承一个类和实现多个接口
* 接口可以继承一个或多个其它接口
*
* 什么时候使用抽象类和接口?
* 具体类 is..a 抽象类 是什么 类的说法
* 抽烟的学生是学生
* 狗是一个动物
*
* ..like..a.. 像什么
* 如果你的类的功能,是由很多不同之间的功能组合而成,那么应该使用接口多实现的方式
*
*
* 定义一个抽象类 Animal 3个方法 吃饭 睡觉 工作
* 2个子类:Dog,Cat
* 定义2个接口 狗要钻火圈,猫要算算数
* 定义2个子类 钻火圈的狗,算算术的猫
*
*
*/
public void show(A a){
}
public static void main(String[] args) {
//A a = new A();
//A a = new B();
//A a1 = new C(); //面向接口编程
//B b1 = new B(); //面向对象编程
//Test t = new Test();
//t.show(a);
//t.show(a1);
//System.out.println(a);
}
}