目录
一.final关键字
1.final使用情况
final可以修饰类,属性,方法和局部变量
在以下情况下,我们可能需要使用final
1)当不希望类被继承时,可以用final修饰
2)当不希望父类的某个方法被子类覆盖/重写(override)时,可以用final修饰
【案例演示:访问修饰符 final 返回类型 方法名】
3)当不希望类的某个属性的值被修改,可以用final修饰
【案例演示:public final double TAX_RATE = 0.08(一般用大写来表示某个属性的值不能修改)】
4)当不希望某个局部变量被修改,可以使用final修饰
【案例演示:final double TAX_RATE = 0.08】
案例代码如下:
//如果我们要求A类不能被其他类继承
//可以使用final修饰 A类
final class A { }
class C {
//如果我们要求hi不能被子类重写
//可以使用final修饰 hi方法
public final void hi() {}
}
class D extends C {
// @Override
// public void hi() {
// System.out.println("重写了C类的hi方法..");//错误
// }
}
//当不希望类的的某个属性的值被修改,可以用final修饰
class E {
public final double TAX_RATE = 0.08;
}
//当不希望某个局部变量被修改,可以使用final修饰
class F {
public void cry() {
//这时,NUM 也称为 局部常量
final double NUM = 0.01;
//NUM = 0.9;//错误
System.out.println("NUM=" + NUM);
}
}
2.使用细节
1)final修饰的属性又叫常量,一般用XX_XX_XX来命名
2)final修饰的属性在定义时必须赋初值,并且以后不能再修改,赋值可以再如下位置之一
a.定义时 如:public final double TAX_RATE = 0.08
b.在构造器中
c.在代码块中
案例代码如下:
class AA {
/*
1. 定义时:如 public final double TAX_RATE=0.08;
2. 在构造器中
3. 在代码块中
*/
public final double TAX_RATE = 0.08;//1.定义时赋值
public final double TAX_RATE2 ;
public final double TAX_RATE3 ;
public AA() {//构造器中赋值
TAX_RATE2 = 1.1;
}
{//在代码块赋值
TAX_RATE3 = 8.8;
}
}
3)如果final修饰的属性是静态的,则初始化的位置只能是
a.定义时 b.在静态代码块 不能在构造器中赋值
案例代码:
class BB {
/*
如果final修饰的属性是静态的,则初始化的位置只能是
1 定义时 2 在静态代码块 不能在构造器中赋值。
*/
public static final double TAX_RATE = 99.9;
public static final double TAX_RATE2 ;
static {
TAX_RATE2 = 3.3;
}
}
4)final类不能继承,但可以实例化对象
5)如果类不是final类,但是含有final方法,则该方法虽然不能被重写,但是可以被继承
6)一般来说,如果一个类已经是final了,没有必要将该类的方法设为final
7)final不能修饰构造方法(即构造器)
8)final和static搭配使用,效率更高,不会导致类的加载,底层编译器做了优化处理
代码案例:
class BBB {
public final static int num = 10000;
static {
System.out.println("BBB 静态代码块被执行");
}
}
System.out.println(BBB.num);
//只调用了静态属性,静态方法不会被调用,不会导致类的加载
9)包装类(integer,Double,Float,Boolean),String 是final类,不能被继承
二.抽象类
1.简单介绍
当父类的某些方法,需要声明,但不确定如何实现,可以将其声明为抽象方法,这个类就是抽象类
快速入门案例:
我们有一个animal类,该类有个eat方法,但是不确定具体方法是什么,在cat类中对该方法进行重写
public class abstract01 {
public static void main(String[] args) {
Cat cat = new Cat("小花");
cat.eat();
}
}
abstract class Animal{
String name;
public Animal(String name) {
this.name = name;
}
public abstract void eat();
}
class Cat extends Animal{
String name;
public Cat(String name) {
super(name);
}
@Override
public void eat() {
System.out.println("吃猫粮");
}
}
2.抽象类的介绍
1)用abstract关键字来修饰一个类时,这个类就叫做抽象类
访问修饰符 abstract 类名{}
2)用abstract关键字来修饰一个方法时,这个类就叫做抽象方法
访问修饰符 abstract 返回类型 方法名(参数列表);//无方法体
3)抽象类的价值更多是在于设计,是设计者设计好后,让子类继承并实现抽象类
3.使用细节
1)抽象类不能被实例化
2)抽象类不一定包含abstract方法
3)一旦类包含了abstract方法,则这个类必须声明为abstract
4)abstract只能修饰类和方法,不能修饰属性和其他
public class AbstractDetail01 {
public static void main(String[] args) {
//抽象类,不能被实例化
//new A();//错误
}
}
//抽象类不一定要包含abstract方法。也就是说,抽象类可以没有abstract方法
//,还可以有实现的方法。
abstract class A {
public void hi() {
System.out.println("hi");
}
}
//一旦类包含了abstract方法,则这个类必须声明为abstract
abstract class B {
public abstract void hi();
}
//abstract 只能修饰类和方法,不能修饰属性和其它的
class C {
// public abstract int n1 = 1;//错误
}
5)抽象类可以有任意成员【抽象类的本质还是类】,比如:非抽象方法,构造器,静态属性等
6)抽象方法不能有主体
即没有大括号:abstract void add();
7)如果一个类继承了抽象类,则它必须实现抽象类的所有方法,除非它自己也声明为abstract类
//如果一个类继承了抽象类,则它必须实现抽象类的所有抽象方法,除非它自己也声明为abstract类
abstract class E {
public abstract void hi();
}
abstract class F extends E {
}
class G extends E {
@Override
public void hi() { //这里相等于G子类实现了父类E的抽象方法,所谓实现方法,就是有方法体
}
}
8)抽象方法不能使用private final 和static来修饰
解释:final:final表示顶级,即方法和其它成员不能被子类重写或修改,而抽象类的作用必须通过子类继承来体现
static:static与方法重写无关
private:private定义的方法无法被其它类调用或重写
三.模板设计模式
1.基本介绍
抽象类体现的就是一种模板的设计,抽象类作为多个子类的通用模板,子类在抽象类的基础上进行扩展,改造,但子类总体上会保留类的行为方式
2.实践案例
abstract public class Template { //抽象类-模板设计模式
public abstract void job();//抽象方法
public void calculateTime() {//实现方法,调用job方法
//得到开始的时间
long start = System.currentTimeMillis();
job(); //动态绑定机制
//得的结束的时间
long end = System.currentTimeMillis();
System.out.println("任务执行时间 " + (end - start));
}
}
public class AA extends Template {
//计算任务
//1+....+ 800000
@Override
public void job() { //实现Template的抽象方法job
long num = 0;
for (long i = 1; i <= 800000; i++) {
num += i;
}
}
public class BB extends Template{
public void job() {//这里也去,重写了Template的job方法
long num = 0;
for (long i = 1; i <= 80000; i++) {
num *= i;
}
}
}
public class TestTemplate {
public static void main(String[] args) {
AA aa = new AA();
aa.calculateTime(); //这里还是需要有良好的OOP基础,对多态
BB bb = new BB();
bb.calculateTime();
}
}
3.补充案例
可能通过上面的案例,有些读者可能还是无法理解什么是模板设计模式,所以我在C站上又学习了几个案例,介绍给大家,希望对各位读者有所帮助。
用代码来实现咖啡和茶的制作
public class exercise01_ {
public static void main(String[] args) {
Coffee coffee = new Coffee();
Tea tea = new Tea();
coffee.prepare();
tea.prepare();
}
public static class Coffee {
public void prepare(){
boil();
brew();
put();
Issugar();
}
public void boil(){
System.out.println("烧水");
}
public void brew(){
System.out.println("冲泡");
}
public void put(){
System.out.println("咖啡放到杯子里");
}
public void Issugar(){
System.out.println("加糖");
}
}
public static class Tea {
public void prepare(){
boil();
brew();
put();
Islemon();
}
public void boil(){
System.out.println("烧水");
}
public void brew(){
System.out.println("冲泡");
}
public void put(){
System.out.println("茶水放到杯子里");
}
public void Islemon(){
System.out.println("加柠檬");
}
}
}
写完代码后发现,咖啡和茶的制作过程又一样的部分,所以我们将相同方法抽取出来,代码如下
public class exercise02_ {
public static void main(String[] args) {
coffee coffee01 = new coffee();
tea tea01 = new tea();
coffee01.prepare();
tea01.prepare();
}
}
abstract class progress{
final void prepare(){
boil();
brew();
put();
add();
}
abstract void brew();
abstract void add();
public void boil(){
System.out.println("烧水");
}
public void put(){
System.out.println("倒进杯子里");
}
}
class coffee extends progress{
@Override
void brew() {
System.out.println("冲咖啡");
}
@Override
void add() {
System.out.println("加糖");
}
}
class tea extends progress{
@Override
void brew() {
System.out.println("泡茶叶");
}
@Override
void add() {
System.out.println("加柠檬");
}
}