回顾
一、面向对象的三大特点
1.封装的含义
2.继承的含义
3.多态的含义
二、封装的实现
1.Java访问权限修饰符
学习小结
2.封装问题引例
package com.Javastudy2;
/**
* @author Y.W.
* @date 2017年8月20日 上午10:49:26
* @Description TODO 类的封装性使用引例
*/
public class P281_12_1 {
public static void main(String[] args) {
MyCat aCat = new MyCat();
aCat.weight = -10.0f; // 设置MyCat的属性值
float temp = aCat.weight; // 获取MyCat的属性值
System.out.println("The weight of a cat is:" + temp);
}
}
class MyCat{
public float weight; // 通过public修饰符,开放MyCat的属性给外界
MyCat(){} // 无参构造方法,无实际含义
}
运行结果:
引例把属性(数据)暴露出来,让外界可以任意接触甚至改变它。运行结果对于程序是没有错误的,赋值是合法的单精度浮点数,但是现实中不可能有重量为负数的猫。
3.类的封装实例
package com.Javastudy2;
/**
* @author Y.W.
* @date 2017年8月20日 上午11:04:25
* @Description TODO 类的封装实例
*/
public class P282_12_2 {
public static void main(String[] args) {
MyCat2 aCat = new MyCat2();
aCat.weight = -10.0f; // 设置MyCat的属性值
float temp = aCat.weight; // 获取MyCat的属性值
System.out.println("The weight of a cat is:" + temp);
}
}
class MyCat2 {
private float weight; // 通过private修饰符,封装属性
MyCat2() {} // 无参构造方法,无实际含义
}
运行结果:
可以看到IDE已经有报错了,编译后同样有报错信息。封装后,外界无法访问私有属性,若需要给这些属性赋值,就需要存取属性的公共接口。
package com.Javastudy2;
/**
* @author Y.W.
* @date 2017年8月20日 上午11:15:40
* @Description TODO 类私有属性的Setter和Getter方法
*/
public class P283_12_3 {
public static void main(String[] args) {
MyCat3 aCat = new MyCat3();
aCat.SetWeight(-10f); // 设置MyCat的属性值
float temp = aCat.GetWeight(); // 获取MyCat的属性值
System.out.println("The weight of a cat is:" + temp);
}
}
class MyCat3 {
private float weight; // 通过private修饰符,封装MyCat的属性
public void SetWeight(float wt) {
if (wt > 0) {
weight = wt;
} else {
System.out.println("weight设置非法(应该>0)。\n 采用默认值");
weight = 10.0f;
}
}
public float GetWeight() {
return weight;
}
}
运行结果:
通常,对属性设置的方法被命名为SetXxx(),其中Xxx为任意有意义的名称,这类方法可被统称为Setter方法,而对属性设置的方法被命名为GetYyy(),其中Xxx为任意有意义的名称,这类方法可被统称为Getter方法
注:见得多的还是setXxx()和getYyy()名称。
封装属性:
private 属性类型 属性名;
封装方法:
private 方法返回类型 方法名称(参数);
package com.Javastudy2;
/**
* @author Y.W.
* @date 2017年8月20日 上午11:40:55
* @Description TODO 方法的封装使用
*/
public class P284_12_4 {
public static void main(String[] args) {
MyCat4 aCat = new MyCat4();
aCat.SetWeight(-10f); // 设置MyCat的属性值
float temp = aCat.GetWeight(); // 获取MyCat的属性值
System.out.println("The weight of a cat is:" + temp);
aCat.MakeSound(); // 会报错
}
}
class MyCat4 {
private float weight; // 通过private修饰符,封装MyCat的属性
public void SetWeight(float wt) {
if (wt > 0) {
weight = wt;
} else {
System.out.println("weight设置非法(应该>0)。\n 采用默认值");
weight = 10.0f;
}
}
public float GetWeight() {
return weight;
}
private void MakeSound() {
System.out.println("Meow meow, my weight is " + weight);
}
}
运行结果:
封装的MakeSound() 是无法外部调用的。
若类中某些数据在初始化时不想再被外界修改,则可以使用构造方法配合私有化的Setter函数来实现该数据的封装,如下例所示。
package com.Javastudy2;
/**
* @author Y.W.
* @date 2017年8月20日 上午11:52:43
* @Description TODO 使用构造方法实现数据的封装
*/
public class P286_12_5 {
public static void main(String[] args) {
MyCat5 aCat = new MyCat5(12, -5); // 通过公有接口设置属性值
float ht = aCat.GetHeight(); // 通过公有接口获取属性值height
float wt = aCat.GetWeight(); // 通过公有接口获取属性值weight
System.out.println("The height of cat is " + ht);
System.out.println("The weight of cat is " + wt);
}
}
class MyCat5 {
// 创建私有化属性weight,height
private float weight;
private float height;
// 在构造方法中初始化私有变量
public MyCat5(float height, float weight) {
SetHeight(height); // 调用私有方法设置height
SetWeight(weight); // 调用私有方法设置weight
}
// 通过private修饰符,封装MyCat的SetWeight方法
private void SetWeight(float wt) {
if (wt > 0) {
weight = wt;
} else {
System.out.println("weight设置非法(应该>0)。\n 采用默认值10");
weight = 10.0f;
}
}
// 通过private修饰符,封装MyCat的SetHeight方法
private void SetHeight(float ht) {
if (ht > 0) {
height = ht;
} else {
System.out.println("height设置非法(应该>0)。\n 采用默认值20");
height = 20.0f;
}
}
// 创建公有方法GetWeight()作为与外界的通信接口
public float GetWeight() {
return weight;
}
// 创建公有方法GetHeight()作为与外界的通信接口
public float GetHeight() {
return height;
}
}
运行结果:
4.封装问题的总结
在Java中,最基本的封装单元是类,类是基于面向对象思想编程语言的基础,程序员可以把具有相同业务性质的代码封装在一个类里,通过接口方法向外部提供服务,同时向外部代码屏蔽类里的服务的具体实现方法。
数据封装的最重要的目的是在于实现“信息隐藏(Information Hidding)”。
封装性是面向对象程序设计的原则之一,使程序达到强内聚(许多功能尽量在类的内部独立完成,不让外界干预),弱耦合(提供给外部尽量少的方法调用)的最终目标。
5.实现封装应该注意的问题
封装的数据是引用数据时,如下例。
package com.Javastudy2;
import java.util.ArrayList;
/**
* @author Y.W.
* @date 2017年8月20日 下午12:59:40
* @Description TODO 返回引用数据时应该注意的问题
*/
public class P288_12_6 {
public static void main(String[] args) {
TestReturn testReturn = new TestReturn();
// 得到该私有数据,不是副本,而是引用
ArrayList intArray = testReturn.getIntArray();
System.out.println(intArray.size());
intArray.add(4); // 修改其值
ArrayList intArray2 = testReturn.getIntArray();
// 该类内部的私有变量已经被改变
System.out.println("在外部修改其私有变量以后其长度为:" + intArray2.size());
}
}
class TestReturn {
// 定义一个私有的ArrayList
private ArrayList intArray = new ArrayList();
public TestReturn() {
// 通过构造方法对其进行初始化
intArray.add(1);
intArray.add(2);
intArray.add(3);
}
// 设置私有数据对应的get函数
ArrayList getIntArray() {
return intArray;
}
}
运行结果:
封装的变量被改变了。
解决办法:
如果返回值是对数据的引用则显示创建该数据的副本,然后返回该副本。
三、继承的实现
1.继承的基本概念
Java支持单继承和多层继承,但不支持多继承。
格式:
class 子类名 extends 父类
语法:
class 父类{
// 定义父类
}
class 子类 extends 父类{
// 用extends关键字实现类的继承
}
Java只继承父类的公有属性和公有方法,以及隐含(不可见)的私有属性。
2.继承问题的引出
package com.Javastudy2;
/**
* @author Y.W.
* @date 2017年8月20日 下午2:28:12
* @Description TODO 继承的引出
*/
public class P291_12_7 {
public static void main(String[] args) {
// 实例化一个Person对象
Person11 person = new Person11("张三", 21);
person.speak();
// 实例化一个Student对象
Student student = new Student("李四", 20, "HAUT");
student.speak();
student.study();
}
}
class Person11 {
String name;
int age;
Person11(String name, int age) {
this.age = age;
this.name = name;
}
void speak() {
System.out.println("我的名字叫:" + name + "我" + age + "岁");
}
}
class Student {
String name;
int age;
String school;
Student(String name, int age, String school) {
this.age = age;
this.name = name;
this.school = school;
}
void speak() {
System.out.println("我的名字叫:" + name + "我" + age + "岁");
}
void study() {
System.out.println("我在" + school + "读书");
}
}
运行结果:
3.实现继承
上例代码略显臃肿,可以改造。
package com.Javastudy2;
/**
* @author Y.W.
* @date 2017年8月20日 下午2:50:21
* @Description TODO 实现继承
*/
public class P293_12_8 {
public static void main(String[] args) {
// 实例化一个Student对象
Student1 s = new Student1("张三", 25, "工业大学");
s.speak();
s.study();
}
}
class Person12 {
String name;
int age;
Person12(String name, int age) {
this.age = age;
this.name = name;
}
void speak() {
System.out.println("我的名字叫:" + name + "我" + age + "岁");
}
}
class Student1 extends Person12 { // 继承Person12
String school;
Student1(String name, int age, String school) {
super(name, age);
this.school = school;
}
void study() {
System.out.println("我在" + school + "读书");
}
}
运行结果:
4.继承的限制
限制1
Java中不允许多重继承,但是可以使用多层继承。
多重继承,指一个类同时继承多个父类的行为和特征功能。
class A{
}
class B{
}
class C extends A,B{ // 错误:多重继承
}
多层继承:指一个类B可以继承来自类A,而另一个类C又继承自B,像这样在继承层上单项继承多个类。
class A{
}
class B extends A{
}
class C extends B{
}
注:编写代码时,多层继承最好不要超过三层。
限制2
从父类继承的私有成员,不能被子类直接使用。
限制3
子类在进行对象实例化时,从父类继承而来的数据成员需要先调用父类的构造方法来初始化,然后再用子类的构造方法来初始化本地的数据成员。
限制4
被final修饰的类不能再被继承。
final在Java之中称为终结器。
package com.Javastudy2;
/**
* @author Y.W.
* @date 2017年8月20日 下午3:33:43
* @Description TODO 继承的final限制
*/
public class P296_12_9 {
public static void main(String[] args) {
SubClass subClass = new SubClass();
}
}
// 定义被final修饰的父类
final class SuperClass {
String name;
int age;
}
// 子类SubClass继承SuperClass
class SubClass extends SuperClass {
// do something
}
思考
一下看了好几页,绝对超出我的临时缓存了,脑瓜子有点疼。继承性还要继续加强。
记于2017年8月20日