面向对象的三大主线:
软件包可以包含类和子包,其帮助管理大型软件系统,将语义相似的类组织到包中,解决类命名冲突的问题。
而关键字package作为Java源文件的第一条语句,即用于声明源文件所在的包;每“.”一次表示一层文件目录,包名都要小写。
其中,JDK中主要的包如下所示:
包名 | 描述 |
---|---|
java.lang | 包含Java语言的核心类,如String、Math、Integer、System、Thread等,提供常用功能 |
java.net | 包含执行与网络相关操作的类和接口 |
java.io | 包含能提供多种输入或输出功能的类 |
java.util | 包含一些实用工具类,如定义系统特性、接口的集合框架类、使用与日期相关的函数等 |
java.text | 包含一些与java格式化相关的类 |
java.sql | 包含进行JDBC数据库编程的相关类/接口 |
java.awt | 包含了构成抽象窗口工具集(abstract window toolkits)的多个类,其被用来构建和管理应用程序的图形用户界面 |
java.applet | 包含applet运行所需的一些类 |
import 包名[.子包名…].<类名 | *>
; 关键字this表示当前对象或当前正在创建的对象,其可以用来修饰属性、方法和构造器。
当形参与成员变量重名时,如果在方法内部需要使用成员变量,必须添加this来声明该变量是类成员;在任意方法内,如果使用当前类的成员变量或成员方法可以在其前面添加this,增强程序的阅读性。
可以在构造器中通过“this(形参列表)”的方式显式的调用当前类的重载的指定构造器,但要求:必须声明在构造器的首行,且需要保证该类中至少有一个构造器是不用this的。
在Java类中使用super来调用父类中的指定操作,即可以修饰或调用父类的属性、方法或构造器。
对比点 | 关键字this | 关键字super |
---|---|---|
访问属性 | 访问本类中的属性,如果本类没有此属性,则从父类中继续查找 | 直接访问父类中的属性 |
访问方法 | 访问本类中的方法 | 直接访问父类中的方法 |
调用构造器 | 调用本类中重载的构造器,必须放在构造器的首行 | 调用父类的构造器,必须放在子类构造器的首行 |
特殊 | 表示当前对象 | 无此概念 |
在Java类中,可用static修饰属性、方法、代码块和内部类,而不能修饰构造器;其主要思想是保证无论该类是否产生对象或无论产生多少对象的情况下,某些特定的数据在内存空间中只有一份。其中,被修饰后的成员具有如下特点:
在Java类中,用static修饰的属性为类变量(类属性),而非static修饰的属性为实例变量。
对比点 | 类变量 | 实例变量 |
---|---|---|
加载时间 | 随着类的加载而加载,早于对象 | 随着对象的创建而加载 |
内存位置 | 存放在静态域中,各对象共同拥有一份,一改则改 | 存放在堆空间中,各对象各自拥有一份 |
调用方式 | “类.类变量” 或 “对象.类变量” | 只能在创建对象后通过“对象.实例变量”的形式来调用 |
对比点 | 类方法 | 非静态方法 |
---|---|---|
加载时间 | 随着类的加载而加载,各对象共同拥有一份 | 随着对象的创建而加载 |
内部可调用 | 只可调用静态的属性或方法,而不能调用非静态的 | 既可调用非静态的属性或方法,也可以调用静态的 |
内部关键字 | 方法内部不可使用this和super关键字,因为其不需要实例就可以访问 | 方法内部可以使用this和super关键字 |
注意:静态的结构随着类的加载而加载,其生命周期早于非静态的结构,同时被回收也要晚于非静态的结构。
静态代码块主要作用是为Java类的类属性进行初始化操作,其随着类的加载而加载,只执行一次,也不可调用非静态的方法和属性。
package com.whut.qiaobc.practice;
public class Person {
/**
* public : 由于JVM需要调用main()方法执行,故其访问权限为公共的
* static : 由于JVM在执行main()方法时无需创建对象,故其为静态的
* void : 该方法无需为JVM返回值,故其返回值为空
* @param args : 命令行参数列表,即执行该程序时所传入的具体参数
* 即若传入的参数为:"qiaobc", "qiaob", "qiaobb",则输出为:
* args[0] = qiaobc,
* args[1] = qiaob,
* args[2] = qiaobb
*/
public static void main(String[] args) {
for (int i = 0; i < args.length; i++) {
System.out.println("args[" + i + "] = " + args[i]);
}
}
}
需求:保证某个类在整个软件系统中只能存在一个对象,且该类只提供一个取得其对象实例的方法;
单例设计模式之饿汉式:
/**
* 单例设计模式之饿汉式:也可通过静态代码块对其进行初始化
* 应用实例:java.lang.Runtime
* @author qiaobc
*/
public class Singleton1 {
// 私有化构造器
private Singleton1() {
// TODO Auto-generated constructor stub
}
// 创建对象实例并私有化、静态化
private static Singleton1 instance= new Singleton1();
// 创建公共的getter()方法获取对象实例、静态的
public static Singleton1 getInstance() {
return instance;
}
}
单例设计模式之懒汉式:与恶汉式的区别在于,懒汉式是在公共方法中才对类进行实例化的,其可能存在线程的安全问题。
/**
* 单例设计模式之懒汉式:存在线程安全问题,但可修复
* @author qiaobc
*/
public class Singleton2 {
// 私有化构造器
private Singleton2() {
// TODO Auto-generated constructor stub
}
// 定义类属性,并私有化、静态化
private static Singleton2 instance = null;
// 创建公共的getter()方法获取对象实例、静态的
public static Singleton2 getInstance() {
// 特点:只有当对象未实例化时才创建,可能存在线程安全问题
if(instance == null) {
instance = new Singleton2();
}
return instance;
}
}
关键字final表示“最终的”,可用来修饰类、属性和方法,具体说明如下:
关键字final修饰的成员变量不能使用默认初始化,其初始化方式主要有:
注意:关键字static和final可以同时修饰属性,表示全局常量,即可以直接被类所调用的常量,如Math.PI。
关键字abstract可以用来修饰类和方法,其前提条件是继承;当我们设计一个类且不需要创建此类的实例时,可以考虑将其设置为抽象类,由其子类提供具体实现该类的抽象方法。
public abstract void methodName();
作用:抽象类是用来模型化那些父类无法确定全部实现,而是由其子类提供具体实现的对象的类。
问题:在航运公司系统中,Vehicle类需要定义两个方法分别计算运输工具的燃料效率和行驶距离;但卡车(Truck)和驳船(RiverBarge)的燃料效率和行驶距离的计算方法完全不同,Vehicle类无法提供计算方法,该如何实现?
// 抽象Vehicle类
public abstract class Vehicle{
public abstract double calcFuelEfficiency(); //计算燃料效率的抽象方法
public abstract double calcTripDistance(); //计算行驶距离的抽象方法
}
// Truck类
public class Truck extends Vehicle{
public double calcFuelEfficiency() {
// 实现计算卡车燃料效率的具体方法
}
public double calcTripDistance() {
// 实现计算卡车行驶距离的具体方法
}
}
// RiverBarge类
public class RiverBarge extends Vehicle{
public double calcFuelEfficiency() {
// 实现计算驳船燃料效率的具体方法
}
public double calcTripDistance() {
// 实现计算驳船行驶距离的具体方法
}
}
抽象类体现的就是一种模板模式的设计,抽象类作为多个子类的通用模板,子类在抽象类的基础上进行扩展和改造,但子类总体上会保留抽象类的行为方式。其解决的问题主要是:
// 抽象类
abstract class Template {
public final void getTime() {
long start = System.currentTimeMillis();
code();
long end = System.currentTimeMillis();
System.out.println("执行时间是:" + (end - start));
}
public abstract void code(); // 抽象方法
}
class SubTemplate extends Template {
public void code() {
for (int i = 0; i < 10000; i++) {
System.out.println(i);
}
}
}
Java语言只支持类的单继承而不支持多继承,但在实际应用中,又经常需要使用多继承来解决问题。为了解决该问题,Java语言提供了接口来实现类的多重继承功能。
接口实质上是一个特殊的抽象类,其是常量与抽象方法的集合,不能包含变量、方法和构造器,具体定义格式如下:
// 接口之间是可以多重继承的,而类之间是单继承的,但类可以实现多个接口
[权限修饰符] interface 接口名 [extends 父接口名列表] {
[public] [static] [final] 常量名; //常量都用public static final默认修饰,可省略
[public] [abstract] 方法名(形参列表); //抽象方法都用public abstract默认修饰,也可省略
}
说明:接口主要用来定义规范,解除耦合关系;其与类是并行的概念,故不可和类重名;另外,接口定义的只是一种功能,该功能不能实例化,但可以被类所实现(implements)。
接口是由类来实现的,实现接口的类必须重写其中所有的抽象方法,才能进行实例化;否则此类只能为抽象类,仍无法进行实例化。其中,接口实现的语法格式如下:
[权限修饰符] class 类名 [extends 父类名] [implements 接口列表]{}
注意:当继承与实现同时存在时,一般先继承后实现;与继承类似,接口与实现类之间也存在多态性。
接口名 对象引用名 = new 接口名() {
// 重写接口的所有抽象方法
}
定义一个用于创建对象的接口,让子类决定实例化哪一个类,即使一个类的实例化延迟到其子类;其主要适用于:
为其他对象提供一种代理以控制对该对象的访问,其示意图如下所示:
在实际开发中,一个类不要去继承一个已经实现好的类,而应该继承一个抽象类,或实现接口。其中,抽象类和接口的对比如下:
对比点 | 抽象类 | 接口 |
---|---|---|
定义 | 包含抽象方法的类 | 全局常量和抽象方法的集合 |
组成 | 常量、变量、构造器、普通方法、抽象方法 | 常量、抽象方法 |
使用 | 子类继承抽象类 | 子类实现接口 |
关系 | 抽象类可以实现多个接口 | 接口不能继承抽象类,但允许继承多个接口 |
常见设计模式 | 模板设计 | 工厂方法、代理模式 |
对象 | 通过对象的多态性产生实例化对象 | 通过对象的多态性产生实例化对象 |
局限 | 单继承 | 无此局限 |
实质 | 作为一个模板 | 作为一个标准或表示一种能力 |
选择 | 抽象类和接口都可以使用时,优先使用接口 | 优先使用接口,避免单继承的局限 |
特殊 | 一个抽象类可以包含多个接口 | 一个接口可以包含多个抽象类 |