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}
}
使用了 static final 修饰的成员变量就被称为常量
**作用:**通常用于记录系统的配置信息
**规范:**常量名大写,单词之间用下划线连接
public static final String STUDENT_SCHOOL_NAME = "五道口职业技术学院";
使用常量记录系统配置信息的优势和执行原理:
代码可读性更好,可维护性更好,因为这个常量可能在很多地方时候,如果需要修改,只需要修改这一个地方即可
原理:程序编译后,常量会被“宏替换‘ 出现常量的地方全部会被替换为其记住的常量(字面量),这样可以保证使用常量和直接用字面量的性能是一样的
什么是抽象类?
在Java中有一个关键字叫:abstract,它就是抽象的意思,可以用它修饰类、成员方法
abstract修饰类,这个类就是抽象类;修饰方法,这个方法就是抽象方法。
修饰符 abstract class 类名{修饰符 abstract 返回值类型 方法名称(形参列表);}
应用场景,因为抽象类的子类必须要实现其抽象方法,所以,当需要强制子类实现某个方法时可以使用。
好处:提高了代码的复用性
场景:有两个方法,这两个方法的开头和结尾,都是相同的代码,只有中间部分不同,这个时候就可以用模板方法来设计
写法:
1,定义一个抽象类
2,在里面定义两个方法* 一个是模板方法,用于把相同的代码放进去* 一个是抽象方法,用于让子类具体实现内容
比如说:写作文,要求开头和结尾必须相同,中间的内容是自己学的 ,这样就可以使用模板方法来更好的实现这个需求。示例代码如下:
abstract class MuBan {// 这里的作文具体的实现方法必须要是final,防止实现类去修改final void write() {System.out.println("在记忆中");
// 在这里补充调用一下,文章的主要内容content();System.out.println("这就是我的好爸爸。");}// 定义一个抽象方法,用来让子类强制实现这个方法abstract void content();
}class Student extends MuBan {@Overridevoid content() {System.out.println("那是一个秋天,风儿那么缠绵,爸爸骑车接我放学,我的脚卡在了车链中,爸爸蹬不动,于是他就站起来蹬..");}
}public class TestAbstract {public static void main(String[] args) {Student student = new Student();student.write();}
}
Java提供了一个关键字interface,用这个关键字我们可以定义出一个特殊的结构:接口。JDK 8之前,接口中只能定义成员变量和成员方法。
public interface 接口名 {// 成员变量(常量)默认是被 public static final修饰// 成员方法(抽象方法) 默认是被 public abstract修饰
}
**注意点:**接口不能创建对象;接口是用来被类实现(implements)的,实现接口的类称为实现类。
修饰符 class 实现类 implements 接口1, 接口2, 接口3 , ... {}
子类可以实现多个接口(接口可以理解成干爹),实现类实现多个接口,必须重写完全部接口的全部抽象方法,否则实现类需要定义成抽象类,这一点和抽象类基本一样,可以结合着记忆。
接口的好处:
JDK 8开始,接口陆续新增了三种形式的方法:
public interface A{/*** 1、默认方法(实例方法):使用用default修饰,默认会被加上public修饰。* 注意:只能使用接口的实现类对象调用*/default void test1(){...}/*** 2、私有方法:必须用private修饰(JDK 9开始才支持)作用:为了把默认方法中公共的部分提出来*/private void test2(){...}/*** 3、类方法(静态方法):使用static修饰,默认会被加上public修饰。* 注意:只能用接口名来调用。*/static void test3(){...}
}
这几个方法的增加,增强了接口的能力,更便于项目的扩展和维护
public interface C extends B , A{
}
注意事项:
interface A{void method();
}interface B{int method();
}interface C implements A,B{ }
一个类实现多个接口,如果多个接口中存在方法签名冲突,则此时不支持多实现。同上
一个类继承了父类,又同时实现了接口,父类中和接口中有同名的默认方法,实现类会优先用父类的
一个类实现了多个接口,多个接口中存在同名的默认方法,可以不冲突,这个类重写该方法即可。
什么是多态?
多态的前提条件:
重点:易错点:重视!重视!重视!
多态是对象,行为的多态,java中的属性(成员变量)没有多态
People people1 = new Student();
people1.run();
这里的Student是People的一个子类,并且重写了父类的run()方法。
那么调用的时候是父类的run还是子类的run呢?
在代码编译的时候,看的是父类,也就是说,**people1.run();**如果people没有这个方法,那么就会报错。但等到执行的时候,看的是等号右边的对象,是谁的就调用谁的重写的方法
好处:
多态形式下,右边对象是解耦合的,更便于扩展和维护。
定义方法时,使用父类类型的形参,可以接收一切子类对象,扩展性更强、更便利。
弊端:
多态状态下的对象不能调用子类的独有的方法。
解决方法:
强制类型转换,即将父类对象转换为子类对象,这样就可以使用了
强制类型转换的注意事项:
存在继承/实现关系就可以在编译阶段进行强制类型转换,编译阶段不会报错。
运行时,如果发现对象的真实类型与强转后的类型不同,就会报类型转换异常(ClassCastException)的错误出来。
通过综合案例来理解:
题目:你是宠物店老板,你的员工负责各种动物的日常喂养,你要做的就是指挥员工去喂养你指定的宠物。
首先定义一个宠物类作为父类:
public class Pet {
// 因为只有成员方法才有多态,所以这里就不在写成员变量
// 定义一个eat方法public void eat(){};
}
定义一个猫类为宠物的子类:
public class Cat extends Pet{// 重写父类的eat方法@Overridepublic void eat() {System.out.println("小猫正在吃猫粮~~~~~");}
}
定义一个狗类为宠物的子类:
public class Dog extends Pet {// 重写父类的eat方法@Overridepublic 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();}}
}
本文发布于:2024-01-28 21:04:14,感谢您对本站的认可!
本文链接:https://www.4u4v.net/it/170644706110268.html
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,我们将在24小时内删除。
留言与评论(共有 0 条评论) |