Java巅峰之路---进阶篇---面向对象(三)

2024-08-29 23:52

本文主要是介绍Java巅峰之路---进阶篇---面向对象(三),希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

Java巅峰之路---进阶篇---面向对象(三)

  • 抽象类和抽象方法
    • 抽象类和方法的介绍
    • 抽象类和抽象方法的注意事项
    • 小练习
  • 接口
    • 接口的介绍
    • 接口的注意事项:
    • 小练习
    • 成员特点与接口的各类关系
      • 接口中成员的特点
        • 补充:JDK8与JDK9新特性
      • 接口与类之间的关系
  • 接口与抽象类的综合练习
  • 适配器设计模式
  • 内部类
    • 内部类的介绍
    • 成员内部类(了解)
    • 静态内部类和局部内部类(了解)
      • 静态内部类
      • 局部内部类
    • 匿名内部类

抽象类和抽象方法

抽象类和方法的介绍

  • 抽象方法:将共性的行为(方法)抽取到父类之后,由于每一个子类执行的内容是不一样的,所以,在父类中不能确定具体的方法体。该方法就可以定义为抽象方法。

解释:例如定义一个吃东西的方法,一个程序员认为应该定义为void eat(String name){…},另一个程序员又认为应该定义为String eat(){…}。这种无法确定方法体,那就在父类中统一确定一种格式,即public abstract void eat();就行

  • 抽象类:如果一个类中存在抽象方法,那么该类就必须声明为抽象类

作用:
抽取共性时,无法确定方法体,就把方法定义为抽象类。强制让子类按照某种格式重写。抽象类所在的类,必须是抽象类。

格式:
public abstract class 类名{}
public abstract 返回值类型 方法名(参数列表);

抽象类和抽象方法的注意事项

  • 抽象类不能实例化(不能new ())
  • 抽象类中不一定有抽象方法,有抽象方法的一定是抽象类
  • 可以有构造方法
  • 抽象类的子类需满足:
    要么重写抽象类的所有抽象方法
    要么是子类是抽象类(不推荐)

演示demo:

父类:

public abstract class Person {private String name;private int age;//作用:当创建子类对象的时,给属性进行赋值的。public Person() {}public Person(String name, int age) {this.name = name;this.age = age;}public String getName() {return name;}public void setName(String name) {this.name = name;}public int getAge() {return age;}public void setAge(int age) {this.age = age;}public abstract void work();public void sleep(){System.out.println("睡觉");}}

子类:

public class Student extends Person{public Student() {}public Student(String name, int age) {super(name, age);}//必须重写work()方法@Overridepublic void work() {System.out.println("学生的工作是学习");}
}

测试类:

public class Test {public static void main(String[] args) {//创建对象//Person p = new Person();报错Student s = new Student("zhangsan",23);System.out.println(s.getName() + ", " + s.getAge());}
}

小练习

需求:

编写带有抽象类的标准lavabean类
青娃frog 属性:名字,年龄 行为:吃虫子,喝水
狗Dog 属性:名字,年龄 行为:吃骨头,喝水
山羊Sheep 属性:名字,年龄 行为:吃+,喝水

所作图:
在这里插入图片描述
代码如下:
父类:

public abstract class Animal {private String name;private int age;public Animal() {}public Animal(String name, int age) {this.name = name;this.age = age;}public String getName() {return name;}public void setName(String name) {this.name = name;}public int getAge() {return age;}public void setAge(int age) {this.age = age;}public void drink(){System.out.println("动物在喝水");}public abstract void eat();
}

所有子类:

public class Dog extends Animal{public Dog() {}public Dog(String name, int age) {super(name, age);}@Overridepublic void eat() {System.out.println("狗吃骨头");}
}public class Frog extends Animal{public Frog() {}public Frog(String name, int age) {super(name, age);}@Overridepublic void eat() {System.out.println("青蛙在吃虫子");}
}public class Sheep extends Animal{public Sheep() {}public Sheep(String name, int age) {super(name, age);}@Overridepublic void eat() {System.out.println("山羊在吃草");}
}

测试类:

public class Test {public static void main(String[] args) {//创建对象Frog f = new Frog("小绿",1);System.out.println(f.getName() + ", " + f.getAge());f.drink();f.eat();}
}

接口

接口的介绍

接口就是一种规则,是对行为的抽象
在这里插入图片描述

格式:
单独定义:
public interface 接口名{}
类链接接口:
public class 类名 implements 接口名{}

注意:
接口和类的实现关系,可以单实现,也可以多实现。
public class 类名 implements 接口名1,接口名2{}
实现类还可以在继承一个类的同时实现多个接口。
public class 类名 extends 父类 implements 接口名1,接口名2{}(若多接口有重名方法,子类只需重写一次即可)
接口的应用

接口的应用场景(接口多态):

  • 接口代表规则,是行为的抽象。想让哪个类拥有一个行为,就让这个类实现对应的接口就可以了。
  • 当一个方法的参数是接口时,可以传递接口所有实现类的对象,这种方式称之为接口多态

接口的注意事项:

  • 接口不能实例化(没有new())
  • 接口和类之间是实现关系,通过implements关键字表示
  • 接口的子类(实现类)
    要么重写接口中的所有抽象方法
    要么是抽象类(不推荐)

小练习

需求:

编写带有接口和抽象类的标准avabean类
青蛙 属性:名字,年龄 行为:吃虫子,蛙泳
狗 属性:名字,年龄 行为:吃骨头,狗创
免子 属性:名字,年龄 行为:吃胡萝卜

所作图:
在这里插入图片描述
代码如下:
接口:

public  interface Swim {public abstract void swim();}

父类:

public abstract class Animal {private String name;private int age;public Animal(String name, int age) {this.name = name;this.age = age;}public Animal() {}public String getName() {return name;}public void setName(String name) {this.name = name;}public int getAge() {return age;}public void setAge(int age) {this.age = age;}public abstract void eat();
}

所有子类:

public class Dog extends Animal implements Swim {public Dog(String name, int age) {super(name, age);}public Dog() {}@Overridepublic void eat() {System.out.println("狗吃骨头");}@Overridepublic void swim() {System.out.println("狗刨");}
}public class frog extends Animal implements Swim {public frog(String name, int age) {super(name, age);}public frog() {}@Overridepublic void eat() {System.out.println("青蛙在吃虫子");}@Overridepublic void swim() {System.out.println("蛙泳中");}
}public class Rubbish extends Animal{public Rubbish(String name, int age) {super(name, age);}public Rubbish() {}@Overridepublic void eat() {System.out.println("兔子在吃胡萝卜");}
}

测试类:

public class Text {public static void main(String[] args) {frog f = new frog("小绿",1);System.out.println(f.getName() + ", " + f.getAge());f.eat();f.swim();Rubbish r = new Rubbish("小白",2);System.out.println(r.getName() + ", " + r.getAge());r.eat();}
}

成员特点与接口的各类关系

接口中成员的特点

  • 成员变量:
    只能是常量
    默认修饰符:public static final
  • 构造方法:

接口不能创建对象,而且接口当中也不需要给子类的成员变量去赋值,所以接口用不着构造方法

  • 成员方法:
    JDK7以前:接口中只能定义抽象方法
    默认修饰符:public abstract
public interface Inter {//public static finalint a = 10;//public abstractvoid method();
}
补充:JDK8与JDK9新特性

JDK8新特性:接口中可以定义有方法体的方法(默认、静态)
作用:解决接口升级的问题

接口中的默认方法:
格式:public default 返回值类型 方法名(参数列表){}
注意:

  • 默认方法不是抽象方法,所以不强制被重写。但是如果被重写,重写的时候去掉default关键字
  • public 可以省略,default不能省略
  • 如果实现了多个接口,多个接口中存在相同名字的默认方法,子类就必须对该方法进行重写
public interface InterA {public abstract void method();public default void show(){System.out.println("InterA接口中的默认方法 ---- show");}
}public interface InterB {public default void show(){System.out.println("InterB接口中的默认方法 ---- show");}
}public class InterImpl implements InterA,InterB{
//抽象方法必须重写@Overridepublic void method() {System.out.println("实现类重写的抽象方法");}//必须重写show()@Overridepublic void show() {System.out.println("重写接口中的默认方法");}
}

接口中的静态方法:
格式:public static 返回值类型 方法名(参数列表){}
注意:

  • 该静态方法只能通过接口名调用(毕竟接口不能实例化),不能通过实现类名或者对象名调用
  • public 可以省略,static不能省略
public interface Inter {public abstract void method();public static void show(){System.out.println("Inter接口中的静态方法");}
}public class InterImpl implements Inter{@Overridepublic void method() {System.out.println("InterImpl重写的抽象方法");}//不叫方法重写,只是该实现类刚好有个重名的静态方法而已public static void show() {System.out.println("InterImpl重写的抽象方法");}
}

JDK9新特性:接口中可以定义私有方法

作用:此方法只为inter接口提供服务,不需要外类访问

格式1:private 返回值类型 方法名(参数列表){}
格式2:private static 返回值类型 方法名(参数列表){}(为本接口静态方法服务的)

接口与类之间的关系

  • 类和类的关系
    继承关系,只能单继承,不能多继承,但是可以多层继承
  • 类和接口的关系
    实现关系,可以单实现,也可以多实现,还可以在继承一个类的同时实多个接口
  • 接口和接口的关系
    继承关系,可以单继承,也可以多继承

如果实现类是实现了最下面的子接口的话,那么该实现类需要重写所有的抽象方法

public interface Inter3 extends Inter1,Inter2{public abstract void method3();
}

接口与抽象类的综合练习

需求:

编写带有接口和抽象类的标准lavabean类
我们现在有乒乓球运动员和篮球运动员,乒乓球教练和篮球教练。
为了出国交流,跟乒乓球相关的人员都需要学习英语。
请用所有知识分析,在这个案例中,哪些是具体类,哪些是抽象类,哪些是接口?
乒乓球运动员:姓名,年龄,学打乒乓球,说英语
篮球运动员:姓名,年龄,学打篮球
乒乓球教练:姓名,年龄,教打乒乓球,说英语
篮球教练:姓名,年龄,教打篮球

所作图1:
两层继承结构+三个接口(繁琐)
在这里插入图片描述
所作图2:
三层继承结构+两个接口(还能简化)
在这里插入图片描述
所作图3:
三层继承结构+一个接口(正解!)
在这里插入图片描述
代码如下:
接口:

public interface English {public abstract void speakEnglish();
}

Person类:

//因为现在我不想让外界去直接创建人的对象
//因为直接创建顶层父类人的对象此时是没有意义的
//所以我就把他写为抽象的。
public abstract class Person {private String name;private int age;public Person() {}public Person(String name, int age) {this.name = name;this.age = age;}public String getName() {return name;}public void setName(String name) {this.name = name;}public int getAge() {return age;}public void setAge(int age) {this.age = age;}
}

子类(最底层子类就不写了):

public abstract class Sporter extends Person{public Sporter() {}public Sporter(String name, int age) {super(name, age);}public abstract void study();
}public abstract class Coach extends Person{public Coach() {}public Coach(String name, int age) {super(name, age);}public abstract void teach();
}

测试类:

public class Test {public static void main(String[] args) {//创建运动员或教练的对象PingPangSporter pps = new PingPangSporter("刘诗雯",23);System.out.println(pps.getName() + ", " + pps.getAge());pps.study();pps.speakEnglish();}
}

适配器设计模式

  • 设计模式是一套被反复使用、多数人知晓的、经过分类编目的、代码设计经验的总结。使用设计模式是为了可重用代码、让代码更容易被他人理解、保证代码可靠性、程序的重用性。
    简单理解:设计模式就是解决问题的各自套路。

  • 适配器模式:解决接口与接口实现类之间的矛盾问题。

总结:
1.当一个接口中抽象方法过多,但是我只要使用其中一部分的时候,就可以适配器设计模式
2.书写步骤:

  • 编写中间类XXXAdapter 实现对应的接口
  • 对接口中的抽象方法进行空实现
  • 让真正的实现类继承中间类,并重写需要用的方法
  • 为了避免其他类创建适配器类的对象,中间的适配器类用abstract进行修饰

若真正的实现类还有“爹”怎么办?只需要让适配器继承那个爹就行了

演示demo:

public interface Inter {public abstract void method1();public abstract void method2();public abstract void method3();public abstract void method4();public abstract void method5();public abstract void method6();public abstract void method7();public abstract void method8();public abstract void method9();public abstract void method10();
}//用适配器空实现所有抽象方法
public abstract class InterAdapter implements Inter{@Overridepublic void method1() {}@Overridepublic void method2() {}@Overridepublic void method3() {}@Overridepublic void method4() {}@Overridepublic void method5() {}@Overridepublic void method6() {}@Overridepublic void method7() {}@Overridepublic void method8() {}@Overridepublic void method9() {}@Overridepublic void method10() {}
}public class InterImpl extends InterAdapter{//我需要用到那个方法,就重写哪个方法就可以了@Overridepublic void method5() {System.out.println("只要用第五个方法");}
}

内部类

内部类的介绍

什么是内部类?
在一个类里边,再定义一个类。
在这里插入图片描述
什么时候用到内部类?
B类表示的事物是A类的一部分,且B单独存在没有意义

比如:汽车的发动机、ArrayList的迭代器、人的心脏等

内部类的访问特点

  • 内部类可以直接访问外部类的成员,包括私有
  • 外部类要访问内部类的成员,必须创建对象

演示demo:

public class Car {String carName;int carAge;private String carColor;public void show(Car this){//Car this是默认存在的//是打印调用者车的名字:宾利System.out.println(this.carName);Engine e = new Engine();System.out.println(e.engineName);}class Engine{String engineName;int engineAge;public void show(){System.out.println(engineName);System.out.println(carName);}}
}

成员内部类(了解)

  • 写在成员未知的,属于外部类的成员(与外部类的成员变量和方法地位是一模一样的)
  • 可以被一些修饰符修饰,比如:private、默认、protected、public、static(静态内部类,JDK16之后)等

获取成员内部类对象

  1. 直接创建格式:外部类名.内部类名 对象名 = 外部类对象.内部类对象;
  2. 被private修饰时:在外部类中编写方法,对外提供内部类的对象

演示demo:

public class Outer {String name;private class Inner{static int a = 10;}public Inner getInstance(){return new Inner();}
}public class Test {public static void main(String[] args) {// Outer.Inner oi = new Outer().new Inner();非私有化修饰时Outer o = new Outer();System.out.println(o.getInstance());}
}

成员内部类如何获取外部类的成员变量

  • 当外部类成员变量和内部类成员变量重名时,在内部类可以用Outer.this.变量名进行访问

演示demo:

public class Outer {private int a = 10;class Inner {private int a = 20;public void show() {int a = 30;//Outer.this 获取了外部类对象的地址值System.out.println(Outer.this.a);//10System.out.println(this.a); //20System.out.println(a); //30}}
}public class Test {public static void main(String[] args) {//创建内部类的对象,并调用show方法Outer.Inner oi = new Outer().new Inner();oi.show();}
}

内存图:
在这里插入图片描述

静态内部类和局部内部类(了解)

静态内部类

静态内部类也是成员内部类中的一种,只能访问外部类中的静态变量和静态方法,如果想访问非静态的需要创建对象。

  • 创建静态内部类对象的格式:
    外部类名.内部类名 对象名 = new 外部类名.内部类名();
  • 调用静态内部类中静态方法的格式:
    外部类名.内部类名.方法名();

演示demo:

public class Outer {//静态内部类static class Inner {public void show1(){System.out.println("非静态的方法被调用了");}public static void show2(){System.out.println("静态的方法被调用了");}}
}public class Test {public static void main(String[] args) {//创建静态内部类的对象//只要是静态的东西,都可以用类名点直接获取Outer.Inner oi = new Outer.Inner();oi.show1();//静态方法Outer.Inner.show2();}
}

局部内部类

  • 将内部类定义在方法里面就叫做局部内部类,类似于方法里面的局部变量
  • 外界是无法直接使用局部内部类,需要在方法内部创建对象并使用。
  • 该类可以直接访问外部类的成员,也可以访问方法内的局部变量。

演示demo:

public class Outer {int b = 20;public void show(){int a = 10;//局部内部类class Inner{String name;int age;public void method1(){System.out.println(a);System.out.println(b);System.out.println("局部内部类中的method1方法");}public static void method2(){System.out.println("局部内部类中的method2静态方法");}}//创建局部内部类的对象Inner i = new Inner();System.out.println(i.name);System.out.println(i.age);i.method1();Inner.method2();}public class Test {public static void main(String[] args) {Outer o = new Outer();o.show();}
}

匿名内部类

什么是匿名内部类?
隐藏了名字的内部类,可以写在成员位置,也可以写在局部位置。

细节:
包含了继承或实现、方法重写、创建对象。
整体就是一个类的子类对象或接口的实现类对象

格式:
在这里插入图片描述
使用场景:
当方法的参数是接口或者类时,以接口为例,可以传递这个接口的实现类对象。如果现实类只要实现一次,就可以用匿名类简化代码

演示demo:

public abstract class Animal {public abstract void eat();public void drink(){System.out.println("喝水");}
}public abstract class Animal {public abstract void eat();public void drink(){System.out.println("喝水");}
}public class Test {public static void main(String[] args) {//编写匿名内部类的代码new Swim(){@Overridepublic void swim() {System.out.println("重写了游泳的方法");}};new Animal(){@Overridepublic void eat() {System.out.println("重写了eat方法");}}.drink();//其本质就是一个子类对象,可以调用父类方法的。method(new Animal() {@Overridepublic void eat() {System.out.println("狗吃骨头");}});}public static void method(Animal a){//Animal a = 子类对象 多态a.eat();//编译看左边,运行看右边}
}

这篇关于Java巅峰之路---进阶篇---面向对象(三)的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/1119205

相关文章

Java实现检查多个时间段是否有重合

《Java实现检查多个时间段是否有重合》这篇文章主要为大家详细介绍了如何使用Java实现检查多个时间段是否有重合,文中的示例代码讲解详细,感兴趣的小伙伴可以跟随小编一起学习一下... 目录流程概述步骤详解China编程步骤1:定义时间段类步骤2:添加时间段步骤3:检查时间段是否有重合步骤4:输出结果示例代码结语作

Java中String字符串使用避坑指南

《Java中String字符串使用避坑指南》Java中的String字符串是我们日常编程中用得最多的类之一,看似简单的String使用,却隐藏着不少“坑”,如果不注意,可能会导致性能问题、意外的错误容... 目录8个避坑点如下:1. 字符串的不可变性:每次修改都创建新对象2. 使用 == 比较字符串,陷阱满

Java判断多个时间段是否重合的方法小结

《Java判断多个时间段是否重合的方法小结》这篇文章主要为大家详细介绍了Java中判断多个时间段是否重合的方法,文中的示例代码讲解详细,感兴趣的小伙伴可以跟随小编一起学习一下... 目录判断多个时间段是否有间隔判断时间段集合是否与某时间段重合判断多个时间段是否有间隔实体类内容public class D

IDEA编译报错“java: 常量字符串过长”的原因及解决方法

《IDEA编译报错“java:常量字符串过长”的原因及解决方法》今天在开发过程中,由于尝试将一个文件的Base64字符串设置为常量,结果导致IDEA编译的时候出现了如下报错java:常量字符串过长,... 目录一、问题描述二、问题原因2.1 理论角度2.2 源码角度三、解决方案解决方案①:StringBui

Java覆盖第三方jar包中的某一个类的实现方法

《Java覆盖第三方jar包中的某一个类的实现方法》在我们日常的开发中,经常需要使用第三方的jar包,有时候我们会发现第三方的jar包中的某一个类有问题,或者我们需要定制化修改其中的逻辑,那么应该如何... 目录一、需求描述二、示例描述三、操作步骤四、验证结果五、实现原理一、需求描述需求描述如下:需要在

Java中ArrayList和LinkedList有什么区别举例详解

《Java中ArrayList和LinkedList有什么区别举例详解》:本文主要介绍Java中ArrayList和LinkedList区别的相关资料,包括数据结构特性、核心操作性能、内存与GC影... 目录一、底层数据结构二、核心操作性能对比三、内存与 GC 影响四、扩容机制五、线程安全与并发方案六、工程

JavaScript中的reduce方法执行过程、使用场景及进阶用法

《JavaScript中的reduce方法执行过程、使用场景及进阶用法》:本文主要介绍JavaScript中的reduce方法执行过程、使用场景及进阶用法的相关资料,reduce是JavaScri... 目录1. 什么是reduce2. reduce语法2.1 语法2.2 参数说明3. reduce执行过程

如何使用Java实现请求deepseek

《如何使用Java实现请求deepseek》这篇文章主要为大家详细介绍了如何使用Java实现请求deepseek功能,文中的示例代码讲解详细,感兴趣的小伙伴可以跟随小编一起学习一下... 目录1.deepseek的api创建2.Java实现请求deepseek2.1 pom文件2.2 json转化文件2.2

Java调用DeepSeek API的最佳实践及详细代码示例

《Java调用DeepSeekAPI的最佳实践及详细代码示例》:本文主要介绍如何使用Java调用DeepSeekAPI,包括获取API密钥、添加HTTP客户端依赖、创建HTTP请求、处理响应、... 目录1. 获取API密钥2. 添加HTTP客户端依赖3. 创建HTTP请求4. 处理响应5. 错误处理6.

Spring AI集成DeepSeek的详细步骤

《SpringAI集成DeepSeek的详细步骤》DeepSeek作为一款卓越的国产AI模型,越来越多的公司考虑在自己的应用中集成,对于Java应用来说,我们可以借助SpringAI集成DeepSe... 目录DeepSeek 介绍Spring AI 是什么?1、环境准备2、构建项目2.1、pom依赖2.2