1,final关键字
1,认识final
final 关键字最终的意思,可以用来修饰(类,方法,变量)
特点:
- 修饰类类不能被继承
- 修饰方法,方法不能被子类重写
- 修饰变量,该变量只能被赋值一次
final修饰基本数据类型,变量存储的数据不能被改变
final修饰引用类型变量,变量存储的地址不能被改变,但是地址所指向的内容可以改变
示例代码如下:
public class Test {
// 注意这里的变量必须要有初始值,因为成员变量如果不赋值的话,是默认值,
// 默认值对于final来说毫无意义,因为后面就不可以修改了,所以需要在定义的时候就赋值
final String name = "jack";
// name = "b"; 报错
public static void main(String[] args) {
// 引用数据类型
final int[] ints = new int[2];
int[] arr1 = {1, 2};
// ints = arr1; // 提示: Cannot assign a value to final variable 'ints'
// 但是可以改变其中的数据
ints[1] = 100;
System.out.println(ints[1]); //100
}
}
2,常量
使用了 static final 修饰的成员变量就被成为常量
作用:通常用于记录系统的配置信息
规范:常量名大写,单词之间用下划线连接
public static final String STUDENT_SCHOOL_NAME = "五道口职业技术学院";
使用常量记录系统配置信息的优势和执行原理:
-
代码可读性更好,可维护性更好,因为这个常量可能在很多地方时候,如果需要修改,只需要修改这一个地方即可
-
原理:程序编译后,常量会被“宏替换‘ 出现常量的地方全部会被替换为其记住的常量(字面量),这样可以保证使用常量和直接用字面量的性能是一样的
2,抽象类
1,认识抽象类
什么是抽象类?
在Java中有一个关键字叫:abstract,它就是抽象的意思,可以用它修饰类、成员方法
abstract修饰类,这个类就是抽象类;修饰方法,这个方法就是抽象方法。
修饰符 abstract class 类名{
修饰符 abstract 返回值类型 方法名称(形参列表);
}
2,注意事项,和特点
- 抽象类中的方法不一定是抽象方法,有抽象方法的类一定是抽象类
- 类该有的成员,抽象类都有 (成员变量,方法,构造器,代码块,匿名内部类)
- 抽象类主要的特点:抽象类不能创建对象,仅作为一种特殊的父类,让子类继承实现
- 一类继承抽象类,必须重写完抽象类的全部抽象方法,否则这个类也必须定义为抽象类
3,抽象类的场景和好处
应用场景,因为抽象类的子类必须要实现其抽象方法,所以,当需要强制子类实现某个方法时可以使用。
好处:提高了代码的复用性
4,应用案例 模板方法设计
场景:有两个方法,这两个方法的开头和结尾,都是相同的代码,只有中间部分不同,这个时候就可以用模板方法来设计
写法:
1,定义一个抽象类
2,在里面定义两个方法
* 一个是模板方法,用于把相同的代码放进去
* 一个是抽象方法,用于让子类具体实现内容
比如说:写作文,要求开头和结尾必须相同,中间的内容是自己学的 ,这样就可以使用模板方法来更好的实现这个需求。示例代码如下:
abstract class MuBan {
// 这里的作文具体的实现方法必须要是final,防止实现类去修改
final void write() {
System.out.println("在记忆中");
// 在这里补充调用一下,文章的主要内容
content();
System.out.println("这就是我的好爸爸。");
}
// 定义一个抽象方法,用来让子类强制实现这个方法
abstract void content();
}
class Student extends MuBan {
@Override
void content() {
System.out.println("那是一个秋天,风儿那么缠绵,爸爸骑车接我放学,我的脚卡在了车链中,爸爸蹬不动,于是他就站起来蹬..");
}
}
public class TestAbstract {
public static void main(String[] args) {
Student student = new Student();
student.write();
}
}
3,接口
1,认识接口
Java提供了一个关键字interface,用这个关键字我们可以定义出一个特殊的结构:接口。JDK 8之前,接口中只能定义成员变量和成员方法。
public interface 接口名 {
// 成员变量(常量)
// 成员方法(抽象方法)
}
注意点:接口不能创建对象;接口是用来被类实现(implements)的,实现接口的类称为实现类。
修饰符 class 实现类 implements 接口1, 接口2, 接口3 , ... {
}
个类可以实现多个接口(接口可以理解成干爹),实现类实现多个接口,必须重写完全部接口的全部抽象方法,否则实现类需要定义成抽象类,这一点和抽象类基本一样,可以结合着记忆。
接口的好处:
- 弥补了类单继承的不足,一个类同时可以实现多个接口。
- 让程序可以面向接口编程,这样程序员就可以灵活方便的切换各种业务实现
2,接口的细节1
JDK 8开始,接口陆续新增了三种形式的方法:
public interface A{
/**
* 1、默认方法(实例方法):使用用default修饰,默认会被加上public修饰。
* 注意:只能使用接口的实现类对象调用
*/
default void test1(){
...
}
/**
* 2、私有方法:必须用private修饰(JDK 9开始才支持)
作用:为了把默认方法中公共的部分提出来
*/
private void test2(){
...
}
/**
* 3、类方法(静态方法):使用static修饰,默认会被加上public修饰。
* 注意:只能用接口名来调用。
*/
static void test3(){
...
}
}
这几个方法的增加,增强了接口的能力,更便于项目的扩展和维护
2,接口的细节2 接口的多继承以及接口的注意事项
public interface C extends B , A{
}
注意事项:
- 一个接口继承多个接口,如果多个接口中存在方法签名冲突,则此时不支持多继承。如下,返回值一个int,一个void这样子就冲突,就不在支持多继承
interface A{
void method();
}
interface B{
int method();
}
interface C implements A,B{ }
-
一个类实现多个接口,如果多个接口中存在方法签名冲突,则此时不支持多实现。同上
-
一个类继承了父类,又同时实现了接口,父类中和接口中有同名的默认方法,实现类会优先用父类的
-
一个类实现了多个接口,多个接口中存在同名的默认方法,可以不冲突,这个类重写该方法即可。
4,多态
1,认识多态
什么是多态?
- 多态是在继承/实现情况下的一种现象,表现为:
- 对象多态,是指同一个对象,在不同时刻可以拥有不同的形态,表现出不同的功能
- 行为多态,是指多个对象的同一个方法表现出的不同的效果
多态的前提条件:
- 有继承/实现关系
- 存在父类引用指向子类对象
- 存在方法的重写
重点:易错点:重视!重视!重视!
多态是对象,行为的多态,java中的属性(成员变量)没有多态
People people1 = new Student();
people1.run();
这里的Student是People的一个子类,并且重写了父类的run()方法。
那么调用的时候是父类的run还是子类的run呢?
在代码编译的时候,看的是父类,也就是说,people1.run();如果people没有这个方法,那么就会报错。但等到执行的时候,看的是等号右边的对象,是谁的就调用谁的重写的方法
2,使用多态的好处,弊端以及类型转换问题
好处:
-
多态形式下,右边对象是解耦合的,更便于扩展和维护。
-
定义方法时,使用父类类型的形参,可以接收一切子类对象,扩展性更强、更便利。
弊端:
多态状态下的对象不能调用子类的独有的方法。
解决方法:
强制类型转换,即将父类对象转换为子类对象,这样就可以使用了
强制类型转换的注意事项:
-
存在继承/实现关系就可以在编译阶段进行强制类型转换,编译阶段不会报错。
-
运行时,如果发现对象的真实类型与强转后的类型不同,就会报类型转换异常(ClassCastException)的错误出来。
通过综合案例来理解:
题目:你是宠物店老板,你的员工负责各种动物的日常喂养,你要做的就是指挥员工去喂养你指定的宠物。
首先定义一个宠物类作为父类:
public class Pet {
// 因为只有成员方法才有多态,所以这里就不在写成员变量
// 定义一个eat方法
public void eat(){
};
}
定义一个猫类为宠物的子类:
public class Cat extends Pet{
@Override
public void eat() {
System.out.println("小猫正在吃猫粮~~~~~");
}
}
定义一个狗类为宠物的子类:
public class Dog extends Pet {
@Override
public void eat() {
System.out.println("狗狗在吃骨头~~~");
}
// 定义一个狗类独有的看门的方法
public void LookHome() {
System.out.println("狗子正在看门~~~~~");
}
}
定义一个饲养员类,有喂养宠物的方法:
public class Feeder {
public void feedPet(Pet pet) {
pet.eat();
}
}
最后就是主人类:
public class Master {
public static void main(String[] args) {
// 主人的宠物有猫,狗
Cat cat = new Cat();
Dog dog = new Dog();
// 这是饲养员
Feeder feeder = new Feeder();
// 主人让饲养员去喂养猫
feeder.feedPet(cat);
// 主人让饲养员去喂养狗
feeder.feedPet(dog);
}
}
通过主人就体现出了多态的好处,在饲养员饲养动作不变的情况下,主人传递什么动物,饲养员就可以去喂养什么动物。
回到最初的问题,那么怎么才能获取到子类中的独有的方法呢?
在饲养员喂养的方法中,将动物类,强制类型转换为Dog类。但是问题又来了,如果传递的参数是Cat该怎么办?
这样就应运而生了instanceof关键字,用来做判断。修改后的代码如下:
public class Feeder {
public void feedPet(Pet pet) {
pet.eat();
// 判断一下,传过来的对象是不是Dog的引用
if (pet instanceof Dog){
// 说明是,这个时候再做强制类型转换
Dog dog = (Dog)pet;
// 转换之后就是dog对象,那么肯定可以调用自己方法
dog.LookHome();
}
}
}
标签:day02,void,多态,接口,面向对象,抽象类,方法,public
From: https://www.cnblogs.com/yfs1024/p/17153489.html