继续浏览精彩内容
慕课网APP
程序员的梦工厂
打开
继续
感谢您的支持,我会继续努力的
赞赏金额会直接到老师账户
将二维码发送给自己后长按识别
微信支付
支付宝支付

Java学习笔记系列【二】类与对象的进一步探索!

qq_感受时光的匆匆流失_0
关注TA
已关注
手记 7
粉丝 19
获赞 154

上次我们讲到创建对象。这次我们深入来研究下对象在内存中的关系。这些对象在内存中的究竟发生哪些操作了?
我们先来看下上次的这个代码。

Public class Puppy{
    public Puppy(String name){
        System.out.println("它的名字是:"+name);
   }
    public static void main(String[] args){
    //创建一个Puppy对象。
      Puppy myPuppy = new Puppy("tommy");
    }
}

重点:Puppy myPuppy = new Puppy(“tommy”);
在解释之前,我们先补充下。因为我们介绍的类和对象是引用数据类型。
而引用数据类型必然存在栈内存-----堆内存的引用关系。
见代码哦亲:

代码:

Puppy myPuppy  //实例化myPuppy,在栈内存中创建myPuppy对象
new Puppy("tommy"); //初始化Puppy,把堆内存中的name赋值为tommy

一图值千金,下面我们来看张图吧。
![图片描述][1]

首先初始化Puppy,在堆内存中把name赋值为tommy.
在实例化myPuppy,在栈内存中创建myPuppy对象,并指向堆内存。

我们在来看个代码:

class Person{   //定义个Person类。(人.)
        String name;  //定义name属性。
        int age;  //定义age属性。
        public void tell(){  //定义tell()行为。方法。
                System.out.println("姓名:"+name+"年龄:"+age);
        }
};

public class Demo{
        public static void main(String args[]){
           Person  per=new Person();  //创建并实例化对象per.
    }
}

其中Person的类图是这样的。
![图片描述][2]

这里来介绍下类图的概念:
类图包含3个组成部分。第1个是Java中定义的类名。第2个是属性。第3个是该类提供的方法。(用UML图来表示的话,第1层为类名,第2层为类的属性,第3层为类的方法。属性和方法之前可以添加一个修饰符。"+"号表示具有公共可见性 "-"号:私有可见性。"#"号:受保护的可见性 "_"号:静态的

看了上面的类图概念是不是有晕了?码段代码来清醒下。

public class Employee{  //定义雇员类。
    private int empID;   //雇员ID.
    public double calcSalary(){  //calcSalary()方法。(薪水)
    }
}

类图
![图片描述][3]
第1层:为java中的Employee类名。
第2层:为Employee类中empID属性,该属性为公共。且是int型的。
第3层:为Employee类中calcSelary();行为,该行为为公共。且是double型

其实上面的代码 Person per =new Person();还可以这样划分。

Person per=null; //声明对象。(赋初为空null)
per=new Person();  //实例化对象。(指向堆内存。)

为了理解,我们还是在码几个程序。


class Person{
String name;
int age;
public void tell(){
System.out.println("姓名:"+name+"年龄:"+age);
}
}

public class Demo01{
public static void main(String args[]){
Person per1=null; //声明对象(赋初值。)
Person per2=null; //声明对象(赋初值。)
per1=new Person(); //实例化对象per1(指向对内存Person)
per2=new Person(); //实例化对象per2.
per1.name="张三"; //改变per1指向的堆内存中name的值
per1.age=30; //改变per1指向的堆内存中age的值.
per2.name="李四"; //改变per2指向的堆内存中name的值
per2.age="33"; //改变per2指向的堆内存中age的值
System.out.println("per1对象中的内容为:");
per1.tell();
System.out.println("per2对象中的内存为:");
per2.tell();
}
}

>代码**运行效果**:
![图片描述][4]
代码在**内存中表现**:
![图片描述][5]

**代码逻辑:**这个per1=new Person();和per2=new Person();是分别指向不同的堆内存空间。然后分别更改per1和per2里指向的堆内存空间里的name和age的值,在输出。

> **所谓的引用数据类型,实际上传递的就是堆内存的使用权,可以同时为一个堆内存空间定义多个栈内存的引用操作。**
来看段代码吧,亲。。

class Person{ //定义Person类。
String name; //定义名字属性。
int age; //定义年龄属性。
public void tell(){ //定义tell行为。
System.out.println("姓名为: "+name+"年龄为: "+age);
}
};
public class Demo02{
public static void main(String args[]){
Person per1 =null; //声明per1对象(赋初值)
Person per2 =null; //声明per2对象(赋初值)
per1 = new Person(); //只实例化per1对象。
per2=per1; //把per1的堆内存空间所有权分配给per2.
per1.name="张三"; //设置per1中name属性内容。
per1.age=30; //设置per1中age属性内容。
per2.name="李四"; //设置per2中name属性内容。
per2.age=33; //设置per2中age属性内容。
System.out.println("per1中对象的内容为:");
per1.tell(); //通过per1对象调用tell()方法。
System.out.println("per2中对象的内容为:");
per2.tell(); //通过per2对象调用tell()方法。
}
}

> **代码运行效果:**
![图片描述][6]
**代码逻辑:**首先声明per1和per对象并赋初值,实例化per1对象,并把per1的堆内存空间所有权分配给per2。也就是说per1和per2指向同一个堆内存空间。首先通过per1变量,更改name="张三",age=30。在通过per2变量,更改为name="李四",age=33。**(覆盖原来的值)**在输出。。。

这段代码在内存中表现形式为:
![图片描述][7]
![图片描述][8]
因为per1和per2都是指向同一个堆内存空间。通过per2来改变name及age的属性值。就等同于per1来改变的。

*我们在来看一道引用传递的例子。*

class Person{ //定义个Person类.(人.)
String name; //定义name属性。
int age; //定义age属性。
public void tell(){
System.out.println("姓名:"+name+"年龄:"+age);
}
}
public class Demo03{
public static void main(String[] args){
Person per1=null; //声明per1对象在栈内存,并赋空值
Person per2=null;//声明per2对象在栈内存,并赋空值
per1=new Person();//实例化per1对象,指向对应的堆内存
per2=new Person();//实例化per2对象,指向对应的堆内存

       per1.name="张三";  //改变per1所指向的堆内存中name值。
       per1.age=30; //改变per1所指向的堆内存中的age值。
       per2.name="李四";
       per2.age=33;

    per2=per1;  //per2指向per1的堆内存空间。之前per2所指向的堆内存空间为垃圾。
    System.out.println("per1对象的内容:");
    per1.tell();
    System.out.println("per2对象的内容:");
    per2.tell();
  }

}


代码逻辑:我们首先声明per1和per2对象,并实例化per1和per2。指向对应的堆内存空间。
![图片描述][9]
然后我们给per1所指向的堆内存空间中name赋值为”张三”,age为30。
给per2所指向的堆内存空间中name赋值为”李四”,age为33。
![图片描述][10]
但是后来per2有重新指向per1所指向的堆内存空间。(之前per2所指向的堆内存空间被jvm视为垃圾空间。)
![图片描述][11]
在执行“System.out.println(“”).....per1.tell();”
”System.out.println(“”)........per2.tell();”
分别调用tell();方法。输出内容。
代码运行效果:
![图片描述][12]
上面的代码因为per2改变了指向,所以其原本的内存空间就没有任何栈的引用。则这样的内存就被称为垃圾空间,等待着垃圾收集机制GC的回收。
我们了解这块内容java中内存是如何划分的,以后不管多复杂的程序都可以按照这个内存划分图来分析滴,亲。
**亲,这次我们就聊的这了,我们下期再见了。荆轲刺秦王。**
> 感谢老铁们再次把宝贵的时间浪费在我的文章上。哀心的感谢各位老铁们。谢谢。。
这里我推荐一个在线UML制图工具。[ProcessOn][13]挺好用的。老铁们有兴趣的可以去逛逛。

  [1]: http://img.mukewang.com/59f212e000014b1705960318.png
  [2]: http://img.mukewang.com/59f217b50001234602030155.png
  [3]: http://img.mukewang.com/59f2c7900001e39e03010126.png
  [4]: http://img.mukewang.com/59f34d720001e00404030150.png
  [5]: http://img.mukewang.com/59f34da9000119ab07420323.png
  [6]: http://img.mukewang.com/59f359e60001a59202780170.png
  [7]: http://img.mukewang.com/59f35fbe00015dfb06150194.png
  [8]: http://img.mukewang.com/59f35fed0001a9bf06330185.png
  [9]: http://img.mukewang.com/59f367650001d04c04910231.png
  [10]: http://img.mukewang.com/59f3680e00012dcb04520145.png
  [11]: http://img.mukewang.com/59f3692800018c9604320163.png
  [12]: http://img.mukewang.com/59f369c70001e05402970165.png
  [13]: https://www.processon.com/
打开App,阅读手记
1人推荐
发表评论
随时随地看视频慕课网APP