栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > Java

day07

Java 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

day07

类的成员之一:成员变量

成员变量的分类

  • 实例变量:没有static修饰,也叫对象属性,属于某个对象的,通过对象来使用
  • 类变量:有static修饰,也叫类变量,属于整个类的,不是属于某个实例、

如何声明成员变量

成员变量的类型可以是Java的任意类型,包括基本数据类型、引用数据类型(类、接口、数组等 例如:声明一个中国人的类

class Chinese{
	static String country;//类变量
	String name;//默认值
    char gender = '男';//显式赋值
}

如何在类外面访问成员变量

类变量

成员变量/实例变量 

代码示例

class Chinese {
    static String country;
    String name;
    char gender = '男';
}

public class Demo {
    public static void main(String[] args) {
        //System.out.println(Chinese.name);错误,非静态成员变量必须通过对象.进行访问

        //创建对象
        Chinese c1 = new Chinese();
        //对象名.非静态成员变量
        System.out.println(c1.name);//null
        //对象名.非静态成员变量
        System.out.println(c1.gender);//男

        //类名.静态成员变量,推荐
        System.out.println(Chinese.country);//null
        //静态的成员变量也可以通过对象.进行访问,不推荐
        System.out.println(c1.country);//null

    }
}

成员变量有默认值

 类变量的值是所有对象共享的,当类变量发生改变的时候,任何此类的对象访问该变量都会发生改变。而实例变量的值是每个对象独立的。

class Chinese {
    static String country;
    String name;
    char gender = '男';
}

public class Demo {
    public static void main(String[] args) {
        //创建对象c1
        Chinese c1 = new Chinese();

        //创建对象c2
        Chinese c2 = new Chinese();

        //给对象c1的name属性赋值张三
        c1.name = "张三";

        //给对象c2的name属性赋值李四
        c2.name = "李四";

        //给对象c2的gender属性赋值女
        c2.gender = '女';

        //给类变量赋值
        Chinese.country = "中国";//推荐

        //访问各个对象的成员变量
        System.out.println("c1.country = " + c1.country); //中国
        System.out.println("c1.name = " + c1.name); //张三
        System.out.println("c1.gender = " + c1.gender);//男
        System.out.println("c2.country = " + c2.country); //中国
        System.out.println("c2.name = " + c2.name);//李四
        System.out.println("c2.gender = " + c2.gender);//女
    }
}


成员变量的内存图

内存是计算机中重要的部件之一,它是与CPU进行沟通的桥梁。其作用是用于暂时存放CPU中的运算数据,以及与硬盘等外部存储器交换的数据。只要计算机在运行中,CPU就会把需要运算的数据调到内存中进行运算,当运算完成后CPU再将结果传送出来。我们编写的程序是存放在硬盘中的,在硬盘中的程序是不会运行的,必须放进内存中才能运行,运行完毕后会清空内存。Java虚拟机要运行程序,必须要对内存进行空间的分配和管理,每一片区域都有特定的处理数据方式和内存管理方式。

详解:

下面我们使用画图的方式来分析一下为什么,类变量的值是所有对象共享的,而实例变量的值是每个对象独立

静态成员变量和实例变量的异同

相同点:

  • 位置类中方法外

不同点:

有无static修饰

  • 静态变量被static修饰
  • 实例变量不能被static修饰

内存中的分数不同  

  • 类变量:内存中只有一份
  • 实例变量:每创建一份都会开辟一块独立的空间

调用方式不同

  • 类变量: 可以使用对象名.属性名和类名.属性名调用,推荐使用类名.属性名调用调用
  • 实例变量:对象名.属性名

生命周期不同:

  • 类变量:随着类的加载而加载 随着类的消亡而消亡
  • 实例变量:随着对象的创建 对象消失(当对象没有引用指向时) 被垃圾回收器回收

存储的位置不一样

  • 类变量:方法区
  • 实例变量:堆中

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

查看下面代码

public class Car {
    String color;// 成员变量

    // 成员方法
    public void drive(String name) {
       //声明在方法上的name和定义在方法里的speed都是局部变量
        int speed = 80;
        System.out.println("汽车正在以" + speed + "迈的速度行驶...");
    }
}

成员变量和局部变量的主要区别如下:

定义的位置不同: 

  • 成员变量定义在类中方法外,
  • 局部变量定义在方法中或者是方法声明上

在内存中的位置不同: 

  • 成员变量是在堆区,
  • 局部变量是在栈区

生命周期不同:

  • 成员变量是随着对象的创建而存在,随着对象的销毁而销毁
  • 局部变量是随着方法的调用而存在,随着方法调用完毕而销毁

默认值不同:

  • 成员变量有默认值
  • 局部变量没有默认值,不赋值不能直接使用
类的成员之二:方法

成员变量是用来存储对象的数据信息的,那么如何表示对象的行为功能呢?就要通过方法来实现

概念:

方法也叫函数,是一个独立功能的定义,是一个类中最基本的功能单元。把一个功能封装为方法的目的是,可以实现代码重用,从而简少代码量。

方法的使用原则

  • 必须先声明后使用。类,变量,方法等都要先声明后使用
  • 不调用不执行,调用一次执行一次。谁先调用,谁先执行
  • 方法执行完毕之后,会回到方法调用处

成员方法分为两类

  • 实例方法:没有static修饰的方法,必须通过实例对象来调用。
  //有参,有返回值的实例方法
    public int getMax(int a, int b) {
        return (a > b ? a : b);
    }
  • 静态方法:有static修饰的方法,也叫类方法,可以由实例对象来调用也可以由类名来调用。推荐使用类名调用
   //有参,有返回值的静态方法
    public static int getMax(int a, int b) {
        return (a > b ? a : b);
    }

声明方法语法格式

格式详解:

  • 修饰符: 修饰符后面一一介绍,例如:public,static等都是修饰符
  • 返回值类型:表示方法运行的结果的数据类型,方法执行后将结果返回到调用者。可以是基本数据类型也可以是引用数据类型,如果无返回值类型就可以使用void来代替
  • 方法名:给方法起一个名字,见名知意,能准确代表该方法功能的名字
  • 参数列表:方法内部需要用到其他方法中的数据,需要通过参数传递的形式将数据传递过来,可以是基本数据类型、引用数据类型。带参方法定义时,参数中的数据类型与变量名都不能缺少,缺少任意一个程序将报错。带参方法定义时,多个参数之间使用逗号(,)分隔。参数列表也可以为空。
  • 方法体:方法要完成特定功能代码
  • return:结束方法,并将方法的结果返回去。如果返回值类型不是void,方法体中必须保证一定有return 返回值;语句,并且要求该返回值结果的类型与声明的返回值类型一致或兼容。如果返回值类型为void时,return 后面不用跟返回值,甚至也可以没有return语句。return语句后面就不能再写其他代码了,否则会报错:Unreachable code

如何在其他类中调用方法

实例方法

类方法

public class Demo02Method {
    //无参,无返回值实例方法
    public void method1() {
        System.out.println("无参,无返回值方法");
    }

    //无参,有返回值静态方法
    public static int method2() {
        return 1;
    }
}

class TestDemo02Method{
    public static void main(String[] args) {
        //创建对象
        Demo02Method method = new Demo02Method();
        //调用实例方法
        method.method1();
        //调用静态方法
        method.method2(); //不推荐
        Demo02Method.method2(); //推荐
    }
}

​形参和实参

  • 形参:在定义方法时方法名后面括号中声明的变量称为形式参数(简称形参)即形参出现在方法定义时。
  • 实参:调用方法时方法名后面括号中的使用的值/变量/表达式称为实际参数(简称实参)即实参出现在方法调用时。

总结:

  • 调用时,需要传“实参”,实参的个数、类型、顺序顺序要与形参列表一一对应如果方法没有形参,就不需要也不能传实参。
  • 调用时,如果方法有返回值,可以接受或处理返回值结果,当然也可以不接收,那么此时返回值就丢失了。如果方法的返回值类型是void,不需要也不能接收和处理返回值结果。

 在本类中访问本类的成员变量和成员方法

  • 直接写成员变量名或者是成员方法名,不需要加“对象名."和"类名."。唯一例外:静态方法中不能直接访问本类的非静态的成员变量和成员方法
public class Demo02Method {
    //无参,无返回值实例方法
    public void method1() {
        method2();//本类中调用其他方法
        System.out.println("无参,无返回值方法");
    }

    //无参,有返回值静态方法
    public static int method2() {
        //method1();错误:静态方法中不能直接访问本类的非静态的成员变量和成员方法
        return 1;
    }
}
方法调用内存分析

方法不调用不执行,调用一次执行一次,每次调用会在栈中有一个入栈动作,即给当前方法开辟一块独立的内存区域,用于存储当前方法的局部变量的值,当方法执行结束后,会释放该内存,称为出栈,如果方法有返回值,就会把结果返回调用处,如果没有返回值,就直接结束,回到调用处继续执行下一条指令。

查看下列代码,分析是如何执行的

package demo01;


public class Demo03GetMax {
    public static void main(String[] args) {
        System.out.println("main...start...");

        //调用方法: 传递的是常量
        int result = getMax(100,200);
        System.out.println("100和200的最大值: "+result);

        //调用方法方法: 传递变量
        int a = 10, b = 20;
        int max = getMax(a,b);
        System.out.println(a+"和"+b+"的最大值: "+max);

        System.out.println("main...end...");

    }

    //设计一个方法可以获取两个int数的较大值,数据来自于参数

    public static int getMax(int a, int b) {
        int max = (a>b) ? a : b;
        return max;//结束方法,并且把max中的数据,返还给方法的调用处/者
    }
}

图解分析

方法的调用总结:

有返回值的方法调用方式

public class Demo01DYMethod {
    public static void main(String[] args) {
        System.out.println("main...start...");

        //1.赋值调用: 把有返回值的方法的调用结果保存到对应的变量中
        //数据类型 变量名称 = 方法名称(参数...);
        int result = getSum(10,20);
        //可以对结果数据做其它操作
        //result *= 100;
        System.out.println("和: "+result);

        //2.输出/打印调用: 把有返回值的方法的调用结果直接交给输出语句
        //System.out.println(方法名称(参数...));
        System.out.println(getSum(100,200));

        //3.单独调用: 既不保存方法的结果,也没有对结果进行输出
        getSum(5,10);

        System.out.println("main...end...");
    }

    //定义方法,获取2个int数字之和
    public static int getSum(int a, int b) {
        int sum = a + b;
        return sum;
    }
}

无返回值的方法调用方式

public class Demo02DYMethod {
    public static void main(String[] args) {
        System.out.println("main...start...");
        //1.单独调用: 既不保存方法的结果,也没有对结果进行输出
        //方法名称(参数...);
        printSum(10,20);

        //2.赋值调用: 把有返回值的方法的调用结果保存到对应的变量中
        //数据类型 变量名称 = 方法名称(参数...);
        //int a = printSum(5,15);//错误的,int变量只能保存整数,但是printSum方法执行结束没有返回任何结果数据
        //void a = printSum(5,15);//错误的,void根本不是数据类型

        //3.输出/打印调用: 把有返回值的方法的调用结果直接交给输出语句
        //System.out.println(方法名称(参数...));
        //System.out.println(printSum(3,2));//错误: 因为printSum方法执行完毕后,没有任何结果返回

        System.out.println("main...end...");
    }

    //定义方法,打印2个int数字之和
    public static void printSum(int a, int b) {
        int sum = a + b;
        System.out.println("和: "+sum);
        return ;//结束方法,返回到方法的调用处,注意没有带回任何数据
    }
}

方法的注意事项

  • 方法不能嵌套定义(在定义方法的内部又定义了其它方法),可以调用其它方法
  • 方法可以嵌套调用
  • 返回值类型,必须要和 return 语句返回的数据的类型要匹配,否则编译失败 。
  • 不能在 return 后面写代码, return 意味着方法结束,所有后面的代码永远不会执行,属于无效代码。
  • void表示无返回值,可以省略return,也可以单独的书写return,后面不能加数据,写个分号
方法重载

概念:

  • 在同一个类中,多个功能相同,但是参数列表不同的多个方法。同时存在一个类中的现象,就叫做方法重载。

作用/目的:

  • 减少程序员的学习和使用成本
  • 减少了方法名称的数量

JVM 调用

  • 根据名称找到对应的方法
  • 根据参数的数量找到对应的方法
  • 根据参数的类型确定最终要调用的方法 (首先: 做类型完全匹配 其次: 完全匹配的找不到,再做自动类型提升的匹配)

方法重载与哪些因素无关

  • 与参数的名称无关
  • 与返回值类型无关
  • 与修饰符无关

方法重载中参数列表不同有哪些情况

  • 参数数量不同
  • 参数类型不同
  • 多个类型,顺序不同

代码示例

public class Demo {
    public static void main(String[] args) {
        method(10,10.0);
    }

    //1.此方法只有一个int类型参数
    public static void method(int a) {

    }
    //2.此方法只有两个int类型参数
    //方法2和方法1参数的数量是不同的,可以构成重载
    public static void method(int a,int b) {

    }
    //3.此方法只有一个double类型参数
    //方法3和方法2参数的数量是不同的,可以构成重载
    //方法3和方法1参数虽然都是只有一个,但是类型不同,可以构成重载
    public static void method(double a) {

    }

    //4.此方法有一个int类型参数和一个double类型参数
    public static void method(int a,double b){

    }
    //5.此方法有一个double类型参数和一个int类型参数
    //方法5和方法4,虽然参数都是2个,但是类型的顺序不同
    public static void method(double a,int b){

    }
}

总结: 同类多个方法同名的前提下,。  只看多个方法的参数(除了名称以外)有区别,就构成重载

方法参数传递

前置知识:

  • 使用=进行赋值的特点:把基本类型变量a的值赋值给基本类型变量b时,其实是把a中的值复制一份给变量b,之后不管如何修改变量b中的值,都不会影响变量a中的值
  • 变量的作用范围:方法内部定义的变量只在所定义的方法内有效(可以使用),出了方法的作用范围,就不能使用了。

基本数据类型作为方法参数

public class Demo {
    public static void main(String[] args) {
        int a = 10;
        int b = 20;
        System.out.println("ms...a="+a);//10
        System.out.println("ms...b="+b);//20
        //调用方法
        change( a , b );
        System.out.println("me...a="+a);//10
        System.out.println("me...b="+b);//20
    }

    public static void change(int a, int b) {
        System.out.println("cs...a="+a);//10
        System.out.println("cs...b="+b);//20
        a = a*10;
        b = b*10;
        System.out.println("ce...a="+a);//100
        System.out.println("ce...b="+b);//200
    }
}

图解:

结论:

  • 基本数据类型的参数,形式参数的改变,不影响实际参数

结论依据:

  • 每个方法在栈内存中,都会有独立的栈空间,方法运行结束后就会弹栈消失

 引用数据类型作为方法参数

public class Demo03RefVar {
    public static void main(String[] args) {
        int[] arr = { 10 , 20 };
        //System.out.println(arr);//数组名称: 保存数组在内存中的地址值[I@1540e19d
        System.out.println("ms...arr[0]="+arr[0]);//10
        System.out.println("ms...arr[1]="+arr[1]);//20
        //调用方法
        change( arr );
        System.out.println("me...arr[0]="+arr[0]);//100
        System.out.println("me...arr[1]="+arr[1]);//200
    }

    public static void change(int[] arr ) {
        System.out.println("cs...arr[0]="+arr[0]);//10
        System.out.println("cs...arr[1]="+arr[1]);//20
        arr[0] = arr[0]*10;
        arr[1] = arr[1]*10;
        System.out.println("ce...arr[0]="+arr[0]);//100
        System.out.println("ce...arr[1]="+arr[1]);//200
    }
}

图解

结论:

  • 对于引用类型的参数,形式参数的改变,影响实际参数的值

结论依据:

  • 引用数据类型的传参,传入的是地址值,内存中会造成两个引用指向同一个内存的效果,所以即使方法弹栈,堆内存中的数据也已经是改变后的结果
转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/831667.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号