抽象类和接口
1.抽象类
1.抽象方法没有方法体 必须存在于抽象类 均使用 abstract 修饰
2.抽象类不能直接 new 对象 必须通过 new 子类的方式创建对象(多态向上转型)
3.子类必须重写抽象类中的所有抽象方法 除非子类也是抽象类
4.抽象类中可以书写普通属性 普通方法 静态方法 构造方法
5.抽象类作为父类 实现多态的方式与之前一致
package com.atguigu.test2;
/**
* 动物类
* abstract : 抽象
*/
public abstract class Animal {
// 属性
private String animalType;
public String getAnimalType() {
return animalType;
}
public void setAnimalType(String animalType) {
this.animalType = animalType;
}
public Animal(String animalType) {
this.animalType = animalType;
}
public Animal() {
}
public static void m1(){
System.out.println("Animal类中的m1方法 ");
}
// 方法
/**
* 1.抽象方法没有方法体 必须存在于抽象类 均使用abstract修饰
* 2.抽象类不能直接new对象 必须通过new子类的方式创建对象(多态向上转型)
* 3.子类必须重写抽象类中的所有抽象方法 除非子类也是抽象类
* 4.抽象类中可以书写普通属性 普通方法 静态方法 构造方法
* 5.抽象类作为父类 实现多态的方式与之前一致
*/
public abstract void eat();
}package com.atguigu.test2;
public class Tiger extends Animal{
@Override
public void eat() {
System.out.println("老虎吃肉");
}
}package com.atguigu.test2;
public abstract class Pet extends Animal{
public abstract void playWithMaster();
}package com.atguigu.test2;
public class Dog extends Pet{
@Override
public void eat() {
System.out.println("狗狗吃骨头");
}
@Override
public void playWithMaster() {
System.out.println("狗狗和主人玩飞盘");
}
}package com.atguigu.test2;
/**
* 类是对象的抽象
* 对象是类的具体
*/
public class TestAnimal {
public static void main(String[] args) {
Animal tiger = new Tiger();
tiger.eat();
Animal dog1 = new Dog();
dog1.eat();
Pet dog2 = new Dog();
dog2.eat();
dog2.playWithMaster();
}
}2. 抽象类实现多态
package com.atguigu.test3;
/**
* 父类: 门
* 子类:防盗门 普通门
*/
public abstract class Door {
private String brand;
private double price;
public String getBrand() {
return brand;
}
public void setBrand(String brand) {
this.brand = brand;
}
public double getPrice() {
return price;
}
public void setPrice(double price) {
this.price = price;
}
public abstract void open();
public abstract void close();
public Door(String brand, double price) {
this.brand = brand;
this.price = price;
}
public Door() {
}
}package com.atguigu.test3;
public class CommonDoor extends Door{
@Override
public void open() {
System.out.println("普通门开门,插入钥匙,轻轻一转,zhi~ya一声,门开了");
}
@Override
public void close() {
System.out.println("普通门关门,随手关门,duang的一声,门关了");
}
}package com.atguigu.test3;
public class SecurityDoor extends Door{
private String password;
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
public SecurityDoor(String brand, double price, String password) {
super(brand, price);
this.password = password;
}
public SecurityDoor() {
}
@Override
public void open() {
System.out.println("防盗门开门,输入密码,按下指纹,门自动打开");
}
@Override
public void close() {
System.out.println("防盗门关门,障碍物识别,自动关门");
}
}package com.atguigu.test3;
/**
* 人类
*/
public class Person {
public void openCommonDoor(CommonDoor cd){
cd.open();
}
public void closeCommonDoor(CommonDoor cd){
cd.close();
}
public void openSecurityDoor(SecurityDoor sd){
sd.open();
}
public void closeSecurityDoor(SecurityDoor sd){
sd.close();
}
// 以上方式分别针对不同的门的种类编写了开和关的方法 如果后续有更多的门的种类
// 还需要继续编写更多的方法 这样设计不合理 不符合开闭原则
// -------------------------------------------------------------
public void openDoor(Door door){
door.open();
}
public void closeDoor(Door door){
door.close();
}
// -------------------------------------------------------------
public Door buyDoor(double money){
if(money > 300){
return new SecurityDoor();
}else{
return new CommonDoor();
}
}
}package com.atguigu.test3;
public class TestPerson {
public static void main(String[] args) {
Person person = new Person();
CommonDoor commonDoor = new CommonDoor();
commonDoor.setBrand("小金刚");
commonDoor.setPrice(200);
SecurityDoor securityDoor = new SecurityDoor();
securityDoor.setBrand("大金刚");
securityDoor.setPrice(500);
person.openDoor(commonDoor);
person.openDoor(securityDoor);
person.closeDoor(commonDoor);
person.closeDoor(securityDoor);
System.out.println("-------------------------------------------------------");
Door door = person.buyDoor(500);
door.open();
door.close();
System.out.println("-------------------------------------------------------");
Door [] doors = new Door[2];
doors[0] = new CommonDoor();
doors[1] = new SecurityDoor();
}
}3.final 关键字
3.1 修饰属性
修饰属性:被 final 修饰的属性称之为常量 名称全部大写 多个单词之间使用下划线分割 常量只能被赋值一次
通常(99%)在定义的时候赋值 或者 在构造方法中赋值 这两种方式都是为了保证在使用常量之前是有值的
基本数据类型:值不能被改变
引用数据类型:地址不能被改变 地址中的内容(属性)是可以改变
package com.atguigu.test4;
/**
* final关键字:修饰属性、方法、类
* 修饰属性:被final修饰的属性称之为常量 名称全部大写 多个单词之间使用下划线分割 常量只能被赋值一次
* 通常(99%)在定义的时候赋值 或者 在构造方法中赋值 这两种方式都是为了保证在使用常量之前是有值的
* 基本数据类型:值不能被改变
* 引用数据类型:地址不能被改变 地址中的内容(属性)是可以改变
*/
public class TestFinalFiled {
final double PI = 3.14;
final int SEAT_COUNT;
final char [] SIGNS = new char[3];
public TestFinalFiled(){
SEAT_COUNT = 60;
}
public TestFinalFiled(double radius) {
SEAT_COUNT = 70;
this.radius = radius;
}
double radius;
public static void main(String[] args) {
TestFinalFiled testFinalFiled = new TestFinalFiled();
// testFinalFiled.pi = 3.24;
testFinalFiled.radius = 10;
System.out.println(testFinalFiled.radius * testFinalFiled.radius * testFinalFiled.PI);
// testFinalFiled.SIGNS = new char[2];
testFinalFiled.SIGNS[0] = 'a';
testFinalFiled.SIGNS[1] = 'b';
testFinalFiled.SIGNS[2] = 'c';
}
}被 final 修饰的属性称之为常量 表示其值或者地址不能被改变
这样的数据通常也没有必要存在多份 所以实际开发中经常会用 static final 修饰不允许被改变的数据
因为只有一份 且 数据无法改变 所以通常也会再加上 public 修饰 称之为:全局 静态 常量
静态常量:通常在定义的时候赋值 或者 在静态代码块中赋值 这两种方式同样是为了保证在使用常量之前是有值的
package com.atguigu.test4;
/**
* 被final修饰的属性称之为常量 表示其值或者地址不能被改变
* 这样的数据通常也没有必要存在多份 所以实际开发中经常会用static final修饰不允许被改变的数据
* 因为只有一份 且 数据无法改变 所以通常也会再加上public修饰 称之为:全局 静态 常量
*
* 静态常量:通常在定义的时候赋值 或者 在静态代码块中赋值 这两种方式同样是为了保证在使用常量之前是有值的
*
*/
public class TestStaticFinalField {
public static final double PI = 3.14;
static final String COUNTRY_NAME;
static{
COUNTRY_NAME = "中华人民共和国";
}
public TestStaticFinalField() {
}
}3.2 修饰方法
final 修饰的方法不能被子类重写
package com.atguigu.test4;
/**
* final修饰的方法不能被子类重写
*/
public class TestFinalMethod {
}
class A{
public final void m1(){
System.out.println("A类m1方法");
}
public void m2(){
System.out.println("A类m2方法");
}
}
class B extends A{
public void m2(){
}
}3.3 修饰类
被 final 修饰的类不能被继承 String 类就是使用 final 修饰的
package com.atguigu.test4;
/**
* 被final修饰的类不能被继承 String类就是使用final修饰的
*/
public class TestFinalClass {
public static void main(String[] args) {
}
}
final class C{
}
class D {
}4. 接口
1.接口中的方法默认都为全局抽象方法 即不管是否书写均使用 public abstract 修饰
2.接口不能直接 new 对象 必须通过 new 实现类(子类)的方式创建对象 (多态向上转型)
3.实现类(子类)必须实现(重写)接口中的所有抽象方法 除非实现类是抽象类 或者 是 接口
4.接口中不能书写普通属性、普通方法、构造方法、静态方法
5.一个类只能继承一个父类 一个实现类可以实现多个接口 接口也可以继承多个接口
6.接口实现多态的方式与之前一致
面试题:Java 支持多继承?
不支持 但是可以使用接口继承多个接口的方式 实现类似多继承的效果
package com.atguigu.test5;
/**
* 面试题:Java支持多继承?
* 不支持 但是可以使用接口继承多个接口的方式 实现类似多继承的效果
*/
public interface USB {
int A = 100; // 默认为全局静态常量 不管是否书写 均使用public static final修饰
/**
* 1.接口中的方法默认都为全局抽象方法 即不管是否书写均使用public abstract修饰
* 2.接口不能直接new对象 必须通过new实现类(子类)的方式创建对象 (多态向上转型)
* 3.实现类(子类)必须实现(重写)接口中的所有抽象方法 除非实现类是抽象类 或者 是 接口
* 4.接口中不能书写普通属性、普通方法、构造方法、静态方法
* 5.一个类只能继承一个父类 一个实现类可以实现多个接口 接口也可以继承多个接口
* 6.接口实现多态的方式与之前一致
*/
void connect();
}package com.atguigu.test5;
import com.atguigu.test5.USB;
public class Mouse implements USB {
@Override
public void connect() {
System.out.println("鼠标连接USB接口,可以操作电脑了");
}
}package com.atguigu.test5;
public abstract class Converter implements USB{
/**
* 转换方法 举例:网线转换器 需要执行转换功能 将水晶头网线转换为USB接口进行传输
*/
public abstract void convert();
}package com.atguigu.test5;
public class UGreenConverter extends Converter{
@Override
public void convert() {
System.out.println("绿联转换器执行水晶头网络转换");
}
@Override
public void connect() {
System.out.println("绿联转换器连接USB接口");
}
}package com.atguigu.test5;
public class TestUSB {
public static void main(String[] args) {
USB usb = new Mouse();
usb.connect();
System.out.println("------------------------------------------------");
USB convert = new UGreenConverter();
convert.connect();
System.out.println("------------------------------------------------");
Converter converter = new UGreenConverter();
converter.connect();
converter.convert();
}
}5. 接口实现手机

接口是一种能力,实现一个接口,即表示具备一个能力,实现多个接口,即表示具备多个能力
关心实现类有何能力,而不关心实现细节
面向接口的约定而不考虑接口的具体实现
当前案例中,能不能将五个抽象方法全部书写在一个接口中呢?
不推荐,不可以,因为如果书写在一个接口中,将增加程序的耦合性,即任何一个手机子类实现了这个接口,将必须重写这个五个抽象方法,即拥有五个功能,将不能根据市场需求灵活的生产不同档次的手机产品。
package com.atguigu.test1;
/**
* 手机类 父类
* 属性:品牌 型号 价格
* 方法:打电话 发短信
*/
public abstract class Phone {
private String brand;
private String type;
private double price;
public String getBrand() {
return brand;
}
public void setBrand(String brand) {
this.brand = brand;
}
public String getType() {
return type;
}
public void setType(String type) {
this.type = type;
}
public double getPrice() {
return price;
}
public void setPrice(double price) {
this.price = price;
}
public Phone() {
}
public Phone(String brand, String type, double price) {
this.brand = brand;
this.type = type;
this.price = price;
}
public abstract void call();
public abstract void sendMessage(String message);
@Override
public String toString() {
return "Phone{" +
"brand='" + brand + '\'' +
", type='" + type + '\'' +
", price=" + price +
'}';
}
}package com.atguigu.test1;
public class CommonPhone extends Phone implements NetWork,Audio,Game{
private String keyboardType;
public String getKeyboardType() {
return keyboardType;
}
public void setKeyboardType(String keyboardType) {
this.keyboardType = keyboardType;
}
public CommonPhone() {
}
public CommonPhone(String brand, String type, double price, String keyboardType) {
super(brand, type, price);
this.keyboardType = keyboardType;
}
@Override
public void call() {
System.out.println("普通手机打电话,按键拨号,体验还行");
}
@Override
public void sendMessage(String message) {
System.out.println("普通手机发短信,按键打字,体验一般:" + message);
}
@Override
public void playAudio(String audioName) {
System.out.println("普通手机播放音乐,音质感人:" + audioName);
}
@Override
public void playGame(String game) {
System.out.println("普通手机打游戏,体验一般:" + game);
}
@Override
public void connect() {
System.out.println("普通手机连接2G网络,体验很一般");
}
}package com.atguigu.test1;
/**
* 智能手机
*/
public class SmartPhone extends Phone implements NetWork,Video,Audio,Photo,Game{
private double screenSize;
public double getScreenSize() {
return screenSize;
}
public void setScreenSize(double screenSize) {
this.screenSize = screenSize;
}
public SmartPhone() {
}
public SmartPhone(String brand, String type, double price, double screenSize) {
super(brand, type, price);
this.screenSize = screenSize;
}
@Override
public void call() {
System.out.println("智能手机打电话,语音拨号,体验很不错");
}
@Override
public void sendMessage(String message) {
System.out.println("智能手机发短信,手写输入,体验很棒:" + message);
}
@Override
public void playAudio(String audioName) {
System.out.println("智能手机播放音频,音质很棒:" + audioName);
}
@Override
public void playGame(String game) {
System.out.println("智能手机打游戏,体验很丝滑:" + game);
}
@Override
public void connect() {
System.out.println("智能手机连接6G网络,飞一般的感觉");
}
@Override
public void takePhoto() {
System.out.println("智能拍照,1亿像素,咔嚓一下记录美好,记录你我");
}
@Override
public void playVideo(String videoName) {
System.out.println("智能手机播放视频,很清晰:" + videoName);
}
}package com.atguigu.test1;
/**
* 播放音频接口
*/
public interface Audio {
void playAudio(String audioName);
}package com.atguigu.test1;
/**
* 打游戏接口
*/
public interface Game {
void playGame(String game);
}package com.atguigu.test1;
/**
* 联网接口
*/
public interface NetWork {
void connect();
}package com.atguigu.test1;
/**
* 拍照接口
*/
public interface Photo {
void takePhoto();
}package com.atguigu.test1;
/**
* 播放视频接口
*/
public interface Video {
void playVideo(String videoName);
}package com.atguigu.test1;
public class TestPhone {
public static void main(String[] args) {
SmartPhone huawei = new SmartPhone("华为", "mate 50 PRO MAX PLUS", 9.9, 25);
huawei.connect();
huawei.call();
huawei.sendMessage("睡了吗?");
huawei.playVideo("《小猪佩奇成人版》");
huawei.playAudio("《最炫民族风》");
huawei.playGame("《原神》");
huawei.takePhoto();
System.out.println("-------------------------------------------------------------------------------");
CommonPhone nokia = new CommonPhone("诺基亚", "N97", 8.8, "九键");
nokia.connect();
nokia.sendMessage("真的睡了吗?");
nokia.call();
nokia.playAudio("《发如雪》");
nokia.playGame("《贪吃蛇》");
}
}6. 接口实现打印机
接口是一种约定,即表示一种规范
程序设计时面向接口的约定而不考虑具体实现

纸张是一种规范,接口也是一种规范,因为纸张和接口有我们公认的执行标准。
package com.atguigu.test2;
/**
* 打印机类
* 属性:墨盒 和 纸张
* 方法:打印
*/
public class Printer {
private InkBox inkBox;
private Paper paper;
public void setInkBox(InkBox inkBox){
this.inkBox = inkBox;
}
public InkBox getInkBox(){
return inkBox;
}
public void setPaper(Paper paper){
this.paper = paper;
}
public Paper getPaper(){
return paper;
}
public void print(){
System.out.println("使用" + this.getInkBox().getInkBoxType() + "墨盒在" + this.getPaper().getPaperSize() + "纸张上打印");
}
}package com.atguigu.test2;
/**
* 墨盒接口
*/
public interface InkBox {
/**
* 获取墨盒的具体类型
* @return
*/
String getInkBoxType();
}package com.atguigu.test2;
public class BlackInkBox implements InkBox{
@Override
public String getInkBoxType() {
return "黑色";
}
}package com.atguigu.test2;
/**
* 彩色墨盒
*/
public class ColorInkBox implements InkBox{
@Override
public String getInkBoxType() {
return "彩色";
}
}package com.atguigu.test2;
/**
* 纸张接口
*/
public interface Paper {
/**
* 返回纸张具体的型号
* @return
*/
String getPaperSize();
}package com.atguigu.test2;
/**
* A4纸
*/
public class A4 implements Paper{
@Override
public String getPaperSize() {
return "A4";
}
}package com.atguigu.test2;
/**
* B5纸张
*/
public class B5 implements Paper{
@Override
public String getPaperSize() {
return "B5";
}
}package com.atguigu.test2;
public class Test {
public static void main(String[] args) {
Printer hp = new Printer();
Paper a4 = new A4();
Paper b5 = new B5();
InkBox black = new BlackInkBox();
InkBox color = new ColorInkBox();
hp.setPaper(a4);
hp.setInkBox(black);
hp.print();
}
}7. 接口和抽象类
什么时候使用接口,什么时候使用抽象类呢?
推荐使用组合,即使用接口实现,因为类只能继承一个父类
当你关注事物的本质,使用抽象类
当你关注某个功能,使用接口