封装继承
一、封装性
描述:封装之前学习过方法,方法就是一种封装,在面向对象的封装性中,本质上也是讲方法的封装
封装性:在面向对象中,不要直接调属性,而是通过set/get方法进行封装
好处:结构更清晰,复用性更强,安全性更强
封装步骤:
1.编写set/get方法,注意规范写法,set用于赋值,get用于取值
2.属性私有化
//面向对象案例:张勇在吃饭
//分析:类-Student; 对象-张勇 属性-姓名,年龄 方法-吃
//问题:年龄为负数--- 会出现,程序没问题,数据不合理的情况
class Student{
private String name;
private int age; //属性私有化,外界不能调用,只能在当前类中使用
public Student() {}
public Student(String name,int age) {
this.name = name;
this.setAge(age); //this调方法
}
public void eat() { //功能性的封装
System.out.println(age+"岁的"+name+"正在吃饭~~");
}
//按照项目中完整实体封装的写法,有多少属性,就有多少set/get
public void setName(String name) {
this.name = name;
}
public String getName() {
return name;
}
//set方法规范:方法名为set+属性名首字母大写,参数名和属性名一致
public void setAge(int age) { //数据(属性)的封装
//注意:此处为了说明安全性,才加的判断;后续没有特殊说明,则直接赋值即可
if(age<=0) { //如果参数有问题,则属性为默认18岁
this.age = 18;
}else { //如果大于0,则直接赋值
this.age = age;
}
}
//get方法规范:方法名为get+属性首字母大写,返回属性值
public int getAge() {
return age;
}
}
public class Test1 {
public static void main(String[] args) {
Student zy = new Student();
zy.setName("张勇");
zy.setAge(-20); //赋值
//zy.age = -1; //从源头上规避直接调属性
System.out.println(zy.getAge()); //取值
zy.eat();
//2.编写带参构造
Student ly = new Student("李勇",-30);
ly.eat();
}
}
二、继承性
理论描述
生活中的继承: 子承父业,儿子继承了父亲的资源
程序中的继承:子类继承父类的属性和方法
如何设定继承关系?什么类是子类?什么类是父类?
两个类满足“is a”的关系,就有继承关系。
子类"is a" 父类 例如:猴子是动物,猴子是子类 动物是父类
找父类—父类有很多,怎么找直接父类
例如: 狗是动物,也是生物,也是物质
重合点(特征和行为接近)越多,越接近直接父类
重合点越少,越接近Object类(后面会分析-老祖宗类)
例如:狗-姓名,年龄,毛色; 吃,摇尾巴,睡; 动物也类似;所以,动物类是狗类的直接父类
继承案例
//面向对象案例出发:狗会跑,鸟会飞,鱼会游;同时它们都能吃能睡;属性都有姓名,年龄;狗和鸟有毛色
//注意:此处侧重点在于继承,暂时不去封装(后面写项目再封装)
//问题:冗余代码特别多;类与类之间完全独立
//找关系:狗是动物,鸟是动物,鱼是动物,都有同一个父类
//根据继承特点:只需将子类共性的部分抽取到父类即可;子类直接继承
//继承作用:减少代码量,提高复用性;提高扩展性
class Animal{
String name;
int age;
public void eat() {
System.out.println(name+"正在吃...");
}
public void sleep() {
System.out.println(name+"正在睡...");
}
}
class Dog extends Animal{ //Dog继承Animal
String color;
public void run() {
System.out.println(name+"正在跑");
}
}
class Bird extends Animal{ //Bird继承Animal
String color;
public void fly() {
System.out.println(name+"正在飞");
}
}
class Fish extends Animal{ //Fish继承Animal
public void swim() {
System.out.println(name+"正在游");
}
}
public class Test1 {
public static void main(String[] args) {
Dog dog = new Dog();
dog.name = "旺财"; //调父类的属性
dog.color = "黄色"; //调自身独有属性
dog.run(); //调自身独有方法
dog.sleep(); //调父类方法
System.out.println("--------------");
Bird bird = new Bird();
bird.name = "八哥";
bird.fly();
bird.eat();
System.out.println("--------------");
Fish fish = new Fish();
fish.name = "小金";
fish.swim();
fish.sleep();
}
}
继承特点
在继承中,没有多继承,但有多级继承
多继承:有多个父类; 多级继承:有父类,父类又有父类…
//案例:爷爷有1000万;爸爸有一辆跑车;儿子有一辆玩具车
class GrandFather{
String name;
public void haveMoney() {
System.out.println(name+"拥有1000万");
}
}
class Father extends GrandFather{ //多级继承
public void haveCar() {
System.out.println(name+"有一辆跑车");
}
}
class Son extends Father/*,GrandFather*/{//没有多继承
public void haveToy() {
System.out.println(name+"有一辆玩具车");
}
}
public class Test2 {
public static void main(String[] args) {
Father father = new Father();
father.name = "大三"; //调爷爷类的属性
father.haveMoney(); //调爷爷类的方法
father.haveCar(); //调自身的方法
//father.haveToy(); //不能调子类的方法
System.out.println("===============");
Son son = new Son();
son.name = "小三";
son.haveMoney(); //调爷爷类的方法
son.haveCar(); //调父类的方法
son.haveToy(); //调自身的方法
}
}
三、不可继承性
- 私有的成员不能被继承
- 构造方法没有继承性
- 不同包的default权限,没有继承性
构造方法测试
//测试案例:构造方法没有继承性---测带参构造
class A{
public A() {
System.out.println("父类A的无参构造");
}
public A(int a) {
System.out.println("父类A的带参构造");
}
}
class B extends A{
}
public class Test1 {
public static void main(String[] args) {
//new B(6); //构造方法没有继承性,不能调用父类A的带参构造
}
}
权限测试
//----------com.qf.d_quanxian包中的两个类----------
public class Animal { //实体类
private String name; //私有权限
int age; //default权限
protected String sex; //保护权限
public String love; //公开权限
public void eat() {
System.out.println(name); //私有权限,在本类中可以使用
System.out.println(age); //默认权限,在本类中可以使用
System.out.println(sex); //保护权限,在本类中可以使用
System.out.println(love); //公开权限,在本类中可以使用
}
}
public class Test1 { //测试类
public static void main(String[] args) {
Animal animal = new Animal();
//System.out.println(animal.name); //私有权限,在同包不同类中不能使用
System.out.println(animal.age); //默认权限,在同包不同类中可以使用
System.out.println(animal.sex); //保护权限,在同包不同类中可以使用
System.out.println(animal.love); //公开权限,在同包不同类中可以使用
}
}
//----------com.qf.e_quanxian2包中的两个类----------
public class Dog extends Animal {
public void show() {
//System.out.println(name); //私有权限,在不同包子类中不能使用
//System.out.println(age); //default权限,在不同包子类中不能使用
System.out.println(sex); //保护权限,在不同包子类中可以使用
System.out.println(love); //公开权限,在不同包子类中可以使用
}
}
public class Test1 {
public static void main(String[] args) {
Animal animal = new Animal();
//System.out.println(animal.name); //私有权限,在不同包无继承关系中不能使用
//System.out.println(animal.age); //默认权限,在不同包无继承关系中不能使用
//System.out.println(animal.sex); //保护权限,在不同包无继承关系中不能使用
System.out.println(animal.love); //公开权限,在不同包无继承关系中可以使用
}
}
四、重写
前面学习过重载的概念:在同一个类中,方法名相同,参数个数或类型不同
重写的前提是继承;
在继承关系中,子类的方法和父类完全一致(包括返回值类型,方法名,参数类型),权限大于或等于父类
重写非常重要,在后面的多态中经常用到
重写应用场景:当父类的方法不适用子类时,子类可重写父类的方法。
//案例:父亲非常绅士的吃饭;儿子狼吞虎咽的吃
class Father{
public void eat() {
System.out.println("父亲非常绅士的吃饭");
}
}
class Son extends Father{
@Override //重写注解,具有检测功能; 如果当前的方法不是重写方法,则报错
public void eat() {
System.out.println("儿子狼吞虎咽的吃饭");
}
}
public class Test1 {
public static void main(String[] args) {
Son son = new Son();
son.eat();
}
}
五、super用法
super表示父类对象;和this有点类似,只是this表示当前对象
在应用上也和this类似;super可以调用属性,方法,构造方法
super VS this
this调属性:调当前对象的属性;如果当前类没有,则根据继承性,调父类属性
this调方法:调当前对象的方法;如果当前类没有,则根据继承性,调父类方法
this调构造方法:调当前类的构造方法
super调属性:调父类的属性
super调方法:调父类的方法
super调构造方法:调父类的构造方法
super调属性
//super调属性:
class Person{
String name="刘亦菲";
}
class Student extends Person{
String name="凤姐";
public void show() {
System.out.println(name); //凤姐-先调自身,自身没有才调父类属性
System.out.println(this.name); //凤姐-先调自身,自身没有才调父类属性
System.out.println(super.name); //刘亦菲-调父类属性
}
}
public class Test1 {
public static void main(String[] args) {
new Student().show();
}
}
super调方法
//super调方法:调的是父类的方法
class Animal{
public void show() {
System.out.println("父类的show方法");
}
}
class Dog extends Animal{
@Override
public void show() {
super.show(); //先调父类的方法
System.out.println("子类的show方法");
}
}
public class Test2 {
public static void main(String[] args) {
new Dog().show();
}
}
super调构造方法
在构造方法中,默认首句会出现super(); 先调用父类无参构造。
为什么这么设计?
原因是,实例化对象的过程是父类资源+子类资源;否则就不会有继承的特点(调父类属性和方法)
class A{
public A() {
System.out.println("父类A的无参构造");
}
public A(int a) {
System.out.println("父类A的带参构造");
}
}
class B extends A{
public B() {
//super();
System.out.println("子类B的无参构造");
}
public B(int a) {
//super(a); //调父类带参 this和super在构造方法中不能共存
this(); //A无参 B无参 B带参
System.out.println("子类B的带参构造");
}
}
public class Test3 {
public static void main(String[] args) {
//new B(); //父类A无参; 子类B无参
new B(66); //父类A无参; 子类B带参
}
}
六、总结与作业
总结
作业
1.以面向对象的思想,编写自定义类描述IT从业者。设定属性包括:姓名,年龄,技术方向,工作年限;方法包括:工作
要求: 属性需要进行封装,且年龄需要合理判断
2.以面向对象的思想,编写自定义类描述图书信息。设定属性包括:书名,作者,出版社名,价格;方法包括:信息介绍
要求:属性需要进行封装,且价格需要合理判断
3.请用面向对象的思想,设计自定义类描述演员和运动员的信息
设定 (注意: 属性可以暂时不封装)
1)演员类:
属性包括:姓名,年龄,性别,毕业院校,代表作
方法包括:自我介绍
2)运动员类:
属性包括:姓名,年龄,性别,运动项目,历史最好成绩
方法包括:自我介始
要求
3)分析演员和运动员的公共成员,提取出父类—人类
4)利用继承机制,实现演员类和运动员类
5)编写测试类,分别实例化演员类和运动员类对象,并调用属性和方法调用
4.爷爷拥有一辆老爷车,爸爸有一辆跑车,我有一辆玩具车;请设计编程案例, 并通过'我'的对象调出所有父类的方法
要求: 使用super调用方法
5. 设计一个父子类的案例; 实例化子类对象时, 要求,先调用父类的带参构造; 再调用子类无参构造