编写思路:
1. 问题:
2. 解决办法:
3. 总结:
对前面的复习
一说到 Java 就不能不说到 Java 是 “纯” 面向对象 (OO-Oriented-Object) 的语言。那什么是面向对象呢 ? 之前我们已经谈到了面向对象中两个最基本也是最重要的概念:类 , 对象。
我们之前谈到:
类是抽象的概念,是对具有共同特征 (静态的) ,共同功能或行为的事物的抽象 | 归纳 | 总结
对象是具体的 , 是某种类型的一个实例。一个对象属于某个类 , 也就具有了这个类的特征和行为。你还能举出现实生活中关于类和对象的例子吗 ?
万物皆对象.
在 java 的世界中要使用类和对象的步骤有哪些呢 ?
1. 定义类 public class Person{}
a) 在这个过程中需要给一个类名 ,类中在大部分情况下有两个信息( 属性和方法 --- 都是指的属性的定义和方法的定义 )
i. 类名的命名规则: 首字符 是字母 ,_ $ ;其他字符是 前面几种 + 数字
ii. 命名规范:每个单词的首字母大写
b) 为了描述类型的信息需要有 属性 :类似于变量的定义
c) 及方法
i. 方法又如何使用呢 ?
2. 定义好了类 我们就可以实例化对象了,实例化 ( 或称创建一个对象的 ) 语法是什么呢? (将 ( 引用 ) 类型 à 对象的过程)
a) 基本类型:int,char,double,float,b oolean
b) 引用类型:String,Math,Scanner,Person … 数组
3. 有了对象,如何方法其属性或方法呢 ?
a) 对属性的赋值 称为写
b) 从属性中读取信息 称为 读
c) 属性可以不赋值,而直接使用 — 与变量不同的
有了前面的基础,让我们一起对面向对象加深一下理解, “ 请记住 : 面向对象就是模拟现实世界 ” ,现实是什么样子,有什么问题,我们都可以用面向对象的思想以及指令对其进行描述。
private 和封装
问题:
在现实生活中有这样一种情况 , 通常一个女孩不能随便说出自己的年龄 , 比如你张的不高,不富又不帅 , 她是不会告诉你年龄的 .
首先,用我们之前的知识, 为了表达女孩这种类型并且她有年龄的这个属性我们可以用代码
public class Girl { int age;} |
此时, 对于其他人来说 , 可以随便的访问她的年龄
public class Client { public static void main(String[] args) { Girl g=new Girl(); g.age=10; System.out.println(" 女孩的年龄为 :"+g.age); // 访问她的年龄 } } |
或者比如对于一个员工来说,他的工资也有保密的要求( 比如只有他的上级才能知道 )
那如何做到这一点呢?
public class Employee { String name ; double salary ; //在外部都可以随便访问 } |
解决办法:
为了达到保密的目的
这就需要关键字private( 私有的 ); 如果我们给 Girl 的 age 添加 private 后 , 代码如下:
public class Girl { private int age ; } |
则对于其他人来说( 在客户端 ):
|
通过上面的代码,我们可以看到private 就是私有的,当类的成员 ( 想想类的成员有哪些 : 属性和方法 ) 增加这个修饰符 (modifier) 将只能在本类的 ” 内部 ” 被访问.
注意: 不是永远不能访问是在类的外部不能访问 . 就好比说你有个 private garden( 私家花园 ). 不是说谁都不能用,而是在家庭内部的成员是可以使用的 .
问题:
通过上面的private 我们已经成功的保护了 girl 的 age 不被其他人随便询问。但如果有一个高富帅想访问呢 ?
解决办法:
所以为了解决这个问题, 我们的代码如下 :
public class Girl { private int age ; public int getAge() { return age ; } public void setAge( int age) { this . age = age; } } |
我们通过添加public 的方法让外部可以访问 . 所谓 public 就是公共的 . 可以让任何人访问 . 就像 public washroom
此处的getAge 和 setAge 都是两个方法 , 跟我们之前学的方法结构上都是一样的 . 请想想他们的结构为什么是一个有返回值一个没有返回值一个有参数一个没参数呢 ?
… …
注意:
1. getAge方法是用来读的 ,setAge 是用来写的 . 如果想让这个属性是只读的 , 那只需要使用 get 方法。如果想要这个方法是可写的 . 那只需要使用 set 。并不是说两个方法必须得同时存在。
2. 尽管他们就是普通的方法,但是方法的名字必须是getXXX 和 setXXX 。这个的原因将在 ” 反射 ” 的概念中进行讲解.
有了以上的代码有的人可能会问: 现在添加了 getter( 对读取方法的统称 ) 和 setter( 对设置方法的统称 ) ,这不是又让 age 属性不安全了吗 ? 而且多写了这么多代码 . 是不是没有必要呢 ?
看看一下代码:
public int getAge() { System. out .println( "你是高富帅吗 ?" ); Scanner input = new Scanner(System. in ); String word = input.next(); if ( "y" .equalsIgnoreCase(word)) return age ; return -1; } |
从以上的代码,就显示了让属性直接可以访问,可通过getter/ setter 让其属性可以被访问的方式是不同的. 因为方法中可以控制逻辑,而属性本身不能。
我们也可以写如下的代码
public int getFangLing () { System. out .println( "你是高富帅吗 ?" ); --- 此处省略若干字 } |
我将方法的名字改为了getFangLing. 则这个属性的名字我们不在叫 age ,而是叫 FangLing 了。切记这一点 !!!
如果 私有的成员变量是boolean 类型,而其 getter 用 isXXX();
以上就是我们通过对属性私有化,然后提供公有的方法对属性进行的 ” 封装 ” .
封装是面向对象的语言的三大特征之一.
当然, 封装本身不只包含将属性封装。从语法上讲 , 我们也可以对任意段代码块进行封装 , 使其成为方法。而我们将属性和方法再进行汇总 , 可就成了我们封装的类。
封装可以让我们程序中的数据更加安全,( 就像我们前面说的女孩的年龄 , 员工的工资 ) 。封装可以让提高我们代码的复用性。 ( 如将某段代码封装在一起变成方法,随处进行调用,且方法是个“黑匣子”我们在调用时完全不需要知道具体的实现细节 ) 。
封装也是面向对象其他特征的实现基础。没有封装也就没有其他的特征.
好了, 如果你对前面的概念理解没有问题 , 请你也举个例子,表达一下封装的概念,加深一下理解吧 !
构造方法
问题:
现在, 再回头看看我们的代码 . 我们现在想没个女孩一定要有自己的年龄 , 且我们要的不是默认值 0 则你会考虑到的代码应该是 :
public class Client { public static void main(String[] args) { Girl g = new Girl(); g.setAge(1 9 ); int fangLing = g. getAge (); System. out .println(fangLing); } } |
但是,如果我们在g.setAge() 之前就访问她的年龄呢 ? 得到的将还是 0
另外,如果为表达女孩的特征,我们可能有更多的属性, 如
import java.util.Scanner;
public class Girl { private String name ; private String address ; private String email ; private String phoneNo ; ---此处省略属性若干 } |
我们想要设置女孩的每个属性需要做的是不断的调用setter
public class Client { public static void main(String[] args) { Girl g = new Girl(); g.setAge(10); g.setAddress( “山东烟台 ” ); g.setEmail( “buGaoSu@ni.com” ); } } |
解决办法
为了解决这个问题, 我们可以设置一个方法 , 一次给所有的变量赋值并且我们要保证在实例化对象的时候就进行调用 。这个方法就是 ” 构造方法 ”
形如:
public Girl(String name, String address, String email, String phoneNo, int age) { this . name = name; this . address = address; this . email = email; this . phoneNo = phoneNo; this . age = age; } |
public Girl(){} |
请注意观察这个方法的特征:
1. 没有返回值类型声明 (注意!也不使用 void)
2. 方法名与类名相同( 再次强调请遵守类名的命名规范 )
符合了以上要求就是 构造方法 ç à 构造方法一定具有以上两个特征。请注意我没有再写其他特征,也就是说我们有再增加其他的构造方法的限定和描述。
既然定义了构造方法,那我们如何调用呢?
实际上我们之前已经调用过了
Person p=new Person(); |
构造方法在调用时,使用new 关键字 |
构造方法的作用: 1. 初始化对象 2. 方便初始化 |
再来回顾一下默认之前编写的代码,
public class Person {} |
我们并未给这个类编写过构造方法, 但是我们依然可以调用构造方法
这是因为: 如果我们不定义构造方法,系统会自动定义无参 ( 没有参数 ) 的构造方法 .
换言之,无论你是否定义构造方法,java 类中一定有它的构造方法。
但是,如果我们自定义了构造方法,则系统将不再提供无参的构造方法。
注意: 以上说的自定义的构造方法,没有限制为是有参的 还是无参的
有了上面的结论,有些人可能就认为: 既然一个类无论如何都有构造方法,假定这个类是 Person ,那是不是一定可以 Person p=new Person(); 了呢 ?
答案是否定的, 原因有两点 :
1. 构造方法的本质是方法, 你可以自定义有参方法 , 这样的话就不能调用无参构造了
2. 构造方法既然是方法,因为方法的前面有修饰符(modifier) public ; 我们如果将构造方法前面增加 private ,则从类的外部也就不能访问构造方法了
我们在之前的setter 中用了关键字 this ,让我们来总结一下 this 的含义 :
this 代表当前类型的对象. 注意是对象。
当我们在使用以下代码时
Person xiaoHong=new Person(); xiaoHong.setName( “ xiaoHong ” ); |
public class Person{ private String name; } |
因为是xiaoHong.setName(); 所以在 Person 类中 this 就是指的 xiaoHong
但是如果其他人调用的话, 那 this 就是其他人了
我们可以通过Eclipse 的快捷键 Alt+shift+s O 自动生成构造方法,而我们往往会给一个类两个构造方法 , 一个是全参的,另一个是无参的 |
重载
问题:
在同一个类中,两个方法可不可以同名
解决办法:
既然是构造方法,那就跟类的名称相同,既然都跟类的名称相同。那这两个方法名就相同了。通过我们的观察可以发现,这样写是没有问题的。
我们把这种方法名相同的情况叫做方法的重载.
以下让我们更详细的描述重载的特征:
1. 方法名相同
2. 参数列表不同,它指的是对应位置上的形参的类型不同,如
a) 参数的个数不同public void m() 和 public void m(int i)
b) 参数的类型不同public void m(int i) 和 public void m(double j)
c) 参数的类型顺序不同public void m(int i,String j) 和 public void m(String j,int i);
d) 注意: 形参变量名称的不同不算不同 ,public void m(int i) 和 public void m(int j);
3. 在同一类中( 这条规则是朴素的,自然的 ) 就像说方法一个在 A 类中 一个在 B 类中,即使他们有再符合以上的两条都不是重载
注意: 我没有对返回值进行限定。
不只构造方法可以进行重载,在同一个类,任意的两个方法都可以叫做重载。
再来想想我们现实中的例子:
如果你家里有一台豆浆机,这台豆浆机可能磨豆浆, 可以榨果汁 , 那让你来用 Java 表达一下这个概念怎么表示呢 ?
注意:我们下面的返回值和参数的类型都不是本示例的重点,所以我们就用简单的两种类型(Dou,ShuiGuo) 进行表述 :
public class DouJiangJi { public String mo DouJiang( Dou dou ){ return "豆浆 " ; } public String zhaGuoZhi( ShuiGuo shuiGuo ){ return "果汁 " ; } } |
OK,这样是可以实现以上说的两个功能的 , 这两个方法名,就像我们平时用的豆浆机上的两个按钮。要磨豆浆就点磨豆浆的按钮,要榨果汁就点榨果汁的按钮。
如果你家里有一位上了年纪的老奶奶,他眼已经花了,已经分不清那两个按钮哪个是哪个了呢? 这就好比方法的调用者,如果有两个按钮,调用者需要记忆并区分两个方法的方法名。当然,方法的定义者要为方法起名也要多费周折。
而我们为何不降豆浆机的两个按钮的名字用一个代替的,如果豆浆机能根据加入的内容直接判断如何去工作岂不是这样的豆浆机更容易使用。那我们也用代码来表达一下
public class DouJiangJi { public String work ( Dou dou ){ return "豆浆 " ; } public String work ( ShuiGuo shuiGuo ){ return "果汁 " ; } } |
也许从定义者的角度,仅仅是一个方法名的不同而已。
而对于调用者来说,我们不再需要记忆两个方法的名字,java 可以根据方法名和参数的不同自动的调用对应的方法。因为在“调用前”,是不清楚具体的返回值的。所以返回值的类型不能作为判断调用那个方法的依据这也正是,为什么返回类型不能作为区分是否重载的原因。
System.out.println();就是一个方法重载的很好例子
继承
问题:
上面我们编写了Girl 类型,现在让我们来描述一下女学生类型
public class GirlStudent { private String name ; private int age ; private String grade ; private String homePhone ; --- --- 省略 getter 和 setter } |
对比我们之前的对Girl 的对应我们会发现,现在的代码无非增加了年级 (Grade) 和家庭电话 (HomePhone) 这两个信息 . 而对于 name 和 age 是在 Girl 中已经存在的。那这样而言, GirlStudent 岂不是重复做了已经在 Girl 中定义的很多信息呢 . 在现实中还有很多这样的事物 , 比如老虎类 和食肉动物 \ 笔记本电脑和电脑;前者都具有了后者的很多特征和功能 ( 属性和方法 ).
解决方案:
为了简化前者的定义,我们需要学习概念 — -继承
在现实中有句话叫做: 龙生龙,凤生凤;老鼠生来会打洞。 这就是继承。当一个类 A 的对象也是类 B 的对象的时候,我们就称类 A 继承了 B 。这是一种是一个的关系,我们也常常谓之 is-a 的关系
前面提到的 女生 也是女孩。老虎也是食肉动物,笔记本电脑也是电脑一样。
注意: 继承关系是 类与类之间的关系。
比如:有 ” 一台 ” 笔记本电脑,它继承了电脑类型,这种说法在面向对象的描述中是不确切的( 可能在现实中可以这么说,但面向对象中不行 ) 。因为 ” 一台 ” 笔记本电脑是具体的,是对象而不是类。也就谈不上具有继承关系了。
那在代码中如何表达继承呢?
public class GirlStudent extends Girl { .--- --- } |
类 A继承了类 B, 类 A 也就具有了类 B 的所有的非私有的属性和方法
注意: 不是所有的属性和方法,是非私有的。
就像在现实生活中,你继承了你父亲的东西,但是如果是他的私人物品那就不能被你继承了, 现在再让我们通过代码来表达一下:
public class Girl { String name ;} |
public class GirlStudent extends Girl {} //注意我只是 extends Girl 没有在类中写任何的代码 |
public class GirlStudentTest { public static void main(String[] args) { GirlStudent girlStudent= new GirlStudent (); girlStudent. name = "欣然 " ; } } |
girlStudent本身不具有 name 属性 , 而 girlStudent 所属的类型 GirlStudent 继承自 Girl
所以,girlStudent 也就具有了 Girl 的属性 name.
还有就是一个类只能有一个直接父类 ( 就想说一个人只能有一个亲爹 , 当然这么说不是很准备,大家还有个亲妈呢 )
以下的代码是同样的
public class Carnivore { public void eat() { System. out .println( "爱吃肉 " ); } } |
public class Tiger extends Carnivore {} |
public class TigerTest { public static void main(String[] args) { Tiger t= new Tiger(); t.eat(); } } |
请你也来分析一下以上的代码
注意:
public class Girl { private String name ; public String getName() { return name ; } public void setName(String name) { this . name = name; } } |
以上的代码将Girl 的 name 属性 private 私有化 , 而增加了 getter 和 setter 来控制访问方式 . 从生活的角度 GirlStudent 是具有 name 属性的。但对于代码而言 , 她紧紧是将 getter 和 setter 方法被继承了, name 属性本身并没有,所以
public class GirlStudentTest { public static void main(String[] args) { GirlStudent girlStudent= new GirlStudent(); girlStudent. name = "欣然 " ; } } |
|
而要访问的话需要通过getter 或 setter 方法 .
在刚刚开始讲继承的时候,我们谈到继承是一种 “ 是- 一个 ” 的关系. 就想老虎是食肉动物。女学生也是女生。数学老师是老师一样。
也就是说一位数学老师( 对象 ) 是一位老师 ( 类型 ) ,此结论先放在这 *********
我们再来想一下,我们之前如何来保存一位数学老师
数学老师 张老师=new 数学老师 ();
ç 等价于 è
MathTeacher msZhang=new MathTeacher();
现在我们来表示一下上面加********* 的那句话,用代码表示就是
Teacher msZhang=new MathTeacher();
翻译一下上面的代码就是
老师 张老师=new 数学老师 ();
前面********* 那一行已经说了数学老师也是一个老师,所以我们能用老师类型来保存数学老师类型。那反之呢 ? 老师一定是数学老师吗 ? 当然不是 , 所以我们不能用数学老师来保存老师对象。如果我们 MathTeacher msZhang=new Teacher(); 编译器就会报错了。
结论也就是:
在面向对象的语言中,可以用父类的变量保存子类的对象;但,不能用子类的变量保存父类的对象。
注意: 要理解我们上面的结论,你要先搞清楚什么是变量什么是对象。
现实 | 代码 |
你这个人是对象,你无论叫小刚还是小红,你这个对象是不变的。而小刚或者小红就是变量名 | Person xiaoGang=new Person(); Person xiaoHong=xiaoGang; |
在大部分情况下,我们说的小刚或小红这个人名,就代表了你这个人,但有的时候,比方说我们将你的名字小刚改成小小刚。这个小刚就仅仅是个人名而已了 | xiaoGang和 xiaoHong 在大部分情况下代表一个人类的对象。 但在我们分析代码的时候,xiaoGang 和 xiaoHong 紧紧是个人名而已 |
我们上一节在讲述构造方法的时候,可以通过快捷键自定生成构造方法,其中会自动产生形如一下的代码
public class Girl extends Person { public Girl() { super (); } } |
那这里的super 代表什么呢 ?
super()代表的是父类的构造方法 . 即使我们把它删除,会被自动调用的。
也就是说: 如果你没有调用父类的构造方法,系统会为子类的构造方法首先调用父类的无参的构造方法。
1. 所谓 ” 你没有调用构造方法. .. ” 也就是说,一旦你自己调用了构造方法,系统也就不调用父类的构造方法了
2. ... ” 子类的构造方法 ” ... 如果不是构造方法,不会自动调用父类的构造方法的
注意: 我没有限定是子类的有参的构造还是无参的构造
3. ... “首先” ... 指的是 super() 必须是构造方法的第一条语句,如
public Girl() { super (); other Code } |
4. ... 父类的无参的构造方法 ... , 系统只会自动调用父类的无参的构造方法而不会自动调用父类的有参的构造方法
如果父类没有无参的构造,则子类找不到无参的构造方法就会报语法错误
重写和多态 ( Polymorphism )
按字面的意思 多态 就是“ 多种状态 ” .再扩展一点来讲,是指的“方法的”多种状态。完整的来说 , 就是父类的变量调用其被重写的方法而表现出来的多种状态。
在上面对多态的解释中,我们有一个概念是全新的--" 重写 "
重写是子类的方法签名与父类的方法签名相同。
方法签名包括:
方法名,
参数列表
返回值
观察以下代码
public class AnimalTest { public static void main(String[] args) { Animal animal0 = new Rabbit(); animal0.eat(); Animal animal1 = new Tiger(); animal1.eat(); } } |
public class Animal { public void eat() { System. out .println( "动物的吃的动作 " ); } } |
public class Rabbit extends Animal { public void eat() { System. out .println( "兔子吃草 " ); } } |
public class Tiger extends Animal { public void eat() { System. out .println( "老虎吃肉 " ); } } |
结果: 兔子吃草 老虎吃肉 |
同种类型的变量( 都是 Animal 类型 ) ,调用了相同的方法( eat 方法) , 但表现出的动作不同,这就是 ” 多态 ”
多态的应用实例问题:
有豆浆机可以磨豆浆,可以榨果汁。在磨豆浆的过程中,豆浆和果汁都会散发出他们各自的味道。请用代码表述以上概念。运行结果如下
+++++豆浆机开始运转 ++++++ 豆子的味道 ========结束 ===========
$$$$$$$豆浆机开始运转 $$$$$$ 水果的香甜 ========结束 =========== |
A bstract
问题:
观察我们之前写的Teacher 类型
public class Teacher { public void jieShao() { System. out .println( "介绍姓名年龄等信息 " ); } public void jiangKe() { } } |
我们写了jiangKe 的方法,而没有写方法体,因为 jiangKe 的具体实现对于不同的老师也是不同。这个方法本身就是不能实现的。那是不是我们就可以删除这个方法了呢。
public class School { public void pingBi(Teacher t ) { t .jieShao(); //能不能看变量 t .jiangKe(); //报错 } } |
因为Teacher 类型没有了 jiangKe 方法的定义,即使所有类型的老师都实现了 jiangKe 的方法也是不行的,因为“能不能看变量的类型”。
解决办法:
我们既要保留方法的签名又不需要方法体,我们就需要一个关键字abstract
public class Teacher { public void jieShao() { System. out .println( "介绍姓名年龄等信息 " ); } public abstract void jiangKe(); } |
我们删除了jiangKe() 后的 { 方法体 } , 同时我们也发现了一个错误。因为如果一个方法是 abstract 的,则它所属的类也一定是 abstract 的,所以
public abstract class Teacher { public void jieShao() { System. out .println( "介绍姓名年龄等信息 " ); } public abstract void jiangKe(); } |
现在再来让再来新建一个HTMLTeacher ,我们发现当 HTMLTeacher extends Teacher 时, HTMLTeacher 必须要实现 Teacher 的抽象方法
public class HTMLTeacher extends Teacher { public void jiangKe() { } } |
哪怕仅仅是给这个方法加一个{}
现在来总结一下,abstract 的特征吧
1. 当不知道如何实现一个方法的时候,需要给这个方法增加abstract 修饰符
2. 当一个方法是abstract ,则它所属的类也一定是 abstract ,反之,不成立 ( 如果一个类是 abstract ,则其中一定存在 abstract 方法 )
3. 一个类继承一个抽象类,也必须重写其中的所有的抽象方法
4. 抽象类不能被实例化
接口
问题:
炎炎夏日,我们现在最缺的就是风扇和空调,他们都可以降温,有共同的功能,那是不是我们该用一个父类来让他们继承呢。我们姑且把这个类叫做降温设备。
public class LowerTemMachiner {} |
public class FengShan extends LowerTemMachiner {} |
public class KongTiao extends LowerTemMachiner{} |
而在寒冷的冬天,暖气和空调又都是升温设备。那还能表示吗?
当然不能,因为KongTiao 已经继承了降温设备。如果他在继承升温设备。除非降温设备和升温设备之间有继承关系,这是不可能的。
这就是java 中的单根继承造成的。
解决办法:
上面的空调和风扇,我们更多的强调的是他们的降温作用。更强调的是功能,我们可以用接口的概念表达以上信息,因为允许一个类同时实现多个接口
public class KongTiao implements owerTemMachiner,HigherTemMachiner{} |
我们先来看看接口的特征:
一个类可以实现(implements) 多个接口 interface
接口是一个规范, 实现了接口也就必须要时间接口中的所有的方法 ( 抽象类除外 )
接口中只能有常量( 稍后解释什么是常量 ) 不能有变量
接口不可以实例化
接口中只能包含抽象方法, 且所有的方法都是 public 的
从上面的特征可以看出:interfac 和 abstract class 的最大区别在于是否支持多继承。
在当前的开发中,我们有一种思想叫做面向接口的编程。在此,先不阐述什么是面向接口的编程,但当一个概念作为一种思想的时候,我们可以想象接口的重要性。
通过下面的代码,我们来“感受”一下面接口的威力
问题:
首先我们对整数进行排序。
其他修饰符
问题:如果想在子类中可访问,非子类中不可访问用什么修饰符
解决办法:protected
问题:如果想在同包中访问,我使用什么修饰符
解决办法:default( 默认的 ) :此关键字不需要(也不能)写,同包可以访问
常量
问题:
我们现在要保存一周的天数. 采用的办法为
int days OfWeek =7; |
但是,如果在使用的过程中,程序员不小心改变了它的值呢? 从逻辑上,这是不合理的。一周的天数不可能被改变。
解决办法:
我们使用常量来解决这个问题
static final int daysOfWeek=7; |
final本身就是不可变的意思 , 既然不可变 , 也便不随着对象的改变而改变,如果是属性,也就自然是 static 的了。
在使用常量时,我们往往为了与变量区分开,采用所有字母都大写的方式进行。如果多个单词在一起,我们如何区分每个单词呢,答案是用 _( 下划线 )
所以,上面的常量定义为
static final int DAYS_OF_WEEK=7; |
回顾,我们在接口interface 中讲到的。
在接口中是不允许生命变量的但可以声明常量
枚举
问题:
常量只能保证自身的值不被改变。
如果我们有学生类型,学生的性别只能是男或女怎么保证呢?
public class Student { private String name ; private String gender ; } |
也许,你会想到通过代码setter 进行控制。但还有更好的解决办法
解决办法:
我们可以将gender 定义为 Genders 类型的变量,而 Genders 的取值只能是固定的几个值。我们可以将 Genders 定义为枚举类型
public enum Genders { Male , Female } |
现在你在创建了Student 对象后,只能为其 gender 属性,赋值为 Genders 类型的值。他们分别是 Male,Female. 并且编译工具可以对这些值进行提示。