封装
封装对象初始流程
package cc.openhome;
class CashCard {
String number;
int balance;
int bonus;
CashCard(String number,int balance,int bonus) {
this.number = number;
this.balance = balance;
this.bonus = bonus;
}
}
构造函数是与类名称同名的方法,不用声明返回类型。为了区别构造函数的参数与类的数据成员同名,在对象数据成员前加上this关键字,表示将参数的值指定给这个对象的数据成员。
封装对象操作流程
可以定义方法,来解决撰写重复流程的问题。方法若有返回值,必须在方法前声明返回值的类型,如果不用返回值,方法名前声明void。在Java命名习惯中,方法名称首字母是小写。
封装对象内部数据
用户撰写程序时,如果有些数据是类所私有,在Java中可以使用private关键字定义。如果没有提供方法存取private成员,那用户就不能存取(除非你愿意提供取值方法)。
在Java命名规范中,取值方法的名称形式是固定的,也就是以get开头,之后接上首字母大写的单词。
封装目的主要就是隐藏对象细节,将对象当作黑箱进行操作。
private也可以用在方法或构造函数声明上,私有方法或构造函数通常是类内部某个共享的演算流程,外界不用知道私有方法的存在。private也可以用在内部类声明。
package cc.openhome;
class CashCard {
private String number;
private int balance;
private int bonus; //使用private定义私有成员
...
void store(int money) { //要修改balance,得通过store()定义的流程
if(money > 0) {
this.balance += money;
if(money >= 1000) {
this.bonus++;
}
}
else {
System.out.println("储值是负的?");
}
}
int getBalance() { //提供取值方法成员
return balance;
}
int getBonus() {
return bonus;
}
int getNumber() {
return number;
}
}
类语法细节
public权限修饰
之前我们的Cashcard类是定义在cc.openhome包中,现在要将CashCard类定义至cc.openhome.virtual包中,除了原始码与位码的文件需求必须符合包层级之外,原始码内容也得做些修改:
package cc.openhome.virtual;
class CashCard {
……
}
修改过后出现错误CashCard is not public in cc.openhome.virtual; cannot be accessed from outside package----
,是因为不同包的类程序代码中,想要直接存取,就会出现这样的错误。
包范围权限:如果没有声明权限修饰的成员,只有在相同包的类程序代码中,才可以直接存取。
如果想在其他包的类程序代码中存取某包的类或对象成员,则该类或对象成员必须是公开成员,在Java中要使用public加以声明。
构造函数、方法、对象前都可以声明public。
包权限:包管理其实还有权限管理上的概念,没有定义任何权限关键字时,就是包权限。
如果类上没有声明public权限关键字,类中的方法就算是public,也等于是包权限了,因为类本身是包权限,其他包根本就无法使用类,那么其中定义的方法也无法使用。
构造函数
在定义类时,可以使用构造函数定义对象建立的初始流程。构造方法是与类名称同名,无须声明返回类型的方法。
public class Some {
private int a = 10;
private Sting text;
public Some (int a, String text) {
this.a = a;
this.text = text;
}
……
}
如果这样建立Some对象,成员a和text会初始两次。a和text分别先初始为0与null,之后在通过构造函数流程,设定为构造函数参数的值。如果定义类时,没有撰写任何构造函数,编译程序会自动加入一个无参数、内容为空的构造函数。所以也可以以自变量方式调用构造函数:Some some = new Some();
只有编译程序自动加入的构造函数,才称为默认构造函数,自行撰写无参数没有内容的构造函数不称为默认构造函数。
如果自行撰写了构造函数,编译程序就不会自动建立默认构造函数。
public class Some {
public Some(int a) {
}
}
那就只有一个具int参数的构造函数,所以就不可以用new Some()来创建对象,而必须使用new Some(1)的形式来创建对象。
构造函数与方法重载
视使用情境或条件的不同,创建对象时也许希望有对应的初始流程。可以定义多个构造函数,只要参数类型或个数不同,这称为重载构造函数。
有些场合建议,如果定义了有参数的构造函数,也可以加入无参数的构造函数,即使内容为空也无所谓,这是为了日后使用上的弹性。
定义方法时也可以进行重载,可为类似功能的方法提供统一名称,但根据参数类型或个数的不同调用对应的方法。返回值类型不可作为方法重载依据。
编译程序在处理重载方法时,会依以下顺序来处理:
1. 还没有装箱动作前可符合自变量个数与类型的方法。
2. 装箱动作后可符合自变量个数与类型的方法。
3. 尝试有不定长度自变量并可符合自变量类型的方法。
4. 找不到合适的方法,编译错误。
使用this
除了被声明为static的地方外,this关键字可以出现在类中的任何地方,在对象建立后为“这个对象”的参考名称。
在Java中,this()代表了调用另一个构造函数,调用哪个构造函数视调用this()时给的自变量类型与个数而定。
this()调用只能出现在构造函数的第一行。
如果撰写了对象初始区块,对象建立之后会先执行对象初始区块,接着才调用指定的构造函数。
对象初始区块:在创建对象之后,调用构造函数之前,想要执行的流程。用{}定义。
static类成员
被声明为static的成员,不会让个别对象拥有,而是属于类,是将类名称作为名称空间。通过类名称与“.”运算符就可以取得static成员。
根据命名习惯,首字母大写就是类,类名称加上“.”运算符直接调用的就是static成员。
在static方法或区块中不能出现this关键字,也不能调用非static方法或区块。但是可以使用static数据成员或方法成员。
import static语法是为了偷懒,但要注意名称冲突问题,有些名称冲突编译程序可通过以下顺序来解析:
- 局部变量覆盖:选用方法中的同名变量、参数、方法名称。
- 成员覆盖:选用类中定义的同名数据成员、方法名次。
- 重载方法比较:使用import的各个静态成员,若有同名冲突,尝试通过重载判断。
不定长度自变量
要使用不定长度自变量,声明参数列时要在类型关键字后加上…。实际上int…声明的变量实际上展开为数组。
package cc.openhome;
public class MathTool {
public static int sum(int... numbers) {
int sum = 0;
for(number : numbers) {
sum += number;
}
return sum;
}
}
使用不定长度自变量时,方法上声明的不定长度参数必须是参数列最后一个。
public void some (int arg1,int arg2,int...varargs) {
...
}
使用两个以上不定长度自变量是不合法的。
内部类
在类中再定义类,这称为内部类。
内部类也可以使用public、protected或private声明。
内部类本身可以存取外部类的成员,通常非静态内部类会声明为private,这类内部类是辅助类中某些操作而设计,外部不用知道内部类的存在。
内部类也可以声明为static。