封装和继承
今日目标:
封装
继承
1.封装
1.为什么要封装:
隐蔽性 安全性
1.类有成员属性和方法两个部分组成,二者都可以供其它类去调用。方法作为一个功能的实现,被调用时不会产生什么问题,属性却不一样,它是属于类和对象的,容易被“非法篡改”。
例如:定义一个类people,有姓名和财产等属性,默认值是:张三和12000.有show方法,输出姓名和财产。定义一个测试类,修改张三的money为-10000;
2.此案例可以看出类和对象的属性毫无隐蔽性可言,可以被随意修改,这样设计出的程序会有很大的安全性问题。
3.为了解决这个问题,java开发者提出了封装的思想。将类的成员属性的访问修饰符规定为私有(private),这样该属性在其它类就不能调用,更不可能被修改。这相当于闭关锁国政策,所以又面临一个问题:连成员属性的正常赋值也不可能在其它类中实现。因此设计者们再次提出了一个方案:成员属性可以间接地在其它类中被访问,也就是中间要设置一道检查和过滤的关卡,这道关卡就是get和set方法,它们被称为getter和setter.
下面我们对刚才的案例进行改进。
实现封装总结:
1.属性访问修饰符定义为私有:private
2.对外提供get和set方法。
package com.Test1;
public class TestPerson {
public static void main(String[] args) {
Person p=new Person();
p.setMoney(12000);
p.setName("张三");
p.setSex('女');
System.out.println(p.getSex());//通过get取值
p.show();
}
}
package com.Test1;
public class Person {//封装
private String name;
private char sex;
private double money;
public void setSex(char sex){
if (sex == '男'||sex=='女') {
this.sex=sex;
}else {
this.sex='男';
}
}
public char getSex(){
return sex;
}
public void setName(String name){
this.name=name;
}
public String getName(){
return name;
}
public void setMoney(double money){
if (money>=0){
this.money=money;
}else {
this.money=0;
}
}
public double getMoney(){
return money;
}
public void show(){
System.out.println(name+"性别为:"+sex+" 财产为:"+money);
}
}
封装快捷键:alt+Insert(右键选择Generate)
然后选择Getter and Setter
点击即可
2.包结构
在开发大型项目时,会有很多功能模块的具体划分,这是需要建立很多的类,将同一层级的类放在一个包中,可使程序的层级结构清晰,提高辨识度。
类似于在资源管理器中新建一个文件夹,有规律的存放和管理资源文件。
导包:导入自己的包和系统包
java.lang包是java语言的核心,它提供了java中的基础类。(java.lang这个包属于系统包,该包中的类不用导入,例如System,String)
3.访问修饰符
下图中:受保护的情况(protected) :子类必须在同一个包中。
1.类的访问修饰符:
Public:对外公开
默认:所在包有效,包以外不能访问 --体现在构造方法上
2.成员访问修饰符(成员属性和成员方法)
Public:对外公开
Protected:受保护的,同一个包的子类可以访问。
默认:同一个包中可以访问
Private:只在当前类有效
4.static和this关键字
Static修饰的,属于类范围的,this代表当前对象。
Static修饰成员属性和方法和代码块
5.继承
1.引语:
如何理解继承,我猜大家首先想到的可能是继承千万家产,走上人生巅峰。梦想是美好的,java里面却不是这样的。
2.概念:
大千世界可以分为很多的类,有大范围的类,例如:动物和人,有小范围的类,例如:老虎,狮子,大象,老师,医生。
那这些类之间有什么关系呢?–包含
这种关系如何表示呢?–继承
总结:继承研究的是两个类之间的范围包含关系,用关键字extends表示。
3.使用:
- 在多个子类中抽取出相同的属性和方法,形成父类的属性和方法
- 在各个子类中继承这些属性和方法的使用权限。
Java中的继承需要从两个方面去理解:
1.在多个子类中抽取出相同的属性和方法,形成父类的属性和方法
案例:
大象和狮子 都具有属性:名称,体重,战斗力;方法:捕食。
可以提取这些相同的属性,形成一个父类 动物类。
创建测试类,在测试类中创建狮子对象,继承父类的属性和方法
优点:
抽取出共有的重复的代码,使用继承,提高代码的复用性
2.对父类成员的继承使用(包含成员属性和成员方法)
抽取出共有的重复的代码,使用继承,提高代码的复用性,
让类与类之间产生关系:extends
继承是两个类之间产生关联关系的唯一的方式
4.继承语法细节:
1.子类构造方法会默认调用父类无参构造方法。
即:在创建子类对象时,也会随即创建父类对象。
为多态提供了前提
2.Java中支持单继承:一个子类只能有一个直接父类
Java中不支持多继承
3.任何一个类,都默认继承Object类,Object类是所有类的父类。
6.this和super的区别
this:
1.本类成员方法中,访问本类成员变量,访问本类另一个成员方法
2.本类构造方法中,访问本类另一个构造方法
Super:
1.在子类成员方法中,访问父类成员变量和成员方法
2.在子类构造方法中,访问父类构造方法
本类的成员变量和局部变量重名,用this区分,
本类的成员变量和父类的变量重名,用super区分
重写(覆盖)和重载
重载:同一个类中,方法名相同方法参数不同,典型应用:无参构造和有参构造
重写:子类和父类同名的方法。
子类方法和父类方法同名,子类方法会覆盖父类方法,称为重写(覆盖),前提,子类方法访问权限必须大于或等于父类方法的访问权限
什么时候会用到覆盖?
案例:手机需要扩展新功能,反复修改代码会带来毁灭性的灾难。此时采用继承是不错的选择
Final
修饰的变量称为常量,值不能被修改
修饰的方法不能被重写,保证安全性和稳定性
修饰的类不能被继承,避免功能被覆盖。
要想让一个类不被其它类继承:
1.用final修饰
2.构造方法私有化
作业:
1.需求说明
使用封装实现电子宠物系统的企鹅类正确输入健康值和亲密度
保证健康值的有效性(0-100),否则取默认值60
保证亲密度的有效性(0-100),否则取默认值60
package com.homework.one;
import java.util.Scanner;
public class TestPets {
static Scanner sc=new Scanner(System.in);
public static void main(String[] args) {
Pets p1 = new Pets();
System.out.println("欢迎您来到宠物店!");
System.out.print("请输入要领养的宠物名字:");
String a=sc.next();
p1.setName(a);
System.out.print("请选择要领养的宠物类型:(1、狗狗2、企鹅)");
String b=sc.next();
p1.setType(b);
System.out.print("请选择"+p1.getType()+"的性别:(1.Q仔 2.Q妹)");
String c=sc.next();
p1.setSex(c);
System.out.print("请输入"+p1.getType()+"的健康值(1~100之间)");
int d=sc.nextInt();
p1.setHealthy(d);
System.out.println("宠物的自白:");
System.out.println("我的名字叫"+p1.getName()+",健康值是"+p1.getHealthy()
+",和主人的亲密度是100,我的性别是"+p1.getSex());
}
}
package com.homework.one;
public class Pets {
private String name;
private String type;
private String sex;
private int healthy;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getType() {
return type;
}
public void setType(String type) {//类型
if (type.equals("1")){
this.type = "狗狗";
}else {
this.type = "企鹅";
}
}
public String getSex() {
return sex;
}
public void setSex(String sex) {
if (sex.equals("1")){
this.sex = "Q仔";
}else {
this.sex = "Q妹";
}
}
public int getHealthy() {
return healthy;
}
public void setHealthy(int healthy) {
if (healthy>=0&&healthy<=100){
this.healthy = healthy;
}else {
System.out.println("健康值应该在1-100之间,默认为60");
this.healthy = 60;
}
}
}
2.需求说明
模拟实现选民投票过程:一群选民进行投票,每个选民只允许投一次票,并且当投票总数达到100时,就停止投票
package com.homework.two;
public class Vote {
public static void main(String[] args) {
System.out.println("请投票");
int i=1;
do {
System.out.println("第"+i+"个村民投票");
i++;
}while (i<=100);
}
}
3.需求说明
使用继承优化电子宠物系统,抽取父类,创建子类,在子类中使用super调用父类构造方法。(选做)
4.编写一个类Student1,代表学员,要求如下:
具有属性:姓名和年龄,其中年龄不能小于16岁,否则输出错误信息
具有方法:自我介绍,负责输出该学员的姓名和年龄。
编写测试类Student1Test进行测试,看是否符合需求。
在学员类的setAge()方法中验证年龄大小。
在测试类中分别测试学员年龄小于16岁、大于16岁时的输出结果
package com.homework.four;
public class Student1 {
private String name;
private int age;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
if (age<16){
System.out.println("年龄不能小于16岁,默认为16岁");
this.age=16;
}else {
this.age = age;
}
}
public void introduce(){
System.out.println("姓名:"+name+" 年龄:"+age);
}
}
package com.homework.four;
import java.util.Scanner;
public class Student1Test {
public static void main(String[] args) {
Student1 s1 = new Student1();
Scanner sc=new Scanner(System.in);
System.out.println("请输入学员的年龄:");
int a=sc.nextInt();
s1.setAge(a);
System.out.println("请输入学员姓名:");
String b=sc.next();
s1.setName(b);
s1.introduce();
}
}
5.编写一个类Student2,代表学员,要求如下:
具有属性:姓名、年龄、性别和专业
具有方法:自我介绍,负责输出该学员的姓名、年龄、性别和专业
具有两个带参构造方法:在第一个构造方法中,设置学员的性别为男,专业为java,其余属性的值由参数给定;在第二个构造方法中,所有属性的值都由参数给定。
编写测试类Student2Test进行测试,分别以两种方式完成对两个Student2对象的初始化工作,并分别调用他们的自我介绍方法,看输出结果是否正确。
在学员类中定义如下两个构造方法完成初始化工作:
Public Student2(Stiring name,int age){}
Public Stduent2(String name,int age,String sex,String subject){}
package com.homework.five;
public class Student2 {
private String name;
private int age;
private String sex;
private String major;
public void introduce(){//介绍
System.out.println("姓名:"+name+"\n年龄:"+age+"\n性别:"+sex+"\n专业:"+major);
}
public Student2(String name, int age, String sex, String major) {
this.name = name;
this.age = age;
this.sex = sex;
this.major = major;
}
public Student2(String sex, String major) {
this.sex = sex;
this.major = major;
}
public Student2() {
}
public String getSex() {
return sex;
}
public void setSex(String sex) {
this.sex = sex;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public String getMajor() {
return major;
}
public void setMajor(String major) {
this.major = major;
}
}
package com.homework.five;
public class Student2Test {
public static void main(String[] args) {
Student2 s2=new Student2("张三",20,"男","java");
s2.introduce();
System.out.println("---------------");
Student2 s1 = new Student2("男","java");
s1.setAge(20);
s1.setName("张三");
s1.introduce();
}
}
6.设计Bird、Fish类,都继承父类Animal的属性和方法info(),并输出他们的信息。参考运行结果如下所示:
我是一只红色的鸟! Color
今年4岁了! age
我是一只5斤重的鱼! weight
今年2岁了! age
提示:
定义父类Animal,具有age属性、info()方法
定义Bird类,具有本身的特有属性color
定义Fish类,具有本身的特有属性weight。
7.兜兜家养了两只家禽:一只鸡和一只鸭。请用面向对象思想的封装、继承的特性进行描述,参考运行结果如下所示:
我叫喔喔,是一只芦花鸡!Name type
我喜欢吃虫子! hobby
我会打鸣!crow
我叫嘎嘎,是一只斑嘴鸭!Name type
我喜欢吃小鱼虾!hobby
我会游泳! swim
提示:
分析上图的运行结果,通过名词找出类、属性,通过动词找出方法
将公有的属性和方法抽象到父类中
让子类继承父类,并实现子类特有的属性和方法
作业二
知识测试题
1.按需求实现功能(构造方法、封装、继承、重写)
(1)编写地址类Address,包含属性:
①城市
②所属区
(2)编写医生类Doctor,包含属性:
①名字
②所属科室
③年龄
④地址:地址类型
⑤性别
⑥print方法打印个人信息
(3)编写老师类Teacher,包含属性
①名字
②年龄
③地址:地址类型
④性别
⑤所授学科
⑥print方法打印个人信息
(4)所有属性封装
(5)根据分析编写一个父类Person和子类产生继承关系
(6)对所有人年龄加上范围控制,不能小于1,不能大于130
(7)重写优化print方法
(8)每个类编写全参和无参构造方法
(9)每个类分别重写toString()方法打印属性&属性值
(10)main方法通过构造方法赋值并且打印对象输出员工信息
(11)注意命名规范,所有命名不得使用拼音,驼峰该驼的驼起来,代码格式,缩进,对齐,每个类单独写一个java文件