day07-面向对象高级一

Java面向对象高级一

  • [ 任务列表 ]
  • 1.final
  • 2.单例类
  • 3.枚举类
  • 4.抽象类
  • 5.接口
  • 6.其他

—————————————————————————————————————————————————————————————————————

1.final

  • final关键字:final是最终的意思,可以修饰类、方法、变量;
    修饰类:该类被称为最终类,特点是不能被继承;
    修饰方法:该方法被成为最终方法,特点是不能被重写了;
    修饰变量:该变量有且仅能被赋值一次。

  • final修饰静态变量,这个变量今后被称为常量,可以记住一个固定值,
    并且程序中不能修改了,通常这个值作为系统的配置信息;
    常量的名称,建议全部大写,多个单词用下划线链接。

  • 变量有哪些?
    1、成员变量:
    ① 静态成员变量
    ② 实例成员变量
    2、③ 局部变量

  • 定义和赋值的问题?
    ① final修饰静态成员变量,必须要先赋值。
    ② final修饰实例变量(一般没有意义),一定要先赋值。可以在定义时赋值,也可以在构造器或实例初始化块中赋值,但必须确保在构造过程结束之前(即创建对象之前)完成赋值,一旦赋值后不可再修改。
    ③ final修饰局部变量,可以先只定义,后面再赋值,但是只能赋值一次;必须在定义时或者同一个方法内的后续代码中明确赋值,只能赋值一次。
    不能先定义后赋值,除非是在定义的同时进行初始化,或者确保在同一作用域内有确定的赋值操作。

  • final修饰变量注意:
    final修饰基本类型的变量,变量存储的数据不能被改变;
    final修饰引用类型的变量,变量存储的地址不能被改变,但地址所指向对象的内容是可以被改变的。(数组,类,接口,String类型……)

public class FinalDemo1 {// ① final修饰静态成员变量,必须要先赋值。public static final String SCHOOL_NAME = "XXX大学";// ② final修饰实例变量(一般没有意义),一定要先赋值。private final String name = "林青霞";public static void main(String[] args) {// ③ final修饰局部变量final double rate ;rate = 3.14;
//      rate = 3.1415;   // 第二次赋值,报错pay(8);FinalDemo1 fd = new FinalDemo1();System.out.println(fd.name);  // 林青霞
//      f.name = "林志玲";  // 第二次赋值,报错System.out.println("-------------------");final int [] arr = new int []{11,22,33,44};
//      arr = new int []{22,33,44,55}; // 第二次赋值,报错// final修饰引用类型的变量,变量存储的地址不能被改变,// 但地址所指向对象的内容是可以被改变的arr[2]= 55;}// 传入的形参变量值不能被修改,以防止恶意修改public static void pay(final double z){
//        z = 9;    // 报错System.out.println(z);}
}// 1. final修饰类:表示该类不能被继承
final class A{
}
//class B extends A{ } // 报错// 2. final修饰方法:表示该方法不能被重写
class C{final void show(){System.out.println("C.m1()");}
}class D extends C{
//    @Override // 报错,不能重写final方法//void show(){//    System.out.println("D.m1()");// }
}

2.单例类

  • 单例类:(是Java的一种软件设计模式)

  • 什么是设计模式?
    一个问题通常有n种解法,其中肯定有一种解法是最优的,这个最优的解法被人总结出来了,称之为设计模式。

  • 关于设计模式,主要学什么?
    1、解决什么问题?
    2、怎么写?

  • 单例设计模式:
    作用:确保每个类只能创建一个对象。
    例如computer上的任务管理器,在Java中是一个JFrame对象(窗口对象),这个任务管理器在电脑上应该只有一个对象,这种就可以设计成单例类,对外就只能创建一个对象。
    还有Java的虚拟机对象,也只创建一个。

  • 写法、实现步骤:
    ① 把类的构造器私有;
    ② 定义一个静态变量(类变量),用于存储对象;
    ③ 定义一个静态方法(类方法),保证返回的是同一个对象。

  • 饿汉式单例:拿对象时,对象早就创建好了。

public class A {private static final A a = new A(); private A(){}public static A getInstance(){return a;}
}
  • 懒汉式单例:拿对象时,才开始创建对象。
public class B {private static B b; private B(){}public static B getInstance(){if(b == null){b = new B();}return b;}
}
public class Test {public static void main(String[] args) {// 目标:设计单例类A a1 = A.getInstance(); // 获取唯一对象A a2 = A.getInstance();System.out.println(a1);  // 地址:sun.superstring.singleinstance.A@2f4d3709System.out.println(a2);  // 地址:sun.superstring.singleinstance.A@2f4d3709System.out.println(a1 == a2);  // true// 这样写不专业,可以随时将A的唯一对象干掉,所以需要写一个get方法,用于返回A类的唯一对象
//        A.a = null;
//        System.out.println(A.a);System.out.println("-------------------------");B b1 = B.getInstance();B b2 = B.getInstance();System.out.println(b1);  // 地址:sun.superstring.singleinstance.B@1d81eb93System.out.println(b2);  // 地址:sun.superstring.singleinstance.B@1d81eb93System.out.println(b1 == b2);  // true}
}// 设计成单例设计模式:饿汉式单例
public class A {// 2.定义一个静态变量,用于记住本类的一个唯一对象// public static A a = new A();  容易被外部修改// private static A a = new A();  只能内部改,不暴露出去private static final A a = new A();  // 推荐// 加上private,防止外部修改;加上final,防止在内部修改// 1.私有化构造方法:确保单例类对外不能创建太多对象,单例才有可能性private A(){}// 3.定义一个静态方法,用于获取本类的唯一对象public static A getInstance(){return a;}
}// 设计成单例设计模式:懒汉式单例
public class B {// 2.定义一个静态变量,用于存储对象private static B b;   // null// 1.私有化构造方法:确保单例类对外不能创建太多对象,单例才有可能性private B(){}// 3.提供一个静态方法返回对象,真正需要对象的时候才开始创建对象public static B getInstance(){if(b == null){b = new B();}return b;}
}

3.枚举类

  • 枚举类:是一种特殊类

  • 枚举类的写法:
    枚举类第一行,只能写枚举类的对象名称,且要用逗号隔开;
    这些名称,本质是常量,每个常量都记住了枚举类的一个对象。

修饰符 enum 枚举类名{名称1,名称2,……;其他成员……;
}
  • 枚举类的特点:
    枚举类都是最终类,不可以被继承,枚举类都是继承java.lang.Enum类的;
    枚举类的第一行只能罗列一些名称,这些名称都是常量,并且每个常量都会记住枚举类的一个对象;
    枚举类的构造器都是私有的(写不写都只能是私有的),因此,枚举类对外不能创建对象;
    所以枚举类是多例模式;
    编译器为枚举对象新增了几个方法。枚举类对象名.ordinal():拿到枚举类对象的索引(指代第几个枚举类对象,从0开始)

  • 多例模式:(对外不能创建对象,又不能被别人继承,里面只有X、Y、Z三个对象,单例是只有一个对象,多例是只能有多个对象)
    单例类也可以理解为枚举对象只有一个;

// 枚举类
public enum A {// 枚举类的第一行:只能罗列枚举对象的名称,这些对象本质是常量X, Y, Z;
}public class Test {public static void main(String[] args) {// 目标:认识枚举类,搞清楚其本质特点。A a1 = A.X;System.out.println(a1);   // XA a2 = A.Y;System.out.println(a2.toString());   // YSystem.out.println(a1.name());   // XSystem.out.println(a2.name());   // YSystem.out.println(a1.ordinal());  // 可以拿枚举对象的索引 0System.out.println(a2.ordinal()); // 索引 1}
}
  • 枚举类的常见应用场景:
    枚举类很适合做信息分类和标志。
    数字迷阵的游戏,控制某个图块上下左右的移动。这些方向的信号可以定义成枚举类;
    或者是某两个数相除,最终结果保留两位小数,其他位数是:直接舍弃down,进一位up,还是四舍五入half_up
public class Constant {public static final int UP = 0; // 上public static final int DOWN = 1; // 下public static final int LEFT = 2; // 左public static final int RIGHT = 3; // 右
}public enum Direction {UP, DOWN, LEFT, RIGHT;
}public class Test2 {public static void main(String[] args) {// 目标:掌握枚举类的应用场景:做信息的分类和标志// 需求:模拟上下左右移动图片// 第一种是常量做信息标志和分类:但参数值不受约束move(Constant.UP);  // direction = 0     向上移动// 第二种是枚举做信息标志和分类:参数值受约束move(Direction.DOWN);  // direction = DOWN    向下移动}// 第二种匹配:使用枚举型变量作为信号标志public static void move(Direction direction){System.out.println("direction = " + direction);// 根据这个方向做移动:上下左右switch (direction){  // switch支持省略枚举对象的前缀:Direction,可以自动去找对应的枚举对象case UP:System.out.println("向上移动");break;case DOWN:System.out.println("向下移动");break;case Direction.LEFT:System.out.println("向左移动");break;case Direction.RIGHT:System.out.println("向右移动");}}// 第一种匹配:使用int型变量作为信号标志public static void move(int direction){System.out.println("direction = " + direction);// 根据这个方向做移动:上下左右switch (direction){case 0:System.out.println("向上移动");break;case 1:System.out.println("向下移动");break;case 2:System.out.println("向左移动");break;case 3:System.out.println("向右移动");break;default:System.out.println("输入有误:");}}
}

4.抽象类

  • 抽象类:
    在Java中有一个关键字叫:abstract,就是抽象的意思,用它可以修饰类、成员方法。
    abstract修饰类,就是抽象类;
    abstract修饰方法,就是抽象方法;
修饰符 abstract class 类名{修饰符 abstract 返回值类型  方法名称(形参列表);
}public abstract class A{// 抽象方法:必须abstract修饰,只有方法签名,不能有方法体public abstract void test(int a);
}
  • 抽象类的注意事项,特点:
    抽象类中不一定要有抽象方法,但是有抽象方法的类必须是抽象类;
    类有的成员(成员变量,成员方法,构造器),抽象类都可以有;
    抽象类最主要的特点是——抽象类不能创建对象,仅作为一种特殊的父类,让子类继承并实现;
    一个类继承抽象类,必须重写完抽象类的全部抽象方法,否则这个类也必须定义成抽象类。
public class AbstractDemo1 {public static void main(String[] args) {
//        A a = new A();  // 错误,抽象类不能创建对象// 抽象类的使命就是被子类继承:就是为了生孩子B b = new B();b.setName("小明");b.setAge(18);System.out.println(b.getName() + ", " + b.getAge());  // 小明 18b.show();  // B类重写了run方法b.show1();  // show1方法}
}// 抽象类,可以不写抽象方法
public abstract class A {private String name;  // 实例变量private int age;   // 实例变量// 无参构造器public A() {   }// 有参构造器public A(String name, int age) {this.name = name;this.age = age;}// 抽象方法:必须用abstract修饰,没有方法体{},只有方法声明public abstract void show();// 实例方法public void show1(){System.out.println("show1方法");}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 class B extends A{// 重写抽象类的run方法,B就成为了一个具体的类;否则B必须定义成抽象类@Overridepublic void show() {System.out.println("B类重写了run方法");}
}
  • 抽象类不能创建对象的原因:
    假设抽象类可以创建对象,那里面的抽象方法怎么执行,抽象方法连方法体都没有(不能抱着抽象类里面不写抽象方法的掉以轻心的心态)

  • 抽象的本质:不应该有具体的对象
    一个类继承抽象类,必须重写抽象类的所有抽象方法,否则这个类也必须定义成抽象类;
    抽象类的使命就是被子类继承:就是为了生孩子

  • 使用抽象类的好处:
    父类知道每个子类都要做某个行为,但为了每个子类要做的情况不一样,父类就定义成抽象方法,交给子类去重写实现;我们设计这样的抽象类,就是为了更好地支持多态。

  • 父类定义的方法,子类不会用,而是用子类重写的方法,所以父类的方法体定义出来是没有用的,所以这些代码是多余的。
    抽象方法,子类是一定要重写的。但是不写成抽象方法也可以实现多态,但是写成抽象方法是一种最佳的实践。
    (虽然abstract不是必须的技术,但是这是一种最优雅的写法,是最佳实践)

public class Test {public static void main(String[] args) {Animal a = new Dog();a.shout();  // 汪汪汪~~~}
}public abstract class Animal {// 每个动物的叫声public abstract void shout();
}public class Cat extends Animal{@Overridepublic void shout() {System.out.println("猫是喵喵喵~~~");}
}public class Dog extends Animal{@Overridepublic void shout() {System.out.println("汪汪汪~~~");}
}
  • 抽象类模板方法设计模式:
    解决了什么问题?
    提供了一个方法作为完成某类功能的模板,模板方法封装了每个实现步骤,但允许子类提供特定步骤的实现。
    模板方法设计模式可以提高代码的复用,并简化子类设计。

  • 怎么写?
    1、定义一个抽象类
    2、在里面定义2个方法
    一个是模板方法:把共同的实现步骤放进去
    一个是抽象方法:不确定的实现步骤,交给具体的子类来完成。

  • 多学一招:
    建议使用final关键字修饰模板方法:这样子类就不能重写模板方法了,因为模板方法一旦重写,就失效了。
    它是给子类使用的,不能被子类重写;
    一旦子类重写了模板方法,模板方法就失效了。

public class Test {public static void main(String[] args) {// 目标:理解抽象类的使用场景之二:模板方法设计模式// 学生和老师都要写一篇作文:《我的爸爸》//           第一段是一样的:我爸爸是一个好人,我特别喜欢他,他对我很好,我来介绍一下://           第二段是不一样的:老师和学生各自写各自的//           第三段是一样的:我爸爸真好,你有这样的爸爸吗?//   解决:抽出一个父类。父类中还抽取一个模板方法给子类直接用。Teacher teacher = new Teacher();  // People teacher = new Teacher(); 这两个是一个意思teacher.write();Student student = new Student();student.write();}
}// 抽象类:老师和学生都是People类
public abstract class People {// 1、模板方法设计模式public final void write(){System.out.println("\t\t\t《我的爸爸》");System.out.println("\t我爸爸是一个好人,我特别喜欢他,他对我很好,我来介绍一下:");// 2、模板方法知道子类一定要写这个正文,但是每个子类写的信息是不同的,父类就定义一个抽象方法//    具体的事件交给子类来重写正文writeMain();System.out.println("\t我爸爸真好,你有这样的爸爸吗?");}// 抽象方法 —— writeMain(); public abstract void writeMain();
}public class Teacher extends People{@Overridepublic void writeMain(){System.out.println("\t我爸爸经常让我站在这里别动,他要去买几斤橘子~~柚子我也吃,毕竟是我爸爸买的,是亲生的!!!");}//    public void write(){
//        System.out.println("\t\t\t《我的爸爸》");
//        System.out.println("\t我爸爸是一个好人,我特别喜欢他,他对我很好,我来介绍一下:");
//        System.out.println("\t我爸爸经常让我站在这里别动,他要去买几斤橘子~~柚子我也吃,毕竟是我爸爸买的,是亲生的!!!");
//        System.out.println("\t我爸爸真好,你有这样的爸爸吗?");
//    }
}public class Student extends People{@Overridepublic void writeMain(){System.out.println("\t我爸爸很厉害,熟知君子六艺,是一个言行合一的君子,我非常喜欢他,他就是我以后找男朋友的标准!!");}//    public void write() {
//        System.out.println("\t\t\t《我的爸爸》");
//        System.out.println("\t我爸爸是一个好人,我特别喜欢他,他对我很好,我来介绍一下:");
//        System.out.println("\t我爸爸很厉害,熟知君子六艺,是一个言行合一的君子,我非常喜欢他,他就是我以后找男朋友的标准!!");
//        System.out.println("\t我爸爸真好,你有这样的爸爸吗?");
//    }
}

5.接口

  • 接口:Java提供了一个关键字interface定义接口;
    JDK 8之前,接口中只能写常量和抽象方法——传统接口(本课学习内容就是传统接口)
public interface 接口名{// 成员变量(常量)// 成员方法(抽象方法)
}
  • 接口的特点:
    接口中的抽象方法都是公开的;(写不写public都是公开的)
    接口不能创建对象;
    接口是用来被类实现(implements)的,实现接口的类称为实现类,一个类可以实现多个接口。(接口可以理解为“干爹”,亲爸继承只能有一个,但是干爹可以有多个。)

  • 接口的好处:
    弥补了类单继承的不足,一个类可以同时实现多个接口,使得类的角色更多,功能更强大;
    让程序可以面向接口编程,这样程序员就可以灵活方便的切换各种业务实现(更利于程序的解耦合)。

// 接口:使用interface关键字定义的
public interface A {// JDK 8之前,接口中只能写常量和抽象方法——传统接口// 1、常量:接口中定义常量可以省略 public static final 不写,默认会加上。String SCHOOL_NAME = "黑马程序员";public static final String SCHOOL_NAME2 = "黑马";  // 前面的 public static final 可以省略不写// 2、抽象方法:接口中定义的方法可以省略 public abstract 不写,默认会加上。//    public abstract void study();void study();String go();
}public interface B {void play();  // 玩
}// C 被称为实现类。同时实现了多个接口
// 要么把C定义成一个抽象类 abstract修饰
// 要么C 全部重写A和B的全部抽象方法
class C implements A, B {@Overridepublic void study() {System.out.println("C类重写了study方法");}@Overridepublic String go() {return "黑马找磊哥";}@Overridepublic void play() {System.out.println("C类重写了play方法");}
}public class Test {public static void main(String[] args) {// 目标:认识接口,搞清楚几口的特点,基本使用System.out.println(A.SCHOOL_NAME);   // 黑马程序员// 注意:接口不能创建对象// 接口是用来被类实现的C c = new C();c.study();   // C类重写了study方法System.out.println(c.go());   // 黑马找磊哥c.play();  // C类重写了play方法}
}
  • 案例:
    A公司设计一个A接口(多个方法名,给出规范)
    让B、C公司分别实现A接口(写一套实现类),看看B、C公司的实现类怎么样,然后哪个实现类好用直接用哪个公司的实现类。

  • 案例收获:
    1.接口定义的抽象方法不能添加形参
    2.传入参数是用在接口的实现类中定义私有的数组,然后定义实现类对象获取数组信息;
    3.接口实现类的命名规则是在接口名后加Impl,作为实现类的类名。

public class Test {public static void main(String[] args) {// 目标:完成接口的小案例。// 题目:/* 1.请设计一个班级学生的信息管理模块:学生的数据有:姓名、性别、成绩2.功能一:要求打印出全班学生的信息;功能二:要求打印出全班学生的平均成绩注意:第一套方案:能打印出班级全部学生的信息;能打印班级全部学生的平均分第二套方案:能打印出班级全部学生的信息(包含男女人数)能打印班级全部学生的平均分(要求是去掉最高分、最低分)要求:系统可以支持灵活的切换这些实现方案 */// 1.定义学生类,创建学生对象,封装学生信息,才能交给别人处理// 2.准备学生数据,自己造一些测试数据Student[] students = new Student[10];students[0] = new Student("张三", '男', 100);students[1] = new Student("李四", '男', 80);students[2] = new Student("王五", '男', 80);students[3] = new Student("赵六", '女', 30);students[4] = new Student("孙七", '女', 90);students[5] = new Student("钱八", '女', 80);students[6] = new Student("钱九", '女', 77);students[7] = new Student("钱十", '女', 90);students[8] = new Student("钱十一", '女', 20);students[9] = new Student("钱十二", '女', 100);// 3.提供两套业务实现方案,支持灵活切换(解耦合):面向接口编程。//     -- 定义一个接口(规范思想):必须完成打印全班学生信息,打印平均分;//     -- 定义第一套实现类,实现接口:实现打印学生信息,实现打印平均分;//     -- 定义第二套实现类,实现接口:实现打印学生信息(男女人数),实现打印平均分(去掉最高分和最低分);ClassDateInter cdi = new ClassDataInterImpl2(students);cdi.printAllStudentsInfos();cdi.printAverageScore();}
}public class Student {private String name;private char sex;private double score;public Student() {}public Student(String name, char sex, double score) {this.name = name;this.sex = sex;this.score = score;}public String getName() {return name;}public void setName(String name) {this.name = name;}public char getSex() {return sex;}public void setSex(char sex) {this.sex = sex;}public double getScore() {return score;}public void setScore(double score) {this.score = score;}
}public interface ClassDateInter {//功能一:要求打印出全班学生的信息void printAllStudentsInfos();//功能二:要求打印出全班学生的平均成绩void printAverageScore();
}public class ClassDataInterImpl1 implements ClassDateInter {private Student [] students; // 用来记住送来的全班学生信息数组。// 用有参构造器来接数据public ClassDataInterImpl1(Student[] students) {this.students = students;}@Overridepublic void printAllStudentsInfos() {for(int i=0; i<students.length; i++){Student s = students[i];System.out.println(s.getName() + " " + s.getSex() + " " + s.getScore());}}@Overridepublic void printAverageScore() {double sum = 0;for (int i = 0; i < students.length; i++) {Student s = students[i];sum += s.getScore();}System.out.println("全班同学平均成绩是:" + sum / students.length);}
}public class ClassDataInterImpl2 implements ClassDateInter {private Student [] students; // 用来记住送来的全班学生信息数组。// 用有参构造器来接数据public ClassDataInterImpl2(Student[] students) {this.students = students;}@Overridepublic void printAllStudentsInfos() {System.out.println("学生信息如下:");int menNum = 0;for(int i=0; i<students.length; i++){Student s = students[i];if(s.getSex() == '男'){menNum++;}System.out.println(s.getName() + " " + s.getSex() + " " + s.getScore());}System.out.println("男同学人数是:" + menNum + " ,女同学的人数是:" + (students.length - menNum));}@Overridepublic void printAverageScore() {System.out.println("平局分如下:");Student s1 = students[0];double sum = s1.getScore();double max = s1.getScore();double min = s1.getScore();for (int i = 1; i < students.length; i++) {Student s = students[i];sum += s.getScore();if(s.getScore() > max){max = s.getScore();}if(s.getScore() < min){min = s.getScore();}}System.out.println("去掉一个最高分:" + max + ",去掉一个最低分:" + min + "\n全班同学平均成绩是:" + (sum - max - min)/ (students.length - 2));}
}
  • JDK8开始,接口新增了三种形式的方法:默认方法,私有方法,类方法(静态方法)
    ① 默认方法(普通实例方法):必须加default修饰
    默认会用public修饰
    如何调用? 使用接口的实现类的对象来调用。
    ② 私有方法(JDK9开始才支持的)
    私有的实例方法。
    如何调用? 只能在接口中,使用接口中的其他实例方法来调用
    ③ 静态方法
    默认会用public修饰
    如何调用? 只能使用当前接口名来调用。
    不允许用实现类来调用当前接口的静态方法。

  • java的接口为什么新增三种形式的方法?
    我们自己写的可能性几乎为0,sun公司自己用的比较多。
    增强了接口的能力,更便于项目的扩展和维护

  • 其实这个在项目中基本用不到,现在三层架构,直接controller自动注入接口的bean,然后在impl实现接口的功能,不会用到这些新增的方法。——可以跳过了

public class Test {public static void main(String[] args) {// 目标:搞清楚接口新增的三种方式,并理解其好处。AImpl a = new AImpl();a.go();   // ===go方法执行了===A.show();  // ===show方法执行了===}
}class AImpl implements A {
}public interface A {// 1、默认方法(普通实例方法):必须加default修饰// 默认会用public修饰// 如何调用? 使用接口的实现类的对象来调用。default void go() {System.out.println("===go方法执行了===");run();  // ===go2方法执行了===}// 2、私有方法(JDK9开始才支持的)//  私有的实例方法。// 如何调用? 只能在接口中,使用接口中的其他实例方法来调用private void run() {System.out.println("===go2方法执行了===");}// 3、静态方法//  默认会用public修饰// 如何调用? 只能使用当前接口名来调用。// 不允许用实现类来调用当前接口的静态方法。static void show(){System.out.println("===show方法执行了===");}
}
  • 接口的注意事项:
    1、接口与接口可以多继承:一个接口可以同时继承多个接口;
    2、一个接口继承多个接口,如果多个接口中存在方法签名冲突,则此时不支持多继承,也不支持多实现;(了解)
    3、一个类继承了父类,又同时实现了接口,如果父类中和接口中有同名的默认方法,实现类会优先用父类的;
    怎么在实现类对象中调用接口的同名方法呢?
    只能中转:在实现类写一个方法,用接口名.super.方法名();调用。// 指定调接口爸爸的方法
    4、一个类实现了多个接口,如果多个接口中存在同名的默认方法,可以不冲突,这个类重写该方法即可。

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

  • 最佳实践:
    集合都是功能——都是用接口做的解耦合
    IO流是抽象类做父类

public class Test {public static void main(String[] args) {// 目标:理解接口的几点注意事项Dog d = new Dog();d.show();Dog2 d2 = new Dog2();d2.show();}
}// 1、接口与接口可以多继承:一个接口可以同时继承多个接口;
interface A {void show1();
}
interface B {void show2();
}
interface C extends A,B {void show3();
}class D implements C {@Overridepublic void show1() {}@Overridepublic void show2() {}@Overridepublic void show3() {}
}// 2、一个接口继承多个接口,如果多个接口中存在方法签名冲突,则此时不支持多继承,也不支持多实现;
interface A1 {void show();
}
interface B1 {
//    String show(); // B1用这个,那么D1实现A1和B1的方法会因签名冲突而报错void show();
}
interface C1 extends A1,B1 {
}
class D1 implements C1 {@Overridepublic void show() {}
}//3、一个类继承了父类,又同时实现了接口,如果父类中和接口中有同名的默认方法,实现类会优先用父类的;
interface A2{default void show(){System.out.println("接口中的 A2 show 方法");}
}
class Animal{public void show(){System.out.println("父类中的 show 方法");}
}
class Dog extends Animal implements A2 {public void go(){super.show(); // 还是找父类的show方法A2.super.show(); // 找A2接口的show方法}
}//4、一个类实现了多个接口,如果多个接口中存在同名的默认方法,可以不冲突,这个类重写该方法即可。
interface A3{default void show(){System.out.println("接口中的 A2 show 方法");}
}
interface B3{default void show(){System.out.println("接口中的 B2 show 方法");}
}
class Dog2 implements A3,B3 {@Overridepublic void show(){System.out.println("重写接口中的 show 方法");A3.super.show();  // 中转B3.super.show();}
}

6.其他

  • 常量:
    使用了static、final修饰的成员变量就称为常量
    public static final String SCHOO_NAME = "黑马";
    作用:常用于记录系统的配置信息

  • 使用常量记录系统配置信息的优势、执行原理:
    代码可读性好,可维护性也更好;
    程序编译后,常量会被宏替换(就是全部替换):出现常量的地方全部会被替换成其记住的字面量,这样可以保证使用常量和字面量的性能是一样的。

  • 设计模式:
    设计模式有20多种,对应20多种软件开发过程中会遇到的问题(总体来说有23种)

  • 关于设计模式,主要学什么?
    1、解决什么问题?
    2、怎么写?

  • 枚举类:
    枚举类都是最终类,不可以被继承,所有的枚举类都是继承java.lang.Enum类的;
    枚举类的构造器都是私有的(写不写都只能是私有的),因此,枚举类对外不能创建对象;
    所以枚举类是多例模式;
    编译器为枚举对象新增了几个方法:枚举类对象名.ordinal():拿到枚举类对象的索引(指代第几个枚举类对象,从0开始)

  • 比较强大的反编译工具:Xjad
    或者用命令行进行反编译:

D:\Desktop>javap .\A.class
Compiled from "A.java"
public final class sun.superstring.enumdemo.A extends java.lang.Enum<sun.superstring.enumdemo.A> {public static final sun.superstring.enumdemo.A X;public static final sun.superstring.enumdemo.A Y;public static final sun.superstring.enumdemo.A Z;public static sun.superstring.enumdemo.A[] values();public static sun.superstring.enumdemo.A valueOf(java.lang.String);static {};
}D:\Desktop>
  • mybatis把JDBC封装成一个框架
    JDBC(Java database Connectivity,Java数据库连接)是Java编程语言中用于执行SQL语句的一套API。它为Java应用程序提供了与各种关系型数据库进行交互的标准方法,使得开发者可以使用统一的接口来访问不同的数据库系统,而无需关心底层数据库的具体实现细节。

  • java的接口为什么新增三种形式的方法?
    我们自己写的可能性几乎为0,sun公司自己用的比较多。
    增强了接口的能力,更便于项目的扩展和维护
    其实这个在项目中基本用不到,现在三层架构,直接controller自动注入接口的bean,然后在impl实现接口的功能,不会用到这些新增的方法。——可以跳过了

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/877588.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

线段树优化建树 CF786B

题解,线段树优化建图。看到区间操作想到用线段树优化建树,建一棵外向树一棵内向树,用线段树点代表整个区间内的所有点。 大佬的图从树上找节点然后连边就可以,最后跑个dijktra就完成了。 我一次就过样例了,改了几次内存就过了这题,太好了!!! #include <bits/stdc++…

数据库安全管理中的用户和角色管理:打造安全高效的数据环境

title: 数据库安全管理中的用户和角色管理:打造安全高效的数据环境 date: 2025/2/1 updated: 2025/2/1 author: cmdragon excerpt: 在数字化时代,数据库作为信息存储和处理的核心,安全管理显得尤为重要。用户和角色管理是保障数据库安全性的重要手段,合理的管理策略不仅能…

如何成为销售顶尖高手?这4个方法绝了!

在销售的世界里,业绩高手们总有一套独特的“制胜法则”。他们不仅对产品了如指掌,更擅长与客户沟通,能够在复杂多变的市场中游刃有余,稳操胜券。玩变化:灵活应变,精准出击 高手们深知,销售没有一成不变的模式。他们懂得根据不同客户、场合和时间,灵活调整沟通方式和销售…

分布式事务之2PC两阶段提交

1. 分布式事务概述 1.1 问题背景 在分布式系统中,业务操作可能跨越多个服务或数据库(如订单服务、库存服务、支付服务),传统单机事务(ACID)无法满足跨网络节点的数据一致性需求。网络不可靠:服务间调用可能失败或超时。 数据一致性:不同节点间的状态需最终一致。 性能与…

【SQL】存储过程、函数、触发器

存储过程 存储过程(Stored Procedure)是一种在数据库中保存的SQL语句集合,它可以执行一系列的数据库操作,例如插入、更新、查询等。存储过程可以提高数据库操作的效率,减少网络流量,并且可以封装复杂的逻辑。定义: 存储过程是一组为了完成特定功能的SQL语句集,这些语句…

[Tools] GitHub Action 部署文档网站

关于部署网站,理论上来讲,只要你有一个服务器,你要采用什么样的方式来部署都是可以的。但是前提是你需要有一个服务器(物理机、云服务器)。 这节课我们部署文档网站选择使用 github 来进行部署,因为 GitHub 为我们提供了一个免费的服务器,一个账号只有一个,只要你在 Gi…

[Tools] VitePress搭建文档网站

创建 API 文档可以选择如下的 3 种方式:功能较少,可以直接写在 README.md 文件里面 内容较多,可以单独写一个文件 API 数量众多(Vue、React 这种级别),需要考虑单独拿一个网站来做详细的文档支持这里我们要搭建的网站实际上就是一个文档网站,这个时候我们可以选择静态站…

[Tools] 搭建文档网站

创建 API 文档可以选择如下的 3 种方式:功能较少,可以直接写在 README.md 文件里面 内容较多,可以单独写一个文件 API 数量众多(Vue、React 这种级别),需要考虑单独拿一个网站来做详细的文档支持这里我们要搭建的网站实际上就是一个文档网站,这个时候我们可以选择静态站…

java中的HsahMap

HsahMap HashMap 是 Java 中最常用的集合类之一,它实现了 Map 接口,基于哈希表存储键值对 HashMap的存储是无顺序的 HashMap存储的是键值对(key-value)其中键key是唯一的,值(value)可以重复。 HashMap的底层是数组和链表 HashMap的常见方法 添加方法: 1,put(K key, V valu…

MyBatis的增删改查实现

首先还是使用上一篇文章相同的数据表和实体类,如下图所示1 package com.loubin.pojo;2 3 public class User {4 private int id;5 private String name;6 private String pwd;7 8 public int getId() {9 return id; 10 } 11 12 public void …