Day5.成员变量,构造方法,this使用方法

2.2成员变量

1.成员变量作用域

类中的属性,也就是直接在类中定义的变量称作成员变量,它定义在方法的外部。

​ 在下面的代码中Person类中的name、gender既不属于eat()方法,也不属于work()方法,而属于

​ Person类本身的属性,他们是Person类的成员变量

代码如下:

public class Person5 {

    public  String name;
    public  String gender;
    public  int age;

    public void eat(String name){
        System.out.println(this.name+"邀请"+name+"共进晚餐");
    }

    public void work(){

        int age =18;
        System.out.println(this.name+age+"岁的工作理念: 搞钱");
    }

    public  void  work(String contect){

        System.out.println(this.name+"的工作理念:"+contect);
    }

    public void  showDetails(){
        System.out.println("姓名是:"+this.name+",性别为"+this.gender+",年龄是:"+this.age);
    }
}

注意:

​ 成员变量可以在声明时赋初始值。

2.局部变量作用域

局部变量就是定义在方法中的变量。
分析:

​ work()方法中的变量age就是局部变量
注意:

​ 虽然成员变量age和局部变量age的名称一样,但表示的却不是同一个变量,一般情况下,局部变量

​ 在使用前需要赋值,否则会编译出错

3.成员变量和局部变量的区别

使用成员变量和局部变量时需要注意如下几点:

​ (1).作用域不同。局部变量的作用域仅限于定义它的方法,在该方法外无法访问它。成员变量的作用域在整个类内部都是可见的,所有的成员方法都可以使用它,如果访问权限允许,还可以在类外部使用成员变量

​ (2).初始值不同,对于成员变量,如果在类定义中没有给它赋予初始值,Java会给它一个默认值,基本数据类型的值为0,引用类型的值为null,但是Java不会给局部变量赋予初始值,因此局部变量必须要定义并赋值后使用

​ (3)在同一个方法中,不允许有同名的局部变量。在不同的方法中,可以有同名的局部变量

​ (4)局部变量可以和成员变量名同名,并且一起使用,局部变量有更高的优先级

4.数据类型

在Java中,变量的类型分为两种:一种是基本数据类型,一种是引用数据类型

​ Java中的引用数据类型包括3种:类、数组、接口

对比基本数据类型和引用数据类型的区别

public class Person {

    public int age;

}
public static void main(String[] args) {

        //基本数据类型
        int num1=11;
        int num2 =num1;
        System.out.println("num1等于:"+num1);
        num2=22;
        System.out.println("把num1赋给num2后,修改num2的值."+"num1等于:"+num1);
        System.out.println("*********");

        //引用数据类型
        Person person1=new Person();
        person1.age=11;
        Person person2=person1;
        System.out.println("person1.age等于:"+person1.age);
        person2.age=22;
        System.out.println("把person1对象赋给person2对象后,修改person2的age属性,"+"person1.age等于:"+person1.age);
    }

​ 分析如下:

​ int为基本数据类型,当初始化num1并赋值后,将num1赋给num2,然后修改num2的值,运行后发现num1的值没有改变。

​ class为引用数据类型,当实例化person1对象并对其属性赋值后,将person1对象赋给person2对象,然后修改person2的值,运行后发现person1的属性值发生变化。

​ 几乎同样的操作,为什么会有完全相反的结果?这是因为int和class在内存种的存储方式不同,这也是基本数据类型和引用数据类型的主要区别。

​ 对于基本数据类型,不同的变量会分配不同的存储空间,并且存储空间中存储的是该变量的值,赋值操作传递的是变量的值,改变一个变量的值不会影响另外一个变量的值

​ 对于引用数据类型,赋值是把原对象的引用(可以理解内存地址)传递给另外一个引用,对数组而言,当用一个数组名直接给另一个数组赋值时,相当于传递一个引用,此时,这两个引用指向同一个数组,也就是指向同一内存空间。

2.3构造方法

Java中,当类创建一个对象时会自动调用该类的构造方法,构造方法分为默认构造方法和带参数的构造方法

1.构造方法的定义

构造方法的主要作用是进行一些数据的初始化

​ 定义构造方法的语法格式如下:



[访问修饰符]  方法名([参数列表]){

​	
​		//省略方法体的代码

​	}

1).构造方法没有返回值

​ 2).默认构造方法没有参数,因此参数列表可选

​ 3).构造方法的方法名与类名相同


为Person类定义一个构造方法

public class Person {

    
    public String name;
    
    public Person(){
        
        this.name="艾琳";
    }

}

分析如下:

​ 示例13的Person的构造方法的作用是当Person类的对象创建时,将这个对象的name属性设置为“艾琳”。

​ 当开发人员没有编写自定义构造方法时,Java会自动默认添加构造方法,默认构造方法没有参数。

注意:

​ 如果自定义一个或多个构造方法,则Java不会自动添加默认构造方法

2.构造方法重载


使用构造方法重载和一般方法重载等技术实现信息的输出

​ Person类

public class Person {

    public String name;
    
    public String gender;
    
    public int age;
    
    public Person(){  //无参的构造方法

        this.name="艾琳";
    }
    
    public Person(String name){
        this.name=name;      //带参数构造方法
    }
    
    public void work(){
        System.out.println(this.name+"的工作理念,干活挣钱又饭吃");
    }
    
    public void work(String contect){
        
        int age =this.age;
        System.out.println(this.name+age+"岁的工作理念:"+contect);
    }
}

测试类:

 public static void main(String[] args) {


        Person guest = new Person("艾琳");

        System.out.println("大家好,欢迎"+guest.name+"来到地球村");

        Scanner input =new Scanner(System.in);

        switch (input.nextInt()){


            case 1:
                guest.gender="男";
                break;

            case 2:
                guest.gender="女";
                break;
            default:
                System.out.println("操作失误");
                return;
        }

        System.out.println("请输入您的年龄:");
        guest.age=input.nextInt();     //为对象的年龄赋值
        guest.work();             //调用无参work()方法
        System.out.println("请重新输入您的工作理念:");
        String contect=input.next();
        guest.work(contect);    //调用有参work()方法
        System.out.println("***********");
    }

分析:

​ 在成员变量的示例中多次用到了this关键字,this的含义是什么呢?

​ this关键字是对一个对象的默认引用,每个实例方法内部都有一个this引用变量,指向调用这个方法的对象,其实就是指当前对象的引用,通俗点理解为本对象自己

this使用举例如下:

(1).this.属性名:

​ 表示本对象自己的属性使用this调用成员变量,解决变量和局部变量的同名冲突

Person类

public class Person {

    public String name;

    public int age;

    public double height;


    public Person(String n,int a,double h){
        name=n;
        age=a;
        height=h;
    }

    public void introduce(){
        System.out.println("我叫"+name+",今年"+age+"岁");
    }

}

测试代码:

public static void main(String[] args) {
        Person person = new Person("张三", 20, 178.5);
        person.introduce();
    }

运行控制台结果:

我叫张三,今年20Process finished with exit code 0

分析:

​ 通过程序的运行结果我们可以看出,在创建对象的时候,对象的属性被赋予了正确初始值。这个程序本身非常的简单,谁都可以理解,但是大家请注意,我们在定义构造方法的时候,把表示姓名、年龄和身高的参数分别命名为:n、a和h,这种命名的可读性有点差,为了提高可读性,我们把构造方法的参数名称修改为name、age和height。

 public Person(String name,int age,double height){
        name=name;
        age=age;
        height=height;
    }

运行结果:

我叫null,今年0Process finished with exit code 0
null0都是数据初始化的值

分析:

​ 为什么这一次的运行结果出现了问题呢?就是因为,修改了构造方法之后,当我们调用构造方法创建对象时,给构造方法所传递的3个参数值“张三”、20和178.5最终并没有赋值到对象的3个属性中。那么,既然参数值没有被赋值到对象的属性中,它们去了哪里呢?修改代码后,构造方法的参数与类所定义的属性同名,根据”同名情况下,局部变量的优先级更高”原则,在构造方法执行的过程中,虚拟机会把参数值赋给”参数本身”,而不是赋值给对象的属性!具体来说,就是我们给构造方法的name参数传递的值是”张三”,而这个”张三”在构造方法执行的过程中,当运行到”name=name;”这条语句时,并没有把”张三”赋值给对象的name属性,而是又重新赋值给了name参数自身。就是因为”张三”最终没有被赋值到对象的name属性中,才导致introduce方法中打印出的name属性是null。当然,age和height这两个参数也是同样的赋值效果

为了能够让虚拟机明白我们所期望的是:把”张三”这个字符串赋值给对象的name属性,而不是”再一次”把它赋值给构造方法的参数,就需要把构造方法中的赋值语句做出如下修改:

public Person(String name,int age,double height){
        this.name=name;
        this.age=age;
        this.height=height;
    }

运行测试,控制台结果如下:

我叫张三,今年20Process finished with exit code 0

分析如下:

​ 这一次,我们在构造方法中,给”=”左边的属性前面都加上了this关键字,经过修改之后,重新运行main方法,就恢复了正常的运行效果。好,现在我们就来探究一下,加了this关键字之后,为什么程序能够”恢复正常”。刚才我们说过,”this”可以被解释为” 本对象自己的…”,按照这个逻辑,”this.name”就可以被解释为”本对象自己的name属性”,所以在执行”this.name=name;”这条语句的时候,虚拟机就会把name参数的值”张三”赋值给对象的name属性。也就是说在这条赋值语句中,”=”左边的”this.name”表示对象的name属性,而”=”右边的name表示方法的name参数。

​ this.name”为什么不能被解释为”本对象自己的name参数”呢?因为”参数”这个概念是就某个方法而言的,它相当于某个方法的”局部变量”,只是这个”局部变量”比起在方法中定义的真正的局部变量来讲有点特殊,它能够接收从主调方法中传递过来的值。因此,当我们说到”参数”这个概念的时候,都是相对于一个”方法”而不是一个”对象”而言的,所以也就不会有”某个对象的参数”这一说法。因此,”this.name”只能被虚拟机认定为本对象自己的name”属性”,绝不会被当作name”参数”。

(2)this.方法名:

表示本对象自己的方法

我们给Person类增加了一个”打招呼”的方法叫做greet。在introduce方法当中,就可以通过”this.方法名”的方式来调用这个方法,表示调用的是”本对象自己的greet”方法。这是this关键字的第二种用法。当然,在introduce方法中并没有出现其他对象,所以方法名前面的this关键字也可以省略不写。

public void greet(){
        System.out.println("hello,大家好");
    }
    
 public void introduce(){
        this.greet();
        System.out.println("我叫"+name+",今年"+age+"岁");
    }

运行结果如下:

hello,大家好
我叫张三,今年20岁
s
Process finished with exit code 0
(3)this关键字

还有另外一种很重要的用法,那就是在this关键字的后面加上小括号,这样就表示调用了某个类自身的构造方法,为了讲解这种用法我们再来修改一下Person类:

​ 我们给Person类又增加了一个构造方法。这个构造方法只有2个参数,并且只初始化2个属性。为了讲述方便,我们把上面的3个参数的构造方法称之为”构造方法①”,把下面的2个参数的构造方法称之为”构造方法②”。通过观察不难发现,这两个构造方法当中前2行代码是相互重复的,为了避免这种重复性的代码出现,我们可以在”构造方法①”当中调用”构造方法②”。调用的方式如下:

//构造方法1
    public Person(String name,int age,double height){
        this(name,age); //调用构造方法2
        this.height=height;
    }
    
     //构造方法2
    public Person(String name,int age){

        this.name=name;
        this.age=age;
    }

在”构造方法①”中,通过”this(参数);”的方式调用了”构造方法②”。这就是this关键字的又一种用法。很多人可能不理解,为什么要通过这种方式来调用构造方法呢?我们难道不能直接写一个”Person(name,age);”来调用吗?这里必须做出解释:在Java语言中,一个类的构造方法与类名相同。但是,一个类当中也可以定义一个与类名相同的”普通方法”,换句话说就是:并不是只有构造方法与类名相同,”普通方法”也可以取和类相同的名称(只不过全世界的程序员都不会这么干)。那么,在这种情况下,编译器如何区分这个方法是”普通方法”还是”构造方法”呢?很简单,”普通方法”的名称前面必须定义返回值类型,而”构造方法”的名称前面则没有返回值类型的定义。这样,编译器就能够分得清哪个是”构造方法”,哪个是”和类同名的普通方法”。

定义的时候分得清,但是在调用的时候,都是通过方法名来调用的,这时如何分得清代码中哪一句调用的是”构造方法”, 哪一句调用的是”和类同名的普通方法”呢?为了解决这个问题,Java语言规定,在本类中调用构造方法的时候,需要通过”this(参数)”的方式来调用。除此之外,Java语言还规定了这种调用方式所必须遵守的规则。首先,这种”this(参数)”的方式只能在”其他构造方法中”使用,不能在普通方法中用。如果在普通方法中按这种方式使用,将被视为语法错误,如下代码:

public void greet(){
        this("张三",20);//此处代码错误,不能在普通方法中调用
        System.out.println("hello,大家好");
    }

其次,在一个构造方法中,用”this(参数)”的形式调用构造方法,”this(参数)”必须写在主调方法的第一行。第三,不能出现相互循环嵌套调用,也就是说,不能在构造方法①中调用构造方法②,又同时在构造方法②中调用构造方法①,如下:

//构造方法1
    public Person(String name,int age,double height){
        this(name,age); //在构造方法1中调用构造方法2
        this.height=height;
    }
    
    //构造方法2
    public Person(String name,int age){
        this(name,age,178.5); //在构造2方法中调用构造方法1

    }

接下来我们再来思考两个问题:首先,在main()方法中执行到”new Person(“张三”,20,178.5);”这句代码时,实际上是调用了构造方法①,而构造方法①中又调用了构造方法②,两个构造方法都被调用到了,那么在内存中会不会创建两个Person对象呢?答案是不会,为什么呢?原因很简单:构造方法①中调用了构造方法②,并没有出现new关键字,调用构造方法②仅仅是完成了name和age这两个属性的初始化,并不会创建出两个对象。

我们要思考的第二个问题是:既然Java语言允许”普通方法”的名称与类名相同,而构造方法也与类名相同,那么在Person以外的类当中如果写上了”Person(参数)”这样的代码,虚拟机如何判断所调用的是普通方法还是构造方法呢?答案也很简单,如果”Person(参数)”的前面出现了new关键字,这就说明调用的是构造方法,否则说明调用的是普通方法。

(4).外部类名.this.属性

this关键字在我们编写内部类代码的时候,还有一种用途,那就是区分属性或方法的具体归属

public class Outter {

    public int a=0; //外部类的属性

    class Inner{

        public void printA(){
            System.out.println(a);//内部类方法调用外部类的属性
        }
    }
}

测试代码:

 public static void main(String[] args) {

        //先创建外部类
        Outter outter = new Outter();
        //再创建外部类的内部类
        Outter.Inner inner = outter.new Inner();
        inner.printA();
    }

运行结果:

0

Process finished with exit code 0
//表示内部类方法调用外部类的属性

分析:

​ 在这段代码中,定义了外部类Outter,Outter有一个属性a,并且Outter中又定义了内部类,在内部类的printA()方法中调用了外部类的a属性。我们都知道,一个内部类可以直接访问它所在外部类的属性和方法。这个特性在我们的上面这段代码中得到了体现。但是,如果内部类中出现了与外部类同名的属性或方法时,该如何区分调用的到底是哪个属性或方法呢?比如说,在Inner类中也出现了a属性,那么输出语句中的a到底是指哪个a呢?很简单,如果输出语句中直接写a,那么调用的是内部类的a属性。为了强调它是内部类的a属性,我们也可以在a的前面加this关键字。如果我们希望调用的是外部类的a属性,可以用”外部类名.this.a”的方式来调用

public class Outter {

    public int a=0; //外部类的属性

    class Inner{
        public  int a=10;//内部类的属性
        public void printA(){
            System.out.println(a);//调用内部类的a属性,输出10
            System.out.println(this.a);//调用内部类的a属性,输出10
            System.out.println(Outter.this.a);//调用外部类的a属性,输出0
        }
    }
}

注意:

​ 因为this是在对象内部指代自身的引用,所以this只能调用实例变量、实例方法和构造方法,不能调用类变量和类方法,也不能调用局部变量。

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Xem626

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值