1.final关键字介绍
——final关键字可以去修饰类、方法、属性和局部变量
2.final关键字的作用
1)final修饰类,这个类不能被其他类继承
2)final修饰方法,方法不能被重写
3)final修饰属性,属性的值不能被修改
4)final修饰局部变量,局部变量的值不能被修改
public class Test {
public static void main(String[] args) {
}
}
//1.final修饰类,类不能被继承
final class Person {
}
//class Stu extends Person {}
//错误,Person类不能被继承
class Animal {
//2.final修饰方法,方法不能被重写
public final void say() {
}
}
class Dog extends Animal {
//错误,不能重写final的方法
//public void say() {}
}
//3.final修饰属性,属性的值不能被修改
class Cat {
private final int age = 10;
public void setAge() {
//错误,final修饰的属性不能被修改
//age = 19;
}
}
//4.final修饰局部变量,局部变量的值不能被修改
class Tiger {
public void sleep() {
final int age = 18;
//final修饰的局部变量不能被修改
//age = 19;
}
}
3.final的细节讨论及实现
1)final修饰的属性叫做常量,常量使用全大写字母表示,若是多单词,单词间使用_隔开
public class Test {
public static void main(String[] args) {
Person person = new Person();
System.out.println(person.MAX_AGE);//130
}
}
class Person {
public final int MAX_AGE = 130;
}
2)final修饰的属性必须要初始化,可以在三个地方初始化:
a.声明定义并初始化
b.构造器中初始化
c.代码块中初始化
public class Test {
public static void main(String[] args) {
Person person = new Person();
//使用
System.out.println(person.MAX_AGE);//130
System.out.println(person.MIN_AGE);//0
System.out.println(person.MAX_NUM);//100
}
}
class Person {
//声明定义并初始化
public final int MAX_AGE = 130;
//构造器中初始化
public final int MIN_AGE;
public Person() {
MIN_AGE = 0;
}
//代码块中初始化
public final int MAX_NUM;
{
MAX_NUM = 100;
}
}
3)若final修饰的属性是静态的,可以在两个地方初始化:
a.声明定义并初始化
b.静态代码块中初始化
public class Test {
public static void main(String[] args) {
//使用
System.out.println(Person.MAX_AGE);//130
System.out.println(Person.MIN_AGE);//0
}
}
class Person {
//声明定义并初始化
public final static int MAX_AGE = 130;
//静态代码块中初始化
public final static int MIN_AGE;
static {
MIN_AGE = 0;
}
}
4)final类不能被继承,但是可以实例化
public class Test {
public static void main(String[] args) {
//final类不能被继承,但是可以实例化
Person person = new Person();
}
}
final class Person {
}
5)若类不是final类,但含有final方法,那么final方法可以被继承,但不能被重写
public class Test {
public static void main(String[] args) {
Colleague colleague = new Colleague();
colleague.say();//final方法可以被继承
}
}
class Person {
public final void say() {
System.out.println("I say: you must success!");
}
}
class Colleague extends Person {
//不能重写父类中final修饰的方法
//public void say() {}
}
6)若一个类已经是final类了,那么其方法没有必要设置为final方法了:因为final类不可能被继承,有final方法也不可能被重写
public class Test {
public static void main(String[] args) {
}
}
final class Person {
//类已经是final修饰的了,那么方法不需要再使用final修饰
//public final void say() {
// System.out.println("I will say: you must success!");
//}
public void say() {
System.out.println("I will say: you must success!");
}
}
7)final不能修饰构造器,能不能说说为什么?
——final修饰的方法约束在子类中不能进行重写,而构造器本身就不能在子类中重写,所以无需final修饰
public class Test {
public static void main(String[] args) {
}
}
class Person {
//final不能修饰构造器
//final public Person() {}
}
8)final和static搭配使用效率更高,不会导致类的加载就可以使用
public class Test {
public static void main(String[] args) {
System.out.println(Person.MAX_AGE);
}
}
class Person {
//final和static搭配使用效率更高,不会导致类的加载就可以使用
public static final int MAX_AGE = 150;
//静态代码块随着类的加载而加载
static {
System.out.println("静态代码块被加载~");
}
}
9)包装类(Integer、Double等)和String类均是使用final修饰的
1.什么是抽象类?什么是抽象方法?
——使用abstract关键字修饰的类/方法叫做抽象类/方法
2.抽象类/方法格式
抽象类:权限修饰符 abstract class 类名 {}
抽象方法:权限修饰符 abstract 返回类型 方法名(形参列表...);
public class Test {
public static void main(String[] args) {
}
}
//当父类的某些方法需要声明,但是又不确定要怎么使用的时候,可以将方法声明为抽象类,那么这个类也是抽象类
//注意,只要方法是抽象方法,那么类也必须是抽象类
abstract class A {
public abstract void say();
}
//使用abstract关键字修饰一个类时,这个类就叫做抽象类
abstract class B {
//使用abstract修饰一个方法的时候,这个方法就是抽象方法,抽象方法无方法体
public abstract void hi();
}
3.抽象类的应用场景
——当我们不知道父类的方法怎么使用的时候,可以把父类方法设置为抽象方法,让子类去实现这个抽象方法,含有抽象方法的类叫做抽象类
4.抽象类的细节讨论及实现
1)抽象类不能被实例化
public class Test {
public static void main(String[] args) {
}
}
//3.抽象类不能被实例化
abstract class C {
}
2)抽象类不一定要包含abstract方法,换种说法,抽象类可以没有抽象方法
3)一个类中只要有abstract方法,那么这个类也要使用abstract修饰
public class Test {
public static void main(String[] args) {
}
}
//抽象类不一定要包含abstract方法,也就是说,抽象类可以没有抽象方法
//一旦一个类中含有了抽象方法,那么这个类必须声明为抽象类
abstract class D {
//抽象方法
public abstract void method();
//非抽象方法
public void depart() {
System.out.println("启程~");
}
}
4)abstract只能修饰类和方法,不能修修饰其他属性
public class Test {
public static void main(String[] args) {
}
}
abstract class E {
//抽象方法
public abstract void radiant();
//6.abstract只能修饰类和方法,不能修饰其他属性
//public abstract int aae;
}
5)抽象类本质还是类,抽象类可以有任意成员【向上转型解决】
public class Test {
public static void main(String[] args) {
}
}
//抽象类的本质还是类,可以有任意成员: 非抽象方法、构造器、静态属性
abstract class F {
//抽象方法
public abstract void live();
//成员变量
public static int age = 10;
public int data = 11;
//构造器
public F() {
}
//非抽象方法
public void board() {
System.out.println("board的意思是董事会~");
}
}
6)抽象方法不能有方法体
7)如果一个类继承了抽象类,则它必须实现抽象类中的所有抽象方法或它也声明为抽象类
public class Test {
public static void main(String[] args) {
}
}
//如果一个类继承了抽象类,那么它必须实现抽象类的所有抽象方法,或者它也声明为抽象类
//抽象类
abstract class Person {
//抽象方法不能有方法体
public abstract void hi();
public abstract void go();
}
//1)实现全部的抽象方法
class Teacher extends Person {
public void hi() {
System.out.println("hi,bro~");
}
public void go() {
System.out.println("bro,go,go,go~");
}
}
//2) 将自己也声明为抽象类
abstract class Stu extends Person {
}
8)抽象方法不能使用private、final和static关键字修饰,因为这些关键字都与重写相违背
//1)为什么不能使用private? ——使用private修饰抽象方法后,这个抽象方法只能在本类使用,其他类不能实现它
//2)为什么不能使用final? ——使用final修饰抽象方法后,该方法不能被重写
//3)为什么不能使用static? ——抽象类不能被实例化,而且静态方法在类加载的时候就加载了,已经分配好了内存空间,
// 抽象类的抽象方法是需要被继承的子类进行重写的
5.抽象类最佳实践 —— 模板设计模式
1)什么是模板设计模式?
——定义一个操作中算法的骨架,而将一些步骤延迟到子类中,模板方法使得子类可以不改变算法的结构,只是重定义该算法的某些特定步骤
2)模板设计模式的优点
——编写一个抽象父类,父类提供了多个子类的通用方法,并把一个或多个方法留给其他子类实现(实现了代码的复用)
3)一个小case快速了解模板设计模式
public class Test {
public static void main(String[] args) {
Calculate calculate = new Calculate();
calculate.getDistance();//调用
}
}
abstract class Pattern {
//抽象方法
public abstract void cal();
public void getDistance() {
long start = System.currentTimeMillis();
cal();//存在动态绑定机制
long end = System.currentTimeMillis();
System.out.println("计算的时间是:" + (end - start));
}
}
class Calculate extends Pattern {
//重写了父类的抽象方法
public void cal() {
long sum = 0;
for (int i = 0; i < 10000000; i++) {
sum += i;
}
}
}
1.什么是接口?
——接口就是给出一些没有实现的方法,把这些方法封装到一起,当某个类要使用的时候,根据具体情况把这些方法写出来
2.接口的格式
interface 接口名 {
属性
抽象方法
}
interface Computer {
int age = 10;
void say();
}
3.类如何和接口完成对接?
class 类名 implements 接口 {
类的属性;
类的方法;
必须实现接口的抽象方法;
}
interface Computer {
int age = 10;
void say();
}
//类实现接口
class Usb implements Computer {
public void say() {
System.out.println("hello~");
}
}
4.接口的细节讨论及实现
1)接口不能实例化
public class Test {
public static void main(String[] args) {
//Person person = new Person();//接口不能实例化
}
}
//接口不能实例化
interface Person {
void say();
}
2)接口中方法都是抽象方法(除掉默认方法、静态方法),且这些抽象方法均是public的,接口中的抽象方法,不需要再写abstract
public class Test {
public static void main(String[] args) {
}
}
interface Computer {
//public void connect();
//abstract void connect();
//抽象方法
void connect();
void listen();
void keyBoard();
//默认方法: 可以在接口中实现具体的方法体
default void say() {
}
//静态方法: 可以在接口中实现具体的方法体
static void sing() {
}
}
3)普通类实现接口,必须把接口中的所有方法均实现
public class Test {
public static void main(String[] args) {
}
}
interface Computer {
//抽象方法
void connect();
void keyBoard();
}
//普通类实现接口中的方法
class Laptop implements Computer {
public void connect() {
System.out.println("连接网络~");
}
public void keyBoard() {
System.out.println("打字~");
}
}
4)抽象类实现接口,可以不用实现接口中的方法
public class Test {
public static void main(String[] args) {
}
}
interface Computer {
//抽象方法
void connect();
void keyBoard();
}
//抽象类可以不用实现接口中的方法
abstract class Honor implements Computer {
}
5)一个类可以同时实现多个接口,接口之间使用逗号隔开
public class Test {
public static void main(String[] args) {
}
}
interface Computer {
//抽象方法
void watch();
void keyBoard();
}
interface Usb {
void connect();
}
//一个类可以同时继承多个接口
class Laptop implements Computer,Usb {
@Override
public void watch() {
}
@Override
public void keyBoard() {
}
@Override
public void connect() {
}
}
6)接口中的属性是public static final 修饰的,所以我们需要初始化
7)接口中的属性访问形式:接口名.属性名
public class Test {
public static void main(String[] args) {
//接口中的属性访问形式:接口名.属性名
System.out.println(Computer.AGE);//18
}
}
interface Computer {
//接口中的属性是public static final 修饰的
//public static final int age = 10;
int AGE = 18;
}
8)接口不能继承其他的类,但是可以继承一个或多个接口,接口间逗号隔开
public class Test {
public static void main(String[] args) {
}
}
interface Computer {
void watch();
}
interface Laptop {
void listen();
}
//接口不能继承其他的类,但是可以继承接口
interface Phone extends Computer,Laptop {
}
9)接口的修饰符只能是pubic和默认,这点跟对类的修饰符是相同的
public class Test {
public static void main(String[] args) {
}
}
//默认接口
interface Computer {
void watch();
}
//单开文件
//public接口
public interface Laptop {
}
5.继承和接口的区别
1)继承解决了代码的复用性和可维护性
2)接口设计好了各种规范,让其他类去实现这些规范(灵活性)
3)继承是拥有了父类的各种功能,而接口可以理解为对子类扩展功能,也可以理解为接口是对Java单继承机制的一种补充
6.接口的多态特性
public class Test {
public static void main(String[] args) {
//接口数组
Computer[] computers = new Computer[2];
//给数组里填充内容
computers[0] = new Laptop();//向上转型
computers[1] = new Phone();//向上转型
print(computers);
}
private static void print(Computer[] computers) {
for (int i = 0; i < computers.length; i++) {
computers[i].listen();
computers[i].watch();
if (computers[i] instanceof Laptop) {
((Laptop) computers[i]).play();//向下转型
} else if (computers[i] instanceof Phone) {
((Phone) computers[i]).game();
} else {
System.out.print("");
}
}
}
}
//接口
interface Computer {
void watch();
void listen();
}
class Laptop implements Computer {
@Override
public void watch() {
System.out.println("用电脑看视频~");
}
@Override
public void listen() {
System.out.println("用电脑听歌~");
}
//特有方法
public void play() {
System.out.println("开黑~");
}
}
class Phone implements Computer {
@Override
public void watch() {
System.out.println("使用手机刷抖音~");
}
@Override
public void listen() {
System.out.println("打开QQ音乐听歌~");
}
//特有方法
public void game() {
System.out.println("王者荣耀走起~");
}
}
7.多态传递现象
public class Test {
public static void main(String[] args) {
//多态传递:Computer --> Usb --> Phone(实现)
//编译类型:Computer 运行类型:Phone
Computer phone = new Phone();
phone.watch();
phone.listen();
//phone.connect();
//为什么不能使用?
//因为编译类型只会找属于本类的,而connect是Usb的方法,不是Computer的方法
Usb phone1 = new Phone();
phone1.listen();
phone1.listen();
phone1.connect();//为什么可以? 因为Usb继承了Computer接口
}
}
interface Computer {
void watch();
void listen();
}
interface Usb extends Computer {
void connect();
}
//要全部实现接口中的方法
class Phone implements Usb {
@Override
public void watch() {
System.out.println("看电影~");
}
@Override
public void listen() {
System.out.println("听歌~");
}
@Override
public void connect() {
System.out.println("连接Usb~");
}
}