Java基础加强重温_02:接口(成分:抽象方法、常量、默认方法、静态方法、私有方法,实现、继承)、final关键字(修饰类、方法)、单例设计模式(懒汉、饿汉)、枚举(底层原理、编译与反编译)
一、接口
接口是更加彻底的抽象,接口成分仅有抽象方法、常量。(JDK1.8之前),接口同样是不能创建对象的。
从jdk1.9开始:接口中允许定义私有方法
定义格式
修饰符 interface 接口名称{ // 抽象方法 // 常量 }
1、接口成分
抽象方法
接口定义的方法全部都是抽象方法,会自动省略 public abstract
// 接口抽象方法 // public abstract void run(); void run();
常量
接口定义的变量是常量,会自动省略 public final static。也就是说在接口中定义的成员变量实际上是一个常量。使用public static final修饰后,变量值就不可被修改,并且是静态化的变量可以直接用接口名访问,所以也叫常量。常量必须要给初始值。常量命名规范建议字母全部大写,多个单词用下划线连接。
// public static final int AGE = 12 ; int AGE = 12; //常量 // public static final String SCHOOL_NAME = "黑马程序员"; String SCHOOL_NAME = "黑马程序员"; // 字符串常量
2、接口的实现和继承
实现
类与接口的关系为实现关系,即类实现接口,实现使用 implements 关键字。 该类可以称为接口的实现类,也可以称为接口的子类。
Java中的类可以实现一个接口,也可以同时实现多个接口,可以理解成实现多个规范,这是合理的。
实现的多个接口中的抽象方法全部需要重写,没有全部重写实现类也变成抽象类。
class 实现类 implements 接口1,接口2,...{ }
继承
接口和接口之间可以继承,可以继承一个,也可以继承多个。接口继承接口就是把其他接口的抽象方法与本接口进行了合并。
- 1、提高代码的复用性
- 2、提高代码的拓展性
interface 子接口 extends 父接口1,父接口2,...{ }
类与接口是实现关系
接口与接口是继承关系
3、JDK1.8以后接口新增特性
含有默认方法和静态方法(>=JDK1.8)
默认方法:
使用 default 修饰,不可省略,供子类调用或者子类重写(子类对象.默认方法)。
权限修饰符默认是 public(默认加上),可以被继承、被重写,但是不能像子类一样使用super调用。
静态方法:
使用 static 修饰,供接口直接调用(接口名.静态方法)。
- 继承、实现都无法重写静态方法
- 静态方法可以被继承,但是不能通过实现继承
理解: 类1 extends 类2 implements 接口,类1能拿到类2的静态方法,但不能拿到接口的静态方法。
接口1 extends 接口2,接口1可以拿到接口2的静态方法
public interface InterFaceName { // 默认方法 public default void method() { // 执行语句 } // 静态方法 public static void method2() { // 执行语句 } }
重写默认方法注意(了解):
子接口重写默认方法时,default关键字可以保留。
实现类重写默认方法时,default关键字不可以保留。
含有私有方法和私有静态方法(>=JDK1.9)
私有方法: 使用 private 修饰,供接口中的默认方法或者静态方法调用。
- 接口定义公开的默认方法和公开的静态方法调用接口的私有方法
定义格式
private [static] 返回值 方法名(参数...) { }
代码示例:
public interface InterFaceName { //私用方法 private void method() { // 执行语句 } //私有静态方法 private static void method() { // 执行语句 } }
普通方法和静态方法的调用:
- 静态方法能调用静态方法
- 普通方法能调用普通方法和静态方法
4、实现多个接口使用注意事项
接口多实现情况下调用各个接口的静态方法
- 调用方式:各自的接口名.静态方法
- 静态方法名一致也不影响,因为可以通过接口名区分
父类中的方法和接口中的默认方法重名问题
方法优先级,就近原则:本类 -> 父类 -> 接口
当多实现情况下,接口中有同名的default方法时,会报错(二义性)
二、final关键字
final是不可改变,最终的含义。可以用于修饰类、方法和变量(成员变量、静态成员变量、局部变量)。
- 类:被修饰的类,不能被继承。
- 方法:被修饰的方法,不能被重写。
- 变量:被修饰的变量,有且仅能被赋值一次。(在定义变量的时候赋值)
1、修饰类
被final修饰的类无法被继承(太监类)
final class 类名 { }
查询API发现像 public final class String 、 public final class Math 、 public final class Scanner等,很多我们学习过的类,都是被final修饰的,目的就是供我们使用,而不让我们所以改变其内容。
2、修饰方法
final修饰的方法无法被子类重写。
修饰符 final 返回值类型 方法名(参数列表){ //方法体 }
代码:
class Fu2 { //void(返回值)前面的修饰符可以随意调换顺序 final public void show1() { System.out.println("Fu2 show1"); } public void show2() { System.out.println("Fu2 show2"); } } class Zi2 extends Fu2 { // @Override // public void show1() { // System.out.println("Zi2 show1"); // } @Override public void show2() { System.out.println("Zi2 show2"); }
3、修饰变量(局部变量、静态成员变量、成员变量)
局部变量
局部变量:在方法中定义的变量。
基本类型的局部变量,被final修饰后,只能赋值一次,不能再更改。
public class FinalDemo1 { public static void main(String[] args) { // 声明变量,使用final修饰 final int a; // 第一次赋值 a = 10; // 第二次赋值 a = 20; // 报错,不可重新赋值 // 声明变量,直接赋值,使用final修饰 final int b = 10; // 第二次赋值 b = 20; // 报错,不可重新赋值 } }
静态成员变量
static修饰的变量被final修饰称之为【常量】。
被final修饰的常量名称,一般都有书写规范,所有字母都大写。
class Video { //等价静态的基本类型变量 //常量有一个命名规范:常量名一般用大写 //快捷键 :ctrl+shift+u,选择部分变大写 //直接通过类名.LEVEL调用,不需要经过构造方法,必须在声明的时候进行初始化 public static final char LEVEL = 3; }
实例成员变量
实例成员变量涉及到初始化的问题,初始化方式有显示初始化和构造器初始化,只能选择其中一个方式初始化
- 显示初始化: 即在定义成员变量的时候立马赋值
public class Student { final int num = 10; }
- 构造器初始化: 在构造方法中赋值一次。
每个构造方法中(有参/无参)都要赋值一次
public class Student { final int num = 10; final int num2; //在无参中赋值 public Student() { this.num2 = 20; // this.num2 = 20; } //在有参中赋值 public Student(String name) { this.num2 = 20; // this.num2 = 20; } }
三、单例设计模式
正常情况下一个类可以创建多个对象。单例设计模式,即一个类只有一个对象实例。
单例设计模式的概念/作用:使得JAVA程序的某个类在运行阶段只能创建一个对象。
实现步骤
现状:一个类可以创建无数个对象。改变为:一个类只能创建一个对象
- 1、私有构造方法,把构造方法通过private隐藏起来
- 2、定义私有静态成员变量存储单例
- 3、通过公开的静态getter方法获取单例
单例设计模式的分类
1.饿汉式单例
饿汉单例设计模式就是使用类的时候已经将对象创建完毕,不管以后会不会使用到该实例化对象,先创建了再说。很着急的样子,故被称为“饿汉模式”。
public class Singleton { // 1.将构造方法私有化,使其不能在类的外部通过new关键字实例化该类对象。 private Singleton() {} // 2.在该类内部产生一个唯一的实例化对象,并且将其封装为private static类型的成员变量。 private static final Singleton instance = new Singleton(); // 3.定义一个静态方法返回这个唯一对象。 public static Singleton getInstance() { return instance; } }
2.懒汉式单例
懒汉单例设计模式就是调用getInstance()方法时实例才被创建,先不急着实例化出对象,等要用的时候才例化出对象。不着急,故称为“懒汉模式”。
public class Singleton { // 2.在该类内部产生一个唯一的实例化对象,并且将其封装为private static类型的成员变量。 private static Singleton instance; // 1.将构造方法私有化,使其不能在类的外部通过new关键字实例化该类对象。 private Singleton() {} // 3.定义一个静态方法返回这个唯一对象。要用的时候才例化出对象 public static Singleton getInstance() { if(instance == null) { instance = new Singleton(); } return instance; } }
3、双重锁形式(解决懒汉式的线程安全问题)
懒汉单例设计模式在多线程环境下可能会实例化出多个对象,不能保证单例的状态。我们在学习完多线程的时候还会再讲解如何解决这个问题。
饿汉式和懒汉式的区别
静态成员变量是声明的时候初始化,还是get的时候初始化
饿汉式还是懒汉式用的多呢?
饿汉式实现更简单,懒汉式其实有线程安全问题(学多线程的时候会学)。
四、多例设计模式(与单例设计模式对应)
1、多例设计模式
https://blog.csdn.net/qq_38737992/article/details/89644649
2、老王讲设计模式(四)——多例模式
https://www.jianshu.com/p/78061e1f79a5
五、枚举
枚举是一个特殊的类,有固定实例个数的类型,我们可以把枚举理解成有固定个数实例的多例模式。即枚举能用来表达固定的几个特定的选项。
枚举定义格式:
public enum 枚举名{ //第一行都是罗列枚举实例,这些枚举实例直接写大写名字即可。 选项1,选项2,....; }
枚举的使用:
作为数据类型使用
枚举名.选项
1、不使用枚举存在的问题
假设我们要定义一个人类,人类中包含姓名和性别。通常会将性别定义成字符串类型,代码演示如下:
public class Person { private String name; private String sex; public Person() { } public Person(String name, String sex) { this.name = name; this.sex = sex; } // 省略get/set/toString方法 }
public class Demo01 { public static void main(String[] args) { Person p1 = new Person("张三", "男"); Person p2 = new Person("张三", "abc"); // 因为性别是字符串,所以我们可以传入任意字符串 } }
不使用枚举存在的问题:可以给性别传入任意的字符串,导致性别是非法的数据,不安全,违反代码的逻辑性。
2、枚举的作用与应用场景
枚举的作用:一个方法接收的参数是固定范围之内的时候,即可以穷举的固定几个选项,那么可使用枚举。
枚举的应用:枚举通常可以用于做信息的分类,如性别,方向,季度等。
入门案例
1、 定义枚举:BOY表示男,GIRL表示女
enum Sex { BOY, GIRL; // 男,女 }
2、Perosn中的性别有String类型改为Sex枚举类型
public class Person { private String name; private Sex sex; public Person() { } public Person(String name, Sex sex) { this.name = name; this.sex = sex; } // 省略get/set/toString方法 }
3.、使用是只能传入枚举中的固定值
public class Demo02 { public static void main(String[] args) { Person p1 = new Person("张三", Sex.BOY); Person p2 = new Person("张三", Sex.GIRL); Person p3 = new Person("张三", "abc"); } }
测试运行。
入门案例枚举底层分析
枚举的本质是一个类,我们刚才定义的Sex枚举最终效果如下(通过编译-反编译后分析):
enum Sex { BOY, GIRL; // 男,女 } //1、枚举Sex是一个final clss 继承了Enum类 final class Sex extends Enum{ //2、枚举中的选项其实是枚举类的常量,用枚举类做数据类型,在静态代码块中初始化 public static final Sex BOY; public static final Sex GIRL; public static SEX[] values(){}; public static SEX valueOf(java.lang.String){}; //3、枚举中的构造方法是私有的,多例(单例) private Sex(){ } //初始化枚举选项 static { BOY = new SEX(); GIRL = new SEX(); }; }
因为枚举的本质是一个类,所以枚举中还可以有成员变量,成员方法等。
public enum Sex { BOY(18), GIRL(16); //成员变量 public int age; // getter/setter方法 Sex(int age) { this.age = age; } //成员方法 public void showAge() { System.out.println("年龄是: " + age); } }
测试类
public class Demo03 { public static void main(String[] args) { Person p1 = new Person("张三", Sex.BOY); Person p2 = new Person("张三", Sex.GIRL); Sex.BOY.showAge(); Sex.GIRL.showAge(); } }
编译和反编译研究枚举底层
枚举是一种特殊的类
编译:
- java文件 -> javac编译 -> class文件
反编译工具:
- class文件 -> 反编译工具 -> java文件
怎么找class文件:
- 模块名右键->show in explorer -> out -> …->包名->class文件
- 如果没有:要编译的类右键->recompile
反编译工具:
- jd-gui、xjad:配合起来用
小结:
枚举的底层
1、枚举是一个final clss 继承了 Enum类
2、枚举中的选项其实是枚举类的常量,在静态代码块中初始化
3、枚举中的构造方法是私有的,多例(单例)。一个选项单例,多个选项多例
4、枚举也能定义方法、构造方法
枚举如果想携带额外信息(改造枚举类Sex):
- 1、在枚举中定义新的成员变量
enum Sex { BOY, GIRL; // 男,女 //如果想枚举额外添加更多的信息 //1、在枚举中定义新的成员变量 private String name; }
- 2、修改构造方法,把新的成员变量加入
enum Sex { BOY, GIRL; // 男,女 //如果想枚举额外添加更多的信息 //1、在枚举中定义新的成员变量 private String name; // 2、修改构造方法,把新的成员变量加入 private Direction(String name) { this.name = name; } }
3、枚举中常量需要根据新的构造方法进行调整
enum Sex { //3、枚举中常量需要根据新的构造方法进行调整,传入参数。 BOY("男"), GIRL("女"); // 男,女 //如果想枚举额外添加更多的信息 //1、在枚举中定义新的成员变量 private String name; // 2、修改构造方法,把新的成员变量加入 private Direction(String name) { this.name = name; } }
增加信息后反编译,初始化选项的static代码块
//初始化枚举选项 static { BOY = new SEX("BOY","男"); GIRL = new SEX("GIRL","女"); };
理解:即定义新的变量,是给选项定义的。选项要传入这个参数。static代码块初始化后选项会携带这个参数。
- 点赞
- 收藏
- 分享
- 文章举报
- Java基础——继承+子父类相关特点+Final关键字+抽象类+模板方法设计模式+接口
- 黑马程序员 Java基础 面向对象:继承、final关键字、抽象类、模版方法模式、接口、多态、Object类
- 黑马程序员_Java基础_面向对象(继承、子父类变量和函数以及构造函数特点、final关键字、抽象类、模版方法模式、接口)
- 2018/01/08JAVA 基础 / 接口与继承 / JAVA的修饰符FINAL详解:final修饰类、方法、基本变量、引用、常量
- interface接口的使用与理解,以及使用接口实现简单的设计方法(代理默认)后续会添加单例模式,常用的懒汉,饿汉默认
- 黑马程序员--JAVA基础_03(继承、final修饰符、抽象、模版方法设计模式)
- JAVA常用基础知识点[继承,抽象,接口,静态,枚举,反射,泛型,多线程...]
- JAVA常用基础知识点[继承,抽象,接口,静态,枚举,反射,泛型,多线程...]
- 阶段1 语言基础+高级_1-3-Java语言高级_02-继承与多态_第5节 final关键字_2_final关键字用于修饰类...
- JAVA常用基础知识点[继承,抽象,接口,静态,枚举,反射,泛型,多线程...]
- 黑马程序员——Java基础:继承、final关键字、抽象、接口、多态
- 黑马程序员——JAVA基础之抽象和接口 , 模版方法设计模式
- 夯实Java基础系列4:一文了解final关键字的特性、使用方法,以及实现原理
- 阶段1 语言基础+高级_1-3-Java语言高级_02-继承与多态_第3节 接口_5_接口的默认方法定义...
- JAVA常用基础知识点[继承,抽象,接口,静态,枚举,反射,泛型,多线程...]
- 夯实Java基础系列4:一文了解final关键字的特性、使用方法,以及实现原理
- 关于static静态的、继承、接口interface、final关键字、单例设计模式总结
- JAVA常用基础知识点[继承,抽象,接口,静态,枚举,反射,泛型,多线程.]
- 阶段1 语言基础+高级_1-3-Java语言高级_02-继承与多态_第3节 接口_4_接口的抽象方法使用...
- 阶段1 语言基础+高级_1-3-Java语言高级_02-继承与多态_第3节 接口_3_接口的抽象方法定义...