Java封装与继承

Java封装与继承

1、垃圾回收机制(Garbage Collection)

JAVA的内存管理实际上指的就是对象的管理,其中包括对象空间的分配和释放。

对象空间的分配:

使用new关键字创建对象即可

对象空间的释放:

将引用数据类型变量赋值null即可。垃圾回收器将负责回收所有“不可达”对象的内存空间。

System.gc() 通知的作用,通知垃圾回收机制回收垃圾,是否回收,什么时候回收无法控制

finalize() 回收垃圾会先调用对象的这个方法

2、package包和导包

在java中我们通过package实现对类的管理,我们将相同功能的类放到一个包中,并且日常项目的分工也是以包作为边界。

注意:同一个包中,不允许有相同的类名。

【示例】包的命名举例

com.object
com.object.demo

注意:com.object和com.object.demo,这两个包没有包含关系,是两个完全独立的包。只是逻辑上看起来后者是前者的一部分。

【示例】包的声明举例

package com.object; // 包的声明,必须在有效代码的第一行(注释不算)
// 以下是业务逻辑所需要的代码
class Person {}

注意:当前包中的类可以直接使用!

2.1 java常用包

常用包 说明
java.lang 包含一些Java语言的核心类,如String、Math、System等。
java.awt 包含了构成抽象窗口工具集(abstract window toolkits)的多个类,这些类被用来构建和管理应用程序的图形用户界面(GUI)。
java.net 包含执行与网络相关的操作的类。
java.io 包含能提供多种输入/输出功能的类。
java.util 包含一些实用工具类,如定义系统特性、使用与日期日历相关的函数。

2.2import导入类

导包的格式:import 包名.类名;

import 导包代码书写的位置:在声明包 package 后,定义所有类 class 前。

【示例】import的使用举例(一)

package com.object; 
// 导入位置:在声明包package后,定义所有类class前。
import java.util.Date; // 导入日期类
public class Test {
	public static void main(String[] args) {
		// 使用Date类
		Date date = new Date();
	}
} 

【示例】import的使用举例(二)

package com.object; 
// 导入位置:在声明包 package后,定义所有类 class前。
import java.util.*; // 导入该包下所有的类。会降低编译速度,但不会降低运行速度。
class Test {
	public static void main(String[] args) {
		// 使用java.util包下的类
		Date date = new Date();
		Scanner s = new Scanner(System.in);
	}
}

注意:如果导入两个同名的类,只能用包名+类名来显示调用相关类。

3、封装(encapsulation)

面向对象编程有三大特性:封装、继承、多态。

封装是指隐藏对象的属性和实现细节,仅对外提供公共的访问方式

封装的优点

  1. 提高代码的安全性。
  2. 提高代码的复用性。

封装原则:

  1. 将不需要对外提供的内容都隐藏起来。
  2. 把属性都隐藏,提供公共方法对其访问。

3.1访问控制符

修饰符 同一个类 同一个包 子类 所有类
private *
default * *
protected * * *
public * * * *

private:表示私有的,作用范围是当前类(类可见性)。

default:表示没有修饰符修饰,作用范围是当前类+当前包(包可见型)。

protected:表示受保护的,作用范围是当前类+当前包+其它包中的子类(子类可见性)。

public:表示公开的,作用范围是是当前类+当前包+其它包(项目可见性)。

注意事项:

  1. 类中的属性和方法访问权限共有四种:private、default、protected和public。
  2. 类的访问权限只有两种:public和default。
  3. 访问权限控制符不能修饰局部变量。

3.2成员变量封装

我们在操作属性时,通常会对数据进行封装,这样就可以增加了数据访问限制,增加了程序可维护性。

实现方式:提供相应的get/set方法来访问相关属性,使用set方法实现对属性的赋值操作,使用get方法实现对属性的取值操作。

关于使用权限修饰符补充:

  1. 属性一般使用private访问权限。
  2. 提供访问相关属性get/set方法通常是public修饰的,以方便对属性的赋值与读取操作。
  3. 一些只用于本类的辅助性方法可以用private修饰,希望其他类调用的方法用public修饰。

【示例】JavaBean的封装实例

class Person {
	// 成员方法,一般使用private修饰
	private String name;
	private int age;
	private boolean marry; // 是否已婚
	// set和get方法,一般使用public修饰
	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;
	}
	// boolean类型的成员变量,get方法是is开头的。
	public boolean isMarry () {
		return marry;
	}
	public void setMarry(boolean marry) {
		this.marry = marry;
	}
}
public class EncapsulationDemo {
	public static void main(String[] args) {
		Person person = new Person();
		// 赋值操作
		// person.name = "小明"; // 编译失败
		person.setName("小明");
		person.setAge(18);
		person.setMarry(true);
		// 取值操作
		// String name = person.name; // 编译失败
		String name = person.getName();
		int age = person.getAge();
		boolean isMarry = person.isMarry);
		System.out.println("name:"+name+" age:"+age+" isMarry:"+isMarry);
	}
}

JavaBean 是一种JAVA语言写成的可重用组件。为写成JavaBean,类必须是具体的和公共的,并且具有无参构造器。JavaBean 通过提供符合一致性设计模式的公共方法将内部域暴露成员属性,并提供set和get方法操作成员成员变量。

【示例】可见性封装的使用案例

class Person {
	// 成员方法
	private String name;
	private int age;
	// 构造方法
	public Person() {}
	public Person(String name, int age) {
		this.name = name;
		// 调用set方法来给年龄赋值
		setAge(age);
	}
	// set和get方法
	public String getName() {
		return name;
	}
	public void setName(String name) {
		this.name = name;
	}
	// 新增需求:获取年龄的时候要求返回虚岁
	public int getAge() {
		return age + 1;
	}
	// 设置年龄的时候是实岁
	public void setAge(int age) {
		// 在赋值之前先判断年龄是否合法
		if (age > 130 || age < 0) {
			this.age = 0; // 不合法赋默认值0
		} else {
			this.age = age; // 合法才能赋值给属性
		}
	}
	// 成员方法
	void show() { 
		// 输出:name: 小明 age: 0,思考:为什么会这样???
		System.out.println("name: " + name + " age: " + age);
	}
}
public class EncapsulationDemo {
	public static void main(String[] args) {
		Person person = new Person();
		// 赋值操作
		person.setName("小明");
		person.setAge(150);
		// 取值操作
		String name = person.getName();
		int age = person.getAge();
		// 调用成员方法
		person.show();
		// 输出:name:小明 age:1,思考:为什么会这样???
		System.out.println("name:" + name + " age:" + age);
	}
}

4、继承(inheritance)

继承是面向对象最显著的一个特性。继承是从已有的类中派生出新的类,新的类能吸收已有类的数据属性和行为,并能扩展新的能力。

在Java之中,如果要实现继承的关系,可以使用如下的语法:

class 父类 {
}
class 子类 extends 父类 {
}

子类又被称为派生类,父类又被称为超类(Super Class)。

【示例】使用extends实现继承

// 父类:Person类
class Person {
	// 成员变量
	private String name;
	// set和get方法
	public String getName() {
		return name;
	}
	public void setName(String name) {
		this.name = name;
	}
	// 成员方法
	public void eat() {
		System.out.println("eat...");
	}
}
// 子类,Teacher类
public class Teacher extends Person {
	// 成员变量
	private String title; // 职称
	// set和get方法
	public String getTitle() {
		return title;
	}
	public void setTitle(String title) {
		this.title = title;
	}
	// 成员方法
	public void teaching() {
		System.out.println("授课...");
	}
}
// 测试类
public class InheritanceDemo {
	public static void main(String[] args) {
		Teacher t = new Teacher();
		t.setName("雨梦"); // 父类属性
		t.setTitle("JavaSE"); // 子类属性
		t.eat(); // 父类方法
		t.teaching(); // 子类方法
		System.out.println("name:"+t.getName()+" age:"+t.getAge());
	}
}

4.1继承的使用要点

继承的好处

  1. 继承的出现提高了代码的复用性,提高软件开发效率。
  2. 继承的出现让类与类之间产生了关系,提供了多态的前提。

继承的注意点

  1. java 只支持单继承,不允许多继承,也就是说一个类只能有一个直接父类。
  2. java 支持多层(重)继承,即一个类的父类可以再去继承另外的父类(继承体系)。
  3. 如果定义一个类时,没有使用extends,则它的父类默认是:java.lang.Object。

5、方法的重写(override)

当父类的方法不能满足子类的需求时,我们可以在子类中重写父类的方法,重写也称为复写。

方法重写需要符合以下三个要点:

  1. == :方法名、形参列表必须相同。

  2. = :访问权限,子类大于等于父类。

    父类的私有方法不能被重写,static修饰的方法不能被重写。

  3. <= :返回值类型和异常类型,子类小于等于父类。

【示例】方法重写案例

// 父类
class Parent {
	public void show(){
		System.out.println("父类中的 show方法执行");
	}
}
// 子类
class Child extends Parent {
	// 子类重写父类的show方法
	public void show(){
		System.out.println("子类中的 show方法执行");
	}
}
public class ExtendsMethodDemo {
	public static void main(String[] args) {
		Child p = new Child();
		p.show(); // 执行的是子类的show方法
	}
}

注意:如果子类重写了父类的方法,通过子类对象调用该方法时,调用的方法就是被覆写过的方法!

如果子类方法需要使用父类方法的功能,可使用super关键字来调用父类方法,该关键字引用了当前对象的父类对象。这样,即沿袭了父类的功能,又定义了子类特有的功能 (super关键字的使用和this非常相似)。

6、super关键字

super可以理解为直接父类对象的引用,或者说super指向子类对象的父类对象存储空间。我们可以通过super来访问父类中被子类覆盖的方法或属性,super的使用和this关键字非常的相似。

【示例】super关键字使用

class Parent {
	String name = "父类";
	public void study() {
		System.out.println("父类中的study方法");
	}
}
class Child extends Parent {
	public void show() {
		// 调用父类的成员方法
		super.study();
		// 调用父类的成员变量
		System.out.println("name:" + super.name);
	}
}
public class SuperDemo extends Parent {
	public static void main(String[] args) {
		new Child().show();
	}
}

6.1super调用父类构造方法

子类继承父类,子类的构造方法必须调用父类的构造方法,如果子类的构造方法中没有显示的调用父类的构造方法,则系统默认调用父类的无参数构造方法。

【示例】默认调用父类的无参数构造方法

class Parent {
	public Parent() {
		System.out.println("parent 构造方法");
	}
}
class Child extends Parent {
	public Child() {
		// 如我们没有显示的使用super(),那么会默认调用父类的无参构造方法
		System.out.println("Child 构造方法");
	}
}
public class SuperDemo {
	public static void main(String[] args) {
		// 创建子类对象,父子类构造方法都执行!!!!
		new Child();
	}
}

若想指定调用父类中的有参构造函数,那么可在supper()中添加参数,指定调用父类中的某个构造函数,而且必须放在构造方法的第一条语句

【示例】指定调用父类构造方法

class Parent {
	String name;
	public Parent() {} // 无参构造方法建议加上!!!
	public Parent(String name) {
		this.name = name;
		System.out.println("parent 构造方法");
	}
}
class Child extends Parent {
	int age;
	public Child(String name, int age) {
		// super(形参列表) 必须放在构造方法的第一行
		super(name);
		this.age = age;
		System.out.println("Child 构造方法");
	}
	void show() {
		// 输出:name:小明 age:18
		System.out.println("name:" + name + " age:" + age);
	}
}
public class SuperDemo {
	public static void main(String[] args) {
		Child child = new Child("小明", 18);
child.show();
	}
}

super()和this()调用构造方法总结:

  1. super():调用父类中的某一个构造方法(必须为构造方法中的第一条语句)。
  2. this():调用本类中某一个构造方法(必须为构造方法中的第一条语句)。

super()和this()都必须在第一条语句,就证明super()和this()不可以同时出现在同一个构造方法中,其原因是super()保证在子类访问父类之前完成对父类的初始化操作,而this()保证父类初始化的唯一性。

thissuper 总结

this和super使用非常的相似,但是表现上却是大不相同,详情请看以下表格。

区别点 this super
定义 this代表本类对象的引用 super代表父类存储空间
使用 this.属性 this.方法 this() super.属性 super.方法() super()
调用构造 调用本类构造,放在第一条语句 调用父类构造,放在第一条语句
查找范围 先从本类找,找不到查找父类 直接查找父类,不查找子类

7、final关键字

final 的意思为最终,不可变。final 是个修饰符,它可以用来修饰类、类中的属性和方法和局部变量,但是不能修饰构造方法。

final的特点

1、final 修饰类不可以被继承,但是可以继承其它类。

class AA {}
final class BB extends AA {} // final修饰类可以继承其他类
class CC extends BB {} // 编译错误,final修饰类不可以被继承

2、final 修饰的方法不可以被覆盖,但子类的方法可以用final修饰。

class AA {
	final public void show1() {}
	void public show2() {}
}
class BB extends AA {
	final public void show1() {} // 编译错误,final修饰的方法不可以被覆盖
	final public void show2() {} // 父类中没有被final修饰方法,子类覆盖后可以加final
}

3、final 修饰的变量称为常量,这些变量只能赋值一次。

final修饰成员变量和静态变量,必须显示的设置初始值,JVM不会设置默认值

常量命名规则:多个有意义的单词连接,所有字符大写,单词之间用下划线分割。

public class FinalDemo {
	// 成员变量必须显示的设置初始值,JVM不会不会设置默认值。
	final String USER_NAME = "xiaoming";
	public static void main(String[] args) {
		// 多个有意义的单词连接,所有字符大写,单词之间用下划线分割.
		final int MAX_VALUE = Integer.MAX_VALUE; 
		// 编译错误,final 修饰的变量称为常量,这些变量只能赋值一次。
		MAX_VALUE = 120;
	}
}

4、final修饰的引用数据类型变量,变量中的地址不能改变,但是指向堆中对象的属性可以修改。

class Person {
	String name = "小明";
}
public class FinalDemo {
	public static void main(String[] args) {
		final Person p = new Person();
		p = new FinalDemo(); // 编译错误,地址值不能更改
		p.name = "小花"; // 地址内的对象属性值可以修改
	}
}

你可能感兴趣的:(Java封装与继承)