Java学习日记基础篇(六)—— 抽象类、接口、final
抽象类
为什么要有抽象类?
因为父类方法有不确定性,我们在Animal中定义了一个方法,但是它会被子类的方法覆盖掉,我们就不知道这个方法原本是做什么的
public class test1
{
public static void main(String[] args) {
}
} class Animal
{
String name;
int age; //动物会叫
public void cry()
{
System.out.println("不知道怎么叫");
//问题是这个方法永远都不会用到
}
}
不会被用到的父类方法
当父类的一些方法不能确定时,可以用 abstract 关键字来修饰该方法或类,称为抽象方法和抽象类。
//抽象类
abstract class Animal
{
String name;
int age;
//动物会叫
abstract public void cry();
} //抽象类仍然可以被继承
定义一个抽象类
public class test1
{
public static void main(String[] args) {
}
}
//抽象类
abstract class Animal
{
String name;
int age;
abstract public void cry();
}
//当一个类继承的父类是抽象类的话
//需要我们把抽象类中的所有的抽象方法全部实现
class Cat extends Animal
{
//实现父类的cry抽象方法
public void cry()
{
}
}
继承一个抽象类
抽象类的注意事项
- 用abstract 关键字来修饰一个类时,这个类就叫做抽象类
- 用abstract 关键字来修饰一个方法时,这个方法就叫做抽象方法
- 抽象方法在编程中用的不是很多,但是爱考
- 抽象类不能被实例化 —— 不能被 new 抽象类
- 抽象类可以没有抽象方法
- 一旦类包含了abstract方法,则这个类必须声明为abstract类
- 抽象方法不能包含主体
- 抽象类中可以有实现的方法,但是如果前面加上abstract就不能被实现
接口
为什么要有抽象类?
usb插槽就是现实中的接口—— 我们可以把手机,U盘都插到插槽上而不用担心出问题,因为usb插槽的厂家和做设备的厂家都遵守了统一的规定和尺寸,排线等等,但是给设备的内部结构显然是不相同的
硬件上的设计在软件中也是大量存在的
package test;
/*
* 作者:woliaoa
* 功能:接口的实现
* 时间:18.9.16
*/
public class test2
{
public static void main(String[] args)
{
Computer computer = new Computer(); //创建
Camera camera1 = new Camera(); //创建Camera
Phone phone1 = new Phone(); //创建Phone
computer.useUsb(camera1); //使用computer中的定义的useUsb方法,并把对象camera1传递给形参
computer.useUsb(phone1);//使用computer中的定义的useUsb方法,并把对象phone1传递给形参 } }
//定义一个接口
interface Usb
{
//在接口中声明了两个方法
public void start();
public void stop();
} //编写照相机类,并实现Usb接口 —— implements是实现的意思
//一个重要的原则,当一个类实现了一个接口,就要求该类把这个接口的所有方法统统实现
class Camera implements Usb
{
public void start()
{
System.out.println("我是相机,我开始工作了");
}
public void stop()
{
System.out.println("我是相机,我停止工作了");
}
} class Phone implements Usb
{
//实现接口中的所有方法
public void start()
{
System.out.println("我是手机,我开始工作了");
}
public void stop()
{
System.out.println("我是手机,我停止工作了");
}
}
//计算机类,
class Computer
{
//开始使用Usb接口
public void useUsb(Usb usb)//前面的是Usb接口 后面的是局部变量usb
{
usb.start(); //让形参usb,调用Usb接口中的start方法
usb.stop(); //让形参usb,调用Usb接口中的stiop方法
}
} 运行结果:
我是相机,我开始工作了
我是相机,我停止工作了
我是手机,我开始工作了
我是手机,我停止工作了
用代码实现USB接口
接口就是给出一些没有内容的方法,封装到一起,到某个类要使用的时候,在根据具体情况把这些方法写出来。语法:
//定义一个接口
interface 接口名
{
被初始化的变量;
方法;
} //使用一个接口
class 类名 implement 接口
{
变量;
方法;
}
接口的注意事项
- 接口不能被实例化 —— 不能被new
- 接口中的所有方法都不能有主体,抽象类中可以有非抽象方法被实现,但是接口中的方法都不能被实现—— 接口是更加抽象的抽象类
- 一个类可以实现多个接口—— class Camera implements Usb,Usb3.0 {.....}
- 接口中可以有变量,但是要被初始化【变量不能用private和protected修饰】
- 接口中的变量本质上都是static的,而且是final的,不管你加不加static修饰
- 在java开发中,我们经常把 经常用的变量,定义在接口中,作为全局变量使用,因为它是静态的。
访问形式:接口名.变量名 - 一个接口不能继承其它的类,但是可以继承别的接口
public class test2
{
public static void main(String[] args)
{
System.out.println(Usb.a); //调用Usb接口中的a变量
} }
//定义一个接口
interface Usb
{
int a=1;
//在接口中声明了两个方法
public void start();
public void stop();
}
调用接口中的变量
小结:接口是更加抽象的抽象类,抽象类里有些方法可以有方法体,接口里的所有方法都没有方法体。接口体现了程序设计的多态和高内聚和低耦合的设计思想。
继承和接口的区别
Java中没有多继承,只有多重继承,但是可以利用接口实现多重继承
小猴子不仅像学习猴子的跳技能,还想学习小鸟的飞行技能,鱼的游泳技能,这时因为java不允许有多继承,所以可以使用接口来弥补这一点
interface Fish
{
public void swimming();
}
interface Bird
{
public void fly();
}
class Monkey
{
int name;
public void jump()
{
System.out.println("猴子会跳");
}
}
//开发的时候,项目经理会定义一堆项目接口,备注上功能,然后让你来完成这个功能
class LittleMonkey extends Monkey implements Fish,Bird
{
public void swimming()
{}
public void fly()
{}
}
继承多个接口
Java的继承是单继承,也就是一个类最多只能有一个父类,这种单继承的机制可以保证类的纯洁性,比C++中的多继承机制间接(对C++的一种改良)。但是,它对子类的扩展有一定的影响,所以我们认为:
- 实现接口可以看做是对继承的一种补充
- 实现接口可在不打破继承关系的前提下,对某个类功能扩展,非常灵活
还有一点继承是层级式的,不太灵活。
假如我们修改了类1,就意味着其它的所有类都会被修改,牵一发而动全身。这也是Java只允许单继承的所带来的缺点。所以java中引入了接口很好的解决了这一点。因为接口只针对实现接口的类才起作用
案例:用接口实现多态
//汽车接口
interface Car
{
String getName(); //汽车名称
int getPrice(); //获得汽车售价
} //宝马
class BMW implements Car
{
public String getName(){
return "BMW";
}
public int getPrice() {
return 300000;
}
} //奇瑞qq
class CheryQQ implements Car
{
public String getName() {
return "CherryQQ";
}
public int getPrice() {
return 20000;
}
} //汽车出售店
public class CarShop
{
//售车收入
private int money = 0;
//卖出一部车
public void sellCar(Car car){
System.out.println("车型:" + car.getName() + " 单价: " + car.getPrice());
//增加卖出车售价的收入
money += car.getPrice();
}
//售车总收入
public int getMoney(){
return money;
} public static void main(String []args){
CarShop aShop = new CarShop();
//卖出一辆宝马
aShop.sellCar(new BMW());
//卖出一辆奇瑞QQ
aShop.sellCar(new CheryQQ());
System.out.println("总收入: " + aShop.getMoney());
}
} 运行结果:
车型:BMW 单价: 300000
车型:CherryQQ 单价: 20000
总收入: 320000
经典案例:用接口实现多态
继承是多态得以实现的基础,从字面上理解,多态就是一种类型(都是Car类型)表现出多种状态(宝马和奇瑞QQ)将一个方法调用同这个方法的所属的主体(也就是对象或类)关联起来叫做绑定,分为前期绑定和后期绑定两种
- 前期绑定:在程序运行之前进行绑定,由编译器和连接程序实现,又叫做静态绑定。比如static方法和final方法,注意:这里也包括private方法,因为它是隐式final的
- 后期绑定:在运行时根据对象的类型进行绑定,由方法调用机制实现,因此又叫做动态绑定或运行时绑定。除了前期绑定外的所有方法都属于后期绑定
public void sellCar(Car car)
{
System.out.println("车型:" + car.getName() + " 单价: " + car.getPrice());
//增加卖出车售价的收入
money += car.getPrice();
} 后期绑定:在编译的时候我们并不知道将来的Car是宝马还是奇瑞,只有在运行的瞬间才知道car是什么类型 public class Carshop
{
int a = 1;
}
前期绑定:在程序运行之前就知道a一定是int且等于1前期绑定和后期绑定的例子
总结:所以在编译的时候能够确定的类型就是前期绑定,在运行的时候才能知道是哪一种类型的话称之为后期绑定
多态就是在后期绑定这种机制上实现的。多态给我们带来的好处是消除了类之间的耦合关系,使程序更容易扩展。比如上例中,新增一种类型汽车的销售,值需要让新定义的类去实现Car接口的所有方法,而无需对原有代码做任何修改,CarShop类的sellCar(Car car)方法就可以处理新的车型了。新增代码如下:
//桑塔纳汽车
class Santana implements Car{
public String getName(){
return "Santana";
}
public int getPrice() {
return 80000;
}
}
final
final可以修饰变量或者方法,在实际开发中,使用很广泛。注:final定义的方法或变量的名字都用下划线定义如
final float rate_aaa_bbb = 3.1415926
在某些情况下,程序员可能有以下需求:
- 当不希望父类的某个方法被子类覆盖(override)时,可以用final关键字修饰
- 当不希望类的某个变量的值被修改,可以用final修饰
- 当不希望类被继承时,可以用final修饰
public class test4
{
public static void main(String[] args)
{
}
} class Aaa
{
//假如说我开发了一个特别好的功能,但是不想别人修改它,此时可以在前面加上一个final类
//给方法用public修饰,则表示不可悲修改,不可悲覆盖
final public void sendMes()
{
System.out.println("发送消息");
}
} class Bbb extends Aaa
{
public void sendMes()
{
System.out.println("发送消息");
}
} 报错:
Cannot override the final method from Aaa
修改final方法的后果
public class test4
{
public static void main(String[] args)
{
Aaa aaa = new Aaa();
Bbb bbb = new Bbb();
bbb.show();
}
} class Aaa
{
int a=0; //如果不给a赋值,a的默认值为0
}
class Bbb extends Aaa
{
public Bbb()
{
a++;
} public void show() {
System.out.println("a=="+a);
}
}
需求2的final实例——通过Bbb类修改Aaa类中a的值
这时可以在a前面定义加上final防止a被修改
final int a = 1;
//如果不希望某个类被继承,可以在前面加上final
//final修饰类则表示该类,不能被继承
final class Aaa
{
int a=0; //如果不给a赋值,a的默认值为0
}
需求3实例
如果一个变量是final的,则必须初始化(赋初值),否则编译不会通过。先定义再赋值也不行
final的注意事项
- final修饰的变量又叫常量,一般用xx_xx_xx来命名
- final修饰的变量在定义是,必须赋初值,并且以后不能再赋值
final什么时候用
- 因为安全的考虑,类的某个 方法不允许修改
- 不想让类被其它类继承
- 某些变量的值时固定不变的,比如国家的汇率
Java学习日记基础篇(六)—— 抽象类、接口、final的更多相关文章
- Java学习日记基础篇(四)——类,对象之成员变量,成员方法,构造方法
面向对象(Object Oriented) 一.面向对象杂谈 面向对象(Object Oriented),我的翻译是以物体为目标的,就是说编程的时候是建立一个物体,然后对这个物体进行操作. Java语 ...
- java学习笔记(基础篇)—抽象与接口的区别
抽象与接口的区别 一.抽象(abstract) 1. 抽象方法 1) 作用:定义规范 2) 抽象方法用来描述具有什么功能,但不提供实现. 3) 如果类中一个方法没有实现就要定义一个抽象方法. 2. 抽 ...
- Java学习日记基础篇(九) —— 集合框架,泛型,异常
集合框架 有事我们会需要一个能够动态的调整大小的数组,比如说要添加新员工但是数组已经满了,并且数组的大小是在定义的时候定死的,所以我们就需要一个能够动态调整大小的数组或者用链表解决,而java中提供了 ...
- Java学习日记基础篇(七) —— 数组、排序
数组 为什么要有数组? 案例:一个养鸡场有六只鸡,他们的体重分别为3kg,5kg,1kg,3.4kg,2kg,50kg.请问这六只鸡的总体重和平均体重是多少? public class test5 { ...
- Java学习日记——基础篇(二)基本语法
变量 变量和常量是程序处理的两种基本数据对象,变量是程序的基本组成单位 变量的目的就是确定目标并提供存放空间 public class Hello { public static void main( ...
- Java学习日记——基础篇(一)常识
JAVA简介 Java的标准 Java是一种语言,一个平台包含JavaSE.JavaEE.JavaME三个版本 JavaSE标准版(属于Java的基础部分,可以开发C/S构架的桌面应用程序) Java ...
- Java学习日记基础篇(八) —— 二进制、位运算、位移运算
二进制 二进制是逢2进位的进位置,0,1是基本算符 原码反码补码 在基本数据类型那里,有详细解释 二进制的最高位数是符号位:0表示整数,1表示负数 正数的原码,反码,补码都一样 负数的反码 = 它的原 ...
- Java学习日记基础篇(三-下)——流程控制之循环控制
循环控制 for循环 语法: for(循环初值;循环条件;步长) { 语句; //循环体 } 例子: import java.io.*; public class Demo4 { public sta ...
- Java学习日记——基础篇(三-上)基本语法之运算符和流程控制
运算符 算术运算符 听其名而知其意,就是用于计算的,java中常用的是: + 加 - 减 * 乘 / 除 % 取模,取余——%可以用来得到两个数相除的余数 小练习——写一个ja ...
随机推荐
- 使用MD5加密字符串
一.概念: MD5码以512位分组来处理输入的信息,且每一分组又被划分为16个32位子分组,经过了一系列的处理后,算法的输出由四个32位分组组成,将这四个32位分组级联后将生成一个128位散列值. 二 ...
- Java定时任务工具详解之Timer篇
Java定时任务调度工具详解 什么是定时任务调度? ◆ 基于给定的时间点,给定的时间间隔或者给定的执行次数自动执行的任务. 在Java中的定时调度工具? ◆ Timer ◆Quartz T ...
- C#基础加强笔记
1面向对象 类:包含字段.属性.函数.构造函数 字段:存储数据 属性:保护字段 get set 函数:描述对象的行为 构造函数:初始化对象,给对象的每个属性赋值 面向对象的好处:让程序具有扩展性 类决 ...
- 正则表达式字符&使用
正则详细解说:https://juejin.im/post/5965943ff265da6c30653879 一.正则表达式中的字符含意 \ 做为转义,即通常在"\"后面的字符不按 ...
- 宽字节 多字节 mbstowcs wcstombs
函数 size_t wcstombs(char *dest, const wchar_t *src, size_t n); //wide-character to a multibyte n:被写入到 ...
- java引用传递和值传递
关于Java传参时是引用传递还是值传递,一直是一个讨论比较多的话题,有论坛说Java中只有值传递,也有些地方说引用传递和值传递都存在,比较容易让人迷惑.关于值传递和引用传递其实需要分情况看待,今天学习 ...
- markdown格式字串转html格式字串
参考:https://www.jianshu.com/p/0eff6cba1b7f 操作: 1.安装python支持包 pip install mkdocs # 含markdown包 或 ...
- 可能是东半球最好的 Curl 学习指南,强烈建议收藏!
本文首发于:微信公众号「运维之美」,公众号 ID:Hi-Linux. 「运维之美」是一个有情怀.有态度,专注于 Linux 运维相关技术文章分享的公众号.公众号致力于为广大运维工作者分享各类技术文章和 ...
- C#一些不太熟悉的类——扩展学习
Process.CloseMainWindow Method 通过向进程的主窗口发送关闭消息来关闭拥有用户界面的进程. 注解 进程执行时,其消息循环处于等待状态. 每次操作系统将 Windows 消息 ...
- github看项目-浏览器插件
浏览器插件,使用浏览器看github项目 原文:浏览 GitHub 太卡了?教你两招!