类和面向对象、多态、继承、抽象类

1、this的含义和使用

  • this含义: this代表当前调用方法的引用,哪个对象调用this所在的方法,this就代表哪一个对象

  • this关键字其主要作用是区分同名的局部变量和成员变量

    • 方法的形参如果与成员变量同名,不带this修饰的变量指的是形参,而不是成员变量
    • 方法的形参没有与成员变量同名,不带this修饰的变量指的是成员变量
  • this的使用格式:

    this.成员变量名
    
  • 使用 this 修饰方法中的变量,解决成员变量被隐藏的问题,

2、继承

2.1.2 继承的含义

继承:在java中指的是“一个类”可以“继承自”“另一个类”。 "被继承的类"叫做: 父类/超类/基类,"继承其他类的类"叫做:子类。继承后,“子类”中就“拥有”了“父类”中所有的成员(成员变量、成员方法)。 “子类就不需要再定义了”。

2.1.3 继承的好处

  1. 提高代码的复用性(减少代码冗余,相同代码重复利用)。
  2. 使类与类之间产生了关系。可以作为多态的前提

继承的格式

通过 extends 关键字,可以声明一个子类继承另外一个父类,定义格式如下:

class 父类 {
	...
}

class 子类 extends 父类 {
	...
}

需要注意Java是单继承的,一个类只能继承一个直接父类,并且满足is-a的关系,例如:Dog is a Animal, Student is a Person

通过继承可以将一些共性的属性,行为抽取到一个父类中,子类只需要继承即可,提供了代码的复用性

继承后成员访问规则

继承后构造方法的访问规则

  • 构造方法不能被继承
class Fu {
    // 构造方法
    Fu(){}
    Fu(String name,int age){}
}

class Zi extends Fu{

}

public class Test {
    public static void main(String[] args) {
        /*
            构造方法的访问规则:父类的构造方法不能被子类继承
            私有成员的访问规则:
            非私有成员的访问规则:
         */
        //Zi zi = new Zi("张三",18);// 编译报错,因为没有继承
    }
}

继承后私有成员的访问规则

父类的“私有成员”可以被子类继承,但子类不能被直接访问。

public class Fu{
    private int num = 100;//私有成员,只能在父类内部使用。
    private void method(){
        System.out.println("私有成员方法");
    }
}
public class Zi extends Fu{

}
public class Demo {
    public static void main(String[] args) {
        Zi z = new Zi();
	    System.out.println(z.num);// 编译错误
        z.method();// 编译错误
    }
}

继承后非私有成员的访问规则

  • 当通过“子类”访问非私有成员时,先在子类中找,如果找到就使用子类的,找不到就继续去“父类”中找。
public class Fu{
    int money = 100;
    public void method(){
        System.out.println("Fu 类中的成员方法method");
    }
}
public class Zi extends Fu{
    int money = 1;
     public void method(){
        System.out.println("Zi 类中的成员方法method");
    }
}
public class Demo{
    public static void main(String[] args){
        Zi z = new Zi();
        System.out.println(z.money);//1
        z.method();// Zi 类中的成员方法method
    }
}

一个java文件中可以定义多个类,但该文件中只能有一个public修饰的类,该类的类名与文件名一致

方法重写

方法重写的概念

方法重写 :子类中出现与父类一模一样的方法时(返回值类型,方法名和参数列表都相同),会出现覆盖效果,也称为重写或者复写。声明不变,重新实现

重写的注意事项

1、方法重写是发生在子父类之间的关系。

2、子类方法重写父类方法,返回值类型、方法名和参数列表都要一模一样。

3、子类方法重写父类方法,必须要保证权限大于等于父类权限。
访问权限从大到小: public > protected > 默认(空) > private

4、使用@Override注解,检验是否重写成功,重写注解校验!
建议重写方法都加上这个注解,一方面可以提高代码的可读性,一方面可以防止重写出错!

方法重写的使用场景:

当父类的方法无法满足子类的需求的时候,子类就会去重写父类的方法

class Fu{
    public void sport(){
        System.out.println("Fu 运动的方式跑步");
    }

    public void run(){
        System.out.println("Fu 第1圈");
        System.out.println("Fu 第2圈");
        System.out.println("Fu 第3圈");
    }
}

class Zi extends Fu{
    // 1、子类方法的实现和父类方法的实现完全不同
    @Override
    public void sport() {
        System.out.println("Zi 运动的方式游泳");
    }

    // 2、子类方法的实现要保留父类方法的功能,但要在父类功能的基础之上额外增加功能
    @Override
    public void run() {
        // 让父类的方法执行=====复制父类的代码过来
        super.run();// 调用父类的方法

        // 额外增加的代码
        System.out.println("Zi 第4圈");
        System.out.println("Zi 第5圈");
        System.out.println("Zi 第6圈");
        System.out.println("Zi 第7圈");
        System.out.println("Zi 第8圈");
        System.out.println("Zi 第9圈");
        System.out.println("Zi 第10圈");
    }
}

this和super关键字

this和super关键字的介绍

  • this:存储的“当前对象”的引用;
    • this可以访问:本类的成员属性、成员方法、构造方法;
  • super:存储的“父类对象”的引用;
    • super可以访问:父类的成员属性、成员方法、构造方法;

this关键字的三种用法

this访问本类成员变量: this.成员变量
用来区分同名的局部变量和成员变量

public class Student{
    String name = "张三";
    public void show(){
        String name = "李四";
        System.out.println("name = " + name);// 李四
        System.out.println("name = " + this.name);// 张三
    }
}

this访问本类成员方法: this.成员方法名();

public class Student{
    public void show(){
        System.out.println("show方法...");
        this.eat(); //基本不用,this可省略,
    }
    public void eat(){
        System.out.println("eat方法...");
    }
}

this访问本类构造方法: this()可以在本类的一个构造方法中,调用另一个构造方法

public class Student{
    public Student(){
        System.out.println("空参构造方法...");
    }

    public Student(String name) {
        this();//当使用this()调用另一个构造方法时,此代码必须是此构造方法的第一句有效代码。
        System.out.println("有参构造方法...");
    }
}
public class Demo {
    public static void main(String[] args) {
            /*
            this访问本类的构造方法:
                访问本类的空参构造方法: this();
                访问本类的有参构造方法: this(有参);
                    注意:
                        1.在构造方法中调用其他构造方法,必须放在构造方法的第一行
                        2.使用this访问本类的构造方法,只能在本类的构造方法中使用
                        3.本类构造方法之间不能同时相互调用
         */
        Student stu2 = new Student();
    }
}

super关键字的三种用法

super访问父类的成员变量: super.父类成员变量名
作用: 区分同名的本类成员变量和父类成员变量

class Fu{
    int num = 100;
}

class Zi extends Fu{
    int num = 10;

    public void show(){
        int num = 1;
        System.out.println("局部变量num:"+num);// 1
        System.out.println("Zi 类中的num:"+this.num);// 10
        System.out.println("Fu 类中的num:"+super.num);// 100
      }
}

super访问父类的成员方法: super.成员方法名();
大多数用在重写方法中

class Fu{
    public void method(){
        System.out.println("Fu method");
    }
}
class Zi extends Fu{
    @Override
    public void method(){
        System.out.println("Zi method");
    }

    public void show(){
        // 访问本类的method方法
        method();
        // 访问父类的method方法
        super.method();
    }
}

super访问父类的构造方法: super()
在子类的构造方法中访问父类的构造方法

public class Fu{
    public Fu(){
        System.out.println("Fu 类的空参构造方法..");
    }
    public Fu(String name, int age) {
        System.out.println("Fu 类的有参构造方法..");
    }
}
public class Zi extends Fu{
    public Zi(){
        super();// 调用父类的空参构造方法
        System.out.println("Zi 类的空参构造方法..");
    }
    public Zi(String name,int age){
        super(name,age);// 调用父类的有参构造方法
         System.out.println("Zi 类的有参构造方法..");
    }
}
public class Demo {
        /*
            super访问父类的构造方法:
                空参构造: super();
                有参构造: super(实参);
                    注意:
                        1.只能在子类的构造方法中访问父类的构造方法
                        2.在子类的构造方法中访问父类的构造方法必须放在第一行
                        3.在子类的构造方法中访问父类的构造方法就是为了给从父类继承过来的属性进行初始化
                        4.子类的构造方法默认会调用父类的空参构造方法
         */
    public static void main(String[] args) {
        Zi zi = new Zi();
        System.out.println("----------------------");
        Zi z2 = new Zi("ldh", 17);
    }
}

super的注意事项

super的注意事项一
super访问成员变量和成员方法: 优先去父类中找,如果有就直接使用,如果没有就去爷爷类中找,如果有,就用,依次类推…

public class Test {
    public static void main(String[] args) {
        /*
            super访问成员变量和成员方法: 优先去父类中找,如果有就直接使用,如果没有就去爷爷类中找,如果有,就用,依次类推...
            java中所有的类都是直接或者间接继承Object类:
                例如: public class Person /*extends Object* /{}   Person类直接继承Object类
                例如: public class Student extends Person{}       Student类间接继承Object类

         */
        Zi zi = new Zi();
        //System.out.println(zi.num);
        zi.method();
    }
}

super的注意事项二
子类的构造方法默认会调用父类的空参构造方法,如果父类中的没有空参构造方法,只定义了有参构造方法,会编译报错
如果显示通过super调用有参,则不需要无参构造方法

子类构造方法中使用super调用父类的构造方法,是为了在创建子类对象的时候,初始化从父类继承过来的属性

继承体系对象的内存图

继承体系内存图原理—父类空间优先于子类对象产生

在每次创建子类对象时,先初始化父类空间,再创建其子类对象本身。目的在于子类对象中包含了其对应的父类空间,便可以包含其父类的成员,如果父类成员非private修饰,则子类可以随意使用父类成员。代码体现在子类的构造方法调用时,一定先调用父类的构造方法。

在这里插入图片描述

继承的特点

  • Java只支持单继承,不支持多继承。
  • 一个类只能有一个父类,但是可以有多个子类。
  • 可以多层继承。

补充: 顶层父类是Object类。所有的类默认继承Object,作为父类。

class A {} 默认继承Object类 直接继承Object类

class B extends A{} B的父类就是A,但是A的父类是Object类 间接继承Object类

java中所有类都是直接或者间接继承Object,所有类都是Object类的子类

3、多态

多态是继封装、继承之后,面向对象的第三大特性。

生活中,比如跑的动作,小猫、小狗和大象,跑起来是不一样的。再比如飞的动作,昆虫、鸟类和飞机,飞起来也是不一样的。可见,同一行为,通过不同的事物,可以体现出来的不同的形态。多态,描述的就是这样的状态。

定义

  • 多态: 是指同一行为,对于不同的对象具有多个不同表现形式。
  • 程序中多态: 是指同一方法,对于不同的对象具有不同的实现.

前提条件【重点】

  1. 继承或者实现【二选一】
  2. 父类引用指向子类对象\接口引用指向实现类对象【格式体现】
  3. 方法的重写【意义体现:不重写,无意义】

实现多态

多态的体现:父类的引用指向它的子类的对象

父类类型 变量名 = new 子类对象;
变量名.方法名();

父类类型:指子类对象继承的父类类型,或者实现的父接口类型。

class Animal{
    public void eat(){
        System.out.println("吃东西");
    }
}

class Dog extends Animal{
    @Override
    public void eat() {
        System.out.println("狗吃骨头...");
    }
}

class Cat extends Animal{
    @Override
    public void eat() {
        System.out.println("猫吃鱼...");
    }
}

public class Test1 {
    public static void main(String[] args) {
        /*
            多态: 同一种行为,不同的事物具有不同的表现形态
            实现多态:
                1.继承或者实现
                2.父类引用指向子类对象\接口引用指向实现类对象
                3.方法重写
         */
        // 父类引用指向子类对象
        Animal anl = new Dog();// 多态
        anl.eat();// 狗吃骨头...

        Animal anl1 = new Cat();
        anl1.eat();// 猫吃鱼...
    }
}

多态时访问成员的特点

多态时成员变量的访问特点

  • 编译看父类,运行看父类(编译看左边,运行看左边)

简而言之:多态的情况下,访问的是父类的成员变量

多态时成员方法的访问特点

  • 非静态方法:编译看父类,运行看子类(编译看左边,运行看右边)
    包括,抽象方法,默认方法
    • 简而言之:编译的时候去父类中查找方法,运行的时候去子类中查找方法来执行
  • 静态方法:编译看左边,运行看左边
    • 简而言之:编译的时候去父类中查找方法,运行的时候去父类中查找方法来执行

注意:多态的情况下是无法访问子类独有的方法

class Animal{
    int num = 10;
    public void method1(){
        System.out.println("Animal 非静态method1方法");
    }
    public static void method2(){
        System.out.println("Animal 静态method2方法");
    }
}
class Dog extends Animal{
    int num = 20;

    public void method1(){
        System.out.println("Dog 非静态method1方法");
    }

    public static void method2(){
        System.out.println("Dog 静态method2方法");
    }
}

public class Test {
    public static void main(String[] args) {
        /*
            多态时访问成员的特点:
                成员变量:编译看父类,运行看父类(编译看左边,运行看左边)
                成员方法:
                    非静态方法:编译看父类,运行看子类(编译看左边,运行看右边)
                    子类没有重写,找父类的
                    
                    静态方法: 编译看父类,运行看父类(编译看左边,运行看左边)
                结论:除了非静态方法是编译看父类,运行看子类,其余都是看父类
         */
        // 父类的引用指向子类的对象
        Animal anl = new Dog();
        System.out.println(anl.num);// 10

        anl.method1();// Dog 非静态method1方法

        anl.method2();// Animal 静态method2方法

    }
}

多态的形式

多态的表现形式:

普通父类多态

public class Fu{}
public class Zi extends Fu{}
public class Demo{
    public static void main(String[] args){
        Fu f = new Zi();//左边是一个“父类”
    }
}
```

抽象父类多态

public abstract class Fu{}
public class Zi extends Fu{}
public class Demo{
    public static void main(String[] args){
        Fu f = new Zi();//左边是一个“父类”
    }
}

父接口多态

public interface A{}
public class AImp implements A{}
public class Demo{
    public static void main(String[] args){
        A a = new AImp();
    }
}

多态的应用场景

  • 变量多态 -----> 意义不大
  • 形参多态----> 常用
  • 返回值多态—> 常用

变量多态
如果变量的类型为父类类型,该变量就可以接收该父类类型的对象或者其所有子类对象

形参多态:
参数类型为父类类型,该参数就可以接收该父类类型的对象或者其所有子类对象

返回值多态:
如果返回值类型为父类类型,那么就可以返回该父类类型的对象或者其所有子类对象

多态的好处和弊端

  • 好处
    提高了代码的扩展性
  • 弊端
    多态的情况下,只能调用父类的共性内容,不能调用子类的特有内容。
public class Test {
    public static void main(String[] args) {
        /*
            多态的好处和弊端:
                好处:提高代码的复用性
                弊端:无法访问子类独有的方法或者成员变量,因为多态成员访问的特点是,编译看父类
         */
        // 父类的引用指向子类的对象
        Animal anl = new Dog();
        anl.eat();
        //anl.lookHome();// 编译报错,因为多态成员访问的特点是,编译看父类,而父类中没有子类独有的功能
    }
}

4、引用类型转换

向上转型

  • 子类类型向父类类型向上转换的过程,这个过程是默认的。
Aniaml anl = new Cat();  

向下转型

  • 父类类型向子类类型向下转换的过程,这个过程是强制的。

容易出现ClassCastException

 Aniaml anl = new Cat();  
 Cat c = (Cat)anl;//向下转型
class Person{}
public class Test {
    public static void main(String[] args) {
        /*
            引用类型转换:
                向上转型:子类类型向父类类型向上转换的过程,这个过程是默认\自动的。
                向下转型:父类类型向子类类型向下转换的过程,这个过程是强制\手动的。
                        格式: 子类类型 对象名 = (子类类型)父类类型的变量;
                        注意:
                            1.向下转型的时候:右边父类类型的变量一定要指向要转型的子类类型的对象
                            2.不管是向上转型还是向下转型,一定满足父子类关系或者实现关系
         */
        // 向上转型:
        Animal anl = new Dog();

        // 向下转型:
        Dog dog = (Dog)anl;

        System.out.println("===================================");
        // 注意:右边父类类型的变量一定要指向要转型的子类类型的对象
        //Animal anl1 = new Animal();
        //Dog d1 = (Dog)anl1;// 运行报错,类型转换异常ClassCastException


        //Animal anl2 = new Cat();
        //Dog d2 = (Dog)anl2;// 运行报错,类型转换异常ClassCastException

        //Animal anl3 = new Person();// 编译报错,因为Animal和Person不是父子关系
        //Animal anl3 = (Animal) new Person();// 编译报错,因为Animal和Person不是父子关系

    }
}

instanceof关键字

向下强转有风险,最好在转换前做一个验证

格式:

变量名 instanceof 数据类型 
如果变量属于该数据类型,返回true。
如果变量不属于该数据类型,返回falseif( anl instanceof Cat){//判断anl是否能转换为Cat类型,如果可以返回:true,否则返回:false
    Cat c = (Cat)anl;//安全转换
}
public class Test {
    public static void main(String[] args) {
        /*
            instanceof关键字:
                为什么要有instanceof关键字?
                    因为在引用类型转换的时候很容易出现类型转换异常,所以为了提高代码的严谨性,转型之前得先判断一下
                怎么使用instanceof关键字判断呢?
                    if(变量名 instanceof 数据类型){

                    }
                 执行:
                    判断前面变量指向的对象类型是否是后面的数据类型:
                        如果前面变量指向的对象类型是属于后面的数据类型,那么就返回true
                        如果前面变量指向的对象类型不是属于后面的数据类型,那么就返回false
         */
        // 向上转型
        Animal anl = new Cat();

        // 向下转型
        //Dog  d = (Dog)anl;// 运行的时候会出现类型转换异常
        // 先判断,再转型
        if (anl instanceof Dog){
            Dog  d = (Dog)anl;
        }

        System.out.println("正常结束");
    }
}

解决多态的弊端

public class Test {
    public static void main(String[] args) {
        /*
            解决多态的弊端:
                弊端:无法访问子类独有的方法或者成员变量,因为多态成员访问的特点是,编译看父类
         */
        // 父类的引用指向子类的对象
        Animal anl = new Dog();// 向上转型
        anl.eat();// 狗吃骨头...

        //anl.lookHome();// 编译报错,因为多态成员访问的特点是,编译看父类,而父类中没有子类独有的功能

        // 先判断,后转型
        if (anl instanceof Dog){
            Dog d = (Dog)anl;// 向下转型
            d.lookHome();// 狗在看家...
        }

        System.out.println("正常结束");
    }
}

5、匿名对象

匿名对象的概述

什么是匿名对象:就是指"没有名字"的对象。

有名字的对象:
    Student stu = new Student();
    stu.show();
    stu.study();
匿名对象:
	new Student();

使用匿名对象

  • 特点:匿名对象只能使用一次

使用场景:

当某个类的对象只需要使用一次的时候,就可以使用该类的匿名对象
例如:方法的参数,方法的返回值

public class Test {
    public static void main(String[] args) {
        /*
            匿名对象:
                概述:没有名字的对象
                特点:匿名对象只能使用一次
                使用场景:当某个类的对象只需要使用一次的时候,就可以使用该类的匿名对象
                        例如:方法的参数,方法的返回值
         */
        // 创建对象
        Student stu1 = new Student("rb",18);// 有名字的对象
        stu1.show();
        stu1.show();

        System.out.println("==================================");
        //匿名对象
        new Student("rb",18).show();// 没有名字的对象
        new Student("rb",18).show();// 没有名字的对象

        System.out.println("==================================");
        // 调用method1方法
        Student stu2 = new Student("rb",18);// 0x11901
        method1(stu2);// 有名字的对象传参
        method1(new Student("rb",18));// 匿名对象的方式传参数

        System.out.println("==================================");
        Student stu3 = method2();// 0x11908
        stu3.show();// 丽颖,18

    }

    public static void method1(Student stu){// 0x11901
        stu.show();
    }


    public static Student method2(){
        //Student stu = new Student("ly",18);// 0x11908
        //return stu;// 0x11908

        return new Student("ly",18);
    }
}

抽象类

抽象类的概述

  • 概述: 使用abstract关键字修饰的类就是抽象类
  • 特点: 这种类不能被创建对象,它就是用来做父类的,被子类继承的

抽象类的定义

格式:

public abstract class 类名{
	构造方法
    成员变量
    成员方法
    抽象方法
}

例如:

public abstract class Person{

}
抽象类中的成员
  • 成员变量

  • 成员方法

  • 构造方法

  • 抽象方法

            普通类和抽象类的区别:
               1.普通类可以创建对象,抽象类不可以创建对象
               2.普通类没有抽象方法,抽象类有抽象方法
    

abstract

抽象方法

是什么?
怎么用?
什么时候用?

抽象方法的概述

  • 没有方法体,使用abstract修饰的方法就是抽象方法

抽象方法的定义

修饰符 abstract 返回值类型 方法名(形参列表);
例如:
	public abstract void work();

抽象方法的使用场景

如果父类中某个方法,所有子类都有不同的实现,那么就可以把该方法定义为抽象方法

抽象方法的作用: 强制要求子类重写的

抽象类的注意事项

  • 抽象类不能被创建对象,就是用来做“父类”,被子类继承的。
  • 抽象类不能被创建对象,但可以有“构造方法”——为成员变量初始化。
  • 抽象类中可以没有抽象方法,但抽象方法必须定义在抽象类中
  • 子类继承抽象类后,必须重写抽象类中所有的抽象方法,否则子类必须也是一个抽象类

模板设计模式

设计模式概述

  • 设计模式就是解决一些问题时的固定思路,也就是代码设计思路经验的总结。

模板设计模式概述

  • 针对某些情况,在父类中指定一个模板,然后根据具体情况,在子类中灵活的具体实现该模板
public abstract class Person{
    // 有方法体的方法: 通用模板
    public void sleep(){
        System.out.println("两眼一闭,就睡觉...");
    }
    
    // 没有方法体的方法(抽象方法):  填充模板(要子类重新实现的)
   public abstract void eat();
}
  • 抽象类体现的就是模板设计思想模板是将通用的东西在抽象类中具体的实现,而模板中不能决定的东西定义成抽象方法,让使用模板(继承抽象类的类)的类去重写抽象方法实现需求

模板模式的实现步骤

  • 定义抽象父类作为模板
  • 在父类中定义"模板方法"— 实现方法(通用模板)+抽象方法(填充模板)
  • 子类继承父类,重写抽象方法(填充父类的模板)
  • 测试类:
    • 创建子类对象,通过子类调用父类的“实现的方法”+ “子类重写后的方法”
// 父类
public abstract class Driver {
    // 开车方法 通用模板
    public void driveCar(){
        System.out.println("开门");
        System.out.println("点火");
        // 姿势??
        ziShi();
        System.out.println("刹车");
        System.out.println("熄火");
    }

    // 姿势方法  填充模板
    public abstract void ziShi();
}

现在定义两个使用模板的司机:

public class NewDriver extends Driver {
    @Override
    public void ziShi() {
        System.out.println("双手紧握方向盘");
    }
}

public class OldDriver extends Driver {
    @Override
    public void ziShi() {
        System.out.println("右手握方向盘左手抽烟");
    }
}

final关键字

final关键字的概述

final: 不可改变。可以用于修饰类、方法和变量。

  • 类:被修饰的类,不能被继承。
  • 方法:被修饰的方法,不能被重写。
  • 变量:被修饰的变量,就只能赋值一次,不能被重新赋值(可以看成常量)

final关键字的使用

修饰类

格式如下:

修饰符 final class 类名 {
  
}
例如:
public final class FinalClassFu {
}
public class FinalClassZi /*extends FinalClassFu*/ {
    // FinalClassFu类被final修饰了,所以不能被继承
}

查询API发现像 public final class Stringpublic final class Mathpublic final class Scanner 等,很多我们学习过的类,都是被final修饰的,目的就是供我们使用,而不让我们所以改变其内容。

修饰方法

格式如下:

修饰符 final 返回值类型 方法名(参数列表){
    //方法体
}

重写被 final修饰的方法,编译时就会报错。

public class FinalMethodFu {
    public final void show(){

    }
}
public class FinalMethodZi extends FinalMethodFu {

    /*@Override
    public void show() {

    }*/
    // 无法重写父类中的show方法,因为父类中的show方法被final修饰了
}

修饰变量

局部变量——基本类型

基本类型的局部变量,被final修饰后,只能赋值一次,不能再更改。代码如下:

public class Test1 {
    public static void main(String[] args) {
        /*
            final修饰局部变量:
                修饰变量:被final修饰的变量,只能赋值一次(常量)
                常量: 常量名一般都是所有字母大写(ctrl+shift+u)
         */
        //final int NUM1 = 10;// 定义num1的同时赋值
        // 编译报错,因为被final修饰的变量只能赋值一次
        //NUM1 = 20;// 重新给num1赋值

       /* int num1 = 10;// 定义num1的同时赋值
        num1 = 20;// 重新给num1赋值*/

        System.out.println("==================================");
        final int NUM2;// 定义num2变量
        NUM2 = 20;// 给num2变量赋值
        // 编译报错,因为被final修饰的变量只能赋值一次
        //NUM2 = 30;


        /*int num2;// 定义num2变量
        num2 = 20;// 给num2变量赋值*/
    }
}

局部变量——引用类型

引用类型的局部变量,被final修饰后,只能指向一个对象,地址不能再更改。但是不影响对象内部的成员变量值的修改,代码如下:

public class FinalDemo2 {
    public static void main(String[] args) {
        // 引用类型
        final Student stu = new Student("张三",18);
        //stu = new Student("李四",19);// 编译报错
        stu.setAge(19);
    }
}

成员变量

成员变量涉及到初始化的问题,初始化方式有两种,只能二选一:

  1. 显示初始化;一般用这种方法

    public class FinalVariable {
        final int NUM1 = 10;
    }
    
  2. 构造方法初始化。

class FinalVariable2{
    // 成员变量
    final int NUM1;

    // 要求:该类中所有的构造方法都要能给该常量赋值一次
    public FinalVariable2(){
        this.NUM1 = 10;
    }

    public FinalVariable2(int NUM1){
        this.NUM1 = NUM1;
    }
}

被final修饰的常量名称,一般都有书写规范,所有字母都大写
ctrl+shift+u idea中变量全部变为大写

static关键字

1.1 static关键字概述

static是一个静态修饰符关键字,表示静态的意思,可以修饰成员变量和成员方法以及代码块。

1.2 static关键字的使用

static修饰成员变量

static 修饰成员变量时,该变量称为类变量。该类的每个对象都共享同一个类变量的值。任何对象都可以更改该类变量的值,但也可以在不创建该类的对象的情况下对类变量进行操作。

静态成员变量在静态区

定义格式:

static 数据类型 变量名; 

静态成员变量的访问方式:

对象名.静态成员变量名; 不推荐
类名.静态成员变量名;  推荐
public class Person {
    // 非静态变量
    String name;// 姓名
    // 静态变量
    static String country;// 国籍

    // 构造方法

    public Person() {
    }

    public Person(String name, String country) {
        this.name = name;
        this.country = country;
    }
}

public class Test {
    public static void main(String[] args) {
        // 创建Person对象
        Person p1 = new Person("张三", "中国");
        System.out.println(p1.name+","+p1.country);// 张三,中国

        System.out.println("=======================");

        // 创建Person对象
        Person p2 = new Person();
        // 没有使用static修饰country,
        // System.out.println(p2.name+","+p2.country);// null,null
        // 使用static修饰country
        System.out.println(p2.name+","+p2.country);// null,中国

        System.out.println("=======================");

        System.out.println(Person.country);// 中国
    }
}

没有static修饰成员变量,成员变量是直接属于对象的
被static修饰的成员变量是属于类的(静态成员变量\类变量),会被该类的所有对象共享

static修饰成员方法

概述

  • 被static修饰的方法会变成静态方法,也称为类方法,该静态方法可以使用类名直接调用。

格式

修饰符 static 返回值类型 方法名 (参数列表){ 
	// 执行语句 
}

访问方式

对象名.方法名(实参);
类名.方法名(实参);   推荐
public class Person {
    // 非静态方法
    public void method1(){
        System.out.println("Person method1...");
    }

    // 静态方法
    public static void method2(){
        System.out.println("Person method2...");
    }
}
public class Test {
    public static void main(String[] args) {
        /*
            static修饰成员方法:
                格式:修饰符 static 返回值类型 方法名(形参列表){方法体}
                特点:被static修饰的成员方法叫做静态成员方法
                使用:
                    对象名.静态成员方法名(实参);
                    类名.静态成员方法名(实参); ----->推荐
         */
        Person p = new Person();
        p.method2();

        // 类名.静态成员方法名(实参);
        Person.method2();

    }
}

静态方法调用的注意事项:

  • 静态方法中不能出现this关键字
  • 静态方法中只能直接访问静态成员变量和静态成员方法
  • 静态方法中不能直接访问非静态成员变量和非静态成员方法
  • 非静态方法中可以直接访问一切成员变量和成员方法

小结:

static修饰成员方法:
	格式: 在返回值类型前面加static关键字
    使用: 类名.静态方法名(实参);
	注意事项:
		1.静态方法中不能出现this
        2.静态方法中只能直接访问静态成员变量和成员方法
        3.非静态方法中可以直接访问一切成员变量和成员方法
static修饰成员变量:
	格式: static 数据类型 变量名;
	使用; 类名.静态成员变量名
    特点;static修饰的变量会被该类的所有对象共享

开发中static的应用

以后的项目中,通常会需要一些“全局变量”或者“全局的工具方法”,这些全局变量和方法,可以单独定义在一个类中,并声明为static(静态)的,可以很方便的通过类名访问

public class Utils {
    // "全局变量"
    public static final int WIDTH = 800;
    public static final int HEIGHT = 800;


    // "全局方法"
    // 找int数组中的最大值
    public static int getArrayMax(int[] arr){
        int max = arr[0];
        for (int i = 0; i < arr.length; i++) {
            if(arr[i] > max){
                max = arr[i];
            }
        }
        return max;
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值