• java基础 --- 关键字 final、this、super、static


    java基础 — 关键字 final、this、super、static

    final

    ​ final关键字代表最终的、不可改变的

    ​ 常见的四种用法:

    ​ ① 可以用来修饰一个类
    ​ ② 可以用来修饰一个方法
    ​ ③ 可以用来修饰一个局部变量
    ​ ④ 可以用来修饰一个成员变量

    1. 可以用来修饰一个类
    	public final class 类名称 {
    		...
    	}
    
    
    • 1
    • 2
    • 3
    • 4

    作用:使当前这个类不能有任何子类。(“太监类”)
    注意:一个类如果是final的,那么其中所有的成员方法都无法进行覆盖重写

    1. 可以用来修饰一个方法
    	修饰符 final 返回值类型 方法名称(参数列表) {
    		方法体
    	}
    
    
    • 1
    • 2
    • 3
    • 4

    作用:当final关键字用来修饰一个方法的时候,这个方法就是最终方法,不能够被覆盖重写
    注意:对于类、方法来说,abstract关键字和final关键字不能同时使用,因为作用相互矛盾

    1. 可以用来修饰一个局部变量
    	// ① 第一种基本数据类型情况下的格式
    	final 基本数据类型 数据名称 =;
    	// ② 引用数据类型情况下的格式
    	final 类型 对象名 = new 类名();
    	//例如:final Student stu = new Student();
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    作用:当final关键字用于修饰局部变量的时候,这个局部变量就不能更改,“一次赋值,终生不变”
    注意:对于 基本类型 来说,不可改变指的是变量当中的数据不可改变,但是对于 引用类型 来说,不可改变的指的是变量当中的地址值不可改变

    1. 可以用来修饰一个成员变量
    对于成员变量来说,如果使用了final关键字修饰,那么这个变量也照样是不可变的
    ① 由于成员变量具有默认值,所以用了final之后必须手动赋值,不会再给默认值了
    ② 对于final的成员变量,要么使用直接赋值,要么通过构造方法赋值,只能二选一
    ③ 必须保证类当中所有重载的构造方法,都最终会对final的成员变量进行赋值
    
    • 1
    • 2
    • 3
    • 4
    1. final finally finalize区别
      **final:可以修饰类、变量、方法,修饰类表示该类不能被继承、修饰方法表示该方法不能被重写、修饰变量表示该变量是一个常量不能被重新赋值。
      f
      inally:**一般作用在try-catch代码块中,在处理异常的时候,通常我们将一定要执行的代码方法finally代码块中,表示不管是否出现异常,该代码块都会执行,一般用来存放一些关闭资源的代码。
      **finalize:**是一个方法,属于Object类的一个方法,而Object类是所有类的父类,该方法一般由垃圾回收器来调用,当我们调用System.gc() 方法的时候,由垃圾回收器调用finalize(),回收垃圾,一个对象是否可回收的最后判断。

    this

    ​ this是自身的一个对象,代表对象本身,可以理解为:指向对象本身的一个指针。

    this不能出现在静态方法中

    ​ this的用法在java中大体可以分为3种:

    1. this.方法

      让类中一个方法,访问该类里的另一个方法或实例变量。

      // 定义一个run()方法,run()方法需要借助jump()方法
      public void run() {
          // 使用this引用调用run()方法的对象
          this.jump();
          System.out.println("正在执行run方法");
      }
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6

      注意:这也可以不用写this,因为调用的是本类中的其他方法,不需要区分

    2. this.属性

      当局部变量与全局变量同名时,总是指向局部的变量(就近原则)。若要指向全局变量,就用 this.属性名 指向成员变量。
      若不同名无冲突,则可以省略this。

      public Person(String name, int age) {
          this.name = name;
          this.age = age;
      }
      
      • 1
      • 2
      • 3
      • 4
    3. 引用本类的构造函数:this([参数1,参数2,…])

      调用本类中的其他构造方法,调用时要放在构造方法的首行,目的是:代码复用。

      this( ) 不能在普通方法中使用,只能写在构造方法中。

      class Person{
          private String name;
          private int age;
          
          public Person() {
          }
       
          public Person(String name) {
              this.name = name;
          }
          public Person(String name, int age) {
              this(name);    // 引用本类的构造方法
              this.age = age;
          }
      }
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
      • 7
      • 8
      • 9
      • 10
      • 11
      • 12
      • 13
      • 14
      • 15

    super

    ​ super和this类似,它指向了当前对象自己的父类型特征(也就是继承过来的那些东西)。

    ​ super和this区别是:this可以看做一个引用变量,保存了该对象的地址,是当前对象整体,而super代表的是父类型特征,是子类局部的一些东西,这些继承过来的东西已经在子类里面了,你可以输出整体this,但不能输出父类型特征super。因为super指向的东西不是一个整体,没法打印输出。

    System.out.println(this);  //输出this.toString()的值
    System.out.println(super);  //编译报错,需要'.'
    
    
    • 1
    • 2
    • 3

    ​ 当在子类对象中,子类想访问父类的东西,可以使用“super.”的方式访问。例如:方法覆盖后,子类内部虽然重写了父类的方法,但子类也想使用一下父类的被覆盖的方法,此时可以使用“super.”的方式。当子类中出现和父类一样的属性或者方法,此时,你要想去调用父类的那个属性或者方法,此时“super.”不能省略。
    ​ this和super都只能在对象内部使用。this代表当前对象本身,super代表当前对象的父类型特征。
    ​ “this.”是一个实例对象内部为了区分实例变量和局部变量。
    ​ “super.”是一个实例对象为了区分是子类的成员还是父类的成员。

    1. 普通的直接引用

      与this类似,super相当于是指向当前对象的父类的引用,这样就可以用super.xxx来引用父类的成员。

    2. 子类中的成员变量或方法与父类中的成员变量或方法同名时,用super进行区分

    3. 引用父类构造函数

      • super(参数):调用父类中的某一个构造函数(应该为构造函数中的第一条语句)。
      • this(参数):调用本类中另一种形式的构造函数(应该为构造函数中的第一条语句)。
    4. 示例

      public class superthis {
          public static void main(String[] args) {
              Student s0 = new Student();
              s0.getInfo();
              s0.printinfo();
      
              Student s1 = new Student("子类属性");
              s1.getInfo();
              s1.printinfo();
      
              Student s2 = new Student("Father","Child");
              s2.getInfo();
              s2.printinfo();
      
          }
      }
      
      class Person{
          protected String name;
      
          public Person(){
              System.out.println("父类无惨构造方法");
          }
          public Person(String name) {
              this.name = name;
          }
      
      }
      
      class Student extends Person{
          private String name;  // 与父类同名属性
      
          public Student(){    // 子类构造方法会隐式调用父类的无参构造方法super()
              System.out.println("子类无参构造方法");
          }
      
          public Student(String name1) {  // 子类构造方法会隐式调用父类的无参构造方法super()
             this.name = name1;
          }
          public Student(String name, String name1) {
              super(name);  // 子类构造方法已经调用了父类构造方法,则不会再隐式调用父类的无参构造方法super()
              this.name = name1;
          }
      
          public void getInfo(){
              System.out.println(this.name);      //Child
              System.out.println(super.name);     //Father
          }
      
          public void printinfo(){
              //System.out.println(super);  // 这一行会编译报错:java:需要.
              System.out.println(this);
          }
      }
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
      • 7
      • 8
      • 9
      • 10
      • 11
      • 12
      • 13
      • 14
      • 15
      • 16
      • 17
      • 18
      • 19
      • 20
      • 21
      • 22
      • 23
      • 24
      • 25
      • 26
      • 27
      • 28
      • 29
      • 30
      • 31
      • 32
      • 33
      • 34
      • 35
      • 36
      • 37
      • 38
      • 39
      • 40
      • 41
      • 42
      • 43
      • 44
      • 45
      • 46
      • 47
      • 48
      • 49
      • 50
      • 51
      • 52
      • 53
      • 54

      输出:

      父类无惨构造方法   // 子类构造方法会隐式调用父类的无参构造方法super()
      子类无参构造方法
      null
      null
      com.fazi.Student@1b6d3586
      父类无惨构造方法  // 子类构造方法会隐式调用父类的无参构造方法super()
      子类属性
      null
      com.fazi.Student@4554617c
      Child
      Father
      com.fazi.Student@74a14482
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
      • 7
      • 8
      • 9
      • 10
      • 11
      • 12

    this和super的区别

    • super: 它引用当前对象的直接父类中的成员(用来访问直接父类中被隐藏的父类中成员数据或函数,基类与派生类中有相同成员定义时如:super.变量名 super.成员函数据名(实参)
    • this:它代表当前对象名(在程序中易产生二义性之处,应使用this来指明当前对象;如果函数的形参与类中的成员数据同名,这时需用this来指明成员变量名)
    • super()和this()类似,区别是,super()在子类中调用父类的构造方法,this()在本类内调用本类的其它构造方法。
      super()和this()均需放在构造方法内第一行。
    • 尽管可以用this调用一个构造器,但却不能调用两个。
    • this和super不能同时出现在一个构造函数里面,因为this必然会调用其它的构造函数,其它的构造函数必然也会有super语句的存在,所以在同一个构造函数里面有相同的语句,就失去了语句的意义,编译器也不会通过。
      this()和super()都指的是对象,所以,均不可以在static环境中使用。包括:static变量,static方法,static语句块。
    • 从本质上讲,this是一个指向本对象的指针, 然而super是一个Java关键字。

    static

    ​ static修饰的东西一般情况下跟对象无关。可以使用的场景:

    在这里插入图片描述

    被static修饰的变量或者方法是独立于该类的任何对象,也就是说,这些变量和方法不属于任何一个实例对象,而是被类的所有的实例对象所共享。

    • 在该类被第一次加载的时候,就会去加载被static修饰的部分,而且只在类第一次使用时加载并进行初始化,注意这是第一次用就要初始化,后面根据需要是可以再次赋值的。
    • static变量值在类加载的时候分配空间,以后创建类对象的时候不会重新分配。赋值的话,是可以任意赋值的!
    • 被static修饰的变量或者方法是优先于对象存在的,也就是说当一个类加载完毕之后,即便没有创建对象,也可以去访问。
    • static关键字还有一个比较关键的作用就是 用来形成静态代码块以优化程序性能。static块可以置于类中的任何地方,类中可以有多个static块。在类初次被加载的时候,会按照static块的顺序来执行每个static块,并且只会执行一次。
    • 静态无法引用非静态,编译报错:Error:(11, 9) java: 无法从静态上下文中引用非静态 变量 per1
    1. static修饰成员变量(类本身)
    • 修饰成员变量,这个变量就不属于对象了,而属于类本身,我们就可以通过“类名.属性名”

    • 只要通过我这个类创建的对象,这些对象都可以共享这个属性

    • 当其中一个对象对类变量进行更改后,其他对象的这个类变量也会更改,以最后的为准

    • 类变量是随着类的加载而加载

    • 类变量放在方法区的静态域里面

    public class staticDm {
        public static void main(String[] args) {
            Person.country = "国家"; // 中国 ->国家
    
            Person per2 = new Person("小泉",50);
            Person.country = "小日本";  // 国家 ->小日本
    
            Person per1 = new Person( "张三",18);
            Person.country = "祖国";  // 最后的赋值:小日本 -> 祖国,所有的类变量都是最后的赋值
    
            per1.show();
            per2.show();
    
            System.out.println("类属性cuntry为:" + Person.country);  // 直接调用类属性
        }
    
    }
    
    class Person {
        String name;
        int age;
        static String country = "中国";
        public Person(String name,int age){
            this.name = name;
            this.age = age;
        }
    
        void show() {
            System.out.println("姓名为:" + name + ",年龄为:" + age + ",国籍为:" + country);
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31

    ​ 输出:

    姓名为:张三,年龄为:18,国籍为:祖国
    姓名为:小泉,年龄为:50,国籍为:祖国
    类属性cuntry为:祖国
    
    • 1
    • 2
    • 3

    ​ final和static的区别

    • finnal修饰的属性不可以被改变,所以被赋值之后就是一个常量,但还是成员属性,在堆中存储
    • static修饰的属性,被称为静态变量,在方法区中存储,所有的Person的对象共享这个属性
    • 一旦在类中定义了一个常量(定义时就要赋值或者在构造方法中赋值),那么类中的所有对象的这个属性值都是一样的,那我们就可以使用static和final共同修饰这个属性,把他放在方法区中,让该类的的所有对象共享此属性,这样比较节省空间
    • 全局常量,就是用static final共同修饰,常量的命名规则:所有单词全部大写,多个单词使用下划线分隔
    1. static修饰方法(类方法)
    • 修饰方法,这个方法就属于类本身了,我可以通过"类名。方法名()"就行调用

    • 随着类而加载

    • 在静态方法里面只能调用静态变量和静态方法,相反在普通方法里可以调用静态方法和静态变量

    • 不能使用this和supper关键字。

    • 加了static的方法,不能再方法内部访问非static的属性和行为;

      原因:1、在静态方法的内部无法确认非static的内容属于哪个对象,它是通过类名调用,这时没有对象----这就相当于工具类

      2、static修饰的方法,在类加载的时候是被首先加载的,然后加载非static内容,所以加载static时 是不知道非static内容的

    ​ **总结:**只有调用的时候无需考虑对象时,才定义为static—工具类的工具方法,可以被定义为static方法

    ​ 工具类:没有产生对象的必要,只要实现某个功能即可,哪个对象完成的都没有影响,比如:分页,转换时间,连接数据库等

    ​ 工具方法:该方法在完成功能的时候,不会对对象的数据产生任何影响

    1. static修饰代码块

      代码块的作用完成初始化

    • 非静态代码块:

      可以给类的属性进行初始化操作,同时还可以调用类的方法(静态的,非静态的)

      里面可以有输出语句

      每创建完一个对象,非静态代码块就加载一次

    • 静态代码块:

      里面可以有输出语句

      随着类加载而加载,只会执行一次,很多时候会将一些只需要进行一次的初始化操作都放在static代码块中进行

      静态代码的加载时机早于非静态代码块

      静态代码块里只能调用类变量和类方法(静态属性和方法)

      作用:jdbc 驱动 用户名 密码 数据库的链接地址

    • 对属性赋值的方法:(1)默认初始化(2)显式的初始化(3)通过set方法或者构造方法(4)代码块

    1. static修饰内部类

      static不能修饰普通类,只能修饰内部类,被static修饰的内部类的创建方式: new OuterClass.InnerClass()

  • 相关阅读:
    软件测试培训俩月上岗,很慌
    01-go基础-07-map(声明map、初始化map、map赋值、遍历map、判断key是否在map中、删除map成员)
    常见的行为型设计模式
    【STM32】DMA数据转运(存储器到外设)
    【Hadoop】 软件
    PMP考完后应该考什么?
    ABC310F Make 10 Again
    c#string常用方法总结
    URI 和 URL 的区别
    寄存器和变量有什么区别
  • 原文地址:https://blog.csdn.net/qq_41187116/article/details/126093267