依旧面向对象Java基础学习

依旧Java基础学习

  • final
    1. 用final修饰类,则类不能被继承
    2. 用final修饰方法,则方法不能被重写
    3. 用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)

  • 接口不能创建对象
  • 接口是用来被类实现的,实现接口的类被称为实现类
  • 一个类可以同时实现多个接口
  • 接口的好处
    1. 弥补了类单继承的不足,一个类可以同时实现多个接口,使类的角色更多,功能更强大。
    2. 使程序可以面向接口编程,方便切换各种业务实现,利于程序解耦合。

传统接口(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();

        }
}

接口新增的三种方法

  1. 默认方法(普通实例方法):使用default修饰,默认被加上public修饰

    • 只能使用接口的实现类对象调用
  2. 私有方法:必须用private修饰

    • 使用接口中的其他实例方法来调用
  3. 类方法(静态方法):使用static修饰,默认被加上public修饰

    • 只能用接口名来调用

注意事项

  1. 接口与接口可以多继承,一个接口可以同时继承多个接口

    • 类与类:单继承,一个类只能继承一个直接父类
    • 类与接口:多实现,一个类可以同时实现多个接口
    • 接口与接口:多继承,一个接口可以同时继承多个接口
  2. 一个接口继承多个接口,如果多个接口中方法冲突了,则此时不支持多重继承,也不支持多实现。

  3. 一个类继承父类,又同时实现接口,如果父类中和接口中有同名的方法,实现类会优先用父类的。

  4. 一个类实现了多个接口,如果多个接口中存在同名的默认方法,可以不冲突,这个类重写该方法即可。

抽象类和接口进行对比

  • 相同点:
    1. 都是抽象形式,都可以有抽象方法,都不能创建对象。
    2. 都是 派生子类形式,抽象类是被子类继承,接口是被实现类实现。
    3. 一个类继承抽象类,或者实现接口,都必须重写完它们的抽象方法,否则自己要成为抽象类。
    4. 都能支持多态,都能实现解耦合。
  • 不同点:
    1. 抽象类中可以定义类的普通成员,接口只能定义常量和抽象方法(还有jdk8以后新增的三个方法)
    2. 抽象类只能单继承,接口可以被类多实现。
    3. 一个类继承抽象类就不能再继承其他类;一个类实现了一个接口,还可以继承其他类或者实现其他接口。
    4. 抽象类体现模板思想,更利于做父类,实现代码的复用性。
    5. 接口更适合做功能的解耦合,解耦合性更强更灵活。

综合小案例

  • 智能家居控制系统

屏幕截图 2025-11-22 221705

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
posted @ 2025-11-23 13:11  芒果学代码  阅读(2)  评论(0)    收藏  举报