1、封装
1.1、封装的概念及特点
- 封装即将类的某些信息隐藏在类内部,不允许外部程序直接访问,并通过该类提供的方法来实现对隐藏信息的操作和访问。简单来说就是,隐藏对象信息,留出访问的接口。
- 举个例子,比如ATM机,我们利用它可以完成存取款、转账、余额查询等等操作。而钞票便是ATM的重要信息,但是我们在外部是无法直接看到这些钞票的,更不可能随意地拿走它(嘿嘿,除非…),这便是ATM机对钞票这个重要信息的隐藏,但同时ATM机提供了相应的操作接口(插卡口、取钞口、操作屏等),用户可以通过简单的操作,便可以获取ATM中存储的钞票。作为用户,根本不会去关心ATM内部在什么位置以什么方式存放这些钞票的,用户只需提供正确的银行卡和密码,并经过简单的操作便可以拿到钞票了。
- 封装的特点:
- 只能通过规定的方法访问数据
- 隐藏类的实例细节,方便修改和实现
1.2、封装的实现
- 实现步骤:
- 修改属性的可见性,将其修饰符设为private(加上private则只能在当前类中访问该属性,即隐藏了信息);
- 创建对应属性的公有(修饰符设为public)的getter和setter方法(及提供了对外开放的可操作接口,其中get为取值,set为赋值);
- 在getter和setter方法中加入属性的控制语句(通常在这里我们可以对属性的合法性进行判断,比如年龄必须大于0等)
- 1.修改
Cat
类代码如下。
- 在编写getter和setter方法的时候可按下图进行操作
- 若只选择getter方法,则该属性便为只读属性了,这样的话也可以控制读写。
public class Cat {
// 1、修改属性的可见性,加上修饰符private,限定只能在当前类内访问
private String name;
private int month;
private double weight;
private String species;
// 创建公有的getter和setter方法
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getMonth() {
return month;
}
public void setMonth(int month) {
// 可以在赋值语句中添加限制,这样更符合实际
if (month <= 0)
System.out.println("宠物猫的年龄必须大于0,赋值有误!");
else
this.month = month;
}
public double getWeight() {
return weight;
}
public void setWeight(double weight) {
this.weight = weight;
}
public String getSpecies() {
return species;
}
public void setSpecies(String species) {
this.species = species;
}
}
- 2.修改CatTest类代码。
public class CatTest {
public static void main(String[] args) {
Cat cat = new Cat();
cat.setName("旺旺");
cat.setMonth(5);
cat.setWeight(3.5);
cat.setSpecies("中华田园");
if (cat.getMonth()>0) {
System.out.println("昵称:" + cat.getName() + ",年龄:" + cat.getMonth() + ",体重:" + cat.getWeight() + ",品种:"
+ cat.getSpecies());
}else {
System.out.println("年龄有误!");
return;
}
}
}
3.运行结果如下所示。
4.补充:我们要编写一个带年龄参数的构造方法(若调用了无参构造,还应额外编写一下无参构造)
public Cat(int month) {
//这里若还用this.month=month的话,那在setter方法中限制条件将无效,若用setter方法赋值,则会生效
this.setMonth(month);
}
- 在
CatTest
类中使用该构造方法。
Cat cat = new Cat(5);//此时我们可以将属性直接赋值
3、使用包进行类管理
- 在计算机中,我们使用文件对信息进行存储,然后用文件夹进行文件管理,同一个文件夹可以存储多个不同的文件,同名的文件只能存储在不同的文件夹,那在Java中是如何进行不同类文件的管理呢?
- 在Java中是用包进行文件的管理的,用以解决同名文件的冲突问题。
- 前面提到过包的命名规则,这里再重申一下,我们一般用域名的倒序+模块+功能的形式来命名(这里我们简单命名一下即可,格式为com.xxx.machanics)。
- 1.新建一个包,功能命名为
com.cxs.machanics
,然后再新建一个Cat类。
package com.cxs.mechanics;//定义包
/**
* 机器猫类
*
* @author chaixingsi
*
*/
public class Cat {
public Cat() {
System.out.println("我是机器猫!");
}
}
- 2.同理在com.cxs.animal 包下的Cat类下的无参构造方法中添加一句
System.out.println("我是宠物猫猫!");
- 3.再新建一个包,命名为
com.cxs.test
,然后新建一个Test
类。
package com.cxs.test;//定义包,并且只能有一个Package语句,必须放于首行
//import com.cxs.animal.*;//第一种:导入com.cxs.animal这个包下的所有类
import com.cxs.animal.Cat;//第二种:导入特定的类,这种加载方式效率要更高一点
//import com.cxs.mechanics.Cat;//这样会导致同名类的冲突(IDE会不清楚到底导入哪个Cat类),可以通过*问题解决
import com.cxs.mechanics.*;//这样在创建机器猫对象的时候得加上包名,不然默认还是调用的宠物猫类
//import com.cxs.*;//这里的含义是加载cxs文件夹下的类(.是代表当前目录),所有会造成无法解析类的错误,
public class Test {
public static void main(String[] args) {
Cat cat = new Cat();
// 第三种:在类名面前加上包名
com.cxs.animal.CatTest test = new com.cxs.animal.CatTest();
// 要想创建一个机器猫,必须按如下形式进行
com.cxs.mechanics.Cat mechanicsCat = new com.cxs.mechanics.Cat();
}
}
3、static关键字
- static是静态的意思。
- 1.在宠物猫
Cat
类当中加一个价格属性,并用public
修饰,如public int price;
。 - 2.然后在修改
Test
代码如下。
package com.cxs.test;
import com.cxs.animal.Cat;
public class Test {
public static void main(String[] args) {
Cat oneCat = new Cat();
oneCat.setName("旺旺");
oneCat.price = 200;
System.out.println(oneCat.getName() + "的售价为" + oneCat.price);
Cat twoCat = new Cat();
twoCat.setName("哈哈");
twoCat.price = 500;
System.out.println(twoCat.getName() + "的售价为" + twoCat.price);
}
}
- 3.运行代码,结果显而易见。
- 4.然后在宠物猫
Cat
类属性价格前面加上static
关键字(如public static int price;
),会在Test类当中有提示(要以静态的方式Cat.price来访问该属性)。
- 5.再次运行代码,结果如下。
- 6.解释:用static修饰的成员叫做静态成员,也叫类成员,它具有这样的一个特征:无论这个类实例化出来多少对象,都会共用同一块静态空间。而在上面的例子中,在price前面加上static修饰后,上面的宠物猫的价格是共用同一块存储空间的,每只实例化出来的宠物猫对象都可以操作这块空间区域,也就是后者将价格做了修改,因此两者的价格也就一样了。
- 7.总结:静态成员有两个特征:
- 静态成员是类对象共享的。
- 静态成员在类加载时产生,销毁时释放,生命周期长。
- 8.下面我们继续修改代码(运行略)。静态属性(类属性)的访问方式有两种(推荐后者):
对象名.属性
或者类名.属性
public class Test {
public static void main(String[] args) {
Cat oneCat = new Cat();
oneCat.setName("旺旺");
oneCat.price=100;
Cat.price = 200;
System.out.println(oneCat.getName() + "的售价为" + oneCat.price);
}
}
- 9.静态方法同静态属性。
- 10.那类前面能加static吗?在类前面加static会提示这个修饰符不合法,只有public、abstract、final三者可以。
- 11.局部变量前也不允许添加static,只能添加final关键字。
- 12.在成员方法中是可以直接访问类的静态成员的(包含属性和方法)。
- 13.静态方法中不能直接访问同一个类中的非静态成员,只能直接调用同一个类中的静态成员,若非要访问,只能在静态方法中实例化出来一个对象,然后通过
对象.成员
的方法来访问。
4、代码块
- 在Java的程序当中,代码一般使用大括号
{}
括起来的,那么在语句当中出现大括号{}
,这就是代码块。 - 当代码块出现在普通方法中时,我们称它为普通代码块,并且普通代码块的执行顺序和一般语句的执行顺序是一样的,都是顺序执行的。
- 当代码块直接在类当中定义时,它便成为构造代码块了。
- 1.修改
Cat
类代码。
public class Cat {
private String name;
private int month;
private double weight;
private String species;
public static int price;
{
System.out.println("我是构造代码块");
}
public Cat() {
System.out.println("我是宠物猫");
}
public void run(String name) {
{
System.out.println("我是普通代码块1");
}
System.out.println(name + "快跑");
{
System.out.println("我是普通代码块2");
}
}
}
- 2.修改Test代码。
public class Test {
public static void main(String[] args) {
Cat oneCat = new Cat();
oneCat.run("旺旺");
}
}
- 3.运行代码结果如下,发现构造代码块是在创建对象的时候调用,会优先无参构造方法的执行(多个构造代码块之间也是顺序执行的)。
- 4.此时若在构造代码块前面加上static,就会变为静态代码块。我们再Cat类当中加上如下代码并运行。
static{
System.out.println("我是静态代码块");
}
- 5.其实,静态代码块是在类加载时调用的,优先构造代码的执行(当然多个静态代码块之间也是顺序执行的)。
- 6.继续修改Test类,我们再实例化一个对象。那么这些代码块会执行几次呢?
public class Test {
public static void main(String[] args) {
Cat oneCat = new Cat();
Cat twoCat = new Cat();
}
}
- 7.下面结果表明,不管实例化多少对象,静态代码块在类加载时只执行一次(可以将执行一次的代码放在静态代码块当中类提高程序效率),而构造代码块执行的次数与实例化对象的数量是一致的。
- 8.另外,我们可以在构造代码块中为当前类当中的成员属性和静态属性赋值,但是在静态代码块中只能给静态属性赋值,不能给成员属性赋值(除非先实例化出来对象,然后通过
对象.成员
的方法来访问)。 - 9.我们再来看一下run(String name)方法。每个代码块是一个独立的作用空间,在run方法中有三个代码块(总共三对{}),因此有三个作用空间。修改run()方法及Test类的代码如下。
public void run(String name) {
{
int temp = 12;
System.out.println("我是普通代码块1,temp=" + temp);
}
System.out.println(name + "快跑");
{
int temp = 13;
System.out.println("我是普通代码块2,temp=" + temp);
}
}
public class Test {
public static void main(String[] args) {
Cat oneCat = new Cat();
oneCat.run("旺旺");
}
}
- 10.运行代码,结果如下。
- 11.若在方法体中也输出temp值会怎么样呢?这时会出错,提示无法解析。这是因为代码块当中的temp的生命周期仅限于代码块的范围。
- 12.那么我们在方法体中再定义一个temp呢?这时代码块2中的temp会提示重复定义,这是因为该方法体中temp生命周期是在它定义的地方开始直到方法的结束。若将方法体的temp移到方法体最上面,则两个代码块中的temp便都重复定义了。
5、Java命名规范
下面我们来总结一下Java的命名规范:
5.1、包
- 所有字母都小写;
- 包命名的路径要符合所开发的系统模块的定义,以便看了包名就明白是哪个模块,从而直接到对应包里找相应的实现。
- 由于Java面向对象的特性,每名开发人员都可以编写属于自己的包,为了保证每个包名的唯一性,在最新的Java编程规范中,要求开发人员在自己定义的包名前面加上唯一的前缀。由于互联网上的域名称是不会重复的,所有多数开发人员采用自己
公司的名称.项目名.模块名.*.*.*
,因此在互联网上域名,可以称作自己程序包的唯一前缀。 - 个人项目包的命名:
- indi:个体项目,指个人发起,但非自己独自完成的项目,可公开或私有的项目,版权主要属于发起者。例如:包名为
indi.发起者名.项目名.模块名.*.*.*
。 - pers:个人项目,指个人发起,独自完成,可分享的项目,版权主要属于个人。例如:包名为
pers.个人名.项目名.模块名.*.*.*
。 - priv:私有项目,指个人发起,独自完成,非公开的私人使用项目,版权属于个人,例如:包名为
priv.个人名.项目名.模块名.*.*.*
。
- indi:个体项目,指个人发起,但非自己独自完成的项目,可公开或私有的项目,版权主要属于发起者。例如:包名为
- 团队项目包的命名:
- team:团队项目指由团队发起,并由该团队开发的项目,版权属于该团队所有。例如:包名为
team.团队名.项目名.模块名.*.*.*
。 - com:公司项目,由项目发起的公司所有。例如:包名为
com.公司名.项目名.模块名.*.*.*
。
- team:团队项目指由团队发起,并由该团队开发的项目,版权属于该团队所有。例如:包名为
5.2、类名
- 类的命名,所有单词的首字母大写。
- 根据约定,Java类名通常以大写字母开头。
- 如果类名称由多个单词组成,则每个单词的首字母均应为大写,例如:TestPage;
- 如果类名中包含单词缩写,则这个缩写的词的首字母均应为大写,例如:XMLExample;
- 还有一点命名技巧就是由于类是设计是用来代表对象的,所有命名类时应尽量选择名词。
5.3、方法名
- 首字母小写,如果是由多个单词组成的话,第一个单词首字母小写,其余单词的首字母应大写。
5.4、变量名
- 主要命名规范有以下三种:
- Camel标记法:首字母是小写的,接下来的单词都以大写字母开头。
- Pascal标记法:首字母是大写的,接下来的单词都以大写字母开头。
- 匈牙利标记法:在以Pascal标记法的变量前面附加小写序列说明该变量的类型。
- 在Java中,我们一般使用匈牙利标记法,格式:
[Prefix]-BaseTag-Name
,其中 [Prefix]是可选的,BaseTag是数据类型的缩写,Name是变量名字,说明变量的作用,具体用法详见百科:匈牙利标记法