This、Final关键字与Java的值传递

目录

解析 this 关键字

this 关键字定义

什么时候使用 this 关键字

怎样使用 this 关键字

解析 final 关键字

final 修饰类

final 修饰方法

final 修饰变量

final 修饰基本数据类型和引用数据类型的变量

Java 的值传递

示例 1:

示例 2:

示例 3:

示例 4:

总结


解析 this 关键字

this 关键字定义

this 关键字代表当前对象的引用。它用于在对象的方法或构造器中引用当前对象。

什么时候使用 this 关键字

使用 this 关键字的原因是有时候我们需要区分局部变量和实例变量(类的成员变量),或者需要在类内部明确引用当前对象时。

怎样使用 this 关键字

this.属性 通常用于在类的方法中调用实例变量,尤其当方法参数的名字和实例变量的名字相同时。

示例代码:

public class Student {

    public String name;



    public void setName(String aaaa) {

        this.name = aaaa;

    }

}



public class Test {

    public static void main(String[] args) {

        Student student = new Student();

        student.setName("aaaa");



        Student student1 = new Student();

        student1.setName("hhhh");

    }

}

代码分析:

this.name 引用的是类的实例变量,而不是方法参数。

设置对象名称 student 和 student1 是为了区分两个不同的对象,分别调用各自的 setName 方法。

this.name 指代的是当前对象的实例变量,而非方法中的局部变量。

this.方法名调用没有 static 关键字修饰的方法时,可以使用 this 来显式地调用该方法。

示例代码:

public class Student {

    public String name;



    public void setName(String name) {

        this.name = name; // 使用 this 调用非静态方法

    }



    public void initialize() {

        this.setName("aaaa"); // 使用 this 调用 setName 方法

    }

}

注意:

在 static 方法中不能使用 this 关键字,因为 static 方法是属于类而不是某个对象的。

示例代码:

public class Student {

    public String name;



    public static void run(String name) {

        // this.name = name; // 错误:不能在 static 方法中使用 this

    }



    public void aaa() {

        // this.setName("aaaa"); // 错误:static 方法不能通过 this 调用

    }

}

原因:

static 修饰的方法和变量是属于类的,不属于某个对象,所以 this 不能用于 static 方法。

static 方法中没有 this 关键字的上下文,因为它们不依赖于任何对象。

this()

this() 用于调用类的构造方法,只能在构造器中使用,且必须是构造器中的第一条语句。

示例代码:

public class Student {

    public String name;



    public Student() {

        // 默认构造方法

    }



    public Student(String name) {

        this();  // 调用无参数的构造方法

    }

}

注意:

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

在一个构造方法中使用 this() 必须是第一条语句。

在一个类中,两个构造方法不能通过 this() 互相调用,否则会引起编译错误。

this() 和 super() 不能同时出现在同一个构造方法中。

解析 final 关键字

final 关键字可以用来修饰类、方法和变量。

final 修饰类

使用 final 修饰的类不能被继承。

示例代码:

public final class A {

    // 这是一个不能被继承的类

}



public class B extends A {  // 错误:无法继承被 final 修饰的类

}
final 修饰方法

使用 final 修饰的方法不能被子类重写。

示例代码:

public class Student {

    public String name;

    public final void run() {

        System.out.println("aaa");

    }

}



public class Test extends Student {

    @Override

    public void run() {  // 错误:无法重写被 final 修饰的方法

        System.out.println("bbb");

    }

}
final 修饰变量

final 修饰的变量成为常量,常量只能被赋值一次,且在类中使用时,必须在声明时初始化。

final 修饰全局变量和局部变量

final 修饰的全局变量(类的成员变量)必须被赋初始值,否则会报错。局部变量(方法内的变量)不需要赋值,但如果要使用则必须赋值。

示例代码:

赋初始值改正后

final 修饰的变量被称为常量,常量只能被赋值一次。

补充:变量的默认值

引用数据类型:默认值为 null

整形(如 int):默认值为 0

浮点型(如 double):默认值为 0.0

布尔型:默认值为 false

char 类型:默认值为 \u0000 (空字符)

final 修饰局部变量

局部变量是在方法内部定义的变量。final 修饰的局部变量不需要在定义时立即赋值,但必须在使用之前进行赋值,否则会报错。

示例代码:

无论局部变量是否被 final 修饰,在使用时都需要初始化。所以,final 对局部变量的影响不大。

final 修饰基本数据类型和引用数据类型的变量

(1)final 修饰基本数据类型的变量

final 修饰的基本数据类型的变量,其值不能被改变。

原因:对于基本数据类型,final 固定的是变量的值。比如:

public class Student {

   public String name;

   int a=10;

   public void run(){

       a=11;

   }

}

基本数据类型被final修饰

publicclass Student {

   public String name;

  final int A=10;

   public void run(){

      A=11;/*此时这里会发生报错*/

   }

流程图解释:

基本数据类型的变量在内存中存储的是其值本身,例如 int a = 10,存储的是值 10。

一旦用 final 修饰,值就不能改变,尝试改变时会发生编译错误。

final 修饰引用数据类型的变量

引用数据类型包括类、数组、接口等。final 修饰的引用数据类型变量,固定的是对象的引用地址,变量无法改变其指向的对象,但对象的内容可以改变。

示例代码:

public class Student {

   int[]arr1 = new int[]{1,2,3};

   int[]brr = new int[]{4,5,6};

   public void change(){

       arr1=brr;

   }

    public void change1(){

       arr1[2]=10;

   }

}

引用数据类型的变量存储的是对象的内存地址。

被 final 修饰后,该引用地址不能改变,但对象内容可以改变。比如可以修改数组的元素,但不能让该变量指向新的数组对象。

示例代码:

public class Student {

   int[]ARR1 = new int[]{1,2,3};

   int[]BRR = new int[]{4,5,6};

   public void change(){

       ARR1=BRR;/*此时,该处代码会发生报错*/

   }

    public void change1(){

      ARR1[2]=10;

   }

}

流程图解释:

Java 的值传递

Java 中只有值传递(传递变量的副本),而没有引用传递。以下通过一些示例代码来进一步理解。

示例 1:
public class A {

    public static void main(String[] args) {

        String nameString = "张三";

        name(nameString);

        System.out.println("main--- > " + nameString);

    }



    public static void name(String name) {

        name = "李四";

        System.out.println("name---> " + name);

    }

}

输出结果:

name---> 李四

main--- > 张三

分析:

第一步:main 方法入栈

程序开始执行 main 方法,main 方法被压入栈中。

定义了一个字符串变量 nameString,其值为 "张三"。

"张三" 存储在字符串常量池中,其地址为 0x1。nameString 保存的是这个地址(0x1)。

第二步:调用 name(nameString) 方法入栈

name(nameString) 方法被调用,将 nameString 的值(0x1)作为参数传入。

方法中定义了一个局部变量 name,其值为 nameString 的值(即 0x1)。

在方法体内,name = "李四" 这一行代码执行,字符串常量池中添加 "李四",其地址为 0x2。

将 0x2 赋值给 name,此时 name 的值为 0x2。

输出 name,打印结果为 "李四"。

第三步:name 方法出栈,返回到 main 方法

name(nameString) 方法执行完毕,出栈。

控制权返回到 main 方法中,继续执行。

输出 nameString,打印结果为 "张三",因为 nameString 仍然指向 0x1(未被修改)。

示例 2:
public class Person {

    private String nameString;

    private int age;

    public Person (String nameString,int age){

        this.age=age;

        this.nameString=nameString;

    }

    @Override

    public String toString(){

        return "Person  [nameString="+ nameString +",age="+age+"]";

    }

    public static void  name(Person  person){

        person.age=20;

        person.nameString="李四";

        person=null;

    }

 

    public static void main(String[] args) {

        Person  person =new person("张三",18);

        System.out.println(person.toString());

        name(person);

        System.out.println(person.toString());

    }

}

输出结果:

Person [nameString=张三, age=18]

Person [nameString=李四, age=20]

分析:

在方法 modifyPerson 中,person 的引用被修改,但这不影响传入的原始对象。因此,尽管 person 参数被设置为 null,但在 main 方法中,person 对象仍然存在且已被修改。

示例 3:
public class Student {

    private String name;

    private int age;

    public Student(String name,int age) {

        this.name = name;

        this.age = age;

     }

@Override

 

    public String toString() {

        return "Student [name=" + name + ", age=" + age + "]";

    }

    public static void change(Student s1, Student s2){

        Student temp = new Student( name: "王五", age: 20);

        temp = s1;

        s1 = s2;

        s2 = temp;

    }

    public static void main(String[] args) {

        Student zhangsan = new Student( name: "张三", age: 18);

        Student lisi = new Student( name: "李四", age: 20);

        Student.change(zhangsan, lisi);

        System.out.println(zhangsan.toString());

        System.out.println(lisi.toString());

    }

}

输出结果:

Student [name=张三, age=18]

Student [name=李四, age=20]

分析:

在方法 change 中,交换的是 s1 和 s2 的引用,而非对象本身。main 方法中的 zhangsan 和 lisi 仍然指向原来的对象,因此输出未发生变化。

示例 4:
class Two{

    byte x;

}

public class Student {

    public static void main(String[] args){

        Student student = new Student();

        student.start(;

    }

    void start( {

    Two two = new Two();

    System.out.print(two.x +" ");Two two2 = fix(two);

    System.out.println(two.x + " "+two2.x);

    }

    Two fix(Two tt) {

    tt.x =42;return tt;

    }

}

输出结果:

0

42 42

总结

this 关键字用于引用当前对象的实例变量或方法,通常在需要区分局部变量和实例变量时使用。

final 关键字用于定义不能更改的类、方法和变量。在使用 final 修饰变量时需要小心,特别是在对象引用和基本数据类型之间的差异。

Java 中的参数传递是值传递,意味着方法操作的是传递的变量副本,而不是变量本身。这一点在理解 Java 的内存管理和对象操作时非常重要。

  • 15
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值