依旧面向对象Java基础学习
依旧Java基础学习
- final
- 用final修饰类,则类不能被继承
- 用final修饰方法,则方法不能被重写
- 用final修饰变量,则变量仅能被赋值一次
单例设计模式(一个类只有一个对象)
//饿汉式单例类
public class A{
//1.私有构造器,确保类对外不能创建对象
private A(){}
//2.定义一个类变量,记住类的一个对象
private static A a = new A();
//3.定义一个类方法,返回这个唯一的对象
public static A getObject(){
return a;
}
}
//懒汉式单例类
public class B{
//1.私有构造器,确保类对外不能创建对象
private B(){}
//2.定义一个类变量,记住类的一个对象
private static B b;//null
//3.定义一个类方法,返回这个唯一的对象
public static B getObject(){
if(b==null){
b=new B();
}
return b;
}
}
抽象类(abstract)
- 抽象类中不一定有抽象方法,但是有抽象方法的一定是抽象类
- 抽象类不能创建对象,仅作为一种特殊的父类,让子类继承并实现
- 它的基本使命就是被继承
- 一个类继承抽象类,必须重写完它继承的所有抽象方法,否则这个类也必须定义成抽象类
模板方法设计模式(提供一个方法作为完成某类功能的模板
- 模板方法封装了每个实现步骤,但允许子类提供特定步骤的实现
- 可以提高代码的复用,并简化子类设计
学生和老师都输出几段话,其中开头和结尾一样,之间的身份说明不一样
package test;
//父类方法
public abstract class Fu {
//定义一个模板来输出这几段话
public final void write(){//使用final关键字,来防止该模板方法被子类重写。
System.out.println("接下来介绍一下我的身份和每天状态:");
writeMain();//其中介绍身份部分由它的子类来具体说明
System.out.println("我每天都要去学校");
}
public abstract void writeMain();//定义一个抽象类来让子类重写它的具体内容
}
//学生类
public class Student extends Fu{
@Override
public void writeMain(){
System.out.println("我是一名学生");//重写具体内容
}
}
//老师类
public class Teacher extends Fu{
@Override
public void writeMain(){
System.out.println("我是一名老师");//重写具体内容
}
}
//定义一个测试类来验证具体输出
class Test {
public static void main(String[] args) {
Student student=new Student();
student.write();//调用父类的write方法来获取模板来输出具体内容,其中身份介绍部分在父类中调用了子类方法来进行修改
Teacher teacher=new Teacher();
teacher.write();
}
}
//结果为:
接下来介绍一下我的身份和每天状态:
我是一名学生
我每天都要去学校
接下来介绍一下我的身份和每天状态:
我是一名老师
我每天都要去学校
接口(interface)
- 接口不能创建对象
- 接口是用来被类实现的,实现接口的类被称为实现类
- 一个类可以同时实现多个接口
- 接口的好处
- 弥补了类单继承的不足,一个类可以同时实现多个接口,使类的角色更多,功能更强大。
- 使程序可以面向接口编程,方便切换各种业务实现,利于程序解耦合。
传统接口(JDK 8之前的版本)
- 该接口中只能写常量和抽象方法
//定义接口
public interface Fu {
//定义一个常量(常量名最好大写)
//public static final String NAME = "Fu";前面的public static final 可省略,因为默认为public静态常量
String NAME = "Fu";
//定义一个抽象方法
//public abstract void eat(); 前面的public abstract可以省略,因为接口中只能定义抽象方法,并且是公开的
void eat();
}
//定义接口
public interface Teacher {
void teach();
}
//定义实现类
public class Student implements Fu,Teacher{//该实现类同时实现多个接口
//实现类实现多个接口,必须重写完所有接口的所有抽象方法,否则这个类必须定义为抽象类
@Override
public void eat() {
}
@Override
public void teach() {
}
}
//测试方法
class Test {
public static void main(String[] args) {
System.out.println(Fu.NAME);//直接通过 接口名.常量名 调用常量
Student s1 = new Student();//实例化对象
s1.eat();//直接调用方法
s1.teach();
}
}
- 小案例
![屏幕截图 2025-11-22 161259]()
//学生类
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
@Data//一键生成set/get toString等方法
@AllArgsConstructor//生成全参构造器
@NoArgsConstructor//生成无参构造器
public class Student {
private String name, sex;
private int score;
}
//定义接口
public interface A {
//定义两个抽象方法
void print();//打印学生信息
void ave();//统计学生平均分
}
//实现类B,实现业务一
public class B implements A{
private final Student[] students ;//定义一个学生类数组接收在测试类中定义的学生信息
//将信息传入类B
public B(Student[] students) {
this.students = students;
}
@Override
public void print() {
System.out.println("学生的信息如下");
for (Student student : students) {
System.out.println(student.getName()+"\t"+student.getSex()+"\t"+student.getScore());
}
}
@Override
public void ave() {
double sum=0;
for (Student student : students) {
sum+=student.getScore();
}
System.out.printf("全班平均分为:%.2f", sum /students.length);
}
}
//实现类C,实现业务二
public class C extends Student implements A{
private final Student[] students;//定义一个学生类数组接收在测试类中定义的学生信息
public C(Student[] student){//将信息传入类B
this.students = student;
}
int sex1=0,sex2=0;
@Override
public void print() {
System.out.println("学生的信息如下");
for (Student student : students) {
if(student.getSex().equals("女"))sex1+=1;
else sex2+=1;
System.out.println(student.getName()+"\t"+student.getSex()+"\t"+student.getScore());
}
System.out.println("其中女生有"+sex1+"人");
System.out.println("其中男生有"+sex2+"人");
}
@Override
public void ave() {
double sum=0;
double max=students[0].getScore();
double min=students[0].getScore();
for (Student student : students) {
if(student.getScore()>max) max=student.getScore();
if(student.getScore()<min) min=student.getScore();
sum+=student.getScore();
}
sum=sum-max-min;
System.out.printf("全班平均分为:%.2f", sum /(students.length-2));
}
}
//测试类
class Test {
public static void main(String[] args) {
//生成学生类对象,并存入数据
Student[] student = new Student[3];
student[0] = new Student("张三","男",90);
student[1] = new Student("李四","女",100);
student[2] = new Student("王五","男",88);
//定义实现类对象B
A demoB=new B(student);
demoB.print();
demoB.ave();
System.out.println();
//定义实现类对象C
A demoC=new C(student);
demoC.print();
demoC.ave();
}
}
接口新增的三种方法
-
默认方法(普通实例方法):使用default修饰,默认被加上public修饰
- 只能使用接口的实现类对象调用
-
私有方法:必须用private修饰
- 使用接口中的其他实例方法来调用
-
类方法(静态方法):使用static修饰,默认被加上public修饰
- 只能用接口名来调用
注意事项
-
接口与接口可以多继承,一个接口可以同时继承多个接口
- 类与类:单继承,一个类只能继承一个直接父类
- 类与接口:多实现,一个类可以同时实现多个接口
- 接口与接口:多继承,一个接口可以同时继承多个接口
-
一个接口继承多个接口,如果多个接口中方法冲突了,则此时不支持多重继承,也不支持多实现。
-
一个类继承父类,又同时实现接口,如果父类中和接口中有同名的方法,实现类会优先用父类的。
-
一个类实现了多个接口,如果多个接口中存在同名的默认方法,可以不冲突,这个类重写该方法即可。
抽象类和接口进行对比
- 相同点:
- 都是抽象形式,都可以有抽象方法,都不能创建对象。
- 都是 派生子类形式,抽象类是被子类继承,接口是被实现类实现。
- 一个类继承抽象类,或者实现接口,都必须重写完它们的抽象方法,否则自己要成为抽象类。
- 都能支持多态,都能实现解耦合。
- 不同点:
- 抽象类中可以定义类的普通成员,接口只能定义常量和抽象方法(还有jdk8以后新增的三个方法)
- 抽象类只能单继承,接口可以被类多实现。
- 一个类继承抽象类就不能再继承其他类;一个类实现了一个接口,还可以继承其他类或者实现其他接口。
- 抽象类体现模板思想,更利于做父类,实现代码的复用性。
- 接口更适合做功能的解耦合,解耦合性更强更灵活。
综合小案例
- 智能家居控制系统

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
@Data
@AllArgsConstructor
@NoArgsConstructor
//定义一个家电类
public class JD implements Switch{
private String name;
private boolean state;
//实现接口的开关功能
@Override
public void change() {
state=!state;
}
}
//定义一个电视类
public class TV extends JD{
//写一个构造方法来产生具体的电视实体
public TV(String name, boolean state) {
super(name, state);
}
}
//定义一个空调类
public class Air extends JD{
//写一个构造方法来产生具体的空调实体
public Air(String name, boolean state) {
super(name, state);
}
}
//定义一个灯类
public class Lamp extends JD{
//写一个构造方法来产生具体的灯实体
public Lamp(String name, boolean state) {
super(name, state);
}
}
//定义一个接口来定义一个开关的抽象功能
public interface Switch {
void change();//定义一个进行开关功能的抽象方法
}
public class ControlSystem {
//将家电类中的家电传入控制系统类中
JD[] jds;
public ControlSystem(JD[] jds) {
this.jds=jds;
}
//定义一个方法输出所有的家电状态
public void printState(){
System.out.println("输出所有的家电状态:");
for (JD jd : jds) {
System.out.println(jd.getName()+"\t"+(jd.isState()? "开":"关"));
}
}
//定义一个方法来接收传入的具体家电,并对其进行开关的操作
public void ChangeState(JD jd){
System.out.println(jd.getName()+"当前状态为:"+(jd.isState()? "开":"关"));
jd.change();
System.out.println(jd.getName()+"操作完状态是:"+(jd.isState()? "开":"关"));
}
}
import java.util.Scanner;
class Test {
public static void main(String[] args) {
//定义一个家电类作为父类来包装这些家电,再定义一个接口类来提出进行开关的功能
//实现家电对象,往家电类中定义一系列家电
JD[] jds=new JD[3];
jds[0]=new TV("小米电视",true);
jds[1]=new Air("美的空调",false);
jds[2]=new Lamp("欧式灯",true);
//利用一个死循环来对家电不断的进行操作
while(true){
//再创建一个开关控制系统类,来进行开关
ControlSystem con=new ControlSystem(jds);
con.printState();//打印所有家电状态
Scanner sc=new Scanner(System.in);
System.out.println("请进行你的操作");
String comment=sc.next();//用户输入命令来指定对哪个家电进行操作
switch(comment){
case "1":
con.ChangeState(jds[0]);
break;
case "2":
con.ChangeState(jds[1]);
break;
case "3":
con.ChangeState(jds[2]);
break;
case "exit":
System.out.println("退出APP");
return;//利用return退出循环
default:
System.out.println("请再次输入:");
}
}
}
}
//进行打开空调操作,输出结果为:
输出所有的家电状态:
小米电视 开
美的空调 关
欧式灯 开
请进行你的操作
2
美的空调当前状态为:关
美的空调操作完状态是:开
输出所有的家电状态:
小米电视 开
美的空调 开
欧式灯 开
请进行你的操作
exit
退出APP

浙公网安备 33010602011771号