--------------------------------------------------------------------------------------------莫听穿林打叶声,一蓑烟雨任平生--------------------------------------------------------------------------------------------

Java笔记day10

一、一个对象的内存调用
    以手机举例
        手机:
            属性:品牌,颜色,价格
            行为:打电话,发短信,学习
        Phone:
            成员变量:brand,color,price
            成员方法:call,sendMessage,study

查看代码
    public class Phone {
        String brand;        //定义成员变量
        String color;
        int price;

        public void call(String s) {        //定义成员方法,打电话
            System.out.println("给" + s + "打电话");
        }
        
        public void sendMessage() {
            System.out.println("群发短信");     //发短信
        }
        
        public void study() {               //学习
            System.out.println("学习");
        }
    }

    class PhoneDemo {
        public static void main(String[] args) {
            Phone p1 = new Phone();         //通过手机类创建一个手机对象
            System.out.println("品牌:" + p1.brand + ",颜色:" + p1.color + ",价格:" + p1.price);  //访问成员变量
            
            p1.brand = "华为";              //手动给成员变量进行赋值操作
            p1.color = "黑色";
            p1.price = 2999;
            System.out.println("品牌:" + p1.brand + ",颜色:" + p1.color + ",价格:" + p1.price);
            
            p1.call("杨老板");              //访问成员方法
            p1.sendMessage();
            p1.study();
        }
    }


    内存调用过程
        首先,Jvm先在方法区生成两个class文件,phone.class和phoneDemo.class,phone.class中有成员变量和成员方法,
    phoneDemo.class里有main方法,在栈里生成一个main方法,main方法中存有p1,p1对应一个地址ox0001(假设),
    对应到堆里面new出来phone区域,这一区域里有成员变量brand,color,price和方法区对应的地址值ox0002(假设)
    此时并未赋值,所以输出时是堆里给出的默认值,null,null,0,然后执行赋值操作,华为,黑色,2999覆盖掉null,null,0
    再次调用时,Jvm就会打印出输入的数据。后面调用方法时p1先在堆里ox0001里寻找成员方法所对应的地址值,这里是ox0002,
    在方法区找到方法之后到栈中执行,执行完第一个方法后栈就会清理这一个方法,然后执行后面的方法,都是执行一个清理一个
    全部执行完之后,清理掉main方法,程序执行完毕。

二、两个对象的内存调用
    如果是两个独立的对象创建,就是和上面的过程类似,但如果是下面的情况,就会出现不同的结果

查看代码
    class PhoneDemo {
        public static void main(String[] args) {
            Phone p1 = new Phone();         //通过手机类创建一个手机对象
            System.out.println("品牌:" + p1.brand + ",颜色:" + p1.color + ",价格:" + p1.price);  //访问成员变量
            
            p1.brand = "华为";              //手动给成员变量进行赋值操作
            p1.color = "黑色";
            p1.price = 2999;
            System.out.println("品牌:" + p1.brand + ",颜色:" + p1.color + ",价格:" + p1.price);
            
            Phone3 p2 = p1;
            p2.price = 3999;
            System.out.println(p1.price);       //输出是3999
            System.out.println(p2.price);       //输出是3999
        }
    }

    输出都是3999,是因为p2.price = 3999;是直接在地址值所对应的堆那个区域里进行的修改,修改但之后p1.price和p2.price都
    指向它,所以会输出同一个值。

三、成员变量和局部变量
    成员变量与局部变量的区别:
        1、在类中的位置不同
            成员变量 类中方法外
            局部变量 方法内或者方法声明上
        2、在内存中的位置不同
            成员变量 堆内存:
                随着对象在堆内存中的创建而出现,所以成员变量是在堆内存中出现
            局部变量 栈内存:
                由于方法执行是在栈中执行,所以在方法中定义的局部变量,也就是存在与栈里。
        3、生命周期不同
            成员变量 随着对象的创建而存在,随着对象的消失而消失
            局部变量 随着方法的调用而存在,随着方法的调用完毕而消失
        4、初始化值不同
            成员变量 有默认的初始化值
                原因:由于成员变量随着对象的创建而存在,而对象的创建是在堆内存中创建,
                    而堆内存中的变量创建的时候系统会给予默认值,所以我们在代码中定义的时候可以不赋值。
            局部变量 没有默认的初始化值,必须先定义,赋值,才能使用。
                原因:由于局部变量随着方法的调用而存在,是在栈里面调用的,而栈里面的变量系统不会给予默认值,
                    所以在代码中定义的时候必须要赋值。
        5、问题:
            1)、成员变量的名称可以和局部变量的名称一样吗?
                可以,调用的时候,访问的变量遵循就近原则。
            2)、方法与方法之间的局部变量可以互相访问吗?
                不可以,因为作用域的范围不同。
        6、举例

查看代码
            class VariableDemo {
                int a;              //直接在类中定义的叫成员变量
            public static void main(String[] args) {
                int a = 20;         //在方法里面定义的叫局部变量
                System.out.println(a);
            }
        }

四、类的举例

查看代码
    class Animal {                          //定义一个动物类,叫的方法
        public void shout() {
            System.out.println("动物叫");
        }
    }

    class Demo1 {
        /*类是一个引用数据类型,所以它可以当作形参的数据类型
          今后看到一个方法上的形参的数据类型是一个类的时候
          实际上它需要的是一个对应类的对象的地址值
        */
        public void fun1(Animal a) {        //相当于Animal a = new Animal();
            a.shout();
        }
    }

    class Demo2 {
        /*当方法的参数是基本数据类型的时候
          调用方法的时候传入的是该基本数据类型实际的数值
        */
        public void fun2(int x, int y) {
            System.out.println(x + y);
        }
    }

    public class ParameterDemo {
        public static void main(String[] args) {
            Demo1 d = new Demo1();      //要想调用fun1()这个方法,就要创建Demo1这个类的对象,只有对象才能去调用方法

            Animal animal = new Animal();   //创建一个Animal类的对象
            d.fun1(animal);

            Demo2 d2 = new Demo2();     //创建Demo2的对象
            int i = 10;
            int j = 20;
            d2.fun2(j, i);
        }
    }

五、匿名对象
1、匿名对象:简单来说,就是没有名字的对象
2、用内存的形式解释:
    我们在学习匿名对象之前,一直都是在堆内存中new对象,然后将地址值赋给栈里面的变量,
    这个变量也就是对象的名字,而匿名对象,就说明没有栈中变量引用。
3、匿名对象的使用场景
    当调用方法的时候,仅仅只调用一次的时候,可以使用匿名对象
    调用多次的时候,不适合使用匿名对象
4、那么,匿名存在的意义是什么?
    某些情况下,我们就想使用一次某个对象中的功能,后续也不会使用它了
    这时候,就可以使用匿名对象,使用完之后,就被JVM认为是一个垃圾空间(栈里面没有引用指向它),等待被回收。
5、匿名对象可以在调用方法的时候被当作参数进行传递
6、举例      

查看代码
    class Computer{
        public void coding(){
            System.out.println("敲代码");
        }
    }

    class Demo3{                            //注:同一个包下,类名不能重复
        public void method(Computer c){
            c.coding();
        }
    }

    public class AnonymousDemo {
        public static void main(String[] args) {

            Computer com = new Computer();      //在没有学习匿名对象之前,我们如果想使用其他类中的方法,就必须创建对象
            com.coding();
            
            new Computer().coding();        //匿名对象

            com.coding();                   //使用第一个对象再调一次方法
            Demo3 demo3 = new Demo3();       //创建Demo3的对象

            System.out.println("=====匿名对象当作参数传递======");      //匿名对象当作参数传递
            demo3.method(new Computer());
        }
    }

六、封装概要
    定义一个学生类:
        成员变量:姓名,年龄
        成员方法:show()

    在正常开发的过程中,会出现一个问题:
        通过对象.变量名的形式给成员变量进行赋值,在赋值年龄的时候,居然可以赋值一些不合理的数据,比如我赋值10000
    根据现实实际情况来看,年龄赋值10000是不合理。
        所以,如果在赋值的时候,加一个判断,校验一下,如果合理,就允许赋值,如果不合理,就不允许赋值,
    那么,在哪里加入判断比较合适呢?
        在Java中测试类中一般情况下,只允许创建对象,调用方法或者访问成员变量
    所以,把添加判断的逻辑代码放到其它类中,而在其它类中有成员变量,成员方法。
    成员变量上只能是定义成员变量,加不了判断。所以只能另外写一个成员方法,来为年龄进行赋值,在赋值的时候加入判断
        虽然可以加入了一个方法传参的形式去给成员变量进行赋值,并且在赋值的时候进行判断,但是如果不使用定义的方法,
    就使用对象名.成员变量的形式去赋值,依旧可以赋值一些不合理的值。
        这时有一个办法可以让外界不能直接的访问到成员变量就好了,这样如果想要进行对成员变量赋值,
    就不能通过对象名.成员变量的形式去赋值,只能通过我们定义的方法去赋值。
        有这样的方法,java替我们考虑到了这样的情况,提供了一个关键字给我们使用,这个关键字叫做:private
    private: 私有的意思,使用private修饰的成员变量,在其他类中不能直接访问
        说到现在的案例,主要引出一个思想:面向对象的三大特征之一-----封装

    封装:
        实际上就是隐藏对象的属性和相关实现细节,仅仅对外提供公共的访问的方式。
    举例:

查看代码
    class Student2 {
        String name;        //定义成员变量
        private int age;

        public void setAge(int x){
            if(x>0 & x<=100){
                age = x;
            }else {
                System.out.println("输入的年龄有误");
            }
        }

        public void show() {        //输出打印该对象的所有成员变量
            System.out.println("姓名:" + name + ",年龄:" + age);
        }
    }

    public class StudentDemo1 {
        public static void main(String[] args) {        
            Student2 s1 = new Student2();    //创建Student2的对象          
            s1.show();          
            
            s1.name = "李玉伟";              //给对象的成员变量进行赋值
            s1.age = 18;
            s1.show();

    //      s1.age = 10000;                 //这是不符合道理的
            s1.setAge(100);
            s1.show();
        }
    }

七、封装
    封装:
        是指隐藏对象的属性和实现细节,仅对外提供公共访问方式。
    好处:
        隐藏实现细节,提供公共的访问方式
        提高了代码的复用性
        提高安全性。
    封装原则:
        将不需要对外提供的内容都隐藏起来。
        把属性隐藏,提供公共方法对其访问。
        封装中的private关键字介绍:
            1、是一个权限修饰符。
            2、可以修饰成员(成员变量和成员方法)
            3、被private修饰的成员只在本类中才能访问。

    练习:
        随机找身边的一个事物,定义一个类
        成员变量用private修饰,提供公共的getXxx()和setXxx()方法
        以及提供一个可以输出所有成员变量的show()方法
        然后定义一个测试类,去创建对象使用看看

查看代码
        class Person {
            private String name;
            private int age;

            public void setName(String s) {
                name = s;
            }

            public String getName() {
                return name;
            }

            public void setAge(int i) {
                age = i;
            }

            public int getAge() {
                return age;
            }

            public void show() {            //提供一个方法可以输出打印所有的成员变量
                fun2();                     //被private修饰的成员方法,只能在本类中进行访问
                System.out.println("姓名:" + name + ",年龄:" + age);
            }

            private void fun2() {
                System.out.println("这是一个被private修饰的成员方法");
            }
        }

        public class PrivateDemo1 {
            public static void main(String[] args) {
                Person p1 = new Person();       //创建Person对象
                //p1.name;              //因为成员变量都被private私有的关键字修饰了,所以在其他类中访问不到。
                //p1.age;               //只用调用公共方法进行获取
                
                String name = p1.getName();
                int age = p1.getAge();
                System.out.println(name + "---" + age);

                p1.setName("杨万里");        //通过公共的方法对成员变量进行赋值
                p1.setAge(18);
                p1.show();
               
                //p1.fun2();                 //被private修饰成员方法,在其他类中也是不可以被访问的。
            }
        }

 

八、this关键字

查看代码
class Student3 {
    private String name;        //定义成员变量
    private int age;
        /*提供公共的getXxx()和setXxx()方法
        回想一下,我们之前给变量进行命名的时候,有一个规则:见名知意,所以我们改一下
        我们根据变量命名规则的见名之意的方式修改了形参的名字,但是运行程序后发现,
        虽然我们也调用了方法,也进行了传参,但是,结果依旧没有成功赋值,这是为什么呢?

    ****因为变量的调用遵循就近原则****

        我们理想上,是想让传进来的这个参数赋值给该对象的成员变量
        实际上传进来的实参的值后面进行赋值的时候,还是赋值给方法上的变量,与成员变量没有关系
        想的是,将传进来的name值赋值给当前对象的name值
        */
    public void setName(String name) { 
        /*Student3.name这种写法,我们没有介绍过
          如果有一个东西可以代表当前调用该方法的对象就好了
          谁可以代替当前方法的对象呢?
          java提供了一个关键字:this
          Student3.name = name;
        这样写,就代表将传进来的参数,赋值给当前调用该方法的对象的成员变量name
        */
        this.name = name;
    }

    public String getName() {
        return name;       //其实这里隐藏了一个this关键字,代表的是返回当前调用该方法的对象的成员变量name
                           //这里相当于 return this.name
    }

    public void setAge(int age) {
        this.age = age;
    }

    public int getAge() {
        return age;
    }

    public void show() {
        System.out.println("姓名:" + name + ",年龄:" + age);
    }

}

public class StudentDemo2 {
    public static void main(String[] args) {
        Student3 s1 = new Student3();       //创建学生对象并对成员变量进行赋值
        s1.setName("杨万里");               //对s1对象的姓名进行赋值
        s1.setAge(18);
        s1.show();                          //调用show()方法查看所有成员变量值
    }
}

 

posted @ 2021-12-04 19:22  等你回眸一笑  阅读(48)  评论(0)    收藏  举报