Java之类的三要素


面向对象设计的三要素:

  • 封装:用于包装数据属性和动作方法;
  • 继承:用于派生并扩展已有类型;
  • 多态:用于父类和子类之间类型转换与类型检查。

1. 类的封装

1.1 类的成员定义

Java中使用class关键字定义类,类内部 的各种要素被称为 类的成员 ,直白点就像类的属性也叫作成员属性、类的方法也叫作成员方法。

  • 类的基本定义语法
    访问控制符 class 类名 {
    [成员变量声明]
    [构造器声明]
    [成员方法声明]
    }

使用成员方法的好处有:

  • 把属性的读写操作分开
    通过get***方法获取某个属性的值,set***方法 修改/设置某个属性的值。
  • 一个方法可以同时修改多个属性的值
  • 一个方法可以同时输出多个属性的值
    我们通常都是一次性把属性的值输出,这时就要用到我们之前所介绍的toString方法 ,并使用String类提供了 == format 方法==用来格式化。

【代码】

	//演示类的封装,对成员属性和成员方法的定义
	public class OrangeConstruct {
    
    
		private String name; // 定义了橘子的名称
		private double weight; // 定义了橘子的重量
		private boolean isRipe; // 定义了橘子是否成熟。true表示成熟,false表示未成熟
		private String place; // 定义了橘子的产地

	// 设置橘子的产地
	public void setPlace(String inputPlace) {
    
    
		place = inputPlace;
		name = (place.equals("淮北")) ? "枳子" : "橘子";
	}

	// 获取橘子的产地
	public String getPlace() {
    
    
		return place;
	}

	// 设置橘子的名称
	public void setName(String inputName) {
    
    
		name = inputName;
	}

	// 获取橘子的名称
	public String getName() {
    
    
		return name;
	}

	// 设置橘子的重量
	public void setWeight(double inputWeight) {
    
    
		weight = inputWeight;
	}

	// 获取橘子的重量
	public double getWeight() {
    
    
		return weight;
	}

	// 设置橘子是否成熟
	public void setRipe(boolean inputRipe) {
    
    
		isRipe = inputRipe;
	}

	// 获取橘子是否成熟
	public boolean getRipe() {
    
    
		return isRipe;
	}

	// 输出各属性字段的取值
	public String toString() {
    
    
		String desc = String.format("这个%s的重量是%f克,%s成熟,产地是%s。", name, weight,
				isRipe ? "已" : "未", place);
		return desc;
	}

 }

1.2 类的构造方法

构造方法的用途:构建并返回类型的实例。

由于构造方法就是要给外部创建实例用的,因此必须声明为public对外开放;同时构造方法的返回值固定是该类的实例,所以不必重复写明它的返回值。

【代码】

	// 不带参数的构造方法是默认的构造方法
	// 如果当前类未定义其它构造方法,则无需显式定义不带参数的构造方法。
	// 如果当前类已定义其它构造方法,则若想继续使用默认的构造方法,就得显式定义不带参数的构造方法。
	public OrangeConstruct() {
    
    
	}

	// 只有一个输入参数的构造方法
	public OrangeConstruct(String inputPlace) {
    
    
		place = inputPlace;
		name = (place.equals("淮北")) ? "枳子" : "橘子";
	}

	// 拥有三个输入参数的构造方法
	public OrangeConstruct(String inputPlace, double inputWeight, boolean inputRipe) {
    
    
		place = inputPlace;
		name = (place.equals("淮北")) ? "枳子" : "橘子";
		weight = inputWeight;
		isRipe = inputRipe;
	}

注意:一旦定义了带输入参数的构造方法,Java在编译时就不会自动补上默认的构造方法。此时,若想继续使用空默认的构造方法,则需在类定义中写明不带参数的构造方法。

1.3 this关键字的用法

  • 引用成员变量

    this.成员变量 //目的:为了区分参数名与属性名相同的情况
    
  • 调用成员方法

    this.成员方法名(参数列表)//成员方法前面的this可加可不加,即使不加也不会产生歧义
    
  • 调用构造方法

    this(构造方法的变量)
    

this 关键字的构造方法的原则:(非继承的办法,而继承就用super)
(1)在构造方法中使用this关键字。则必须作为其第一条语句;
(2)只能在构造方法中使用this关键字来调用所在类中的其他构造方法;
(3)只能使用this关键字调用其他构造方法,不能使用方法名调用。

【代码】

//演示如何使用this关键字来操作成员属性、成员方法和构造方法
public class OrangeThis {
    
    
	private String name; // 定义了橘子的名称
	private double weight; // 定义了橘子的重量
	private boolean isRipe; // 定义了橘子是否成熟。true表示成熟,false表示未成熟
	private String place; // 定义了橘子的产地

	// 设置橘子的产地
	public void setPlace(String place) {
    
    
		// this.place表示这个place是该类的属性变量,没加this前缀的place是该方法的输入参数
		this.place = place;
		this.name = (place.equals("淮北")) ? "枳子" : "橘子";
	}

	// 获取橘子的产地
	public String getPlace() {
    
    
		return this.place;
	}

	// 设置橘子的名称
	public void setName(String name) {
    
    
		this.name = name;
	}

	// 获取橘子的名称
	public String getName() {
    
    
		return this.name;
	}

	// 设置橘子的重量
	public void setWeight(double weight) {
    
    
		this.weight = weight;
	}

	// 获取橘子的重量
	public double getWeight() {
    
    
		return this.weight;
	}

	// 设置橘子是否成熟
	public void setRipe(boolean isRipe) {
    
    
		this.isRipe = isRipe;
	}

	// 获取橘子是否成熟
	public boolean getRipe() {
    
    
		return this.isRipe;
	}

	// 不带参数的构造方法是默认的构造方法
	// 如果当前类未定义其它构造方法,则无需显式定义不带参数的构造方法。
	// 如果当前类已定义其它构造方法,则
	public OrangeThis() {
    
    
	}

	// 只有一个输入参数的构造方法
	public OrangeThis(String place) {
    
    
		setPlace(place); // 调用该类的成员方法
		// 此时成员方法前面的this可加可不加,即使不加也不会产生歧义
		// this.setPlace(place);
	}

	// 拥有三个输入参数的构造方法
	public OrangeThis(String place, double weight, boolean isRipe) {
    
    
		// 在一个构造方法中调用另一个构造方法,不能直接写类的名称,而要使用this指代构造方法
		this(place);
		this.weight = weight;
		this.isRipe = isRipe;
	}

	// 输出各属性字段的取值
	public String toString() {
    
    
		String desc = String.format("这个%s的重量是%f克,%s成熟,产地是%s。", name, weight,isRipe ? "已" : "未", place);
		return desc;
	}

}

综上所述,类在内部使用成员属性保持数据,通过成员方法表达动作,类的初始化操作则由专门的构造方法完成,并且讨论了this关键字的用法。

2. 类的继承

2.1 类的简单继承

继承说明:

  • Java只支持单继承,不允许多重继承;

  • Java支持多层继承
    一个父类派生子类,子类又可派生子类;

  • 子类继承父类,也就是说父类的成员属性与方法;

  • 子类不能继承父类的构造方法
    构造方法是不能被继承的,但在子类中可以使用super调用父类的构造器;

  • 父类不能拥有子类新增的属性和方法。

2.2 父类: 关键字super的用法

  • 引用父类被覆盖的成员变量
  • 调用父类被重写的成员方法
  • 调用父类的构造方法:子类的构方过程中必须调用其父类的构方
    super关键字调用父类构方的原则:
    (1)在子类构方中使用super关键字时,必须作为构造方法商务第一条语句;
    (2)只能在子类构方中使用super关键字来调用父类的构方;
    (3)只能使用super关键字调用父类构造方法,不能使用方法名之间调用父类构造方法。

2.3 几种开放性修饰符

开放性修饰符 说明
public 公共的,允许所有人访问
无修饰符 友好的,允许当地人访问,对同一个包下面的类很友好
protected 受保护的,允许本家族访问,包括自身及其子类
private 私有的,只有自身可以访问

3. 类的多态

所谓多态,意思是有多种状态。多态的实现依赖于继承,先声明一个父类的实例,再与合适之时给它分别赋予不同的子类实例,此后操作该实例就仿佛操作子类的实例一般。

多态性的3个必要条件:

  • 类的继承
  • 方法重写
  • 父类引用指向子类对象(当父类的方法被重写后,实际当中new的是哪个子类对象,那就调用其方法)

3.1 对象变量多态性

  1. 上转型对象

    父类 父类对象 = 子类实例
    

主要特征:

  • 上转型对象只能访问父类中声明的成员变量和成员方法,不能操作子类新增的成员字段和成员方法;
  • 上转型对象访问重写的同名方法时实际调用的是子类的方法;访问重写的同名变量时实际调用的是父类的变量。

小结:上转型对象调用子类和父类同名的重写方法,则调用的是子类重写父类的方法,如果是调用成员变量则调用的是父类的同名成员变量。(方法、变量与父类当中的属性同名的情况下)。

  1. 下转型对象(强制转换型)

    子类 子类对象 = (子类)父类实例
    

主要特征:

  • 必须通过强制转换将上转型对象还原回子类对象,这时该对象又具备了子类所有的功能和特性。

3.2 对象的类型检查

考虑到父类的对象变量引用的对象类型有可能是父类型,将导致强制向下转型失败,这是Java专门提供了一个类型检查的关键字instanceof,使用格式形式如“A(对象变量名) instanceof B(类型名)”,意思是检查A实例是否属于B类型。

【代码】

	// 利用关键字instanceof检查某实例的归属类
	private static void checkInstance(Chicken chicken) {
    
    
		if (chicken instanceof Cock) {
    
     // 判断这只鸡是不是公鸡
			System.out.println("检查对象实例:这是只公鸡。");
		} else if (chicken instanceof Hen) {
    
     // 判断这只鸡是不是母鸡
			System.out.println("检查对象实例:这是只母鸡。");
		} else {
    
    
			System.out.println("检查对象实例:这既不是公鸡也不是母鸡。");
		}
	}

3.3 终态:关键字final的用法

final可修饰的实体及其产生的影响:

  • 一旦某个类被final修饰,则该类无法再派生出任何子类;
  • 一旦某个成员属性被final修饰,则该属性不能再次赋值,形同常量;
  • 一旦某个成员方法被final修饰,则该方法禁止被子类重写。

对于外部而言,访问终态属性和终态方法的方式并没改变,即“ 实例名称.成员名称

【补充:重写与重载的区别】

重写 总结
1.发生在父类与子类之间
2.方法名,参数列表(参数个数、类型、顺序),返回类型(除过子类中方法的返回类型是父类中返回类型的子类)必须相同
3.访问修饰符的限制一定要大于被重写方法的访问修饰符(public>protected>default>private)
4.重写方法一定不能抛出新的检查异常或者比被重写方法申明更加宽泛的检查型异常

重载 总结
1.重载Overload是一个类中多态性的一种表现
2.重载要求同名方法的参数列表不同(参数类型,参数个数甚至是参数顺序)
3.重载的时候,返回值类型可以相同也可以不相同。无法以返回型别作为重载函数的区分标准

猜你喜欢

转载自blog.csdn.net/weixin_46312449/article/details/111312023