这一块的内容主要是有关final以及多态的概述和使用。
1.final
-
final关键字是最终的意思,可以修饰 类、成员变量、成员方法
- 修饰类,类不能被继承
- 修饰变量,变量就变成了常量,只能被赋值一次
- 修饰方法,方法不能被重写
- 在构造方法初始化完成之前赋值完毕(修饰的是非静态的常量)
-
常量:
- 字面值常量:
“java”、100、false - 自定义常量:
修饰变量,变量就变成了常量
final int x = 100;//此刻的x就是一个常量
- 字面值常量:
-
final变量的引入:
由于继承中有一个现象,子类的方法和父类的方法声明一样,出现重写现象,所以,父类的功能就会被子类覆盖。但有时候,我们不想让子类覆盖父类的方法或者功能,只能让子类使用,这个时候,针对这种情况,Java就提供了一个关键字:final
举例1:子类无法重写父类中被final修饰的方法
class Fu1{
public final void show(){
System.out.println("这是父类的方法");
}
}
class Zi extends Fu1{
// public void show(){
// System.out.println("子类无法重写父类的方法");
// }
}
public class ZiDemo {
public static void main(String[] args) {
Zi zi = new Zi();
zi.show();
}
}
//这是父类的方法
举例2:final修饰的变量不能被修改
class Fu2{
int num = 10;
final int num2 = 20;
public final void fun(){
System.out.println("这是父类的方法");
}
}
class Zi2 extends Fu2{
int num1 = 100;
public void show(){
num = 100;
// num2 = 20;//这也是一个不能被重写的变量
System.out.println(num);
System.out.println(num2);
}
// public void fun(){
// System.out.println("这是一个不能被重写的方法");
// }
}
public class FinalDemo1 {
public static void main(String[] args) {
Zi2 zi2 = new Zi2();
zi2.show();
zi2.fun();//这里打印的是父类的方法
final int x = 20;
// x = 30;//这是一个不能被该的变量
System.out.println(x);
}
}
//100
//20
//这是父类的方法
//20
- 面试题:final修饰局部变量
1、在方法内部,该变量不能被改变
2、final修饰引用数据类型的时候,引用的地址值不能发生改变,但是,该对象的堆内存里面的值是可以改变的
class Student1{
int age = 10;
}
public class FinalTest1 {
public static void main(String[] args) {
int x = 10;
x = 100;
System.out.println(x);
System.out.println("------------------");
final int y = 20;
// y = 200;//Java无法为最终变量y分配值
System.out.println(y);
System.out.println("------------------");
Student1 student1 = new Student1();
System.out.println(student1.age);
System.out.println("------------------");
final Student1 student2 = new Student1();
System.out.println(student2.age);
student2.age = 20;
System.out.println(student2.age);
System.out.println("------------------");
// student2 = new Student1();//Java无法为最终变量s2分配值
}
}
//100
//------------------
//20
//------------------
//10
//------------------
//10
//20
//------------------
2.多态
- 多态概述:某一个事物,在不同时刻表现出来的不同状态
- 举例:
水:
固态、液态、气态
固态的水是水、液态的水是水、气态的水是水
水果:
苹果、香蕉、西瓜
苹果是水果、香蕉是水果、西瓜是水果
但不能说水果是苹果、水果是香蕉 - 我们通过观察这些例子发现,要想有多态,必须要有继承,继承是多态的前提
- 多态的条件:
- 要有继承的关系
- 要有方法的重写
其实没有也可以,但是没有重写就没有意义 - 要有父类引用指向子类对象
父 f = new 子();
- 多态中成员访问特点
- 成员变量
编译看左边,运行看左边 - 构造方法
创建子类对象的时候,先访问父类的构造方法,对父类的数据先进行初始化 - 成员方法
编译看左边,运行看右边
因为成员方法存在重写,所以访问看右边 - 静态成员方法
编译看左边,运行看左边
由于被static修饰的都是与类相关的,算不上重写,所以,运行的时候,访问的还是左边的
- 成员变量
多态中访问成员变量、成员方法、静态成员方法举例:
class Fu3{
int num = 100;
int num2 = 20;
public void show(){
System.out.println("这是父类中的成员方法");
}
public static void show2(){
System.out.println("这是父类中的静态成员方法");
}
}
class Zi3 extends Fu3{
int num = 1000;
int num2 = 40;
public void show(){
System.out.println("这是子类中的成员方法");
}
public void fun(){
System.out.println("这是子类中的另一个成员方法");
}
public static void show2(){
System.out.println("这是子类中的静态成员方法");
}
}
public class Polymorphic {
public static void main(String[] args) {
Fu3 f = new Zi3();
System.out.println(f.num2);//成员变量,编译看左边,运行看左边
f.show();//成员方法,编译看左边,运行看右边
f.show2();//静态成员方法,编译看左边,运行还是看左边
}
}
//20
//这是子类中的成员方法
//这是父类中的静态成员方法
- 多态的好处
1、提高了代码的维护性(这是继承保证的)
2、提高了程序的扩展性(这是多态决定的) - 多态的弊端
不能访问子类的特有功能
多态的弊端举例:
在这个例子中,我们就无法访问子类的特有方法function
class Fu4{
public void show(){
System.out.println("这是父类的方法");
}
}
class Zi4 extends Fu4{
public void show(){
System.out.println("这是子类的方法");
}
public void function(){
System.out.println("这是子类特有的方法");
}
}
public class PolymorphicDemo3 {
public static void main(String[] args) {
Fu4 f = new Zi4();
f.show();
// f.function();//Error:(23, 10) java: 找不到符号
}
}
-
多态中的转型
我们刚刚发现了,子类不能调用自己特有的方法如果我就想使用多态来调用自己子类的特有方法,怎么办呢
这时我们就要使用到多态中的转型
Zi5 z = (Zi5) f2;多态中转型的使用:
向上转型:Fu5 f = new Zi5();
向下转型:Zi5 z = (Zi5) f2;
注意:这样的转型,必须要求f2必须是能够转换成z的,也就是说,他俩必须要是继承关系子类转换为父类,向上转型:自动转换
父类转换为子类,向下转型:强制转换
class Fu5{
public void show(){
System.out.println("这是父类的方法");
}
}
class Zi5 extends Fu5{
public void show(){
System.out.println("这是子类重写父类的方法");
}
public void function(){
System.out.println("这是子类特有的方法");
}
}
public class PolymorphicDemo4 {
public static void main(String[] args) {
Fu5 f = new Zi5();
f.show();
//多态中的转型,我们既然可以将子类的对象赋值给父,为什么不能把父的引用赋值给子引用
//将子的对象赋值给父
Fu5 f2 = new Zi5();
//将父的引用赋值给子的引用
Zi5 z = (Zi5)f2;
z.show();
z.function();
}
}
//这是子类重写父类的方法
//这是子类重写父类的方法
//这是子类特有的方法
- 多态的内存图
- 多态向下转型的一种异常
class Animal5{
public void eat(){}
}
class Dog5 extends Animal5{
public void eat(){}
public void lookDoor(){}
}
class Cat5 extends Animal5{
public void eat(){}
public void paShu(){}
}
public class PolymorphicDemo5 {
public static void main(String[] args) {
Animal5 a = new Dog5();
a.eat();
// a.lookDoor();
Dog5 d = (Dog5) a; //在我自己看来,这地方就直接相当于是:Dog5 d = new Dog5() ,就可以直接使用Dog5里面所有的东西了
a = new Cat5();
a.eat();
// ((Cat5) a).paShu();
Cat5 cat5 = (Cat5)a;
cat5.eat();
cat5.paShu();
a = new Animal5();
// Dog5 dd = (Dog5)a;//因为这个a现在是赋给了cat,而这句话dog和cat,两个没有继承关系,所以报错
}
}
- 附上一道很有意思的题目,结果在代码最后
package com.bigdata.shujia12;
/*
看程序写结果:先判断有没有问题,如果没有,写出结果
多态访问成员方法的特点:
编译看左边,运行看右边
存在继承的时候:
1、子类中有父类一样的方法,叫重写
2、子类中没有出现父类的方法(没有 明确重写),方法直接继承自父类
*/
class A {
public void show() {
show2();
}
public void show2() {
System.out.println("我");
}
}
class B extends A {
public void show() {
show2();
}
public void show2() {
System.out.println("爱");
}
}
class C extends B {
public void show() {
super.show();
}
public void show2() {
System.out.println("你");
}
}
public class DuoTaiTest4 {
public static void main(String[] args) {
A a = new B();
a.show(); // 爱
B b = new C();
b.show(); //你 //方法的重写
}
}
//爱
//你
感谢阅读,我是啊帅和和,一位大数据专业即将大四学生,祝你快乐。