Day17---学习Java第二弹
2021-07-27
对象和类
对象引用传递初步分析
引用传递的精髓:同一块堆内存空间,可以同时被多个栈内存所指向,不同的栈可以修改同
一块堆内存的内容。
下面通过若干个程序,以及程序的内存分配图,来进行代码的讲解。
我们来看一个范例:
class Person {
String name ;
int age ;
public void tell() {
System.out.println("姓名:" + name + ",年龄:" + age) ;
}
}
public class TestDemo {
public static void main(String args[]) {
Person per1 = new Person() ; // 声明并实例化对象
per1.name = "张三" ;
per1.age = 20 ;
Person per2 = per1 ; // 引用传递
per2.name = "李四" ;
per1.tell() ;
}
}
对应的内存分配图如下:
再来看另外一个:
class Person {
String name ;
int age ;
public void tell() {
System.out.println("姓名:" + name + ",年龄:" + age) ;
}
}
public class TestDemo {
public static void main(String args[]) {
Person per1 = new Person() ; // 声明并实例化对象
Person per2 = new Person() ;
per1.name = "张三" ;
per1.age = 20 ;
per2.name = "李四" ;
per2.age = 30 ;
per2 = per1 ;// 引用传递
per2.name = "王五" ;
per1.tell() ;
}
}
对应的内存分配图如下:
垃圾:指的是在程序开发之中没有任何对象所指向的一块堆内存空间,这块空间就成为垃圾,所有的垃圾将等待GC(垃圾收集器)不定期的进行回收与空间的释放。
面向对象的封装性
封装(encapsulation)又叫隐藏实现(Hiding the implementation)。就是只公开代码单元的对外接口,而隐藏其具体实现。比如手机,手机的键盘,屏幕,听筒等,就是其对外接口。你只需要知道如何按键就可以使用手机,而不需要了解手机内部的电路是如何工作的。封装机制就像手机一样只将对外接口暴露,而不需要用户去了解其内部实现。
在研究封装性之前,先来看一段代码:
1 package com.wz.classandobj;
2
3 class Book{
4
5 String title;
6 double price;
7
8 public void getInfo(){
9 System.out.println("图书的名称:"+title+" 图书的价格:"+price);
10 }
11 }
12
13 public class TestDemo {
14 public static void main(String args[]) {
15 Book book = new Book();
16 book.title = "Java开发";
17 book.price = -89.9;
18 book.getInfo();
19 }
20 }
运行结果:
图书的名称:Java开发 图书的价格:-89.9
以上代码没有任何语法错误,却存在一个业务逻辑的错误,因为图书的价格不能为负数。造成这种情况的的原因在于:对象可以在一个类的外部直接访问属性。
如何解决?我们需要将Book类中的属性设置为对外不可见(只能是本类访问),可以使用private关键字来定义属性。
修改之前的代码如下:
1 package com.wz.classandobj;
2
3 class Book{
4
5 private String title;
6 private double price;
7
8 public void getInfo(){
9 System.out.println("图书的名称:"+title+" 图书的价格:"+price);
10 }
11 }
12
13 public class TestDemo {
14 public static void main(String args[]) {
15 Book book = new Book();
16 book.title = "Java开发";
17 book.price = -89.9;
18 book.getInfo();
19 }
20 }
运行:
1 Exception in thread "main" java.lang.Error: Unresolved compilation problems: 2 The field Book.title is not visible 3 The field Book.price is not visible 4 5 at com.wz.classandobj.TestDemo.main(TestDemo.java:16)
但是,要想让程序可以正常运行,那么必须让外部可以操作Book类的属性。在Java开发中,针对属性有这样的定义,在类中定义的属性都要求使用private声明,如果属性需要被外部所使用,那么按照要求,定义属性相应的setter和getter方法,以Book类中的String title 为例:
(1)setter方法是设置属性内容:
public void setTitle(String t)
注意:有参数。
(2)getter方法是取得属性内容:
public String getTitle()
注意:无参数。
范例:为Book类的封装属性设置setter和getter。
1 package com.wz.classandobj;
2
3 class Book{
4
5 private String title;
6 private double price;
7
8 public String getTitle() {
9 return title;
10 }
11
12 public void setTitle(String title) {
13 this.title = title;
14 }
15
16 public double getPrice() {
17 return price;
18 }
19
20
21 public void setPrice(double price) {
22 this.price = price;
23 }
24
25 public void getInfo(){
26 System.out.println("图书的名称:"+title+" 图书的价格:"+price);
27 }
28 }
29
30 public class TestDemo {
31 public static void main(String args[]) {
32 Book book = new Book();
33 book.setTitle("Java开发");
34 book.setPrice(-89.9);
35 book.getInfo();
36 }
37 }
运行结果:
图书的名称:Java开发 图书的价格:-89.9
发现,图书的价格是负数,需要加入检查业务逻辑错误的代码,可以在setter中增加验证,如果值为正,赋值,否则为默认值0.0:
public void setPrice(double price) {
if(price > 0.0){
this.price = price;
}
}
对于数据验证,在Java标准开发中应该由辅助代码完成。在实际开发中,setter往往只是简单的设置属性内容,getter只是简单的取得属性内容。
开发建议:以后在定义类的时候,所有的属性都要编写private封装,封装之后的属性如果需要被外部操作,则编写setter、getter。