1、抽象类⭐
概述
-
父类觉得子类一定要做某个功能,但是每个子类指挥调用自己重写后的方法,父类方法因此没有什么意义于是将其定义为抽象类,约束子类一定要重写该方法
-
抽象类:用abstract修饰,拥有抽象方法的类必须是抽象类
-
抽象方法:必须用abstract修饰,只有方法签名没有方法体
//父类:抽象类 abstract class Student{ //抽象方法 public abstract void study(); } //子类1 class Xiaoming extends Student{ @Override public void study(){ System.out.println("小明在学习"); } } //子类2 class Xiaohong extends Student{ @Override public void study(){ System.out.println("小红也在学习"); } }
使用
-
一个类继承了抽象类,必须重写完抽象类的全部抽象方法,否则这个类也必须定义为抽象类
//定义一个员工类:老师,班主任都要工作,睡觉 abstract class Employee{ public abstract void work(); public abstract void sleep(); } //子类1老师:重写了抽象类中全部两个方法 class Teacher extends Employee{ @Override public void work() { System.out.println("老师要讲课"); } @Override public void sleep() { System.out.println("老师睡觉睡得很少"); } } //子类班2主任:如果只重写了一个,没重写完所有的方法,则这个子类也要变成抽象类,+abstract abstract class Headteacher extends Employee{ @Override public void work() { System.out.println("班主任要管理班级"); } }
特点
-
有得有失:抽象类得到了抽象方法的能力,失去了创建对象的能力
-
Q:抽象类是否有构造器,抽象类是否可以创建对象?
A:抽象类有构造器,有成员变量,成员方法,但是不能创建对象。抽象类是为了被子类继承的,构造器也是为了在子类创建对象时默认调用父类构造器时使用的,隐藏的super();
-
抽象类可能有抽象方法,抽象方法不能被直接调用
抽象类设计模板模式
- 模板模式作用:部分实现部分抽象,极大简化功能代码,提高开发效率
/*
作文模板案例:
标题第一段和最后一段固定,正文部分让使用者自己写
*/
public class ExtendsDemo2 {
public static void main(String[] args) {
Middleparagraph middle = new Middleparagraph();
middle.printEssay();
}
}
//父类:一个抽象类的作文模板
abstract class Template2{
//标题和最后一段固定,作为实例变量
private String title = "\t\t\t\t《日记》";
private String lastparagraph = "\t春节要到了,提前祝大家新年快乐!";
//第一段第二段的内容用抽象方法
public abstract String firstparagraph();
public abstract String secondparagraph();
//写一个方法来输出这篇小作文
public void printEssay(){
System.out.println(title);
System.out.println(firstparagraph());
System.out.println(secondparagraph());
System.out.println(lastparagraph);
}
}
//子类:中间段落内容重写一二段
class Middleparagraph extends Template2{
@Override
public String firstparagraph() {
return "\t2021.2.7\t多云转晴\n\t冬天外面好冷但是我好喜欢,因为我的♥是冰冰的。";
}
@Override
public String secondparagraph() {
return "\t今天又是沉迷“青年大学习”的一天。学习新思想,争做新青年!";
}
}
/*
输出结果:
《日记》
2021.2.7 多云转晴
冬天外面好冷但是我好喜欢,因为我的♥是冰冰的。
今天又是沉迷“青年大学习”的一天。学习新思想,争做新青年!
春节要到了,提前祝大家新年快乐!
*/
2、接口⭐
概述
-
接口是更加彻底的抽象,jdk1.8之前接口中只能是抽象方法和常量
--接口中的抽象方法可以省略public abstract
-
常量:是由public static final修饰的,只有一份且必须赋值一次,不可改变
--常量书写规范全部大写,多个单词用_连接
--接口中的常量可以省略public static final
-
定义格式:
修饰符 interface 接口名{ //实现——接口 }
-
接口是很规范的,实现接口的类必须重写完接口中全部的抽象方法
public interface InterfaceDemo{
//1、接口中的抽象方法可以省略public abstract
void go();
void introduce(String name);
//2、接口中的常量可以省略public static final
String MY_NAME = "Jayven";
}
实现
-
类与类 —— 子类 继承extends 父类
类与接口—— 实现类 实现implements 接口
-
格式:
修饰符 class 实现类名称 implements 接口1,接口2,接口3,……{ }
接口可以多实现,一个类可以实现多个接口
实现接口的类叫实现类
public class InterfaceDemo { public static void main(String[] args) { Pet pet = new Pet("旺财", "小明"); pet.eat(); pet.feed(); } } //接口1——Animal interface Animal{ void eat(); } //接口2——Person interface Person{ void feed(); } //实现类 class Pet implements Animal,Person{ private String dogname; private String name; public Pet(String dogname, String name) { this.dogname = dogname; this.name = name; } @Override public void eat(){ System.out.println("名叫"+dogname+"的狗子在进食"); } @Override public void feed() { System.out.println(name+"正在给"+dogname+"喂食"); } } /* 名叫旺财的狗子在进食 小明正在给旺财喂食 */
接口新增方法
-
jdk1.8之前——接口中只能是抽象方法和常量
jdk1.8之后——新增三个方法
-
默认方法(实例方法):必须用接口实现类的对象访问
public class InterfaceDemo { public static void main(String[] args) { // 1.默认方法:必须用接口的实现类对象调用 Dog dog = new Dog(); dog.run(); // 2.静态方法:必须(只能)用接口的名称来访问 Animal.eat(); } } //实现类 class Dog implements Animal{ } interface Animal{ //1、默认方法(实例方法),用接口实现类的对象访问 //用default修饰,默认会加上public修饰 default void run(){ //jump(); //调用私有方法jump 1.9之后使用 System.out.println("动物都还挺能跑的"); } }
-
静态方法:必须用接口的名称访问
//2、静态方法 static void eat(){ jump(); //调用私有方法jump 1.9之后使用 System.out.println("肉食动物会捕食"); }
-
私有方法:只能被接口中的其他方法调用,jdk1.9以后
//3、私有方法 private void jump(){ System.out.println("私有方法被调用了"); }
-
接口多实现注意事项
-
如果实现多个接口,多个接口中的同名静态方法并不会冲突,原因是只能通过各自接口名访问静态方法
-
当一个子类继承了一个父类并同时实现多个接口时,父类中的成员方法与接口中的默认方法重名,子类会就近选择父类中的方法执行
public class InterfaceDemo { public static void main(String[] args) { Dog dog = new Dog(); dog.run(); //输出结果:父类成员方法中的run方法 } } class Dog extends Animal implements A { } class Animal{ public void run(){ System.out.println("父类成员方法中的run方法"); } } interface A{ default void run(){ System.out.println("接口默认方法中的run方法"); } }
-
如果实现多个接口,多个接口中存在同名的默认方法,实现类必须重写这个方法
-
接口中,没有构造器,不能创建对象,因为接口是更加彻底的抽象,没有构造器无法创建对象
3、代码块
-
类的五大成分(成员变量,构造器,方法,代码块,内部类)
-
静态代码块:
-
有static修饰,属于当前类本身,与类一起优先加载,加载时自动触发执行
-
格式
static{ }
-
作用:可以在类执行方法之前进行静态资源数据的初始化操作
-
-
实例代码块:
- 无static修饰的代码块,属于类的每个对象,与对象一起加载
- 每次创建对象的时候都会自动执行一次实例代码块
- 作用:可以用于初始化实力资源的数据
- 实例代码块的代码最终会提取到每个构造器中去执行
4、final关键字
- final可以修饰类,方法,变量
- final修饰类:类不能被继承(绝育)
- final修饰方法:方法不能重写
- final和abstract属于互斥关系,final让方法不能重写,abstract必须重写全部抽象方法否则也要变成抽象类
- final修饰局部变量:变量值被保护无法再进行二次修改
- final修饰静态成员变量:变量变成常量,值不变,变量名大写,多个单词有_连接。可以在定义的时候赋值一次;在静态代码块中赋值一次
- final修饰实例成员变量:可以在定义的时候赋值一次;可以在实例代码块中赋值一次;可以在全部构造器中赋值一次
5、单例模式⭐
概述
-
含义:单例模式是一种常用的软件设计模式,通过单例模式可以保证系统中应用该模式的这个类永远只有一个实例。即一个类永远只有一个对象实例
-
应用场景:当只需要一个对象的时候,以便于节约内存提高性能,防止内存溢出
-
饿汉单例设计模式和懒汉单例设计模式
饿汉单例设计模式
-
在用类获取对象的时候,对象已经提前创建好了
-
设计步骤:
- 定义一个类,把构造器私有
- 定义一个静态变量存储一个对象
- 提供一个返回单例对象的方法
public class SingleInstanceDemo01 { public static void main(String[] args) { SingleInstance01 ins1 = SingleInstance01.getIns(); SingleInstance01 ins2 = SingleInstance01.getIns(); System.out.println(ins1 == ins2); //true 说明两个对象取自同一个对象 SingleInstance01 ins3 = SingleInstance01.INS; SingleInstance01 ins4 = SingleInstance01.INS; System.out.println(ins3 == ins4); //true } } class SingleInstance01{ //2、利用封装的思想把创建好的对象私有 private static SingleInstance01 ins = new SingleInstance01(); //补充:也可以不用方法直接把对象公开 public static final SingleInstance01 INS = new SingleInstance01(); //1、把构造器私有不能随意创建对象 private SingleInstance01() { } //3、再用一个方法返回这个对象给使用的人 public static SingleInstance01 getIns() { return ins; } }
懒汉单例模式
-
在用类获取单例对象的时候,才开始创建一个对象,而不是提前做好一个对象
-
设计步骤:
- 定义一个类,把构造器私有
- 定义一个静态变量存储一个对象
- 提供一个返回单例对象的方法,如果没有对象就创建,有对象就直接返回
public class SingleInstanceDemo02 { public static void main(String[] args) { SingleInstence02 ins1 = SingleInstence02.getInstance(); SingleInstence02 ins2 = SingleInstence02.getInstance(); System.out.println(ins1 == ins2); //true } } class SingleInstence02{ //2、定义一个静态变量用来存储对象,但此时不创建对象 private static SingleInstence02 ins; //1、先把构造器私有化 public SingleInstence02() { } //3、提供一个方法来返回这个对象,判断是否存在对象 public static SingleInstence02 getInstance(){ //如果空,就创建 if (ins == null){ ins = new SingleInstence02(); } return ins; } }
6、枚举
-
枚举是一种特殊类型,主要用于做信息的标志和分类
-
定义格式:
修饰符 enum 枚举类名称{ //第一行列出枚举类的对象名称,相当于多例模式 }
-
特点:
- 枚举类默认继承了java.lang.Enum,枚举类是不能被继承的,构造器默认私有
- 枚举类第一行列出枚举类的对象名称,相当于多例模式
- 第一行是常量名称,实际存储的就是枚举类对象
public class EnumDemo { public static void main(String[] args) { Sex b = Sex.GIRL; System.out.println(b); //GIRL System.out.println(b.ordinal()); // 1 ordinal()获取枚举的索引 // 拿枚举类中的全部实例对象到一个数组中去:values() Season[] seasons = Season.values(); for(int i = 0 ; i < seasons.length ; i++){ Season s = seasons[i]; System.out.println(s +"-->"+s.ordinal()); /* SPRING-->0 SUMMER-->1 AUTOUM-->2 WINTER-->3 */ } } } enum Sex{ BOY , GIRL ; } enum Season{ SPRING , SUMMER , AUTOUM , WINTER ; }