目录
1. 抽象类
1.抽象方法没有方法体吗,必须存在于抽象类中 均使用 abstract 修饰
2.抽象类不能直接 new 对象,必须通过 new 子类的方式创建对象(即多态向上转型)
3.子类必须重写抽象类中的所有抽象方法,除非子类也是抽象对象
4.抽象类中可以写普通属性、静态属性,普通方法、静态方法,构造方法
5.抽象类实现多态的方式与之前一致
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(){}
static int num ;
public abstract void eat();//抽象方法
public static void main(String[] args) {、
}
}
public class Tiger extends Animal{
@Override
public void eat() {
System.out.println("老虎吃人");
}
}
public abstract class Pet extends Animal{
public abstract void playWithMaster();
}
public class Dog extends Pet{
@Override
public void eat() {//重写间接父类的抽象方法
System.out.println("狗吃骨头");
}
@Override
public void playWithMaster() {//重写直接父类的抽象方法
System.out.println("狗狗陪主人玩飞盘");
}
}
public class TestAnimal {
public static void main(String[] args) {
// Animal animal = new Animal();
Animal tiger = new Tiger();
tiger.eat();
System.out.println("--------------------------------------");
Dog dog = new Dog();
dog.eat();
dog.playWithMaster();
System.out.println("--------------------------------------");
Animal dog1 = new Dog();//间接父类
dog1.eat();
Pet dog2 = new Dog();
dog2.eat();
dog2.playWithMaster();
}
}
2. 抽象类实现多态
5.抽象类实现多态的方式与之前一致
向上转型三种方式
1.父类作为形参 子类作为实参
2. 声明父类类型的返回值 实际返回值为子类类型
3.父类类型的数组/集合 实际元素为子类类型
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 Door() {
}
public Door(String brand, double price) {
this.brand = brand;
this.price = price;
}
public abstract void open();
public abstract void close();
}
public class CommonDoor extends Door{
private String key;
public String getKey() {
return key;
}
public void setKey(String key) {
this.key = key;
}
public CommonDoor() {
}
public CommonDoor(String brand, double price, String key) {
super(brand, price);
this.key = key;
}
@Override
public void open() {
System.out.println("普通门插入钥匙,zhiya一声 门开了");
}
@Override
public void close() {
System.out.println("普通门关门,duang的一声,关门");
}
}
public class SecurityDoor extends Door{
private String password;
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
public SecurityDoor() {
}
public SecurityDoor(String brand, double price, String password) {
super(brand, price);
this.password = password;
}
@Override
public void open() {
System.out.println("防盗门开门,输入密码,门开了");
}
@Override
public void close() {
System.out.println("防盗门关门,自动关门");
}
}
public class Person {
public void openCommonDoor(CommonDoor cd){
cd.open();
}
public void closeCommonDoor(CommonDoor cd){
cd.close();
}
public void openSecurityDoor(SecurityDoor securityDoor){
securityDoor.open();
}
public void closeSecurityDoor(SecurityDoor securityDoor){
securityDoor.close();
}
// --------------------------------------------------------------------
public void openDoor(Door door){
door.open();
}
public void closeDoor(Door door){
door.close();
}
// --------------------------------------------------------------------
public Door buyDoor(double money){
if(money > 500){
return new SecurityDoor();
}else{
return new CommonDoor();
}
}
}
public class TestDoor {
public static void main(String[] args) {
Person zs = new Person();
CommonDoor commonDoor = new CommonDoor("小金刚", 500, "原配钥匙");
SecurityDoor securityDoor = new SecurityDoor("大金刚", 1000, "admin666");
zs.openDoor(commonDoor);
zs.openDoor(securityDoor);
System.out.println("------------------------------------------");
Door door = zs.buyDoor(333);
zs.openDoor(door);
System.out.println("------------------------------------------");
Door [] doors = new Door[2];
doors[0] = new CommonDoor();
doors[1] = new SecurityDoor();
}
}
3. final关键字
final 关键字可以用于修饰属性、方法、类
final关键字与我们之前所学习的访问修饰符无关
3.1 final 修饰属性
被 final 修饰的属性称为常量,常量名称要求全部大写,多个单词之间用 _ 分割
通常(99%)在定义的时候赋值,或者在构造方法中赋值
以上两种方式都是为了保证在使用常量之前是有值的
基本数据类型:被final修饰的基本数据类型,一旦定义就不能再改变
引用数据类型:被final修饰的引用数据类型,定义之后地址不能再改变 ,值可以改变
public class TestFinalField {
final double PI = 3.14;
double radius;
final String COUNTRY_NAME;
final char [] SIGN = new char[3];
final Dog DOG = new Dog();
public TestFinalField() {
COUNTRY_NAME = "中华人民共和国";
}
public TestFinalField(double radius) {
this.radius = radius;
COUNTRY_NAME = "中华人民共和国";
}
public static void main(String[] args) {
TestFinalField testFinalField = new TestFinalField();
testFinalField.radius = 10;
// testFinalField.pi = 3.24;
// testFinalField.COUNTRY_NAME = "中国";
testFinalField.SIGN[0] = 'A';
testFinalField.SIGN[1] = 'B';
testFinalField.SIGN[2] = 'C';
testFinalField.DOG.strain = "金毛";
System.out.println(testFinalField.radius * testFinalField.radius * testFinalField.PI );
TestFinalField testFinalField1 = new TestFinalField();
}
}
再实际开发中,被final修饰的属性表示常量,没必要存在多份,可以在加上static修饰
static final 修饰的内容:静态 常量
被static修饰的常量通常在定义的时候赋值 或者在静态代码块中赋值
以上两种方式都是为了保证在使用常量之前都是有值的
public class TestFinalStaticField {
public static final double PI = 3.14;
static final String COUNTRY_NAME;
static{
COUNTRY_NAME = "中国";
}
public TestFinalStaticField() {
}
}
3.2 final修饰方法
被 final 修饰的方法表示(可以被继承)不能被子类重写
public class TestFinalMethod {
}
class A{
public void m1(){
System.out.println("A 类m1方法");
}
public final void m2(){
System.out.println("A 类m2方法");
}
}
class B extends A{
public void m1(){
System.out.println("B 类重写m1方法");
}
public static void main(String[] args) {
B b = new B();
b.m1();
b.m2();
}
}
3.3 final修饰类
被 final 修饰的类不能被其他类继承
public class TestFinalClass {
public static void main(String[] args) {
}
}
final class C extends B{
}
4. 接口
接口使用关键字interface修饰
interface:界面
UI:User Interface 用户交互界面
接口是一种约定、一种规范 接口只关注约定本身 不关注具体实现
接口是一种能力 谁实现了这个接口,谁就拥有了某项能力
1.接口中的方法默认为全局抽象方法 不管是否书写均使用 public abstract 修饰
2.接口不能直接 new 对象 必须通过 new 实现类(子类)的方式创建对象(多态向上转型)
3.实现类(子类)必须实现(重写)接口中所有的抽象方法,除非实现类也是抽象类 或者 接口
4.接口中不能书写普通属性 普通方法(JDK7-) 静态方法(JDK7-) 构造方法
5.接口可以继承多个接口 一个类也可以实现多个接口 多个接口之间使用逗号分割
6.接口实现多态的方式与之前一致
面试题:Java支持多继承吗?
不支持 但是可以使用接口继承多个接口的方式 实现类似多继承的效果
public interface USB {
public static final int NUM = 10;
void connect();
public default void m1(){
}
public static void main(String[] args) {
}
}
public class Mouse implements USB{
@Override
public void connect() {
System.out.println("鼠标链接上USB接口 可以点击世界了");
}
}
public abstract class Converter implements USB{
/**
* 转换方法
*/
public abstract void convert();
}
public class HuaWeiConverter extends Converter{
@Override
public void convert() {
System.out.println("将网络进行转换");
}
@Override
public void connect() {
System.out.println("连接USB接口实现网络传输");
}
}
public class TestUSB {
public static void main(String[] args) {
// USB usb = new USB();
USB mouse = new Mouse();
mouse.connect();
System.out.println("--------------------------------");
USB converter1 = new HuaWeiConverter();
converter1.connect();
HuaWeiConverter huaWeiConverter = new HuaWeiConverter();
huaWeiConverter.convert();
huaWeiConverter.connect();
}
}
手机案例
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 abstract void call();
public abstract void sendMessage(String message);
}
public class CommonPhone extends Phone implements Audio,NetWork,Game{
private String keyboardType; // 键盘类型 比如 九键 二十六键
public String getKeyboardType() {
return keyboardType;
}
public void setKeyboardType(String keyboardType) {
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 gameName) {
System.out.println("普通手机打游戏,很经典:" + gameName);
}
@Override
public void connect() {
System.out.println("普通手机连接2G网络 体验非一般");
}
}
public class SmartPhone extends Phone implements Video, Audio,Game,Photo, NetWork {
private double screenSize; // 屏幕尺寸
public double getScreenSize() {
return screenSize;
}
public void setScreenSize(double screenSize) {
this.screenSize = screenSize;
}
@Override
public void call() {
System.out.println("智能手机打电话,语音拨号,体验很棒");
}
@Override
public void sendMessage(String message) {
System.out.println("智能手机发短信,语音输入,体验很棒");
}
@Override
public void playAudio(String audioName) {
System.out.println("智能手机播放音乐,音质很棒:" + audioName);
}
@Override
public void playGame(String gameName) {
System.out.println("智能手机打游戏,很丝滑:" + gameName);
}
@Override
public void connect() {
System.out.println("智能手机连接5G网络 飞一般的感觉");
}
@Override
public void takePhoto() {
System.out.println("咔嚓一下 记录美好 记录你我");
}
@Override
public void playVideo(String videoName) {
System.out.println("智能手机播放视频,高清画质,很流畅:" + videoName);
}
}
public class SmartPhone extends Phone implements Video, Audio,Game,Photo, NetWork {
private double screenSize; // 屏幕尺寸
public double getScreenSize() {
return screenSize;
}
public void setScreenSize(double screenSize) {
this.screenSize = screenSize;
}
@Override
public void call() {
System.out.println("智能手机打电话,语音拨号,体验很棒");
}
@Override
public void sendMessage(String message) {
System.out.println("智能手机发短信,语音输入,体验很棒");
}
@Override
public void playAudio(String audioName) {
System.out.println("智能手机播放音乐,音质很棒:" + audioName);
}
@Override
public void playGame(String gameName) {
System.out.println("智能手机打游戏,很丝滑:" + gameName);
}
@Override
public void connect() {
System.out.println("智能手机连接5G网络 飞一般的感觉");
}
@Override
public void takePhoto() {
System.out.println("咔嚓一下 记录美好 记录你我");
}
@Override
public void playVideo(String videoName) {
System.out.println("智能手机播放视频,高清画质,很流畅:" + videoName);
}
}
package com.atguigu.test6;
/**
* 音频接口
*/
public interface Audio {
void playAudio(String audioName);
}
package com.atguigu.test6;
/**
* 游戏接口
*/
public interface Game {
void playGame(String gameName);
}
package com.atguigu.test6;
/**
* 联网接口
*/
public interface NetWork {
void connect();
}
package com.atguigu.test6;
/**
* 拍照接口
*/
public interface Photo {
void takePhoto();
}
package com.atguigu.test6;
/**
* 视频接口
*/
public interface Video {
void playVideo(String videoName);
}
package com.atguigu.test6;
/**
* @author WHD
* @description TODO
* @date 2023/4/14 16:33
*/
public class TestPhone {
public static void main(String[] args) {
CommonPhone nokia = new CommonPhone();
nokia.setBrand("诺基亚");
nokia.setPrice(850);
nokia.setType("N95");
nokia.setKeyboardType("九键");
nokia.connect();
nokia.sendMessage("睡了吗?");
nokia.call();
nokia.playAudio("《想你的夜》");
nokia.playGame("《贪吃蛇》");
System.out.println("----------------------------------------------------------");
SmartPhone huawei = new SmartPhone();
huawei.setBrand("华为");
huawei.setPrice(5500);
huawei.setType("Mate 50 PRO MAX PLUS");
huawei.setScreenSize(15);
huawei.connect();
huawei.sendMessage("真的睡了吗?");
huawei.call();
huawei.playAudio("《我的滑板鞋-庞老师》");
huawei.playVideo("《战狼》");
huawei.takePhoto();
huawei.playGame("《王者荣耀》");
}
}
打印机案例
组成部分-属性:墨盒 纸张
墨盒本身就是一种规范,所以我们可以使用接口描述
纸张本身也是一种规范,也可以用接口来描述
功能-方法:打印
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().getPaperType() +"纸张上打印");
}
}
package com.atguigu.test1;
/**
* 墨盒接口
*/
public interface InkBox { //墨盒接口
String getInkBoxType();
}
public class BlackInkBox implements InkBox{ //实现墨盒
@Override
public String getInkBoxType() {
return "黑色墨盒";
}
}
public class ColorInkBox implements InkBox{ //实现墨盒
@Override
public String getInkBoxType() {
return "彩色墨盒";
}
}
public interface Paper { //纸张接口
String getPaperType();
}
public class A4 implements Paper{ //实现纸张接口
@Override
public String getPaperType() {
return "A4";
}
}
public class B5 implements Paper{ //实现接口
@Override
public String getPaperType() {
return "B5";
}
}
public class TestPrinter {
public static void main(String[] args) {
Printer hp = new Printer();//实例打印机对象
Paper a4 = new A4();//实例纸张对象
Paper b5 = new B5();//实例对象
hp.setPaper(a4);
InkBox black = new BlackInkBox();//实例墨盒对象
InkBox color = new ColorInkBox();
hp.setInkBox(black);
hp.print();
System.out.println("-------------------------------------------------");
InkBox [] inkBoxes = new InkBox[3];//数组类
inkBoxes[0] = new BlackInkBox();
inkBoxes[1] = new ColorInkBox();
}
}
4. 抽象类和接口的区别
相同点
代表系统的抽象层
都不能被实例化
都能包含抽象方法
用于描述系统提供的服务,不必提供具体实现
不同点
在抽象类中可以为部分方法提供默认实现(属性等),而接口中只能包含抽象方法
抽象类便于复用,接口便于代码维护
一个类只能有一个直接父类,但可以实现多个接口
使用原则
接口做系统与外界交互的窗口
接口提供服务
接口本身一旦制定,就不允许随意修改
抽象类可以实现部分功能,还有部分功能可作为系统的扩展点
面向对象的设计原则
多组合,少继承
针对接口编程
针对扩展开放,针对改变关闭
当关注事物的本质,使用抽象类 因为抽象类可以写普通属性来描述事物
当关注某个功能,使用接口 接口不能写普通属性来描述事物 只能描述抽象行为