该系列文章系个人读书笔记及总结性内容,任何组织和个人不得转载进行商业活动!
第四章:方法操作实例变量-对象的行为
状态影响行为,行为影响状态;
对象有状态和行为两种属性,对应实例变量和方法;类的每个实例可以维持自己的实例变量;
面向对象的重点之一就是
行为会依据状态来决定:
换句话说,就是方法会使用到实例变量的值;
比如,大狗叫声的大,小狗叫声小,声音数实例变量,叫是方法;
类所描述的是对象知道什么和执行什么:
编写类时,是在描述JVM应该如何制作该类型的对象;
任一类的每个实例都带有相同方法,但是方法可以依据实例变量的值来表现不同的行为;
比如歌曲song是一个类,具体的音乐就是实例,播放音乐时只会播放当前名字的音乐,虽然播放方法都是相同的;
song.play(title);
方法的参数:你可以传值给方法
比如你可以告诉狗叫几声:dog.bark(3);
可能会用到形参(parameter)或实参(argument)来调用传给方法的参数;
关于形式参数和实际参数,可以这样区分:
方法会运用形参,调用一方会传入实参;
实参是传给方法的值,传入后就成了形参;
参数跟局部(local)变量是一样的;有类型和名称,可在方法内运用;
如果方法需要参数,就必须传给他适当类型的值;
void bark(int numOfBarks){numOfBarks = numOfBarks - 1}
这里调用必须传以int类型表示的值,在方法中numOfBarks可作为一般的变量使用;
你可以从方法中取返回值:
方法可以有返回值,每个方法都声明返回值类型;
void类型,代表并没有任何返回类型;
也可以声明一个方法,回传给调用方法指定的返回值;int giveSecret(){return 0;}
如果你将一个方法声明有返回值,你就必须返回所声明类型的值(或声明类型兼容的值);(后续多态章节会讨论更多细节)
你可以向一个方法中传递一个以上的参数:
方法可以有多个参数,声明时以逗号分开,传入时也是;
且方法的参数一定要以正确数量、类型和顺序来传递参数;
Java是通过值传递的,也就是说通过copy传递:
int x = 7;
void go(int z){}
以x为参数传入go()这个方法中,x的字节组合会被拷贝并装进z中;
在方法中改变z的值,并不影响x的值,它只是一个copy;即方法无法改变调用方法所传入的参数;
方法只能有一个返回值,多个返回值时可以把返回类型说明为int的数组,将值装进数组中返回;如果是混合类型的多值返回,后续的ArrayList时会再讨论;
知识小问答:
如果传入的参数是对象而不是primitive主数据类型会怎样?
在java中传递的所用东西都是值,但此值是变量所携带的值;引用对象的变量所携带的是远程控制而不是对象本身;
若你对方法传入参数,实际上传入的是远程控制的拷贝;
一定要返回所声明的类型吗?
可以返回会被隐含转换成声明类型的其他类型值;但若声明的类型容器小于想要返回的类型时,必须做明确转换;
返回值也可以被忽略,Java并未要求一定要处理返回值;这代表你要的是方法的行为而不是返回值;
要点:
类定义对象的所知所为;
对象所知是实例变量;
对象所为者是方法;
方法可依据实例变量来展现不同的行为;
方法可使用参数,单参或多参;
传入方法的参数必须符合声明时的数量、顺序和类型;
传入与传出方法的值类型可以隐含的方法或明确的缩小;
方法必须声明返回值;
运用参数与返回类型:
Getter和Setter(正式的应该叫Accessor与Mutator):
可以然你执行get和set;
Getter返回实例变量的值;
Setter取用一个参数来设定实例变量的值;
示例:
String brand;
String getBrand(){return brand;}
void setBrand(String aBrand){brand = aBrand;}
封装(Encapsulation):
不封装可能会很难看;
比如通过圆点运算符来存取,就好比使用遥控器直接控制某对象的实例变量,但如果控制器落在坏人手里就糟了;
所以我们要创建Setter方法给所有的实例变量,并寻找某种方法强制其他程序都必须通过Setter来设定变量而不是直接存取;
这样,就可以在Setter方法中检查,确保实例变量被设定为合理的值;
如:public void setHeight(int ht){if(ht > 0){height = ht;}}//设置身高大于0;
数据隐藏:
从不良数据改成可以保护数据且让你还能修改数据的方式如下:
——使用共有与私有这两个存取修饰符(access modifier);
封装的基本原则:
将你的实例变量标记为私有的,并提供公有的getter与setter来控制存取动作;
(当有了更多的Java设计与编写经验之后,会有许多不同做法);
将实例变量标记为private;
将getter与setter标记为public;
采访一个即将被封装的对象引用:
封装会对我的实例变量加上绝对领域,因此没有人能够恶搞我的变量;(比如身高就不能是负数)
强迫其他程序一定经过setter,如此就能检查参数并判断是否可以执行;
setter也许可以退回不合理的值,或是抛出Exception、或者自己进行取小数点的动作;
重点是setter中可以执行任何动作;
实例变量应该要标记为private,并通过getter与setter来存取,如此才能有机会确保实例变量值会落在合法的范围内;
示例(Code-GoodDogTestDrive.java GoodDog.java)
class GoodDogTestDrive{
public static void main(String[] args){
GoodDog one = new GoodDog();
GoodDog two = new GoodDog();
one.setSize(50);
two.setSize(10);
System.out.println(one.getSize());
System.out.println(two.getSize());
one.bark();
two.bark();
}
}
class GoodDog{
private int size;
public int getSize(){
return size;
}
public void setSize(int aSize){
size = aSize;
}
public void bark(){
if(size > 60){
System.out.println("big");
}else if(size > 20){
System.out.println("middle");
}else{
System.out.println("small");
}
}
}
log:
bogon:180131-第四章 huaqiang$ javac *.java
bogon:180131-第四章 huaqiang$ java GoodDogTestDrive
50
10
middle
small
数组中对象的行为:(已封装的对象)
数组中的对象就如同其他的对象一样,区别在于如何存取;
pets[0].setSize(30);
pets[0].getSize();
声明与初始化实例变量:
变量的声明至少需要名称与类型;声明的同时也可以初始化(赋值)变量;
但如果你没有初始实例变量时,调用getter会发生什么事?
实例变量永远都会有默认值:
integers——0
floating points——0.0
boolean——false
reference——null
数字的primitive(包括char)的预设为0,boolean的预设为false,对象引用则为null;
注意null代表没有操作对象的远程控制,远程控制它是个引用而不是对象;
实例变量与局部变量:
实例变量是声明在类内而不是方法中;
局部变量是声明在方法中的;
局部变量在使用前必须初始化;(否则通不过编译)
对于方法的参数,局部变量的规则也同样适用:
他们在方法中声明(方法的参数列表中);
方法调用但没传参数,编译器会报错,所以方法的参数一定会被初始化,编译器会确保方法被调用时会有与声明所相符的参数;
变量的比较:(primitive主数据类型或引用)
两个primitive主数据类型的变量比较,使用“==”;
两个引用变量是否引用到堆上的同一对象,实用“==”;
需要知道两个对象是否真正相等(意义上的相等),需要使用equals()方法;
这里==只用阿里比对两个变量的字节组合,实质所表示的意义则不重要;