封装继承

一、封装性

描述:封装之前学习过方法,方法就是一种封装,在面向对象的封装性中,本质上也是讲方法的封装

封装性:在面向对象中,不要直接调属性,而是通过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. 设计一个父子类的案例; 实例化子类对象时, 要求,先调用父类的带参构造; 再调用子类无参构造