Java 学习笔记 ------第五章 对象封装

本章学习目标:

  • 了解封装的概念与实现
  • 定义类、构造函数与方法
  • 使用方法重载与不定长度自变量
  • 了解static方法

一、Java封装概念

在面向对象程式设计方法中,封装(英语:Encapsulation)是指,一种将抽象性函式接口的实作细节部份包装、隐藏起来的方法。
封装可以被认为是一个保护屏障,防止该类的代码和数据被外部类定义的代码随机访问。
要访问该类的代码和数据,必须通过严格的接口控制。
封装最主要的功能在于我们能修改自己的实现代码,而不用修改那些调用我们代码的程序片段。
适当的封装可以让程式码更容易理解与维护,也加强了程式码的安全性。

Java封装类实例:

public class EncapTest{

   private String name;
   private String idNum;
   private int age;

   public int getAge(){
      return age;
   }

   public String getName(){
      return name;
   }

   public String getIdNum(){
      return idNum;
   }

   public void setAge( int newAge){
      age = newAge;
   }

   public void setName(String newName){
      name = newName;
   }

   public void setIdNum( String newId){
      idNum = newId;
   }
}

以上实例中public方法是外部类访问该类成员变量的入口。
通常情况下,这些方法被称为getter和setter方法。
因此,任何要访问类中私有成员变量的类都要通过这些getter和setter方法。
通过如下的例子说明EncapTest类的变量怎样被访问:

public class RunEncap{

   public static void main(String args[]){
      EncapTest encap = new EncapTest();
      encap.setName("James");
      encap.setAge(20);
      encap.setIdNum("12343ms");

      System.out.print("Name : " + encap.getName()+ 
                             " Age : "+ encap.getAge());
    }
}
output:
Name : James Age : 20

二、构造函数的重载

如果定义类时,没有撰写任何构造函数,编译程序会自动加入一个无参数、内容为空的构造函数,称为默认构造函数。可以定义多个构造函数,只要参数类型或个数不同,这称为重载构造函数

public class SomeClass {
	public void someMethod(){
	}
	
	public void someMethod(int i){
	}
	
	public void someMethod(float f){
	}
	
	public void someMethod(int i,float f){
	}
}

编译程序在处理重载函数时,会依以下顺序来处理:
(1)还没有装箱动作前可符合自变量个数与类型的方法
(2)装箱动作后可符合自变量个数与类型的方法
(3)尝试有不定长度自变量并可符合自变量类型的方法
(4)找不到合适的方法,编译错误

三、static和final

final定义的变量可以看做一个常量,不能被改变;
final定义的方法不能被覆盖;
final定义的类不能被继承。
final static 就是再加上static的特性就可以了

static和final是没有直接关系的

static 是在内存中分配一块区域,供整个类通用,所有的类的对象都享有它的共同的值

static 和final的区别###

一、static :

什么情况下我们要使用static呢?
1、只想用一个存储区域来保存一个特定的数据——无论要创建多少个对象,甚至根本不创 建对象。
2、我们需要一个特殊的方法,它没有与这个类的任何对象关联。也就是说,即使没有创建对象,也需要一个能调用的方法。
为满足这两方面的要求,可使用static(静态)关键字。
下面我先举个例子:

一旦将什么东西设为static,数据或方法就不会同那个类的任何对象实例联系到一起。所以尽管从未创建那个类的一个对象,仍能调用一个static方法,或访问一些static数据。
为了将数据成员或方法设为static,只需在定义前置和这个关键字即可。
例如,下述代码能生成一个static数据成员,并对其初始化:

class StaticTest { 
Static int i = 47; 
}

现在,尽管我们制作了两个StaticTest对象,但它们仍然只占据StaticTest.i的一个存储空间。这两个对象都共享同样的i。请考察下述代码:
StaticTest st1 = new StaticTest();
StaticTest st2 = new StaticTest();
此时,无论st1.i还是st2.i都有同样的值47,因为它们引用的是同样的内存区域。
有两个办法可引用一个static变量。正如上面展示的那样,可通过一个对象命名它,如st2.i。亦可直接用它的类名引用,而这在非静态成员里是行不通的(最好用这个办法引用static变量,因为它强调了那个变量的“静态”本质)。
StaticTest.i++;
其中,++运算符会使变量增值。此时,无论st1.i还是st2.i的值都是48。

类似的逻辑也适用于静态方法。既可象对其他任何方法那样通过一个对象引用静态方法,亦可用特殊的语法格式“类名.方法()”加以引用。静态方法的定义是类似的:

class StaticFun { 
static void incr() { StaticTest.i++; } 
} 

从中可看出,StaticFun的方法incr()使静态数据i增值。可用典型的方法调用incr():

StaticFun sf = new StaticFun(); 
sf.incr();

或者,由于incr()是一种静态方法,所以可通过它的类直接调用:
StaticFun.incr();
对方法来说,static一项重要的用途就是帮助我们在不必创建对象的前提下调用那个方法。
举简单一例如下:

public class TestStatic { 
public static void main(String args[]){ 
PhoneCard mycard_1 = new PhoneCard();//创建第一张卡对象 
PhoneCard mycard_2 = new PhoneCard();//创建第二张卡对象

mycard_1.addFee = 0.8;//给第一张卡的附加费addFee赋值为0.8 
//注意到我们没有给第二张卡赋值

System.out.println("第一张卡的附加费:" + mycard_1.addFee); 
System.out.println("第二张卡的附加费:" + mycard_2.addFee); 
//发现没有?输出结果中第二张卡的附加费也是0.8 了。 
System.out.println("卡的附加费:" + PhoneCard.addFee); 
//该句的打印输出表明卡类的附加费都是0.8 
} 
}

class PhoneCard{ 
static double addFee;//静态域addFee 
}

该例创建了两个类,PhoneCard类只定义了一个变量,TestStatic类里创建了两个PhoneCard类对象,并给其中的一个对象的附加费addFee赋值,而另一个对象没赋值。

由上例可以看出,静态域保存在类的公共存储单元,而不是保存在对象的存储单元内。

static 修饰方法时是同理。

二、final:

final可修饰类、域(变量和常量)、方法 (而static不修饰类)

1、final修饰类,表示该类不可被继承。
如定义了一个final类:

final class SnowBird{ 
int i; 
String s; 
static void fly(){ 
System.out.println("snowbird is flying"); 
} 
}

//现在定义一个类,试图继承SnowBird类:

public class Bird extends SnowBird{ 
public static void main(String[] args){ 
SnowBird.fly(); 
} 
}

把上面的两个类拷贝到文件中,文件名保存为Bird.java ,现在编译看看会出现什么问题?
出错信息是:cannot inherit from final SnowBird
表明final 类不可被继承。

那么,final修饰变量是怎么样呢?
2、final修饰变量
程序中经常需要定义各种类型的常量,如:3.24268,"201"等等。这时候我们就用final来修饰一个类似于标志符名字。如:

final String connectNumber = "201"; 

final表明 connectNumber是一个常量,它的取值在整个过程都不会改变。

如果把final 去掉则connectNumber就成为变量了。

有时我们为了节省空间,常量通常声明为 static .因为如上所说的 static 用的是类的内存空间。

3、修饰方法:
final修饰的方法,称为最终方法。最终方法不可被子类重新定义,即不可被覆盖。
如父类定义了public void fly(){ ....}
则子类就不能定义
public void fly(){。。。。。。}
但注意覆盖与重载的区别。不能被覆盖并不是不能被重载,如你还可以定义
public void fly(int i){.....},

举个例子如下:

class FinalValue { 
static final int i = 1; 
final void fly(){ 
System.out.println("SnowBird is flying over FinalValue "); 
} 
}

class TestFinal extends FinalValue { 
int i = 2; 
void fly(){ 
System.out.println("SnowBird is flying over TestFinal"); 
System.out.println("In class FinalValue static Final i = "+ FinalValue.i); 
System.out.println("In class TestFinal i = "+ i); 
} 
void fly(String s){ 
System.out.println("fly("+ s + ")"); 
} 
}

public class Test { 
public static void main(String args[]){ 
TestFinal tf = new TestFinal(); 
tf.fly(); 
tf.fly("ok"); 
System.out.println(tf.i); 
} 
} 

把上面的程序保存为Test.java编译看看,出现什么错误?
然后,把TestFinal类中的 void fly(){ ... } 注解掉
即 如下

/* void fly(){ 
System.out.println("SnowBird is flying over TestFinal"); 
System.out.println("In class FinalValue static Final i = "+ FinalValue.i); 
System.out.println("In class TestFinal i = "+ i); 
}*/

现在再编译看看通过了吗? 可见重载与覆盖的区别了吧。 还发现 FinalValue中的 i 与 TestFinal中的 i 没关系 。因为对于变量而言,重定义只是父类的同名域被隐藏了而已。

posted @ 2016-02-29 10:10  20135113肖昱  阅读(1793)  评论(0编辑  收藏  举报