Java面向对象(三)

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();
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值