final关键字
我们如果说父类的东西不想让子类去继承:
可以使用private修饰或者static
由于继承方法中有一个现象:方法重写
所以,当方法可以被重写的时候,父类原本的方法还在,但是调用是子类重写后的
方法,如果我依旧想保留父类原本的方法,不想让子类重写,但是呢,我想让子类去用
针对于这样的情况,java提供了一个关键字:final
定义
final: 最终的意思,不可以改变的意思。
使用格式
一般情况下,把final放在访问权限修饰与返回值之间
常见的情况下,final不仅可以修饰成员方法,也可以修饰类,变量
class Father4{
//被final修饰的成员方法,不能被子类重写。
public final void fun(){
System.out.println("这是父类的fun方法");
}
}
class Son4 extends Father4{
// public void fun(){
// System.out.println("这是父类的fun方法");
// }
}
public class ExtendsDemo6 {
public static void main(String[] args) {
}
}
final:最终的意思,它可以修饰变量,类,方法
特点:
1、被final所修饰的类无法被其他类所继承
//被final修饰的类不能被继承
final class Fu1{
}
class Zi1 extends Fu1{
}
public class FinalDemo1 {
public static void main(String[] args) {
}
}
2、被final修饰的方法,子类无法重写,但是在同一个类中可以出现同名不同参数列表的被final修饰的方法,这是重载
class Fu1{
public final void fun1(){
System.out.println("这是父类中的fun1方法");
}
public final void fun1(String s){
System.out.println("这是父类中的fun1方法");
}
}
总结一句话:被final修饰的方法不能被重写,但是可以被重载
3、被final修饰的变量变成了常量,无法再重新分配值。
class Fu1{
public final void fun1(){
System.out.println("这是父类中的fun1方法");
}
public final void fun1(String s){
System.out.println("这是父类中的fun1方法");
}
}
class Zi1 extends Fu1{
final int a=10; //被final修饰的变量变成了常量,无法再重新分配值。
public void fun2(){
System.out.println("a:"+a);
}
}
public class FinalDemo1 {
public static void main(String[] args) {
Zi1 zi1 = new Zi1();
zi1.fun2();
zi1.a=200;
zi1.fun2();//报错
}
}
常量:
A: 字面值常量:
10,12.34,"hello",'a',true
B: 自定义常量
其实就是被final修饰的变量。
final int a = 10;
注意:被final修饰变量,只要在构造方法完毕之前赋值就可以了。下面是两种赋值途径
class Fu2{
final int b;
Fu2(){
b = 30;//构造方法完毕前赋值
System.out.println(b);
}
}
public class FinalDemo3 {
public static void main(String[] args) {
}
}
class Fu2{
final int b;
{
b = 100;//构造代码块赋值
}
Fu2(){
System.out.println(b);
}
}
public class FinalDemo3 {
public static void main(String[] args) {
}
}
4、被final修饰的局部变量是基本数据类型的时候,不可以修改值
public class FinalDemo2 {
public static void main(String[] args) {
int a=10;
System.out.println(a);
a=100;
System.out.println(a);
final int b=20;
System.out.println(b);
b=200;//b被final修饰,所以不可以重新赋值
System.out.println(b);//报错
}
}
5、被final修饰的局部变量是引用数据类型的时候,该对象的地址值是无法改变的, 但是引用堆内存中的变量是可以发生改变。
class Student {
int age = 18;
}
public class FinalDemo2 {
public static void main(String[] args) {
Student s1 = new Student();
System.out.println(s1.age);
final Student s2 = new Student();
System.out.println(s2.age);
//s2 = s1;报错。被final修饰的局部变量s2是引用数据类型,地址值无法改变
s2.age = 20;//age并没有被final修饰,所以可以改变
System.out.println(s2.age);
}
}
多态的概述
程序引例
/*
多态概述:
某一个事物,在不同时刻表现出来的不同状态。
举例:
水(气态,液态,固态)
多态的前提:(同时满足)
1、要有继承关系
2、要有方法重写
你可以不去重写,但是呢,如果不重写,从常理来说,就无法体现子类的特性
3、要有父类引用指向子类对象
父 fu = new 子();
动物 d = new 狗(); //读法:从右往左去读 狗是动物
水 s = new 冰(); //读法:从右往左去读 冰是水
*/
class Animal{
String name;
String type;
public void eat(){
System.out.println("吃饭");
}
}
//1、要有继承关系
class Dog extends Animal{
//2、要有方法重写
@Override
public void eat() {
System.out.println("狗吃肉");
}
}
public class PolymorphicDemo1 {
public static void main(String[] args) {
//3、要有父类引用指向子类对象//多态类创建对象
Animal animal = new Dog();
}
}
多态访问成员的特点
程序示例
/*
多态访问成员的特点:
1、成员变量
编译看左边,运行也看左边。
编译看左边:指的是看父类中有没有该成员,如果有说明编译不报错,可以进行访问
运行看左边:指的是编译不报错的前提下,去访问父类中的成员。
2、构造方法
创建子类对象的时候,初始化子类先调用子类的构造方法,
子类中的构造方法第一句默认有一个super()
3、成员方法
编译看左边,运行看右边
编译看左边:指的是看父类中有没有该成员,如果有说明编译不报错,可以进行访问
运行看右边:指的是编译不报错的前提下,去访问子类中的成员。
4、静态方法
编译看左边,运行也看左边
(算不上重写了,访问的是类本身的东西)
记忆方法:除了成员方法:编译看左边,运行看右边
其他都是:编译看左边,运行也看左边
*/
class Animal{
int a = 10;
Animal(){
System.out.println("Animal中的无参构造方法");
}
public void eat(){
System.out.println("吃饭");
}
public static void sleep(){
System.out.println("睡觉");
}
}
class Dog extends Animal{
int a = 20;
Dog(){
System.out.println("Dog中的无参构造方法");
}
@Override
public void eat() {
System.out.println("狗吃肉");
}
public static void sleep(){
System.out.println("侧着睡");
}
}
public class PolymorphicDemo1 {
public static void main(String[] args) {
// 多态类创建对象
Animal animal = new Dog();
// System.out.println(animal.a); //输出结果为Animal类中的a值为10
animal.eat();
animal.sleep();
// 静态成员可以通过类名调用
// Animal.sleep();
}
}
多态的好处
- 代码扩展性很好(由继承所带来的好处)
- 代码的维护性很好(由多态所带来的好处)
父类静态成员全局共享
父类中,static修饰的静态成员变量以及静态成员方法由全局共享
class A{
//父类中的静态成员可以看作是一个全局共享的
public static int a = 10;
public static void fun(){
System.out.println("hello");
}
}
class B extends A{
}
}
public class ExtendsQuestion {
public static void main(String[] args) {
B b = new B();
System.out.println(b.a);//10 (父类成员变量全局共享)
b.fun();//hello (父类成员方法全局共享)
}
}
class A{
//父类中的静态成员可以看作是一个全局共享的
public static int a = 10;
public static void fun(){
System.out.println("hello");
}
}
class B extends A{
public void fun2(){
a = 200;
System.out.println(a);
}
}
public class ExtendsQuestion {
public static void main(String[] args) {
B b = new B();
System.out.println(b.a);//10 (先初始化父类成员变量)
b.fun();//hello (先初始化父类成员方法)
b.fun2();//200 (子类的成员方法)
System.out.println(b.a);//200 (子类成员变量)
}
}
class A{
//父类中的静态成员可以看作是一个全局共享的
public static int a = 10;
public static void fun(){
System.out.println("hello");
}
}
class B extends A{
public void fun2(){
a = 200;
System.out.println(a);
}
public static void fun(){
System.out.println("world");
}
}
public class ExtendsQuestion {
public static void main(String[] args) {
B b = new B();
System.out.println(b.a);//10
b.fun();//world (子类静态成员方法属于本类,static修饰的成员与父类没有继承关系)
b.fun2();//200
System.out.println(b.a);//200
}
}
多态向下转型
多态的前提
1、要有继承的关系
2、子类要重写父类中的方法
3、要有父类的引用指向子类对象
多态的弊端:
多态无法使用子类特有的方法
class Father1{
public void fun(){
System.out.println("这是父类中的fun方法");
}
}
class Son1 extends Father1{
public void fun(){
System.out.println("这是子类中的fun方法");
}
public void show(){
System.out.println("这是子类中特有的show方法");
}
}
public class PolymorphicDemo1 {
public static void main(String[] args) {
//多态创建子类对象
Father1 f = new Son1();
f.fun();//这是子类中的fun方法(多态与成员方法的关系:编译看左,运行看右)
//需求:现在我想调用子类中特有的方法,咋办
//f.show();
}
}
需求:现在我想调用子类中特有的方法,咋办
f.show();
多态的弊端:
多态无法使用子类特有的方法
我就想使用子类特有的功能,能否使用? 能
使用子类特有功能的方法
1、创建对应的子类并调用方法
可以,但是不推荐,很多时候会占用堆内存空间
class Father2 {
public void fun() {
System.out.println("这是父类的fun方法");
}
}
class Son2 extends Father2 {
public void fun() {
System.out.println("这是子类的fun方法");
}
public void show() {
System.out.println("这是子类的show方法");
}
}
public class PolymorphicDemo2 {
public static void main(String[] args) {
Son2 son2 = new Son2();
son2.show();
2、java提我们考虑到了这一点,提供了一个技术给我们使用:向下转型
把父类的引用强制转换成子类的引用
子类类名 变量名 = (子类类名)父类的引用
class Father2 {
public void fun() {
System.out.println("这是父类的fun方法");
}
}
class Son2 extends Father2 {
public void fun() {
System.out.println("这是子类的fun方法");
}
public void show() {
System.out.println("这是子类的show方法");
}
}
public class PolymorphicDemo2 {
public static void main(String[] args) {
//多态创建子类对象(向上转型)
Father2 f = new Son2();
f.fun();
//多态中的向下转型
Son2 s = (Son2) f;
s.show();
}
}
对象之间转型的问题:
1、向上转型
其实就是多态创建对象的写法
Fu f = new Son();
2、向下转型
Son s = (Son)f;
基本数据类型之间的强转:
int a = 10;
byte b = (byte)a;
向下转型的注意事项:
要求必须是存在继承关系的
class Father2 {
public void fun() {
System.out.println("这是父类的fun方法");
}
}
class Son2 extends Father2 {
public void fun() {
System.out.println("这是子类的fun方法");
}
public void show() {
System.out.println("这是子类的show方法");
}
}
class Demo{
}
public class PolymorphicDemo2 {
public static void main(String[] args) {
Father2 f = new Son2();
Demo d = (Demo) f;//报错。Demo类与Father2类不存在继承的关系
}
}
对多态向下转型的理解
多态的向下转型:
存在多态的前提:(缺一不可)
1、要有继承关系
2、要有方法重写
3、要有父类的引用指向子类对象
class 曹操{
int age = 50;
public void fight(){
System.out.println("赤壁之战")
}
}
class 曹植 extends 曹操{
int age = 28;
public void fight(){
System.out.println("习武练习");
}
public void xieShi(){
System.out.println("写诗,习惯将名字写在诗的尾部");
}
}
某一天,要发生赤壁之战,曹操拉肚子了,临时战场上没有人指挥,曹植看到了
他立刻换上父亲的衣服,贴上假胡子,假扮父亲上战场指挥。
//这种现象,叫向上转型,多态的引用
曹操 c = new 曹植();
c.fight(); // "习武练习"
//一旦写诗就暴漏了
//c.xieShi();
这时候,曹操上完厕所了回来,告知曹植说我回来了。
这时候曹植脱下父亲的衣服,撕掉假扮的胡子,回到自己的身份
//这个现象叫做向下转型
曹植 c2 = (曹植)c;
c.fight();
//这时候就可以写诗了
c.xieShi();